diff --git a/.github/workflows/app-test.yml b/.github/workflows/app-test.yml new file mode 100644 index 0000000..56d65b1 --- /dev/null +++ b/.github/workflows/app-test.yml @@ -0,0 +1,51 @@ +name: app-test + +on: + push: + branches: [master] + paths: + - '**' + - '!*.md' + - '!LICENSE' + - '!.github/**' + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + app-test: + runs-on: ${{ matrix.os }} + name: Test NodeJS ${{ matrix.node_version }} on ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + node_version: ['16', '18', '20'] + os: [windows-latest, macos-latest, ubuntu-latest] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup NodeJS ${{ matrix.node_version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node_version }} + cache: npm + cache-dependency-path: '**/package-lock.json' + + - name: Cache dependencies + uses: actions/cache@v2 + id: npm-cache + with: + path: | + **/node_modules + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + - name: Install dependencies + if: steps.npm-cache.outputs.cache-hit != 'true' + run: npm i + + - name: Test module script + run: npm run test diff --git a/.gitignore b/.gitignore index ac95060..c142c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ release/ dist/ +tests/results/ .eslintcache vite-plugin-electron.log diff --git a/electron-builder.json5 b/electron-builder.json5 index 26209f6..3167731 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -10,7 +10,7 @@ buildResources: './buildAssets/installer/', output: './release/${version}', }, - files: ['dist/**/*', '!release/**/*'], + files: ['dist/**/*', '!release/**/*', '!tests/**/*'], fileAssociations: [ { ext: 'swf', diff --git a/package-lock.json b/package-lock.json index 3c47b3a..fce51f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "serve-handler": "^6.1.5" }, "devDependencies": { + "@playwright/test": "^1.36.1", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@typescript-eslint/parser": "^6.1.0", @@ -44,12 +45,14 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.33.0", "eslint-plugin-react-hooks": "^4.6.0", + "playwright": "^1.36.1", "prettier": "^3.0.0", "typescript": "^5.1.6", "vite": "^4.4.6", "vite-plugin-electron": "^0.12.0", "vite-plugin-electron-renderer": "^0.14.5", - "vite-plugin-eslint": "^1.8.1" + "vite-plugin-eslint": "^1.8.1", + "xvfb-maybe": "^0.2.1" }, "engines": { "node": ">=16.0.0" @@ -3504,6 +3507,25 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.1.tgz", + "integrity": "sha512-YK7yGWK0N3C2QInPU6iaf/L3N95dlGdbsezLya4n0ZCh3IL7VgPGxC6Gnznh9ApWdOmkJeleT2kMTcWPRZvzqg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.36.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -10219,6 +10241,34 @@ "node": ">=4" } }, + "node_modules/playwright": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.36.1.tgz", + "integrity": "sha512-2ZqHpD0U0COKR8bqR3W5IkyIAAM0mT9FgGJB9xWCI1qAUkqLxJskA1ueeQOTH2Qfz3+oxdwwf2EzdOX+RkZmmQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "playwright-core": "1.36.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright-core": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.1.tgz", + "integrity": "sha512-7+tmPuMcEW4xeCL9cp9KxmYpQYHKkyjwoXRnoeTowaeNat8PoBMk/HwCYhqkH2fRkshfKEOiVus/IhID2Pg8kg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/plist": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", @@ -12178,6 +12228,46 @@ "node": ">=8.0" } }, + "node_modules/xvfb-maybe": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xvfb-maybe/-/xvfb-maybe-0.2.1.tgz", + "integrity": "sha512-9IyRz3l6Qyhl6LvnGRF5jMPB4oBEepQnuzvVAFTynP6ACLLSevqigICJ9d/+ofl29m2daeaVBChnPYUnaeJ7yA==", + "dev": true, + "dependencies": { + "debug": "^2.2.0", + "which": "^1.2.4" + }, + "bin": { + "xvfb-maybe": "src/xvfb-maybe.js" + } + }, + "node_modules/xvfb-maybe/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/xvfb-maybe/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/xvfb-maybe/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -14526,6 +14616,17 @@ "tslib": "^2.4.0" } }, + "@playwright/test": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.1.tgz", + "integrity": "sha512-YK7yGWK0N3C2QInPU6iaf/L3N95dlGdbsezLya4n0ZCh3IL7VgPGxC6Gnznh9ApWdOmkJeleT2kMTcWPRZvzqg==", + "dev": true, + "requires": { + "@types/node": "*", + "fsevents": "2.3.2", + "playwright-core": "1.36.1" + } + }, "@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -19400,6 +19501,21 @@ } } }, + "playwright": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.36.1.tgz", + "integrity": "sha512-2ZqHpD0U0COKR8bqR3W5IkyIAAM0mT9FgGJB9xWCI1qAUkqLxJskA1ueeQOTH2Qfz3+oxdwwf2EzdOX+RkZmmQ==", + "dev": true, + "requires": { + "playwright-core": "1.36.1" + } + }, + "playwright-core": { + "version": "1.36.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.1.tgz", + "integrity": "sha512-7+tmPuMcEW4xeCL9cp9KxmYpQYHKkyjwoXRnoeTowaeNat8PoBMk/HwCYhqkH2fRkshfKEOiVus/IhID2Pg8kg==", + "dev": true + }, "plist": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", @@ -20818,6 +20934,42 @@ "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "dev": true }, + "xvfb-maybe": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xvfb-maybe/-/xvfb-maybe-0.2.1.tgz", + "integrity": "sha512-9IyRz3l6Qyhl6LvnGRF5jMPB4oBEepQnuzvVAFTynP6ACLLSevqigICJ9d/+ofl29m2daeaVBChnPYUnaeJ7yA==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "which": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index f0f2fcc..d22bef1 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,17 @@ "dev:debug:force": "vite -d --force", "build": "npm run build:pre && electron-builder -wml", "build:pre": "tsc && vite build", + "build:dir": "npm run build:pre && electron-builder --dir", "build:mac": "npm run build:pre && electron-builder --mac", "build:win": "npm run build:pre && electron-builder --windows", "build:linux": "npm run build:pre && electron-builder --linux", "format": "prettier .", - "format:fix": "prettier . --write" + "format:fix": "prettier . --write", + "test": "npm run build:dir && xvfb-maybe -- playwright test", + "test:nobuild": "xvfb-maybe -- playwright test" }, "devDependencies": { + "@playwright/test": "^1.36.1", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@typescript-eslint/parser": "^6.1.0", @@ -49,12 +53,14 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.33.0", "eslint-plugin-react-hooks": "^4.6.0", + "playwright": "^1.36.1", "prettier": "^3.0.0", "typescript": "^5.1.6", "vite": "^4.4.6", "vite-plugin-electron": "^0.12.0", "vite-plugin-electron-renderer": "^0.14.5", - "vite-plugin-eslint": "^1.8.1" + "vite-plugin-eslint": "^1.8.1", + "xvfb-maybe": "^0.2.1" }, "dependencies": { "@emotion/react": "^11.11.1", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..37cb067 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + outputDir: 'tests/results', +}); diff --git a/src/main/index.ts b/src/main/index.ts index 0fbf28c..1172060 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -56,7 +56,7 @@ global.APP_VERSION_CODE = pkg.versionCode; global.APP_VERSION_DATE = pkg.versionDate; global.APP_AUTHOR = pkg.author; global.APP_RUFFLE_VERSION_DATE = pkg.ruffleVersionDate; -global.ENV_IS_DEV = !app.isPackaged; +global.ENV_IS_DEV = process.env.E2E === 'yes' ? false : !app.isPackaged; global.ENV_OS = CURRENT_OS; global.ENV_IS_WINDOWS = CURRENT_OS === 'Windows'; global.ENV_IS_MAC = CURRENT_OS === 'macOS'; diff --git a/src/renderer/components/layouts/Layout.tsx b/src/renderer/components/layouts/Layout.tsx index f9ed172..925b48d 100644 --- a/src/renderer/components/layouts/Layout.tsx +++ b/src/renderer/components/layouts/Layout.tsx @@ -44,6 +44,7 @@ const Layout = ({ {title} {withTail ? titleTail : ''} + - diff --git a/src/renderer/screens/Explorer.tsx b/src/renderer/screens/Explorer.tsx index 49dd493..029b21f 100644 --- a/src/renderer/screens/Explorer.tsx +++ b/src/renderer/screens/Explorer.tsx @@ -142,6 +142,7 @@ const Explorer = () => {
{ + setTimeout(() => resolve(true), milliseconds); + }); +} + +function isElementVisible(selector: string, waitingMilliseconds = 100) { + return new Promise((resolve) => { + setTimeout(async () => { + expect(await appWindow.isVisible(selector), `Confirm selector '${selector}' is visible`).toBe( + true, + ); + resolve(true); + }, waitingMilliseconds); + }); +} + +test.beforeAll(async () => { + // Open Electron app from build directory + appElectron = await electron.launch({ + args: ['dist/main/index.js'], + env: { E2E: 'yes' }, + }); + appWindow = await appElectron.firstWindow(); + + await appWindow.waitForEvent('load'); +}); + +test('Environment check', async () => { + const isPackaged = await appElectron.evaluate(async ({ app }) => app.isPackaged); + + expect(isPackaged, 'Confirm that is in development mode').toBe(false); +}); + +test('Document element check', async () => { + await isElementVisible('#uiFileOpen'); +}); + +test.afterAll(async () => { + await waiting(3000); + await appElectron.close(); +});