Skip to content

Commit f59e791

Browse files
committed
feat: improve playwright support for electron
This patch adds the possibility to disable natively rendered elements by setting the environment variable THEIA_ELECTRON_DISABLE_NATIVE_ELEMENTS to 1. We need this functionality for testing menu actions or use cases that involve file choosers using electron playwright. When the environment variable is set, the app loader enforces the rendering of HTML menus that playwright can access. Contributed on behalf of STMicroelectronics Signed-off-by: Olaf Lessenich <[email protected]>
1 parent 312c7d0 commit f59e791

18 files changed

+298
-40
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2022 EclipseSource and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
import { PlaywrightTestConfig } from '@playwright/test';
18+
import baseConfig from './playwright.config';
19+
20+
const ciConfig: PlaywrightTestConfig = {
21+
...baseConfig,
22+
workers: 1,
23+
retries: 1
24+
};
25+
26+
export default ciConfig;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
import { PlaywrightTestConfig } from '@playwright/test';
18+
19+
const config: PlaywrightTestConfig = {
20+
testDir: '../lib/tests',
21+
testMatch: ['**/*.js'],
22+
workers: 2,
23+
// Timeout for each test in milliseconds.
24+
timeout: 60 * 1000,
25+
use: {
26+
baseURL: 'http://localhost:3000',
27+
browserName: 'chromium',
28+
screenshot: 'only-on-failure'
29+
},
30+
preserveOutput: 'failures-only',
31+
reporter: [
32+
['list'],
33+
['allure-playwright']
34+
]
35+
};
36+
37+
export default config;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
import { PlaywrightTestConfig } from '@playwright/test';
18+
19+
import baseConfig from './playwright.config';
20+
21+
const debugConfig: PlaywrightTestConfig = {
22+
...baseConfig,
23+
workers: 1,
24+
timeout: 15000000
25+
};
26+
27+
export default debugConfig;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// *****************************************************************************
2+
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License v. 2.0 which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// This Source Code may also be made available under the following Secondary
9+
// Licenses when the conditions for such availability set forth in the Eclipse
10+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
// with the GNU Classpath Exception which is available at
12+
// https://www.gnu.org/software/classpath/license.html.
13+
//
14+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
// *****************************************************************************
16+
17+
import { PlaywrightTestConfig } from '@playwright/test';
18+
19+
import baseConfig from './playwright.config';
20+
21+
const headfulConfig: PlaywrightTestConfig = {
22+
...baseConfig,
23+
workers: 1,
24+
use: {
25+
...baseConfig.use,
26+
headless: false
27+
}
28+
};
29+
30+
export default headfulConfig;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
// override existing rules for ui-tests package
3+
"rules": {
4+
"no-undef": "off", // disabled due to 'browser', '$', '$$'
5+
"no-unused-expressions": "off"
6+
}
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
// override existing rules for ui-tests playwright package
3+
"rules": {
4+
"no-null/no-null": "off"
5+
}
6+
}

examples/playwright/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
"lint": "eslint -c ./.eslintrc.js --ext .ts ./src",
2020
"lint:fix": "eslint -c ./.eslintrc.js --ext .ts ./src --fix",
2121
"playwright:install": "playwright install chromium",
22-
"ui-tests": "yarn build && playwright test",
23-
"ui-tests-headful": "yarn build && playwright test --headed",
22+
"ui-tests": "yarn build && playwright test --config=./configs/playwright.config.ts",
23+
"ui-tests-ci": "yarn build && playwright test --config=./configs/playwright.ci.config.ts",
24+
"ui-tests-headful": "yarn build && playwright test --config=./configs/playwright.headful.config.ts",
2425
"ui-tests-report-generate": "allure generate ./allure-results --clean -o allure-results/allure-report",
2526
"ui-tests-report": "yarn ui-tests-report-generate && allure open allure-results/allure-report"
2627
},

examples/playwright/src/tests/theia-electron-app.test.ts

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,96 @@ import { TheiaExplorerView } from '../theia-explorer-view';
1919
import { TheiaAboutDialog } from '../theia-about-dialog';
2020
import { ElectronLaunchOptions, TheiaElectronAppLoader } from '../theia-app-loader';
2121
import { TheiaWorkspace } from '../theia-workspace';
22+
import { TheiaApp } from '../theia-app';
2223

24+
test.describe.configure({ mode: 'serial' });
2325
test.describe('Theia Electron Application', () => {
2426

27+
let app: TheiaApp;
28+
let ws: TheiaWorkspace;
29+
30+
test.beforeAll(async () => {
31+
ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
32+
app = await TheiaElectronAppLoader.load(new ElectronLaunchOptions('../electron', '../../plugins'), ws);
33+
});
34+
35+
test.afterAll(async () => {
36+
await app.page.close();
37+
});
38+
2539
test('should load and show main content panel', async () => {
26-
const ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
27-
const app = await TheiaElectronAppLoader.load(new ElectronLaunchOptions('../electron', '../../plugins'), ws);
2840
expect(await app.isMainContentPanelVisible()).toBe(true);
41+
});
2942

30-
const quickCommand = app.quickCommandPalette;
43+
test('open about dialog using menu', async () => {
44+
await (await app.menuBar.openMenu('Help')).clickMenuItem('About');
45+
const aboutDialog = new TheiaAboutDialog(app);
46+
expect(await aboutDialog.isVisible()).toBe(true);
47+
await aboutDialog.page.getByRole('button', { name: 'OK' }).click();
48+
expect(await aboutDialog.isVisible()).toBe(false);
49+
});
3150

32-
await quickCommand.open();
33-
expect(await quickCommand.isOpen()).toBe(true);
51+
test('open file via file menu and cancel', async () => {
52+
await (await app.menuBar.openMenu('File')).clickMenuItem('Open File...');
53+
const fileDialog = await app.page.waitForSelector('div[class="dialogBlock"]');
54+
expect(await fileDialog.isVisible()).toBe(true);
55+
await app.page.getByRole('button', { name: 'Cancel' }).click();
56+
expect(await fileDialog.isVisible()).toBe(false);
57+
});
58+
59+
test('open sample.txt via file menu', async () => {
60+
const menuEntry = 'Open File...';
61+
62+
await (await app.menuBar.openMenu('File')).clickMenuItem(menuEntry);
63+
64+
const fileDialog = await app.page.waitForSelector('div[class="dialogBlock"]');
65+
expect(await fileDialog.isVisible()).toBe(true);
66+
67+
const fileEntry = app.page.getByText('sample.txt');
68+
await fileEntry.click();
69+
await app.page.getByRole('button', { name: 'Open' }).click();
3470

71+
const span = await app.page.waitForSelector('span:has-text("content line 2")');
72+
expect(await span.isVisible()).toBe(true);
73+
});
74+
75+
test('open about dialog using command', async () => {
76+
const quickCommand = app.quickCommandPalette;
3577
await quickCommand.open();
3678
await quickCommand.type('About');
3779
await quickCommand.trigger('About');
38-
expect(await quickCommand.isOpen()).toBe(false);
3980
const aboutDialog = new TheiaAboutDialog(app);
4081
expect(await aboutDialog.isVisible()).toBe(true);
41-
await aboutDialog.close();
82+
await aboutDialog.page.getByRole('button', { name: 'OK' }).click();
4283
expect(await aboutDialog.isVisible()).toBe(false);
84+
});
4385

86+
test('select all using command', async () => {
87+
const quickCommand = app.quickCommandPalette;
4488
await quickCommand.type('Select All');
4589
await quickCommand.trigger('Select All');
4690
expect(await quickCommand.isOpen()).toBe(false);
91+
});
4792

93+
test('toggle explorer view using command', async () => {
94+
const quickCommand = app.quickCommandPalette;
4895
await quickCommand.open();
4996
await quickCommand.type('Toggle Explorer');
5097
await quickCommand.trigger('Toggle Explorer View');
51-
expect(await quickCommand.isOpen()).toBe(false);
5298
const explorerView = new TheiaExplorerView(app);
5399
expect(await explorerView.isDisplayed()).toBe(true);
100+
await quickCommand.open();
101+
await quickCommand.type('Toggle Explorer');
102+
await quickCommand.trigger('Toggle Explorer View');
103+
expect(await explorerView.isDisplayed()).toBe(false);
54104
});
55105

106+
test('toggle explorer view using menu', async () => {
107+
await (await app.menuBar.openMenu('View')).clickMenuItem('Explorer');
108+
const explorerView = new TheiaExplorerView(app);
109+
expect(await explorerView.isDisplayed()).toBe(true);
110+
await (await app.menuBar.openMenu('View')).clickMenuItem('Explorer');
111+
expect(await explorerView.isDisplayed()).toBe(false);
112+
});
56113
});
114+

examples/playwright/src/tests/theia-output-view.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,19 @@
1414
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
// *****************************************************************************
1616

17-
import { expect } from '@playwright/test';
17+
import { expect, test } from '@playwright/test';
1818
import { TheiaOutputViewChannel } from 'src/theia-output-channel';
1919
import { TheiaApp } from '../theia-app';
20+
import { TheiaBrowserAppLoader } from '../theia-app-loader';
2021
import { TheiaOutputView } from '../theia-output-view';
21-
import test, { page } from './fixtures/theia-fixture';
2222

23-
let app: TheiaApp;
24-
let outputView: TheiaOutputView;
25-
let testChannel: TheiaOutputViewChannel;
23+
let app: TheiaApp; let outputView: TheiaOutputView; let testChannel: TheiaOutputViewChannel;
2624

2725
test.describe('Theia Output View', () => {
2826

29-
test.beforeAll(async () => {
30-
app = await TheiaApp.load(page);
27+
test.beforeAll(async ({ browser }) => {
28+
const page = await browser.newPage();
29+
app = await TheiaBrowserAppLoader.load(page);
3130
});
3231

3332
test('should open the output view and check if is visible and active', async () => {

examples/playwright/src/tests/theia-terminal-view.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@
1414
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
// *****************************************************************************
1616

17-
import { expect } from '@playwright/test';
17+
import { expect, test } from '@playwright/test';
1818
import { TheiaApp } from '../theia-app';
19+
import { TheiaBrowserAppLoader } from '../theia-app-loader';
1920
import { TheiaWorkspace } from '../theia-workspace';
20-
import test, { page } from './fixtures/theia-fixture';
2121
import { TheiaTerminal } from '../theia-terminal';
2222

2323
let app: TheiaApp;
2424

2525
test.describe('Theia Terminal View', () => {
2626

27-
test.beforeAll(async () => {
27+
test.beforeAll(async ({ browser }) => {
28+
const page = await browser.newPage();
2829
const ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
29-
app = await TheiaApp.load(page, ws);
30+
app = await TheiaBrowserAppLoader.load(page, ws);
3031
});
3132

3233
test('should be possible to open a new terminal', async () => {

0 commit comments

Comments
 (0)