Skip to content

Commit

Permalink
eclipse-theia#10793 Fix playwright tests for Windows and MacOS
Browse files Browse the repository at this point in the history
- Fix workspace path encoding for Windows
- Stabilize workspace path fetching
- Fix explorer review title button selectors
- Introduce OSUtil helper functions
- Fix shortcuts for MacOS
- Improve opening of TheiaViews (speeds up tests by approx. 10s)

Contributed on behalf of STMicroelectronics

Signed-off-by: Nina Doschek <ndoschek@eclipsesource.com>

Fixes eclipse-theia#10793
  • Loading branch information
ndoschek committed Mar 2, 2022
1 parent 481d2cf commit a1cae0e
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 22 deletions.
17 changes: 11 additions & 6 deletions examples/playwright/src/theia-explorer-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { TheiaMenuItem } from './theia-menu-item';
import { TheiaRenameDialog } from './theia-rename-dialog';
import { TheiaTreeNode } from './theia-tree-node';
import { TheiaView } from './theia-view';
import { elementContainsClass, normalizeId } from './util';
import { elementContainsClass, normalizeId, OSUtil, urlEncodePath } from './util';

const TheiaExplorerViewData = {
tabSelector: '#shell-tab-explorer-view-container',
Expand Down Expand Up @@ -75,16 +75,17 @@ export class TheiaExplorerView extends TheiaView {
}

async refresh(): Promise<void> {
await this.clickButton('__explorer-view-container_title:navigator.refresh');
await this.clickButton('navigator.refresh');
}

async collapseAll(): Promise<void> {
await this.clickButton('__explorer-view-container_title:navigator.collapse.all');
await this.clickButton('navigator.collapse.all');
}

protected async clickButton(id: string): Promise<void> {
await this.activate();
const viewElement = await this.viewElement();
await viewElement?.hover();
const button = await viewElement?.waitForSelector(`#${normalizeId(id)}`);
await button?.click();
}
Expand Down Expand Up @@ -161,7 +162,11 @@ export class TheiaExplorerView extends TheiaView {

protected treeNodeId(filePath: string): string {
const workspacePath = this.app.workspace.path;
return `${workspacePath}:${workspacePath}/${filePath}`;
const nodeId = `${workspacePath}:${workspacePath}${OSUtil.fileSeparator}${filePath}`;
if (OSUtil.isWindows) {
return urlEncodePath(nodeId);
}
return nodeId;
}

async clickContextMenuItem(file: string, path: string[]): Promise<void> {
Expand Down Expand Up @@ -199,8 +204,7 @@ export class TheiaExplorerView extends TheiaView {

async getNumberOfVisibleNodes(): Promise<number> {
await this.activate();
await this.app.quickCommandPalette.type('Refresh in Explorer');
await this.app.quickCommandPalette.trigger('File: Refresh in Explorer');
await this.refresh();
const fileStatElements = await this.visibleFileStatNodes(DOT_FILES_FILTER);
return fileStatElements.length;
}
Expand All @@ -224,6 +228,7 @@ export class TheiaExplorerView extends TheiaView {
await renameDialog.enterNewName(newName);
confirm ? await renameDialog.confirm() : await renameDialog.close();
await renameDialog.waitForClosed();
await this.refresh();
}

}
4 changes: 2 additions & 2 deletions examples/playwright/src/theia-quick-command-palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

import { ElementHandle } from '@playwright/test';
import { TheiaPageObject } from './theia-page-object';
import { USER_KEY_TYPING_DELAY } from './util';
import { OSUtil, USER_KEY_TYPING_DELAY } from './util';

export class TheiaQuickCommandPalette extends TheiaPageObject {

selector = '.quick-input-widget';

async open(): Promise<void> {
await this.page.keyboard.press('Control+Shift+p');
await this.page.keyboard.press(OSUtil.isMacOS ? 'Meta+Shift+p' : 'Control+Shift+p');
await this.page.waitForSelector(this.selector);
}

Expand Down
4 changes: 2 additions & 2 deletions examples/playwright/src/theia-rename-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
// *****************************************************************************

import { TheiaDialog } from './theia-dialog';
import { USER_KEY_TYPING_DELAY } from './util';
import { OSUtil, USER_KEY_TYPING_DELAY } from './util';

export class TheiaRenameDialog extends TheiaDialog {

async enterNewName(newName: string): Promise<void> {
const inputField = await this.page.waitForSelector(`${this.blockSelector} .theia-input`);
await inputField.press('Control+a');
await inputField.press(OSUtil.isMacOS ? 'Meta+a' : 'Control+a');
await inputField.type(newName, { delay: USER_KEY_TYPING_DELAY });
await this.page.waitForTimeout(USER_KEY_TYPING_DELAY);
}
Expand Down
9 changes: 6 additions & 3 deletions examples/playwright/src/theia-text-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@
// *****************************************************************************

import { ElementHandle } from '@playwright/test';
import { join } from 'path';

import { TheiaApp } from './theia-app';
import { TheiaEditor } from './theia-editor';
import { normalizeId } from './util';
import { normalizeId, OSUtil, urlEncodePath } from './util';

export class TheiaTextEditor extends TheiaEditor {

constructor(filePath: string, app: TheiaApp) {
// shell-tab-code-editor-opener:file:///c%3A/Users/user/AppData/Local/Temp/cloud-ws-JBUhb6/sample.txt:1
// code-editor-opener:file:///c%3A/Users/user/AppData/Local/Temp/cloud-ws-JBUhb6/sample.txt:1
super({
tabSelector: normalizeId(`#shell-tab-code-editor-opener:file://${app.workspace.escapedPath}/${filePath}:1`),
viewSelector: normalizeId(`#code-editor-opener:file://${app.workspace.escapedPath}/${filePath}:1`) + '.theia-editor'
tabSelector: normalizeId(`#shell-tab-code-editor-opener:file://${urlEncodePath(join(app.workspace.escapedPath, OSUtil.fileSeparator, filePath))}:1`),
viewSelector: normalizeId(`#code-editor-opener:file://${urlEncodePath(join(app.workspace.escapedPath, OSUtil.fileSeparator, filePath))}:1`) + '.theia-editor'
}, app);
}

Expand Down
1 change: 1 addition & 0 deletions examples/playwright/src/theia-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class TheiaView extends TheiaPageObject {
if (!this.data.viewName) {
throw new Error('View name must be specified to open via command palette');
}
await this.app.quickCommandPalette.type('View: Open View');
await this.app.quickCommandPalette.trigger('View: Open View...', this.data.viewName);
await this.waitForVisible();
return this;
Expand Down
23 changes: 15 additions & 8 deletions examples/playwright/src/theia-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
// *****************************************************************************

import * as fs from 'fs-extra';
import { tmpdir } from 'os';
import { sep } from 'path';
import * as path from 'path';
import { resolve } from 'path';
import { OSUtil, urlEncodePath } from './util';

export class TheiaWorkspace {

Expand All @@ -30,14 +29,14 @@ export class TheiaWorkspace {
* @param {string[]} pathOfFilesToInitialize Path to files or folders that shall be copied to the workspace
*/
constructor(protected pathOfFilesToInitialize?: string[]) {
this.workspacePath = fs.mkdtempSync(`${tmpdir}${sep}cloud-ws-`);
this.workspacePath = fs.mkdtempSync(`${OSUtil.tmpDir}${OSUtil.fileSeparator}cloud-ws-`);
}

/** Performs the file system operations preparing the workspace location synchronously. */
initialize(): void {
if (this.pathOfFilesToInitialize) {
for (const initPath of this.pathOfFilesToInitialize) {
const absoluteInitPath = path.resolve(process.cwd(), initPath);
const absoluteInitPath = resolve(process.cwd(), initPath);
if (!fs.pathExistsSync(absoluteInitPath)) {
throw Error('Workspace does not exist at ' + absoluteInitPath);
}
Expand All @@ -47,15 +46,23 @@ export class TheiaWorkspace {
}

get path(): string {
return this.workspacePath;
let workspacePath = this.workspacePath;
if (!OSUtil.osStartsWithFileSeparator(this.workspacePath)) {
workspacePath = `${OSUtil.fileSeparator}${workspacePath}`;
}
if (OSUtil.isWindows) {
// Drive letters in windows paths have to be lower case
workspacePath = workspacePath.replace(/.:/, matchedChar => matchedChar.toLowerCase());
}
return workspacePath;
}

get urlEncodedPath(): string {
return this.path.replace(/[\\]/g, '/');
return urlEncodePath(this.path);
}

get escapedPath(): string {
return this.path.replace(/:/g, '%3A').replace(/[\\]/g, '%5C');
return this.path.replace(/:/g, '%3A');
}

clear(): void {
Expand Down
19 changes: 19 additions & 0 deletions examples/playwright/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// *****************************************************************************

import { ElementHandle } from '@playwright/test';
import { tmpdir, platform } from 'os';
import { sep } from 'path';

export const USER_KEY_TYPING_DELAY = 80;

Expand All @@ -23,6 +25,10 @@ export function normalizeId(nodeId: string): string {
return nodeId.replace(/[.:,%/\\]/g, matchedChar => '\\' + matchedChar);
}

export function urlEncodePath(path: string): string {
return path.replace(/\\/g, '/');
}

export async function toTextContentArray(items: ElementHandle<SVGElement | HTMLElement>[]): Promise<string[]> {
const contents = items.map(item => item.textContent());
const resolvedContents = await Promise.all(contents);
Expand Down Expand Up @@ -70,3 +76,16 @@ export async function elementId(element: ElementHandle<SVGElement | HTMLElement>
if (id === null) { throw new Error('Could not get ID of ' + element); }
return id;
}

export namespace OSUtil {
export const isWindows = platform() === 'win32';
export const isMacOS = platform() === 'darwin';
// The platform-specific file separator '\' or '/'.
export const fileSeparator = sep;
// The platform-specific location of the temporary directory.
export const tmpDir = tmpdir();

export function osStartsWithFileSeparator(path: string): boolean {
return path.startsWith(fileSeparator);
}
}
3 changes: 2 additions & 1 deletion examples/playwright/tests/theia-main-menu.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// *****************************************************************************

import { expect } from '@playwright/test';
import { OSUtil } from '../src/util';
import { TheiaApp } from '../src/theia-app';
import { TheiaMenuBar } from '../src/theia-main-menu';
import test, { page } from './fixtures/theia-fixture';
Expand Down Expand Up @@ -56,7 +57,7 @@ test.describe('Theia Main Menu', () => {
expect(label).toBe('New File');

const shortCut = await menuItem?.shortCut();
expect(shortCut).toBe('Alt+N');
expect(shortCut).toBe(OSUtil.isMacOS ? 'N' : 'Alt+N');

const hasSubmenu = await menuItem?.hasSubmenu();
expect(hasSubmenu).toBe(false);
Expand Down

0 comments on commit a1cae0e

Please sign in to comment.