diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2ec6033e73..65a487ee4e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -103,10 +103,6 @@ jobs: id: 1 - name: "search" id: 2 - - name: "viewer,infoDrawer" - id: 3 - - name: "copyMoveActions" - id: 6 - name: "deleteActions" id: 7 - name: "editActions,favoriteActions" diff --git a/e2e/playwright/search/.eslintrc.json b/e2e/playwright/search/.eslintrc.json new file mode 100644 index 0000000000..44c4872a8d --- /dev/null +++ b/e2e/playwright/search/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../.eslintrc.json", + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "parserOptions": { + "project": [ + "e2e/playwright/search/tsconfig.e2e.json" + ], + "createDefaultProgram": true + }, + "plugins": [ + "rxjs", + "unicorn" + ], + "rules": { + "@typescript-eslint/no-floating-promises": "off" + } + } + ] +} diff --git a/e2e/playwright/search/exclude.tests.json b/e2e/playwright/search/exclude.tests.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/e2e/playwright/search/exclude.tests.json @@ -0,0 +1 @@ +{} diff --git a/e2e/playwright/search/playwright.config.ts b/e2e/playwright/search/playwright.config.ts new file mode 100644 index 0000000000..e5612fef90 --- /dev/null +++ b/e2e/playwright/search/playwright.config.ts @@ -0,0 +1,44 @@ +/*! + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { PlaywrightTestConfig } from '@playwright/test'; +import { CustomConfig, getGlobalConfig, getExcludedTestsRegExpArray } from '@alfresco/playwright-shared'; +import EXCLUDED_JSON from './exclude.tests.json'; + +const config: PlaywrightTestConfig = { + ...getGlobalConfig, + + grepInvert: getExcludedTestsRegExpArray(EXCLUDED_JSON, 'Search'), + projects: [ + { + name: 'Search', + testDir: './src/tests', + use: { + users: [] + } + } + ] +}; + +export default config; diff --git a/e2e/playwright/search/project.json b/e2e/playwright/search/project.json new file mode 100644 index 0000000000..d53fd8db6e --- /dev/null +++ b/e2e/playwright/search/project.json @@ -0,0 +1,22 @@ +{ + "name": "search-e2e", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "e2e/playwright/search", + "projectType": "application", + "targets": { + "e2e": { + "executor": "nx:run-commands", + "options": { + "commands": ["npx playwright test --config=e2e/playwright/search/playwright.config.ts"] + }, + "configurations": { + "production": { + "devServerTarget": "content-ce:serve:production" + } + } + }, + "lint": { + "executor": "@angular-eslint/builder:lint" + } + } +} diff --git a/e2e/playwright/search/src/tests/search-results-general.spec.ts b/e2e/playwright/search/src/tests/search-results-general.spec.ts new file mode 100644 index 0000000000..eadced1968 --- /dev/null +++ b/e2e/playwright/search/src/tests/search-results-general.spec.ts @@ -0,0 +1,155 @@ +/*! + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { expect } from '@playwright/test'; +import { ApiClientFactory, Utils, test, TrashcanApi, NodesApi, SitesApi } from '@alfresco/playwright-shared'; + +test.describe('Search Results - General', () => { + let trashcanApi: TrashcanApi; + let nodesApi: NodesApi; + let sitesApi: SitesApi; + + const username = `user1-${Utils.random()}`; + const random = Utils.random(); + + const file = `test-file-${random}.txt`; + const folder = `test-folder-${random}`; + const site = `test-site-${random}`; + + test.beforeEach(async ({ loginPage }) => { + try { + await loginPage.loginUser({ username, password: username }, { withNavigation: true, waitForLoading: true }); + } catch (error) { + console.error(`beforeEach failed: ${error}`); + } + }); + + test.beforeAll(async () => { + try { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + trashcanApi = await TrashcanApi.initialize(username, username); + nodesApi = await NodesApi.initialize(username, username); + sitesApi = await SitesApi.initialize(username, username); + await nodesApi.createFolder(folder); + await nodesApi.createFile(file, '-my-'); + await sitesApi.createSite(site); + } catch (error) { + console.error(`beforeAll failed: ${error}`); + } + }); + + test.afterAll(async () => { + try { + await trashcanApi.emptyTrashcan(); + await nodesApi.deleteCurrentUserNodes(); + } catch (error) { + console.error(`afterAll failed: ${error}`); + } + }); + + test('[C290005] Only files are returned when Files option is the only one checked', async ({ searchPage }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.checkOnlyFiles(); + await searchPage.searchInput.searchFor(`*${random}`); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290006] Only folders are returned when Folders option is the only one checked', async ({ searchPage }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.checkOnlyFolders(); + await searchPage.searchInput.searchFor(`*${random}`); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290007] Files and folders are returned when both Files and Folders options are checked', async ({ searchPage }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.checkFilesAndFolders(); + await searchPage.searchInput.searchFor(`*${random}`); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeFalsy(); + }); + + test('[C290008] Only libraries are returned when Libraries option is checked', async ({ searchPage }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.checkLibraries(); + await searchPage.searchInput.searchFor(`*${random}`); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + }); + + test('[C279162] Results are updated automatically when changing the search term', async ({ searchPage }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.searchFor(file); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeTruthy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeFalsy(); + + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.searchFor(folder); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(file)).toBeFalsy(); + expect(await searchPage.dataTable.isItemPresent(folder)).toBeTruthy(); + }); + + test('[C279178] Results are returned when accessing an URL containing a search query', async ({ searchPage, personalFiles }) => { + await searchPage.acaHeader.searchButton.click(); + await searchPage.searchInput.searchButton.click(); + await searchPage.searchInput.checkLibraries(); + await searchPage.searchInput.searchFor(site); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + + const url = searchPage.page.url(); + + await personalFiles.navigate(); + await personalFiles.page.goto(url); + await searchPage.dataTable.body.waitFor(); + + expect(await searchPage.dataTable.isItemPresent(site)).toBeTruthy(); + }); +}); diff --git a/e2e/playwright/search/tsconfig.e2e.adf.json b/e2e/playwright/search/tsconfig.e2e.adf.json new file mode 100644 index 0000000000..87cbcf775a --- /dev/null +++ b/e2e/playwright/search/tsconfig.e2e.adf.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.adf.json", + "compilerOptions": { + "outDir": "../../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es2017", + "types": ["jasmine", "jasminewd2", "node"], + "skipLibCheck": true, + "paths": { + "@alfresco/playwright-shared": ["../../../projects/aca-playwright-shared/src/index.ts"] + } + }, + "exclude": ["node_modules"] +} diff --git a/e2e/playwright/search/tsconfig.e2e.json b/e2e/playwright/search/tsconfig.e2e.json new file mode 100755 index 0000000000..c317985239 --- /dev/null +++ b/e2e/playwright/search/tsconfig.e2e.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es2017", + "types": ["jasmine", "jasminewd2", "node", "@playwright/test"], + "skipLibCheck": true, + "paths": { + "@alfresco/playwright-shared": ["../../../projects/aca-playwright-shared/src/index.ts"] + } + }, + "exclude": ["node_modules"] +} diff --git a/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts b/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts index 1110404b0b..62addb8c29 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/dataTable/data-table.component.ts @@ -37,6 +37,7 @@ export class DataTableComponent extends BaseComponent { } public pagination = new PaginationComponent(this.page); + body = this.getChild('.adf-datatable-body') getEmptyFolderLocator = this.getChild('.adf-empty-folder'); getEmptyContentTitleLocator = this.getChild('adf-empty-content .adf-empty-content__title'); getEmptyContentSubTitleLocator = this.getChild('adf-empty-content .adf-empty-content__subtitle'); diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-input.component.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-input.component.ts index 6adf0d7388..df71aa1db4 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/search/search-input.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-input.component.ts @@ -28,7 +28,18 @@ import { timeouts } from '../../../utils'; export class SearchInputComponent extends BaseComponent { private static rootElement = 'aca-page-layout'; - public searchButton = this.getChild('aca-search-input .app-search-button'); + public searchOptionsArea = this.page.locator('mat-checkbox'); + public searchInput = this.getChild('input[id="app-control-input"]'); + public searchButton = this.getChild('.app-search-button'); + public searchButtonWindow = this.page.locator('#app-search-button'); + public searchInputWindow = this.page.locator('.app-search-control'); + public searchInputWindowInput = this.page.locator('.app-search-control input'); + public searchOptions = this.page.locator('#search-options'); + public searchFilesOption = this.searchOptionsArea.getByText(' Files '); + public searchLibrariesOption = this.searchOptionsArea.getByText(' Libraries '); + public searchFoldersOption = this.searchOptionsArea.getByText(' Folders '); + + getIconByName = (name: string): Locator => this.getChild('.mat-icon', { hasText: name }); /** @@ -48,4 +59,71 @@ export class SearchInputComponent extends BaseComponent { await this.getCellLinkByName(name).dblclick(); await this.spinnerWaitForReload(); } + + async clickLibrariesOption() { + await this.searchLibrariesOption.click(); + } + + async clickFilesOption() { + await this.searchFilesOption.click(); + } + + async clickFoldersOption() { + await this.searchFoldersOption.click(); + } + + async isFoldersOptionChecked() { + const optClass = await this.searchFoldersOption.getAttribute('class'); + return optClass.includes('mat-checkbox-checked'); + } + + async isFilesOptionChecked() { + const optClass = await this.searchFilesOption.getAttribute('class'); + return optClass.includes('mat-checkbox-checked'); + } + + async isLibrariesOptionChecked() { + const optClass = await this.searchLibrariesOption.getAttribute('class'); + return optClass.includes('mat-checkbox-checked'); + } + + async clearOptions() { + if (await this.isFilesOptionChecked()) { + await this.clickFilesOption(); + } + if (await this.isFoldersOptionChecked()) { + await this.clickFoldersOption(); + } + if (await this.isLibrariesOptionChecked()) { + await this.clickLibrariesOption(); + } + } + + async checkOnlyFolders() { + await this.clearOptions(); + await this.clickFoldersOption(); + } + + async checkOnlyFiles() { + await this.clearOptions(); + await this.clickFilesOption(); + } + + async checkLibraries() { + await this.clearOptions(); + await this.clickLibrariesOption(); + } + + async checkFilesAndFolders() { + await this.clearOptions(); + await this.clickFilesOption(); + await this.clickFoldersOption(); + } + + async searchFor(text: string) { + await this.searchInputWindow.click(); + await this.searchInputWindowInput.clear(); + await this.searchInputWindow.type(text); + await this.searchButtonWindow.click(); + } }