From 4ffff0b1657b4da662215d9fadb0c2a2c4cd4352 Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 21:51:49 +0300 Subject: [PATCH 1/7] added step to interact with electron app menu --- .github/workflows/pull-request.yml | 9 +++++- CHANGELOG.md | 6 ++++ package.json | 2 +- src/electron.ts | 23 ++++++++++++++ test-e2e/apps/electron/main.js | 20 +++++------- test-e2e/apps/electron/menuTemplate.js | 34 +++++++++++++++++++++ test-e2e/apps/electron/newWindow.js | 14 +++++++++ test-e2e/features/electron/electron.feature | 7 ++++- test-e2e/webui.ts | 8 +++-- 9 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 test-e2e/apps/electron/menuTemplate.js create mode 100644 test-e2e/apps/electron/newWindow.js diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 06a0b92..b3ab14a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -23,7 +23,14 @@ jobs: - run: npm run test - run: npm run install:browsers - run: npm run test:e2e - - name: junit report + - name: junit report (web) + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: './test-e2e/report.xml' + fail_on_failure: true + - run: xvfb-run npm run test:e2e:electron + - name: junit report (electron) uses: mikepenz/action-junit-report@v4 if: always() with: diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0505e..bbd08da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how :microscope: - experimental +## [Unreleased] +- :rocket: added step to interact with electron app menu +```gherkin +When I click 'Test > Open Page' electron menu +``` + ## [2.9.0] - :rocket: added capability to execute script on electron main process ```gherkin diff --git a/package.json b/package.json index e6a4afe..4ea9a4d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "install:browsers": "playwright install", "test:e2e": "qavajs run --config test-e2e/webui.ts", "test:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile electron", - "debug:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile electron", + "debug:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile debugElectron", "debug:e2e": "qavajs run --config test-e2e/webui.ts --profile debug" }, "repository": { diff --git a/src/electron.ts b/src/electron.ts index 77be9f6..ab25799 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -20,4 +20,27 @@ When('I execute {value} function/script on electron app', async function (fn: Me */ When('I execute {value} function/script on electron app and save result as {value}', async function (fn: MemoryValue, memoryKey: MemoryValue) { memoryKey.set(await this.playwright.driver.evaluate(await fn.value())); +}); + +/** + * Click electron menu + * @param {string} menuPath - menu path + * @example I click 'File > Edit' electron menu + */ +When('I click {value} electron menu', async function (menu: MemoryValue) { + await this.playwright.driver.evaluate(async ({ Menu }: { Menu: any }, { menuPath }: { menuPath: string }) => { + const path = menuPath.split(/\s*>\s*/) as string[]; + const menu = Menu.getApplicationMenu(); + if (!menu) throw new Error('Menu is not set'); + const firstMenu = path.shift() as string; + const findItemPredicate = (item: string) => (menu: any) => menu.label === item || menu.role === item; + let currentMenu = menu.items.find(findItemPredicate(firstMenu)); + if (!currentMenu) throw new Error(`Menu '${firstMenu}' is not found`); + for (const pathItem of path) { + if (!currentMenu?.submenu) throw new Error(`Menu '${pathItem}' does not have submenu`); + currentMenu = currentMenu.submenu.items.find(findItemPredicate(pathItem)); + if (!currentMenu) throw new Error(`Menu '${pathItem}' is not found`); + } + currentMenu.click() + }, { menuPath: await menu.value() }); }); \ No newline at end of file diff --git a/test-e2e/apps/electron/main.js b/test-e2e/apps/electron/main.js index 03fad56..b269178 100644 --- a/test-e2e/apps/electron/main.js +++ b/test-e2e/apps/electron/main.js @@ -1,5 +1,7 @@ -const { app, BrowserWindow, ipcMain } = require('electron') +const { app, BrowserWindow, ipcMain, Menu } = require('electron') const path = require('node:path') +const menuTemplate = require('./menuTemplate'); +const handleOpenNewWindow = require('./newWindow'); function createWindow () { const mainWindow = new BrowserWindow({ @@ -10,20 +12,9 @@ function createWindow () { } }) - mainWindow.loadFile('index.html') + return mainWindow.loadFile('index.html') } -function handleOpenNewWindow() { - const newWindow = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - preload: path.join(__dirname, 'preload.js') - } - }) - - newWindow.loadFile('newWindow.html') -} app.whenReady().then(() => { createWindow() @@ -38,6 +29,9 @@ app.whenReady().then(() => { } event.returnValue = null }) + + const menu = Menu.buildFromTemplate(menuTemplate); + Menu.setApplicationMenu(menu); }) app.on('window-all-closed', function () { diff --git a/test-e2e/apps/electron/menuTemplate.js b/test-e2e/apps/electron/menuTemplate.js new file mode 100644 index 0000000..8b21de0 --- /dev/null +++ b/test-e2e/apps/electron/menuTemplate.js @@ -0,0 +1,34 @@ +const handleOpenNewWindow = require("./newWindow"); + +module.exports = [ + { + label: 'Default', + submenu: [ + { + label: 'Open Page', + click: () => { + handleOpenNewWindow() + } + } + ] + }, + { + label: 'Test', + submenu: [ + { + label: 'Open Page', + click: () => { + handleOpenNewWindow() + } + } + ] + }, + { + label: 'Help', + submenu: [ + { + role: 'about', + } + ] + } +]; \ No newline at end of file diff --git a/test-e2e/apps/electron/newWindow.js b/test-e2e/apps/electron/newWindow.js new file mode 100644 index 0000000..e25a3b3 --- /dev/null +++ b/test-e2e/apps/electron/newWindow.js @@ -0,0 +1,14 @@ +const { BrowserWindow } = require('electron') +const path = require('node:path') + +module.exports = function handleOpenNewWindow() { + const newWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + newWindow.loadFile('newWindow.html') +} \ No newline at end of file diff --git a/test-e2e/features/electron/electron.feature b/test-e2e/features/electron/electron.feature index f33b974..460b070 100644 --- a/test-e2e/features/electron/electron.feature +++ b/test-e2e/features/electron/electron.feature @@ -10,4 +10,9 @@ Feature: electron Scenario: evaluate script on main process and save result to memory * I execute '$js(async ({ app }) => app.getAppPath())' script on electron app and save result as 'appPath' - * I expect '$appPath' memory value to contain 'test-e2e/apps/electron' \ No newline at end of file + * I expect '$appPath' memory value to contain 'test-e2e/apps/electron' + + Scenario: open menu + * I click 'Test > Open Page' electron menu + * I switch to 'qavajs electron app new window' window + * I click 'Close Current Window Electron Button' \ No newline at end of file diff --git a/test-e2e/webui.ts b/test-e2e/webui.ts index bb40ce5..33b3fa6 100644 --- a/test-e2e/webui.ts +++ b/test-e2e/webui.ts @@ -34,7 +34,7 @@ const common = { }, format: [ '@qavajs/console-formatter', - 'junit:test-e2e/report.xml', + ['junit', 'test-e2e/report.xml'], ['@qavajs/html-formatter', 'test-e2e/report.html'] ], formatOptions: { @@ -87,7 +87,6 @@ export const electron = { ...common, paths: ['test-e2e/features/electron/*.feature'], retry: 0, - // tags: '@debug', browser: { logLevel: 'warn', timeout: { @@ -100,4 +99,9 @@ export const electron = { } }, parallel: 1 +} + +export const debugElectron = { + ...electron, + tags: '@debug', } \ No newline at end of file From bf0e613345a8a6e75bb746c6e3777e29c7b6d217 Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 22:00:11 +0300 Subject: [PATCH 2/7] added virtual display --- .github/workflows/pull-request.yml | 22 +++++++++++++--------- package.json | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index b3ab14a..e4f5d22 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,15 +21,19 @@ jobs: - run: npm ci - run: npm run build - run: npm run test - - run: npm run install:browsers - - run: npm run test:e2e - - name: junit report (web) - uses: mikepenz/action-junit-report@v4 - if: always() - with: - report_paths: './test-e2e/report.xml' - fail_on_failure: true - - run: xvfb-run npm run test:e2e:electron +# - run: npm run install:browsers +# - run: npm run test:e2e +# - name: junit report (web) +# uses: mikepenz/action-junit-report@v4 +# if: always() +# with: +# report_paths: './test-e2e/report.xml' +# fail_on_failure: true + - name: setup virtual display + run: | + export DISPLAY=:99 + sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & + - run: npm run test:e2e:electron - name: junit report (electron) uses: mikepenz/action-junit-report@v4 if: always() diff --git a/package.json b/package.json index 4ea9a4d..0276487 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "tsc", "test": "vitest --coverage run", - "install:browsers": "playwright install", + "install:browsers": "playwright install chromium --with-deps", "test:e2e": "qavajs run --config test-e2e/webui.ts", "test:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile electron", "debug:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile debugElectron", From 611505398f01794cfbc2e1bdf06fa44af483f3da Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 22:01:41 +0300 Subject: [PATCH 3/7] added xvfb run --- .github/workflows/pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index e4f5d22..76d951d 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -33,7 +33,7 @@ jobs: run: | export DISPLAY=:99 sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & - - run: npm run test:e2e:electron + - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x720x24" npm run test:e2e:electron - name: junit report (electron) uses: mikepenz/action-junit-report@v4 if: always() From 3a503dbf30ed8c7663bdf4c5ff1638b632aa51e1 Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 22:08:25 +0300 Subject: [PATCH 4/7] added electron args --- test-e2e/webui.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-e2e/webui.ts b/test-e2e/webui.ts index 33b3fa6..04a5d21 100644 --- a/test-e2e/webui.ts +++ b/test-e2e/webui.ts @@ -24,7 +24,7 @@ const common = { video: { event: ['onFail'], dir: 'video', - size: { width: 800, height: 600 }, + size: {width: 800, height: 600}, attach: true }, screenshot: { @@ -76,7 +76,7 @@ export const debug = { video: { event: ['afterScenario'], dir: 'video', - size: { width: 800, height: 600 }, + size: {width: 800, height: 600}, attach: true } }, @@ -94,7 +94,7 @@ export const electron = { }, capabilities: { browserName: 'electron', - args: ['test-e2e/apps/electron/main.js'], + args: ['test-e2e/apps/electron/main.js', '--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu'], headless: false } }, From 4a23d1880001386126ff2017dd7b9d537100b643 Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 22:09:35 +0300 Subject: [PATCH 5/7] reactivated web tests --- .github/workflows/pull-request.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 76d951d..3b5bd73 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,14 +21,14 @@ jobs: - run: npm ci - run: npm run build - run: npm run test -# - run: npm run install:browsers -# - run: npm run test:e2e -# - name: junit report (web) -# uses: mikepenz/action-junit-report@v4 -# if: always() -# with: -# report_paths: './test-e2e/report.xml' -# fail_on_failure: true + - run: npm run install:browsers + - run: npm run test:e2e + - name: junit report (web) + uses: mikepenz/action-junit-report@v4 + if: always() + with: + report_paths: './test-e2e/report.xml' + fail_on_failure: true - name: setup virtual display run: | export DISPLAY=:99 From 3f2e42cd2e42d6ecc1f8745031c6e2a2f3aef979 Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Mon, 8 Sep 2025 22:11:39 +0300 Subject: [PATCH 6/7] install only chromium --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0276487..6a238df 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "tsc", "test": "vitest --coverage run", - "install:browsers": "playwright install chromium --with-deps", + "install:browsers": "playwright install chromium", "test:e2e": "qavajs run --config test-e2e/webui.ts", "test:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile electron", "debug:e2e:electron": "qavajs run --config test-e2e/webui.ts --profile debugElectron", From 10a45a40b3e2691cfbf7bf8a4ea210a0281546cb Mon Sep 17 00:00:00 2001 From: Oleksandr_Halichenko Date: Tue, 9 Sep 2025 09:34:34 +0300 Subject: [PATCH 7/7] moved electron tests into separate job --- .github/workflows/pull-request.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 3b5bd73..29f0982 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,7 +8,7 @@ on: - v1 jobs: - test: + test-web: strategy: matrix: version: [ 20, 22, 24 ] @@ -29,6 +29,16 @@ jobs: with: report_paths: './test-e2e/report.xml' fail_on_failure: true + test-electron: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + - run: npm ci + - run: npm run build + - run: npm run test - name: setup virtual display run: | export DISPLAY=:99 @@ -39,4 +49,4 @@ jobs: if: always() with: report_paths: './test-e2e/report.xml' - fail_on_failure: true + fail_on_failure: true \ No newline at end of file