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();
+ }
}