Skip to content

Commit

Permalink
feat: improve playwright support for electron
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
xai committed Jul 28, 2023
1 parent 2e1e3d3 commit 2b018b0
Show file tree
Hide file tree
Showing 27 changed files with 346 additions and 87 deletions.
26 changes: 26 additions & 0 deletions examples/playwright/configs/playwright.ci.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// *****************************************************************************
// Copyright (C) 2022 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { PlaywrightTestConfig } from '@playwright/test';
import baseConfig from './playwright.config';

const ciConfig: PlaywrightTestConfig = {
...baseConfig,
workers: 1,
retries: 1
};

export default ciConfig;
37 changes: 37 additions & 0 deletions examples/playwright/configs/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// *****************************************************************************
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { PlaywrightTestConfig } from '@playwright/test';

const config: PlaywrightTestConfig = {
testDir: '../lib/tests',
testMatch: ['**/*.js'],
workers: 2,
// Timeout for each test in milliseconds.
timeout: 60 * 1000,
use: {
baseURL: 'http://localhost:3000',
browserName: 'chromium',
screenshot: 'only-on-failure'
},
preserveOutput: 'failures-only',
reporter: [
['list'],
['allure-playwright']
]
};

export default config;
27 changes: 27 additions & 0 deletions examples/playwright/configs/playwright.debug.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// *****************************************************************************
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { PlaywrightTestConfig } from '@playwright/test';

import baseConfig from './playwright.config';

const debugConfig: PlaywrightTestConfig = {
...baseConfig,
workers: 1,
timeout: 15000000
};

export default debugConfig;
30 changes: 30 additions & 0 deletions examples/playwright/configs/playwright.headful.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// *****************************************************************************
// Copyright (C) 2021 logi.cals GmbH, EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { PlaywrightTestConfig } from '@playwright/test';

import baseConfig from './playwright.config';

const headfulConfig: PlaywrightTestConfig = {
...baseConfig,
workers: 1,
use: {
...baseConfig.use,
headless: false
}
};

export default headfulConfig;
7 changes: 7 additions & 0 deletions examples/playwright/configs/ui-tests.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// override existing rules for ui-tests package
"rules": {
"no-undef": "off", // disabled due to 'browser', '$', '$$'
"no-unused-expressions": "off"
}
}
6 changes: 6 additions & 0 deletions examples/playwright/configs/ui-tests.playwright.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
// override existing rules for ui-tests playwright package
"rules": {
"no-null/no-null": "off"
}
}
5 changes: 3 additions & 2 deletions examples/playwright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
"lint": "eslint -c ./.eslintrc.js --ext .ts ./src",
"lint:fix": "eslint -c ./.eslintrc.js --ext .ts ./src --fix",
"playwright:install": "playwright install chromium",
"ui-tests": "yarn build && playwright test",
"ui-tests-headful": "yarn build && playwright test --headed",
"ui-tests": "yarn build && playwright test --config=./configs/playwright.config.ts",
"ui-tests-ci": "yarn build && playwright test --config=./configs/playwright.ci.config.ts",
"ui-tests-headful": "yarn build && playwright test --config=./configs/playwright.headful.config.ts",
"ui-tests-report-generate": "allure generate ./allure-results --clean -o allure-results/allure-report",
"ui-tests-report": "yarn ui-tests-report-generate && allure open allure-results/allure-report"
},
Expand Down
6 changes: 3 additions & 3 deletions examples/playwright/src/tests/theia-app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
// *****************************************************************************

import { expect, test } from '@playwright/test';
import { TheiaBrowserAppLoader } from '../theia-app-loader';
import { TheiaAppLoader } from '../theia-app-loader';

test.describe('Theia Application', () => {

test('should load and should show main content panel', async ({ page }) => {
const app = await TheiaBrowserAppLoader.load(page);
test('should load and should show main content panel', async ({ playwright, browser }) => {
const app = await TheiaAppLoader.load({ playwright, browser });
expect(await app.isMainContentPanelVisible()).toBe(true);
});

Expand Down
91 changes: 81 additions & 10 deletions examples/playwright/src/tests/theia-electron-app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,117 @@
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { expect, test } from '@playwright/test';
import { TheiaExplorerView } from '../theia-explorer-view';
import { TheiaAboutDialog } from '../theia-about-dialog';
import { ElectronLaunchOptions, TheiaElectronAppLoader } from '../theia-app-loader';
import { TheiaAppLoader } from '../theia-app-loader';
import { TheiaWorkspace } from '../theia-workspace';
import { TheiaApp } from '../theia-app';
import { TheiaMenuBar } from 'src/theia-main-menu';

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

let app: TheiaApp;
let ws: TheiaWorkspace;
let menuBar: TheiaMenuBar;

test.beforeAll(async ({ playwright, browser }) => {
ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
const args = {
useElectron: {
electronAppPath: '../electron',
pluginsPath: '../../plugins'
},
playwright: playwright,
browser: browser

}
;
app = await TheiaAppLoader.load(args, ws);
menuBar = app.menuBar;
});

test.afterAll(async () => {
await app.page.close();
});

test('should load and show main content panel', async () => {
const ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
const app = await TheiaElectronAppLoader.load(new ElectronLaunchOptions('../electron', '../../plugins'), ws);
expect(await app.isMainContentPanelVisible()).toBe(true);
});

const quickCommand = app.quickCommandPalette;
test('open about dialog using menu', async () => {
await (await menuBar.openMenu('Help')).clickMenuItem('About');
const aboutDialog = new TheiaAboutDialog(app);
expect(await aboutDialog.isVisible()).toBe(true);
await aboutDialog.page.getByRole('button', { name: 'OK' }).click();
expect(await aboutDialog.isVisible()).toBe(false);
});

await quickCommand.open();
expect(await quickCommand.isOpen()).toBe(true);
test('open file via file menu and cancel', async () => {
await (await menuBar.openMenu('File')).clickMenuItem('Open File...');
const fileDialog = await app.page.waitForSelector('div[class="dialogBlock"]');
expect(await fileDialog.isVisible()).toBe(true);
await app.page.getByRole('button', { name: 'Cancel' }).click();
expect(await fileDialog.isVisible()).toBe(false);
});

test('open sample.txt via file menu', async () => {
const menuEntry = 'Open File...';

await (await menuBar.openMenu('File')).clickMenuItem(menuEntry);

const fileDialog = await app.page.waitForSelector('div[class="dialogBlock"]');
expect(await fileDialog.isVisible()).toBe(true);

const fileEntry = app.page.getByText('sample.txt');
await fileEntry.click();
await app.page.getByRole('button', { name: 'Open' }).click();

const span = await app.page.waitForSelector('span:has-text("content line 2")');
expect(await span.isVisible()).toBe(true);
});

test('open about dialog using command', async () => {
const quickCommand = app.quickCommandPalette;
await quickCommand.open();
await quickCommand.type('About');
await quickCommand.trigger('About');
expect(await quickCommand.isOpen()).toBe(false);
const aboutDialog = new TheiaAboutDialog(app);
expect(await aboutDialog.isVisible()).toBe(true);
await aboutDialog.close();
await aboutDialog.page.getByRole('button', { name: 'OK' }).click();
expect(await aboutDialog.isVisible()).toBe(false);
});

test('select all using command', async () => {
const quickCommand = app.quickCommandPalette;
await quickCommand.type('Select All');
await quickCommand.trigger('Select All');
expect(await quickCommand.isOpen()).toBe(false);
});

test('toggle explorer view using command', async () => {
const quickCommand = app.quickCommandPalette;
await quickCommand.open();
await quickCommand.type('Toggle Explorer');
await quickCommand.trigger('Toggle Explorer View');
expect(await quickCommand.isOpen()).toBe(false);
const explorerView = new TheiaExplorerView(app);
expect(await explorerView.isDisplayed()).toBe(true);
await quickCommand.open();
await quickCommand.type('Toggle Explorer');
await quickCommand.trigger('Toggle Explorer View');
expect(await explorerView.isDisplayed()).toBe(false);
});

test('toggle explorer view using menu', async () => {
await (await menuBar.openMenu('View')).clickMenuItem('Explorer');
const explorerView = new TheiaExplorerView(app);
expect(await explorerView.isDisplayed()).toBe(true);
await (await menuBar.openMenu('View')).clickMenuItem('Explorer');
expect(await explorerView.isDisplayed()).toBe(false);
});
});

7 changes: 3 additions & 4 deletions examples/playwright/src/tests/theia-explorer-view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { expect, test } from '@playwright/test';
import { TheiaBrowserAppLoader } from '../theia-app-loader';
import { TheiaAppLoader } from '../theia-app-loader';
import { TheiaApp } from '../theia-app';
import { DOT_FILES_FILTER, TheiaExplorerView } from '../theia-explorer-view';
import { TheiaWorkspace } from '../theia-workspace';
Expand All @@ -27,10 +27,9 @@ test.describe('Theia Explorer View', () => {
let app: TheiaApp;
let explorer: TheiaExplorerView;

test.beforeAll(async ({ browser }) => {
const page = await browser.newPage();
test.beforeAll(async ({ playwright, browser }) => {
const ws = new TheiaWorkspace(['src/tests/resources/sample-files1']);
app = await TheiaBrowserAppLoader.load(page, ws);
app = await TheiaAppLoader.load({ playwright, browser }, ws);
explorer = await app.openView(TheiaExplorerView);
await explorer.waitForVisibleFileNodes();
});
Expand Down
7 changes: 3 additions & 4 deletions examples/playwright/src/tests/theia-main-menu.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { expect, test } from '@playwright/test';
import { TheiaApp } from '../theia-app';
import { TheiaBrowserAppLoader } from '../theia-app-loader';
import { TheiaAppLoader } from '../theia-app-loader';
import { TheiaMenuBar } from '../theia-main-menu';
import { OSUtil } from '../util';

Expand All @@ -27,9 +27,8 @@ test.describe('Theia Main Menu', () => {
let app: TheiaApp;
let menuBar: TheiaMenuBar;

test.beforeAll(async ({ browser }) => {
const page = await browser.newPage();
app = await TheiaBrowserAppLoader.load(page);
test.beforeAll(async ({ playwright, browser }) => {
app = await TheiaAppLoader.load({ playwright, browser });
menuBar = app.menuBar;
});

Expand Down
12 changes: 5 additions & 7 deletions examples/playwright/src/tests/theia-output-view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { expect } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { TheiaOutputViewChannel } from 'src/theia-output-channel';
import { TheiaApp } from '../theia-app';
import { TheiaAppLoader } from '../theia-app-loader';
import { TheiaOutputView } from '../theia-output-view';
import test, { page } from './fixtures/theia-fixture';

let app: TheiaApp;
let outputView: TheiaOutputView;
let testChannel: TheiaOutputViewChannel;
let app: TheiaApp; let outputView: TheiaOutputView; let testChannel: TheiaOutputViewChannel;

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

test.beforeAll(async () => {
app = await TheiaApp.load(page);
test.beforeAll(async ({ playwright, browser }) => {
app = await TheiaAppLoader.load({ playwright, browser });
});

test('should open the output view and check if is visible and active', async () => {
Expand Down
7 changes: 3 additions & 4 deletions examples/playwright/src/tests/theia-preference-view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { expect, test } from '@playwright/test';
import { TheiaApp } from '../theia-app';
import { TheiaBrowserAppLoader } from '../theia-app-loader';
import { TheiaAppLoader } from '../theia-app-loader';
import { DefaultPreferences, PreferenceIds, TheiaPreferenceView } from '../theia-preference-view';

// the tests in this file reuse a page to run faster and thus are executed serially
Expand All @@ -25,9 +25,8 @@ test.describe('Preference View', () => {

let app: TheiaApp;

test.beforeAll(async ({ browser }) => {
const page = await browser.newPage();
app = await TheiaBrowserAppLoader.load(page);
test.beforeAll(async ({ playwright, browser }) => {
app = await TheiaAppLoader.load({ playwright, browser });
});

test.afterAll(async () => {
Expand Down
Loading

0 comments on commit 2b018b0

Please sign in to comment.