From bb3d525475ad2021248384ceb7d4da650c71ab54 Mon Sep 17 00:00:00 2001 From: Nina Doschek Date: Mon, 21 Aug 2023 12:14:37 +0200 Subject: [PATCH] playwright: Update to latest versions and add new page objects - Update `playwright` to the latest version - Extend page objects for compact and nested folders - Extend ExplorerView tests with compact folders Signed-off-by: Nina Doschek --- examples/playwright/package.json | 6 +-- .../src/tests/theia-explorer-view.test.ts | 45 +++++++++++++++++++ .../playwright/src/theia-explorer-view.ts | 44 +++++++++++++----- examples/playwright/src/theia-tree-node.ts | 12 +++++ yarn.lock | 44 +++++++++--------- 5 files changed, 115 insertions(+), 36 deletions(-) diff --git a/examples/playwright/package.json b/examples/playwright/package.json index 33e4af44653cf..190afc368a583 100644 --- a/examples/playwright/package.json +++ b/examples/playwright/package.json @@ -29,13 +29,13 @@ "src" ], "dependencies": { - "@playwright/test": "^1.32.1", + "@playwright/test": "^1.37.1", "fs-extra": "^9.0.8" }, "devDependencies": { "@types/fs-extra": "^9.0.8", - "allure-commandline": "^2.21.0", - "allure-playwright": "^2.1.0", + "allure-commandline": "^2.23.1", + "allure-playwright": "^2.5.0", "rimraf": "^2.6.1", "typescript": "~4.5.5" }, diff --git a/examples/playwright/src/tests/theia-explorer-view.test.ts b/examples/playwright/src/tests/theia-explorer-view.test.ts index 7977acfb2ad8a..fccbe5b55efe6 100644 --- a/examples/playwright/src/tests/theia-explorer-view.test.ts +++ b/examples/playwright/src/tests/theia-explorer-view.test.ts @@ -110,8 +110,11 @@ test.describe('Theia Explorer View', () => { }); test('should be able to check if compact folder "sampleFolderCompact/nestedFolder1/nestedFolder2" exists', async () => { + const fileStatElements = await explorer.visibleFileStatNodes(); // default setting `explorer.compactFolders=true` renders folders in a compact form - single child folders will be compressed in a combined tree element expect(await explorer.existsDirectoryNode('sampleFolderCompact/nestedFolder1/nestedFolder2', true /* compact */)).toBe(true); + // the `existsDirectoryNode` function will expand the folder, hence we wait for the file nodes to increase as we expect a txt child file node + await explorer.waitForFileNodesToIncrease(fileStatElements.length); }); test('should provide file stat node by path of compact folder "sampleFolderCompact/nestedFolder1/nestedFolder2/sampleFile1-1.txt"', async () => { @@ -141,4 +144,46 @@ test.describe('Theia Explorer View', () => { expect(await explorer.existsFileNode('sample.txt')).toBe(true); }); + test('should open context menu on nested folder segment "nestedFolder1"', async () => { + expect(await explorer.existsDirectoryNode('sampleFolderCompact/nestedFolder1/nestedFolder2', true /* compact */)).toBe(true); + const folder = await explorer.getFileStatNodeByLabel('sampleFolderCompact/nestedFolder1/nestedFolder2', true /* compact */); + const menu = await folder.openContextMenuOnSegment('nestedFolder1'); + expect(await menu.isOpen()).toBe(true); + + const menuItems = await menu.visibleMenuItems(); + expect(menuItems).toContain('New File...'); + expect(menuItems).toContain('New Folder...'); + expect(menuItems).toContain('Open in Terminal'); + expect(menuItems).toContain('Find in Folder...'); + + await menu.close(); + expect(await menu.isOpen()).toBe(false); + }); + + test('should rename compact folder "sampleFolderCompact" to "sampleDirectoryCompact', async () => { + expect(await explorer.existsDirectoryNode('sampleFolderCompact/nestedFolder1/nestedFolder2', true /* compact */)).toBe(true); + await explorer.renameNode( + 'sampleFolderCompact/nestedFolder1/nestedFolder2', 'sampleDirectoryCompact', + true /* confirm */, 'sampleFolderCompact' /* nodeSegmentLabel */); + expect(await explorer.existsDirectoryNode('sampleDirectoryCompact/nestedFolder1/nestedFolder2', true /* compact */)).toBe(true); + }); + + test('should delete nested folder "sampleDirectoryCompact/nestedFolder1/nestedFolder2"', async () => { + const fileStatElements = await explorer.visibleFileStatNodes(); + expect(await explorer.existsDirectoryNode('sampleDirectoryCompact/nestedFolder1/nestedFolder2', true /* compact */)).toBe(true); + await explorer.deleteNode('sampleDirectoryCompact/nestedFolder1/nestedFolder2', true /* confirm */, 'nestedFolder2' /* nodeSegmentLabel */); + await explorer.waitForFileNodesToDecrease(fileStatElements.length); + const updatedFileStatElements = await explorer.visibleFileStatNodes(); + expect(updatedFileStatElements.length).toBe(fileStatElements.length - 1); + }); + + test('should delete compact folder "sampleDirectoryCompact/nestedFolder1"', async () => { + const fileStatElements = await explorer.visibleFileStatNodes(); + expect(await explorer.existsDirectoryNode('sampleDirectoryCompact/nestedFolder1', true /* compact */)).toBe(true); + await explorer.deleteNode('sampleDirectoryCompact/nestedFolder1', true /* confirm */, 'sampleDirectoryCompact' /* nodeSegmentLabel */); + await explorer.waitForFileNodesToDecrease(fileStatElements.length); + const updatedFileStatElements = await explorer.visibleFileStatNodes(); + expect(updatedFileStatElements.length).toBe(fileStatElements.length - 1); + }); + }); diff --git a/examples/playwright/src/theia-explorer-view.ts b/examples/playwright/src/theia-explorer-view.ts index 9d70214086628..45d66d572a7dc 100644 --- a/examples/playwright/src/theia-explorer-view.ts +++ b/examples/playwright/src/theia-explorer-view.ts @@ -47,8 +47,8 @@ export class TheiaExplorerFileStatNode extends TheiaTreeNode { return elementContainsClass(this.elementHandle, 'theia-DirNode'); } - async getMenuItemByNamePath(...names: string[]): Promise { - const contextMenu = await this.openContextMenu(); + async getMenuItemByNamePath(names: string[], nodeSegmentLabel?: string): Promise { + const contextMenu = nodeSegmentLabel ? await this.openContextMenuOnSegment(nodeSegmentLabel) : await this.openContextMenu(); const menuItem = await contextMenu.menuItemByNamePath(...names); if (!menuItem) { throw Error('MenuItem could not be retrieved by path'); } return menuItem; @@ -106,8 +106,8 @@ export class TheiaExplorerView extends TheiaView { return []; } - async getFileStatNodeByLabel(label: string): Promise { - const file = await this.fileStatNode(label); + async getFileStatNodeByLabel(label: string, compact = false): Promise { + const file = await this.fileStatNode(label, compact); if (!file) { throw Error('File stat node could not be retrieved by path fragments'); } return file; } @@ -202,11 +202,11 @@ export class TheiaExplorerView extends TheiaView { return nodeId; } - async clickContextMenuItem(file: string, path: string[]): Promise { + async clickContextMenuItem(file: string, path: string[], nodeSegmentLabel?: string): Promise { await this.activate(); - const fileStatNode = await this.fileStatNode(file); + const fileStatNode = await this.fileStatNode(file, !!nodeSegmentLabel); if (!fileStatNode) { throw Error('File stat node could not be retrieved by path fragments'); } - const menuItem = await fileStatNode.getMenuItemByNamePath(...path); + const menuItem = await fileStatNode.getMenuItemByNamePath(path, nodeSegmentLabel); await menuItem.click(); } @@ -248,9 +248,9 @@ export class TheiaExplorerView extends TheiaView { return fileStatElements.length; } - async deleteNode(path: string, confirm = true): Promise { + async deleteNode(path: string, confirm = true, nodeSegmentLabel?: string): Promise { await this.activate(); - await this.clickContextMenuItem(path, ['Delete']); + await this.clickContextMenuItem(path, ['Delete'], nodeSegmentLabel); const confirmDialog = new TheiaDialog(this.app); await confirmDialog.waitForVisible(); @@ -258,9 +258,9 @@ export class TheiaExplorerView extends TheiaView { await confirmDialog.waitForClosed(); } - async renameNode(path: string, newName: string, confirm = true): Promise { + async renameNode(path: string, newName: string, confirm = true, nodeSegmentLabel?: string): Promise { await this.activate(); - await this.clickContextMenuItem(path, ['Rename']); + await this.clickContextMenuItem(path, ['Rename'], nodeSegmentLabel); const renameDialog = new TheiaRenameDialog(this.app); await renameDialog.waitForVisible(); @@ -285,4 +285,26 @@ export class TheiaExplorerView extends TheiaView { } } + async waitForFileNodesToIncrease(numberBefore: number): Promise { + const fileStatNodesSelector = `${this.viewSelector} .theia-FileStatNode`; + await this.page.waitForFunction( + (predicate: { selector: string; numberBefore: number; }) => { + const elements = document.querySelectorAll(predicate.selector); + return !!elements && elements.length > predicate.numberBefore; + }, + { selector: fileStatNodesSelector, numberBefore } + ); + } + + async waitForFileNodesToDecrease(numberBefore: number): Promise { + const fileStatNodesSelector = `${this.viewSelector} .theia-FileStatNode`; + await this.page.waitForFunction( + (predicate: { selector: string; numberBefore: number; }) => { + const elements = document.querySelectorAll(predicate.selector); + return !!elements && elements.length < predicate.numberBefore; + }, + { selector: fileStatNodesSelector, numberBefore } + ); + } + } diff --git a/examples/playwright/src/theia-tree-node.ts b/examples/playwright/src/theia-tree-node.ts index 6114bbbf89c12..27967ea8593d5 100644 --- a/examples/playwright/src/theia-tree-node.ts +++ b/examples/playwright/src/theia-tree-node.ts @@ -23,6 +23,7 @@ import { TheiaMenu } from './theia-menu'; export class TheiaTreeNode { labelElementCssClass = '.theia-TreeNodeSegmentGrow'; + nodeSegmentLabelCssClass = '.theia-tree-compressed-label-part'; expansionToggleCssClass = '.theia-ExpansionToggle'; collapsedCssClass = '.theia-mod-collapsed'; @@ -66,4 +67,15 @@ export class TheiaTreeNode { return TheiaContextMenu.open(this.app, () => this.elementHandle.waitForSelector(this.labelElementCssClass)); } + async openContextMenuOnSegment(nodeSegmentLabel: string): Promise { + const treeNodeLabel = await this.elementHandle.waitForSelector(this.labelElementCssClass); + const treeNodeLabelSegments = await treeNodeLabel.$$(`span${this.nodeSegmentLabelCssClass}`); + for (const segmentLabel of treeNodeLabelSegments) { + if (await segmentLabel.textContent() === nodeSegmentLabel) { + return TheiaContextMenu.open(this.app, () => Promise.resolve(segmentLabel)); + } + } + throw new Error('Could not find tree node segment label "' + nodeSegmentLabel + '"'); + } + } diff --git a/yarn.lock b/yarn.lock index 7b80f2c2101fc..c89541b2757fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1556,13 +1556,13 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@playwright/test@^1.32.1": - version "1.35.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.35.1.tgz#a596b61e15b980716696f149cc7a2002f003580c" - integrity sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA== +"@playwright/test@^1.37.1": + version "1.37.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.37.1.tgz#e7f44ae0faf1be52d6360c6bbf689fd0057d9b6f" + integrity sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg== dependencies: "@types/node" "*" - playwright-core "1.35.1" + playwright-core "1.37.1" optionalDependencies: fsevents "2.3.2" @@ -2733,25 +2733,25 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.6.3, ajv@^8.9.0: require-from-string "^2.0.2" uri-js "^4.2.2" -allure-commandline@^2.21.0: - version "2.23.0" - resolved "https://registry.yarnpkg.com/allure-commandline/-/allure-commandline-2.23.0.tgz#fdea57adee905808c0953ac51a234e474e9f5c27" - integrity sha512-bfAbyQzke0Gj48bxIAhHOcJ6DluYeR4uz3iQ1wJWx7TgGA1gazN1PXUtpr+wnX9eXCTRApEuggaJIduLik7Wsg== +allure-commandline@^2.23.1: + version "2.23.1" + resolved "https://registry.yarnpkg.com/allure-commandline/-/allure-commandline-2.23.1.tgz#b72ee444f586ab6ea403006960dfb4e641524c76" + integrity sha512-Qi1P8aFTwcD2XOYr4xqysPbgXFrl5JLY9jDBVQfOb6xkZ7/UtISfW6j0sAyVgMXyXQqYiQDSBcVS2wr1bm1Xlg== -allure-js-commons@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/allure-js-commons/-/allure-js-commons-2.4.0.tgz#1f75ff0ac153e30aaf4a4eb835fc6e55ee6610c6" - integrity sha512-mIQKAA91ihtMPzHJh7fQib/8MhZaUQ0oYtqFzS//5/Q+ILbMWW3WD2ISWtwniFAF2XWdRFjZ013IfUuKusbh1g== +allure-js-commons@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/allure-js-commons/-/allure-js-commons-2.5.0.tgz#ea589a25d61bbd9b117ba62d06ee2bc3e138bfad" + integrity sha512-CqhzJciKfM0fxImbfRSctPXTxnzxhD2rM1tX/ZkcyKyWzNmjdCn1n5j3/r5gPYeRfIT1NthLYcUF802tJ05QDg== dependencies: properties "^1.2.1" uuid "^8.3.0" -allure-playwright@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/allure-playwright/-/allure-playwright-2.4.0.tgz#8b8ce4ac27290dbc87120029d12aefc8b1477b75" - integrity sha512-YtOdQXKPUFFfXVEPUaH5ebNf/2tLmJ1q898l+TPCPBeTQWVpKxLJm5yQkBbu+cmbsN+FGCsfDHFiqcS/r6f71w== +allure-playwright@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/allure-playwright/-/allure-playwright-2.5.0.tgz#734662971a4377f32ba341555c141f128a8ef453" + integrity sha512-DjkC9PLwmakzr9TrJ7jjv2tZBtO0i1vTDuvJcO9EhcqhejkGecupc5VtczxrDAlR7wWS4GCeOHTCT8mchBonxQ== dependencies: - allure-js-commons "2.4.0" + allure-js-commons "2.5.0" anser@^2.0.1: version "2.1.1" @@ -8895,10 +8895,10 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -playwright-core@1.35.1: - version "1.35.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.35.1.tgz#52c1e6ffaa6a8c29de1a5bdf8cce0ce290ffb81d" - integrity sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg== +playwright-core@1.37.1: + version "1.37.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.37.1.tgz#cb517d52e2e8cb4fa71957639f1cd105d1683126" + integrity sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA== postcss-modules-extract-imports@^3.0.0: version "3.0.0"