diff --git a/e2e/playwright/search/src/tests/search-sorting.spec.ts b/e2e/playwright/search/src/tests/search-sorting.spec.ts
new file mode 100644
index 000000000..ce98d0312
--- /dev/null
+++ b/e2e/playwright/search/src/tests/search-sorting.spec.ts
@@ -0,0 +1,180 @@
+/*!
+ * 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,
+ FileActionsApi,
+ TEST_FILES,
+ SearchPage,
+ SortByDirection,
+ SortByType
+} from '@alfresco/playwright-shared';
+
+test.describe('Search sorting', () => {
+ const random = Utils.random();
+
+ const user1 = `user1-${random}`;
+ const user2 = `user2-${random}`;
+
+ const parent = `parent-${random}`;
+ let parentId: string;
+
+ const fileJpg = {
+ name: `search-sort-${random}-file-1.jpg`,
+ source: TEST_FILES.JPG_FILE.path
+ };
+
+ const filePdf = {
+ name: `search-sort-${random}-file-2.pdf`,
+ title: 'search sort title',
+ description: 'search-sort-${random}-file',
+ source: TEST_FILES.PDF.path
+ };
+
+ let nodesApi1: NodesApi;
+ let trashcanApi1: TrashcanApi;
+ let fileActionsApi1: FileActionsApi;
+ let nodesApi2: NodesApi;
+ let trashcanApi2: TrashcanApi;
+ let fileActionsApi2: FileActionsApi;
+
+ test.beforeAll(async () => {
+ try {
+ const apiClientFactory = new ApiClientFactory();
+ await apiClientFactory.setUpAcaBackend('admin');
+ await apiClientFactory.createUser({ username: user1 });
+ await apiClientFactory.createUser({ username: user2 });
+ nodesApi1 = await NodesApi.initialize(user1, user1);
+ trashcanApi1 = await TrashcanApi.initialize(user1, user1);
+ fileActionsApi1 = await FileActionsApi.initialize(user1, user1);
+ nodesApi2 = await NodesApi.initialize(user2, user2);
+ trashcanApi2 = await TrashcanApi.initialize(user2, user2);
+ fileActionsApi2 = await FileActionsApi.initialize(user2, user2);
+ } catch (error) {
+ console.error(`beforeAll failed : ${error}`);
+ }
+
+ parentId = (await nodesApi1.createFolder(parent)).entry.id;
+
+ await nodesApi1.setGranularPermission(parentId, true, user2, 'Collaborator');
+
+ await fileActionsApi1.uploadFileWithRename(fileJpg.source, fileJpg.name, parentId);
+ await fileActionsApi2.uploadFileWithRename(filePdf.source, filePdf.name, parentId, filePdf.title, filePdf.description);
+
+ await fileActionsApi1.waitForNodes(fileJpg.name, { expect: 1 });
+ await fileActionsApi2.waitForNodes(filePdf.name, { expect: 1 });
+ });
+
+ test.beforeEach(async ({ loginPage }) => {
+ await Utils.tryLoginUser(loginPage, user1, user1, 'beforeEach failed');
+ });
+
+ test.afterAll(async () => {
+ await Utils.deleteNodesSitesEmptyTrashcan(nodesApi1, trashcanApi1, 'afterAll failed');
+ await Utils.deleteNodesSitesEmptyTrashcan(nodesApi2, trashcanApi2, 'afterAll failed');
+ });
+
+ async function testSearchSorting(
+ searchPage: SearchPage,
+ sortBy: SortByType,
+ sortOrder: SortByDirection,
+ expectedFirstFile: string,
+ expectedSecondFile: string
+ ) {
+ await searchPage.searchWithin(`search-sort *${random}`, 'files');
+
+ await searchPage.searchSortingPicker.sortBy(sortBy, sortOrder);
+
+ expect(await searchPage.dataTable.getNthRow(1).textContent()).toContain(expectedFirstFile);
+ expect(await searchPage.dataTable.getNthRow(2).textContent()).toContain(expectedSecondFile);
+ }
+
+ [
+ {
+ column: 'Name',
+ id: 'C277728',
+ firstFile: fileJpg.name,
+ secondFile: filePdf.name
+ },
+ {
+ column: 'Type',
+ id: 'C277740',
+ firstFile: filePdf.name,
+ secondFile: fileJpg.name
+ },
+ {
+ column: 'Size',
+ id: 'C277738',
+ firstFile: filePdf.name,
+ secondFile: fileJpg.name
+ },
+ {
+ column: 'Created date',
+ id: 'C277734',
+ firstFile: fileJpg.name,
+ secondFile: filePdf.name
+ },
+ {
+ column: 'Modified date',
+ id: 'C277736',
+ firstFile: fileJpg.name,
+ secondFile: filePdf.name
+ },
+ {
+ column: 'Relevance',
+ id: 'C277727',
+ firstFile: fileJpg.name,
+ secondFile: filePdf.name
+ },
+ {
+ column: 'Modifier',
+ id: 'C277732',
+ firstFile: fileJpg.name,
+ secondFile: filePdf.name
+ }
+ ].forEach((testCase) => {
+ test(`[${testCase.id}] Sort by ${testCase.column}`, async ({ searchPage }) => {
+ await testSearchSorting(searchPage, testCase.column as SortByType, 'asc', testCase.firstFile, testCase.secondFile);
+ });
+ });
+
+ test('[C277722] Sorting options are displayed', async ({ searchPage }) => {
+ await searchPage.searchWithin(`search-sort *${random}`, 'files');
+ await searchPage.searchSortingPicker.actionMenu.click();
+
+ expect(await searchPage.searchSortingPicker.isSortOrderButtonDisplayed()).toBe(true);
+
+ await searchPage.searchSortingPicker.clickSortByDropdown();
+
+ const expectedOptions = ['Relevance', 'Filename', 'Title', 'Modified date', 'Modifier', 'Created date', 'Size', 'Type'];
+ expectedOptions.sort((a, b) => a.localeCompare(b));
+ const optionListed = await searchPage.searchSortingPicker.getSortByOptionsList();
+ expect(optionListed).toEqual(expectedOptions);
+ });
+});
diff --git a/e2e/protractor/suites/search/search-input.test.ts b/e2e/protractor/suites/search/search-input.test.ts
deleted file mode 100644
index 1c35e196d..000000000
--- a/e2e/protractor/suites/search/search-input.test.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*!
- * 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 { BrowsingPage, LoginPage, Utils } from '@alfresco/aca-testing-shared';
-
-describe('Search input', () => {
- const loginPage = new LoginPage();
- const page = new BrowsingPage();
- const { toolbar } = page;
- const { searchInput } = page.pageLayoutHeader;
-
- beforeAll(async () => {
- await loginPage.loginWithAdmin();
- });
-
- beforeEach(async () => {
- await Utils.pressEscape();
- await page.clickPersonalFiles();
- });
-
- it('[C289847] Search icon is displayed in toolbar and clicking on it displays search input container', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
-
- expect(await searchInput.isSearchContainerDisplayed()).toBe(true, 'search controls not displayed');
- });
-
- it('[C289848] Search options are displayed when clicking in the search input', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- expect(await searchInput.isOptionsAreaDisplayed()).toBe(true, 'Search options not displayed');
- expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled');
- expect(await searchInput.isFoldersOptionEnabled()).toBe(true, 'Folders option not enabled');
- expect(await searchInput.isLibrariesOptionEnabled()).toBe(true, 'Libraries option not enabled');
- expect(await searchInput.isFilesOptionChecked()).toBe(false, 'Files option is checked');
- expect(await searchInput.isFoldersOptionChecked()).toBe(false, 'Folders option is checked');
- expect(await searchInput.isLibrariesOptionChecked()).toBe(false, 'Libraries option is checked');
- });
-
- it('[C289849] Search options are correctly enabled / disabled', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
-
- await searchInput.clickFilesOption();
- expect(await searchInput.isFoldersOptionEnabled()).toBe(true, 'Folders option not enabled');
- expect(await searchInput.isLibrariesOptionEnabled()).toBe(false, 'Libraries option not disabled');
-
- await searchInput.clickFilesOption();
- expect(await searchInput.isFoldersOptionEnabled()).toBe(true, 'Folders option not enabled');
- expect(await searchInput.isLibrariesOptionEnabled()).toBe(true, 'Folders option not enabled');
-
- await searchInput.clickFoldersOption();
- expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled');
- expect(await searchInput.isLibrariesOptionEnabled()).toBe(false, 'Libraries option not disabled');
-
- await searchInput.clickFoldersOption();
- expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled');
- expect(await searchInput.isLibrariesOptionEnabled()).toBe(true, 'Libraries option not enabled');
-
- await searchInput.clickLibrariesOption();
- expect(await searchInput.isFilesOptionEnabled()).toBe(false, 'Files option not disabled');
- expect(await searchInput.isFoldersOptionEnabled()).toBe(false, 'Folders option not disabled');
-
- await searchInput.clickLibrariesOption();
- expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled');
- expect(await searchInput.isFoldersOptionEnabled()).toBe(true, 'Folders option not enabled');
- });
-});
diff --git a/e2e/protractor/suites/search/search-results-files-folders.test.ts b/e2e/protractor/suites/search/search-results-files-folders.test.ts
deleted file mode 100644
index 982d5b83c..000000000
--- a/e2e/protractor/suites/search/search-results-files-folders.test.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-/*!
- * 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 { AdminActions, LoginPage, SearchResultsPage, RepoClient, Utils } from '@alfresco/aca-testing-shared';
-
-describe('Search results - files and folders', () => {
- const random = Utils.random();
- const username = `user-${random}`;
-
- const file = `test-file-${random}.txt`;
- let fileId: string;
- const fileTitle = 'file title';
- const fileDescription = 'file description';
-
- /* cspell:disable-next-line */
- const fileRussian = `любимый-сайт-${random}`;
- let fileRussianId: string;
-
- const folder = `test-folder-${random}`;
- let folderId: string;
- const folderTitle = 'folder title';
- const folderDescription = 'folder description';
-
- const site = `test-site-${random}`;
-
- const apis = {
- user: new RepoClient(username, username)
- };
-
- const loginPage = new LoginPage();
- const page = new SearchResultsPage();
- const { searchInput } = page.pageLayoutHeader;
- const { dataTable, breadcrumb, toolbar } = page;
- const adminApiActions = new AdminActions();
-
- beforeAll(async () => {
- await adminApiActions.createUser({ username });
-
- fileId = (await apis.user.nodes.createFile(file, '-my-', fileTitle, fileDescription)).entry.id;
- await apis.user.nodes.updateNodeContent(fileId, 'edited by user');
- folderId = (await apis.user.nodes.createFolder(folder, '-my-', folderTitle, folderDescription)).entry.id;
- fileRussianId = (await apis.user.nodes.createFile(fileRussian)).entry.id;
- await apis.user.sites.createSite(site);
-
- await apis.user.search.waitForApi(username, { expect: 2 });
- await apis.user.queries.waitForSites(site, { expect: 1 });
-
- await loginPage.loginWith(username);
- });
-
- beforeEach(async () => {
- await page.refresh();
- await page.clickPersonalFilesAndWait();
- });
-
- afterAll(async () => {
- await Promise.all([
- apis.user.nodes.deleteNodeById(fileId),
- apis.user.nodes.deleteNodeById(fileRussianId),
- apis.user.nodes.deleteNodeById(folderId),
- apis.user.sites.deleteSite(site)
- ]);
- });
-
- it('[C290029] Search file with special characters', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkFilesAndFolders();
- await searchInput.searchFor(fileRussian);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(fileRussian)).toBe(true, `${fileRussian} is not displayed`);
- });
-
- it('[C279177] Location column redirect - file in user Home', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkFilesAndFolders();
- await searchInput.searchFor(file);
- await dataTable.waitForBody();
-
- await dataTable.clickItemLocation(file);
- expect(await breadcrumb.getAllItems()).toEqual(['Personal Files']);
- });
-});
diff --git a/e2e/protractor/suites/search/search-results-general.test.ts b/e2e/protractor/suites/search/search-results-general.test.ts
deleted file mode 100644
index 6b7e8df17..000000000
--- a/e2e/protractor/suites/search/search-results-general.test.ts
+++ /dev/null
@@ -1,156 +0,0 @@
-/*!
- * 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 { AdminActions, LoginPage, SearchResultsPage, RepoClient, Utils } from '@alfresco/aca-testing-shared';
-import { browser } from 'protractor';
-
-describe('Search results general', () => {
- const random = Utils.random();
- const username = `user-${random}`;
-
- const file = `test-file-${random}.txt`;
- let fileId: string;
- const folder = `test-folder-${random}`;
- let folderId: string;
- const site = `test-site-${random}`;
-
- const apis = {
- user: new RepoClient(username, username)
- };
-
- const loginPage = new LoginPage();
- const page = new SearchResultsPage();
- const { searchInput, toolbar } = page.pageLayoutHeader;
- const dataTable = page.dataTable;
- const adminApiActions = new AdminActions();
-
- beforeAll(async () => {
- await adminApiActions.createUser({ username });
-
- fileId = (await apis.user.nodes.createFile(file)).entry.id;
- folderId = (await apis.user.nodes.createFolder(folder)).entry.id;
- await apis.user.sites.createSite(site);
-
- await apis.user.search.waitForApi(username, { expect: 1 });
- await apis.user.queries.waitForSites(site, { expect: 1 });
-
- await loginPage.loginWith(username);
- });
-
- afterAll(async () => {
- await Promise.all([apis.user.nodes.deleteNodeById(fileId), apis.user.nodes.deleteNodeById(folderId), apis.user.sites.deleteSite(site)]);
- });
-
- beforeEach(async () => {
- await page.refresh();
- });
-
- afterEach(async () => {
- await Utils.pressEscape();
- await page.clickPersonalFiles();
- });
-
- it('[C290005] Only files are returned when Files option is the only one checked', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkOnlyFiles();
- await searchInput.searchFor(`*${random}`);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(file)).toBe(true, `${file} not displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(false, `${folder} is displayed`);
- expect(await dataTable.isItemPresent(site)).toBe(false, `${site} is displayed`);
- });
-
- it('[C290006] Only folders are returned when Folders option is the only one checked', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkOnlyFolders();
- await searchInput.searchFor(`*${random}`);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(file)).toBe(false, `${file} is displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(true, `${folder} not displayed`);
- expect(await dataTable.isItemPresent(site)).toBe(false, `${site} is displayed`);
- });
-
- it('[C290007] Files and folders are returned when both Files and Folders options are checked', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkFilesAndFolders();
- await searchInput.searchFor(`*${random}`);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(file)).toBe(true, `${file} not displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(true, `${folder} not displayed`);
- expect(await dataTable.isItemPresent(site)).toBe(false, `${site} is displayed`);
- });
-
- it('[C290008] Only libraries are returned when Libraries option is checked', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(`*${random}`);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(file)).toBe(false, `${file} is displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(false, `${folder} is displayed`);
- expect(await dataTable.isItemPresent(site)).toBe(true, `${site} not displayed`);
- });
-
- it('[C279162] Results are updated automatically when changing the search term', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.searchFor(file);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(file)).toBe(true, `${file} is not displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(false, `${folder} is displayed`);
-
- await searchInput.clickSearchButton();
- await searchInput.searchFor(folder);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(file)).toBe(false, `${file} is displayed`);
- expect(await dataTable.isItemPresent(folder)).toBe(true, `${folder} is not displayed`);
- });
-
- it('[C279178] Results are returned when accessing an URL containing a search query', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(site);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(site)).toBe(true, `${site} not displayed`);
-
- const url = await browser.getCurrentUrl();
-
- await page.clickPersonalFiles();
- await browser.get(url);
- await page.waitForResults();
-
- expect(await dataTable.isItemPresent(site)).toBe(true, `${site} not displayed`);
- });
-});
diff --git a/e2e/protractor/suites/search/search-results-libraries.test.ts b/e2e/protractor/suites/search/search-results-libraries.test.ts
deleted file mode 100644
index 847541f4f..000000000
--- a/e2e/protractor/suites/search/search-results-libraries.test.ts
+++ /dev/null
@@ -1,245 +0,0 @@
-/*!
- * 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 { AdminActions, LoginPage, SearchResultsPage, RepoClient, Utils, SITE_VISIBILITY, SITE_ROLES } from '@alfresco/aca-testing-shared';
-
-describe('Search results - libraries', () => {
- const random = Utils.random();
- const username = `user-${random}`;
-
- const site1 = {
- name: `lib-${random}-1`,
- id: `site-${random}-1`
- };
- const site2 = {
- name: `site-2-${random}`,
- id: `site-${random}-2`
- };
- const site3 = {
- name: `my-lib-${random}`,
- id: `site3-${random}`
- };
- const site4 = {
- name: `my-site-${random}`,
- id: `site4-${random}`,
- description: 'site description'
- };
-
- const userSitePrivate = `user-site-${random}-private`;
- const userSiteModerated = `user-site-${random}-moderated`;
- const userSitePublic = `user-site-${random}-public`;
-
- const siteRussian = {
- /* cspell:disable-next-line */
- name: `любимый-сайт-${random}`,
- id: `site-russian-id-${random}`
- };
-
- const adminSite1 = `admin-${random}-site1`;
- const adminSite2 = `admin-${random}-site2`;
- const adminSite3 = `admin-${random}-site3`;
- const adminSite4 = `admin-${random}-site4`;
- const adminPrivate = `admin-${random}-sitePrivate`;
-
- const apis = {
- user: new RepoClient(username, username)
- };
-
- const loginPage = new LoginPage();
- const page = new SearchResultsPage();
- const { searchInput, toolbar } = page.pageLayoutHeader;
- const dataTable = page.dataTable;
- const adminApiActions = new AdminActions();
-
- beforeAll(async () => {
- try {
- await adminApiActions.createUser({ username });
-
- await apis.user.sites.createSite(site1.name, SITE_VISIBILITY.PUBLIC, '', site1.id);
- await apis.user.sites.createSite(site2.name, SITE_VISIBILITY.PUBLIC, '', site2.id);
- await apis.user.sites.createSite(site3.name, SITE_VISIBILITY.PUBLIC, '', site3.id);
- await apis.user.sites.createSite(site4.name, SITE_VISIBILITY.PUBLIC, site4.description, site4.id);
-
- await apis.user.sites.createSite(userSitePublic, SITE_VISIBILITY.PUBLIC);
- await apis.user.sites.createSite(userSiteModerated, SITE_VISIBILITY.MODERATED);
- await apis.user.sites.createSite(userSitePrivate, SITE_VISIBILITY.PRIVATE);
-
- await apis.user.sites.createSite(siteRussian.name, SITE_VISIBILITY.PUBLIC, '', siteRussian.id);
-
- await adminApiActions.sites.createSite(adminSite1, SITE_VISIBILITY.PUBLIC);
- await adminApiActions.sites.createSite(adminSite2, SITE_VISIBILITY.PUBLIC);
- await adminApiActions.sites.createSite(adminSite3, SITE_VISIBILITY.PUBLIC);
- await adminApiActions.sites.createSite(adminSite4, SITE_VISIBILITY.PUBLIC);
- await adminApiActions.sites.addSiteMember(adminSite1, username, SITE_ROLES.SITE_CONSUMER.ROLE);
- await adminApiActions.sites.addSiteMember(adminSite2, username, SITE_ROLES.SITE_CONTRIBUTOR.ROLE);
- await adminApiActions.sites.addSiteMember(adminSite3, username, SITE_ROLES.SITE_COLLABORATOR.ROLE);
- await adminApiActions.sites.addSiteMember(adminSite4, username, SITE_ROLES.SITE_MANAGER.ROLE);
-
- await adminApiActions.sites.createSite(adminPrivate, SITE_VISIBILITY.PRIVATE);
-
- await adminApiActions.login();
- await adminApiActions.sites.waitForSitesToBeCreated([adminSite1, adminSite2, adminSite3, adminSite4]);
-
- await apis.user.sites.waitForSitesToBeCreated([
- site1.id,
- site2.id,
- site3.id,
- site4.id,
- userSitePublic,
- userSiteModerated,
- userSitePrivate,
- siteRussian.id
- ]);
-
- await apis.user.queries.waitForSites(random, { expect: 12 });
-
- await loginPage.loginWith(username);
- } catch {}
- });
-
- afterAll(async () => {
- try {
- await adminApiActions.sites.deleteSites([adminSite1, adminSite2, adminSite3, adminSite4, adminPrivate]);
- await apis.user.sites.deleteSites([site1.id, site2.id, site3.id, site4.id, userSitePublic, userSiteModerated, userSitePrivate, siteRussian.id]);
- } catch {}
- });
-
- beforeEach(async () => {
- await Utils.pressEscape();
- await page.clickPersonalFiles();
- });
-
- it('[C290012] Search library - full name match', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(site1.name);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(site1.name)).toBe(true, `${site1.name} not displayed`);
- expect(await dataTable.isItemPresent(site2.name)).toBe(false, `${site2.name} displayed`);
- expect(await dataTable.isItemPresent(site3.name)).toBe(false, `${site3.name} displayed`);
- expect(await dataTable.isItemPresent(site4.name)).toBe(false, `${site4.name} displayed`);
- });
-
- it('[C290013] Search library - partial name match', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(`lib-${random}`);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(site1.name)).toBe(true, `${site1.name} not displayed`);
- expect(await dataTable.isItemPresent(site2.name)).toBe(false, `${site2.name} displayed`);
- expect(await dataTable.isItemPresent(site3.name)).toBe(true, `${site3.name} not displayed`);
- expect(await dataTable.isItemPresent(site4.name)).toBe(false, `${site4.name} displayed`);
- });
-
- it('[C290014] Search library - description match', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(site4.description);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(site1.name)).toBe(false, `${site1.name} displayed`);
- expect(await dataTable.isItemPresent(site2.name)).toBe(false, `${site2.name} displayed`);
- expect(await dataTable.isItemPresent(site3.name)).toBe(false, `${site3.name} displayed`);
- expect(await dataTable.isItemPresent(site4.name)).toBe(true, `${site4.name} not displayed`);
- });
-
- it('[C290016] Results page columns', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(site1.name);
- await dataTable.waitForBody();
-
- const expectedColumns = ['Name', 'Description', 'My Role', 'Visibility'];
- const actualColumns = await dataTable.getColumnHeadersText();
-
- await expect(actualColumns).toEqual(expectedColumns);
- });
-
- it('[C290017] Library visibility is correctly displayed', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(`user-site-${random}`);
- await dataTable.waitForBody();
-
- const expectedSitesVisibility = {
- [userSitePrivate]: SITE_VISIBILITY.PRIVATE,
- [userSiteModerated]: SITE_VISIBILITY.MODERATED,
- [userSitePublic]: SITE_VISIBILITY.PUBLIC
- };
-
- const sitesList = await dataTable.getSitesNameAndVisibility();
-
- for (const site of Object.keys(expectedSitesVisibility)) {
- expect(sitesList[site]).toEqual(expectedSitesVisibility[site]);
- }
- });
-
- it('[C290018] User role is correctly displayed', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(`admin-${random}-site`);
- await dataTable.waitForBody();
-
- const expectedSitesRoles = {
- [adminSite1]: SITE_ROLES.SITE_CONSUMER.LABEL,
- [adminSite2]: SITE_ROLES.SITE_CONTRIBUTOR.LABEL,
- [adminSite3]: SITE_ROLES.SITE_COLLABORATOR.LABEL,
- [adminSite4]: SITE_ROLES.SITE_MANAGER.LABEL
- };
-
- const sitesList: any = await dataTable.getSitesNameAndRole();
-
- for (const site of Object.keys(expectedSitesRoles)) {
- expect(sitesList[site]).toEqual(expectedSitesRoles[site]);
- }
- });
-
- it('[C290019] Private sites are not displayed when user is not a member', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(`admin-${random}-site`);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(adminPrivate)).toBe(false, `${adminPrivate} is displayed`);
- });
-
- it('[C290028] Search libraries with special characters', async () => {
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.checkLibraries();
- await searchInput.searchForLibrary(siteRussian.name);
- await dataTable.waitForBody();
-
- expect(await dataTable.isItemPresent(siteRussian.name)).toBe(true, `${siteRussian.name} not displayed`);
- });
-});
diff --git a/e2e/protractor/suites/search/search-sorting.test.ts b/e2e/protractor/suites/search/search-sorting.test.ts
deleted file mode 100644
index 27a542f02..000000000
--- a/e2e/protractor/suites/search/search-sorting.test.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-/*!
- * 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 { AdminActions, LoginPage, SearchResultsPage, RepoClient, Utils, FILES } from '@alfresco/aca-testing-shared';
-
-describe('Search sorting', () => {
- const random = Utils.random();
-
- const user1 = `user1-${random}`;
- const user2 = `user2-${random}`;
-
- const parent = `parent-${random}`;
- let parentId: string;
-
- const fileJpg = {
- name: `search-sort-${random}-file-1.jpg`,
- source: FILES.jpgFile
- };
-
- const filePdf = {
- name: `search-sort-${random}-file-2.pdf`,
- title: 'search sort title',
- description: 'search sort',
- source: FILES.pdfFile
- };
-
- const apis = {
- user1: new RepoClient(user1, user1),
- user2: new RepoClient(user2, user2)
- };
-
- const loginPage = new LoginPage();
- const page = new SearchResultsPage();
- const { searchInput } = page.pageLayoutHeader;
- const { dataTable, toolbar } = page;
- const adminApiActions = new AdminActions();
-
- beforeAll(async () => {
- await adminApiActions.createUser({ username: user1 });
- await adminApiActions.createUser({ username: user2 });
- parentId = (await apis.user1.nodes.createFolder(parent)).entry.id;
-
- await apis.user1.nodes.setGranularPermission(parentId, true, user2, 'Collaborator');
-
- await apis.user1.upload.uploadFileWithRename(fileJpg.source, parentId, fileJpg.name);
- await apis.user2.upload.uploadFileWithRename(filePdf.source, parentId, filePdf.name, filePdf.title, filePdf.description);
-
- await apis.user1.search.waitForNodes(`search-sort-${random}`, { expect: 2 });
-
- await loginPage.loginWith(user1);
- });
-
- beforeEach(async () => {
- await Utils.pressEscape();
- await page.clickPersonalFilesAndWait();
- await toolbar.clickSearchIconButton();
- await searchInput.clickSearchButton();
- await searchInput.searchFor(`search-sort *${random}`);
- await dataTable.waitForBody();
- });
-
- afterAll(async () => {
- await apis.user1.nodes.deleteNodeById(parentId);
- });
-
- it('[C277722] Sorting options are displayed', async () => {
- expect(await page.sortingPicker.isSortOrderButtonDisplayed()).toBe(true, 'Sort order button not displayed');
-
- await page.sortingPicker.clickSortByDropdown();
-
- const expectedOptions = ['Relevance', 'Filename', 'Title', 'Modified date', 'Modifier', 'Created date', 'Size', 'Type'];
- const optionListed = await page.sortingPicker.getSortByOptionsList();
- expect(optionListed).toEqual(expectedOptions, 'Incorrect sort options list');
- });
-
- it('[C277728] Sort by Name', async () => {
- await page.sortingPicker.sortBy('Filename', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
-
- await page.sortingPicker.sortBy('Filename', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
- });
-
- it('[C277740] Sort by Type', async () => {
- await page.sortingPicker.sortBy('Type', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
-
- await page.sortingPicker.sortBy('Type', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
- });
-
- it('[C277738] Sort by Size', async () => {
- await page.sortingPicker.sortBy('Size', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
-
- await page.sortingPicker.sortBy('Size', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
- });
-
- it('[C277734] Sort by Created date', async () => {
- await page.sortingPicker.sortBy('Created date', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
-
- await page.sortingPicker.sortBy('Created date', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
- });
-
- it('[C277736] Sort by Modified date', async () => {
- await page.sortingPicker.sortBy('Modified date', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
-
- await page.sortingPicker.sortBy('Modified date', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
- });
-
- it('[C277727] Sort by Relevance', async () => {
- await page.sortingPicker.sortBy('Relevance', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
-
- await page.sortingPicker.sortBy('Relevance', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
- });
-
- it('[C277732] Sort by Modifier', async () => {
- await page.sortingPicker.sortBy('Modifier', 'asc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(fileJpg.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(filePdf.name);
-
- await page.sortingPicker.sortBy('Modifier', 'desc');
-
- expect(await dataTable.getNthSearchResultsRow(1).getText()).toContain(filePdf.name);
- expect(await dataTable.getNthSearchResultsRow(2).getText()).toContain(fileJpg.name);
- });
-});
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 f67e69324..f86006d3d 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
@@ -78,6 +78,13 @@ export class DataTableComponent extends BaseComponent {
getRowByColumnTitleAndItsCellValue = (columnTitle: string, cellValue: string | number): Locator =>
this.page.locator(`//div[contains(@title, '${columnTitle}')]//span[contains(text(), '${cellValue}')]/ancestor::adf-datatable-row`);
+ /**
+ * Method used in cases where we want to retrieve a row from the datatable based on its numerical order within the array.
+ *
+ * @returns reference to cell element which contains text.
+ */
+ getNthRow = (orderNum: number): Locator => this.getRowLocator.nth(orderNum);
+
/**
* Method used in cases where user have possibility to navigate "inside" the element (it's clickable and has link attribute).
* Perform action .click() to navigate inside it
diff --git a/projects/aca-playwright-shared/src/page-objects/components/index.ts b/projects/aca-playwright-shared/src/page-objects/components/index.ts
index 74c2a84a5..301a91697 100644
--- a/projects/aca-playwright-shared/src/page-objects/components/index.ts
+++ b/projects/aca-playwright-shared/src/page-objects/components/index.ts
@@ -35,6 +35,7 @@ export * from './adf-info-drawer.component';
export * from './viewer.component';
export * from './search/search-input.component';
export * from './search/search-overlay.components';
+export * from './search/search-sorting-picker.components';
export * from './breadcrumb/breadcrumb.component';
export * from './sidenav.component';
export * from './aca-header.component';
diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-sorting-picker.components.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-sorting-picker.components.ts
new file mode 100755
index 000000000..63e3f9240
--- /dev/null
+++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-sorting-picker.components.ts
@@ -0,0 +1,85 @@
+/*!
+ * 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
+ * along with Alfresco. If not, see .
+ */
+
+import { Page } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export type SortByType = 'Relevance' | 'Title' | 'Filename' | 'Modified date' | 'Modifier' | 'Created date' | 'Size' | 'Type';
+export type SortByDirection = 'asc' | 'desc';
+
+export class SearchSortingPicker extends BaseComponent {
+ private static rootElement = '#aca-button-action-menu';
+
+ public actionMenu = this.page.locator('[data-automation-id="auto_header_content_id_$thumbnail"]');
+ public sortOrderButton = this.page.locator('#aca-button-sorting-menu');
+ public sortByDropdownExpanded = this.page.locator('.mat-menu-panel').first();
+ public sortByList = this.page.locator('.mat-menu-panel button');
+
+ constructor(page: Page, rootElement = SearchSortingPicker.rootElement) {
+ super(page, rootElement);
+ }
+
+ async waitForSortByDropdownToExpand(): Promise {
+ await this.sortByDropdownExpanded.waitFor();
+ }
+
+ async isSortOrderButtonDisplayed(): Promise {
+ return this.sortOrderButton.isVisible();
+ }
+
+ async isSortByDropdownExpanded(): Promise {
+ return this.sortByDropdownExpanded.isVisible();
+ }
+
+ async clickSortByDropdown(): Promise {
+ await this.sortOrderButton.click();
+ await this.waitForSortByDropdownToExpand();
+ }
+
+ async getSortByOptionsList(): Promise {
+ let sortOptionsCount = await this.sortByList.count();
+ let sortByOptions: string[] = [];
+ for (let i = 1; i < sortOptionsCount; i++) {
+ let textContent = (await this.sortByList.nth(i).textContent()).trim();
+ sortByOptions.push(textContent);
+ }
+ sortByOptions.sort((a, b) => a.localeCompare(b));
+ return sortByOptions;
+}
+
+ async sortBy(option: SortByType, direction: SortByDirection): Promise {
+ await this.actionMenu.click();
+ await this.clickSortByDropdown();
+
+ if (!(await this.isSortByDropdownExpanded())) {
+ await this.clickSortByDropdown();
+ }
+ const elem = this.sortByList.getByText(option);
+ const optionId = await elem.getAttribute('id');
+ await elem.click();
+ const directionSortElement = this.page.locator(`[id="${optionId}-${direction.toLocaleLowerCase()}"]`);
+ await directionSortElement.click();
+ await this.progressBarWaitForReload();
+ }
+}
diff --git a/projects/aca-playwright-shared/src/page-objects/pages/search.page.ts b/projects/aca-playwright-shared/src/page-objects/pages/search.page.ts
index 13b59d41a..3efe7f421 100644
--- a/projects/aca-playwright-shared/src/page-objects/pages/search.page.ts
+++ b/projects/aca-playwright-shared/src/page-objects/pages/search.page.ts
@@ -24,7 +24,7 @@
import { Page } from '@playwright/test';
import { BasePage } from './base.page';
-import { DataTableComponent, MatMenuComponent, ViewerComponent, SearchInputComponent, SearchOverlayComponent, SidenavComponent } from '../components';
+import { DataTableComponent, MatMenuComponent, ViewerComponent, SearchInputComponent, SearchOverlayComponent, SidenavComponent, SearchSortingPicker } from '../components';
import { AcaHeader } from '../components/aca-header.component';
import { AdfConfirmDialogComponent, AdfFolderDialogComponent } from '../components/dialogs';
@@ -44,6 +44,7 @@ export class SearchPage extends BasePage {
public viewer = new ViewerComponent(this.page);
public searchInput = new SearchInputComponent(this.page);
public searchOverlay = new SearchOverlayComponent(this.page);
+ public searchSortingPicker = new SearchSortingPicker(this.page);
public sidenav = new SidenavComponent(this.page);
public confirmDialogComponent = new AdfConfirmDialogComponent(this.page);