diff --git a/e2e/playwright/search/exclude.tests.json b/e2e/playwright/search/exclude.tests.json index b3736414d..031cfa0f6 100644 --- a/e2e/playwright/search/exclude.tests.json +++ b/e2e/playwright/search/exclude.tests.json @@ -1,5 +1,6 @@ { - "C290019": "https://alfresco.atlassian.net/browse/ACS-6928", - "C290018": "https://alfresco.atlassian.net/browse/ACS-6928", - "C699046-3": "https://hyland.atlassian.net/browse/ACS-7464" + "C290019": "https://hyland.atlassian.net/browse/ACS-6928", + "C290018": "https://hyland.atlassian.net/browse/ACS-6928", + "C699046-3": "https://hyland.atlassian.net/browse/ACS-7464", + "C699498": "https://hyland.atlassian.net/browse/ACS-7682" } \ No newline at end of file diff --git a/e2e/playwright/search/src/tests/search-filters-categories.e2e.ts b/e2e/playwright/search/src/tests/search-filters-categories.e2e.ts new file mode 100644 index 000000000..2af7558f0 --- /dev/null +++ b/e2e/playwright/search/src/tests/search-filters-categories.e2e.ts @@ -0,0 +1,84 @@ +/*! + * Copyright © 2005-2024 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, NodesApi, TrashcanApi, FileActionsApi, TEST_FILES, CategoriesApi } from '@alfresco/playwright-shared'; +import { CategoryLinkBody, CategoryPaging, CategoryEntry } from '@alfresco/js-api'; + +test.describe('Search - Filters - Categories', () => { + let nodesApi: NodesApi; + let trashcanApi: TrashcanApi; + let categoriesApi: CategoriesApi; + let categoryData: CategoryPaging | CategoryEntry; + let categoryId: string; + + const randomId = Utils.random(); + const username = `user-${randomId}`; + const fileNamePdf = `${randomId}-fileNameKb.pdf`; + const fileNameJpg = `${randomId}-fileNameMb.jpg`; + + const newSubcategories = [{ name: 'e2e' }]; + + test.beforeEach(async ({ loginPage }) => { + await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed'); + }); + + test.beforeAll(async () => { + try { + const apiClientFactory = new ApiClientFactory(); + await apiClientFactory.setUpAcaBackend('admin'); + await apiClientFactory.createUser({ username }); + nodesApi = await NodesApi.initialize(username, username); + trashcanApi = await TrashcanApi.initialize(username, username); + categoriesApi = await CategoriesApi.initialize('admin'); + const fileActionsApi = await FileActionsApi.initialize(username, username); + await fileActionsApi.uploadFileWithRename(TEST_FILES.PDF.path, fileNamePdf, '-my-'); + const jpgFileId = (await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, fileNameJpg, '-my-')).entry.id; + categoryData = await categoriesApi.createCategory('-root-', newSubcategories); + if (categoryData instanceof CategoryEntry) { + categoryId = categoryData.entry.id; + const categoryLinkBodyCreate: CategoryLinkBody[] = [{ categoryId: categoryData.entry.id }]; + await categoriesApi.linkNodeToCategory(jpgFileId, categoryLinkBodyCreate); + } + } catch (error) { + console.error(`beforeAll failed: ${error}`); + } + }); + + test.afterAll(async () => { + await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed'); + await categoriesApi.deleteCategory(categoryId); + }); + + test('[C699498] Filter by categories', async ({ searchPage }) => { + await searchPage.searchWithin(randomId, 'files'); + await searchPage.searchFilters.categoriesFilter.click(); + await searchPage.searchFiltersCategories.addOptionInput.fill(newSubcategories[0].name); + await searchPage.searchFilters.dropdownOptions.first().click(); + await searchPage.searchFilters.menuCardApply.click(); + + await expect(searchPage.dataTable.getRowByName(fileNamePdf)).toBeHidden(); + await expect(searchPage.dataTable.getRowByName(fileNameJpg)).toBeVisible(); + }); +}); diff --git a/e2e/playwright/search/src/tests/search-filters-logic.e2e.ts b/e2e/playwright/search/src/tests/search-filters-logic.e2e.ts index b7804cb4f..470785f8c 100644 --- a/e2e/playwright/search/src/tests/search-filters-logic.e2e.ts +++ b/e2e/playwright/search/src/tests/search-filters-logic.e2e.ts @@ -80,7 +80,7 @@ test.describe('Search - Filters - Logic', () => { await searchPage.searchFiltersLogic.matchAllInput.fill( `${logicFile1NameSplit[0]} ${logicFile1NameSplit[1]} ${logicFile1TitleSplit[1]} ${logicFile1DescriptionSplit[1]}` ); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); await expect(searchPage.dataTable.getRowByName(logicFile1.name)).toBeVisible(); @@ -92,7 +92,7 @@ test.describe('Search - Filters - Logic', () => { await searchPage.searchFiltersLogic.matchAnyInput.fill( `${logicFile1NameSplit[2]}-${logicFile1NameSplit[3]} ${logicFile1TitleSplit[0]} ${logicFile1DescriptionSplit[0]}` ); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(2); @@ -106,7 +106,7 @@ test.describe('Search - Filters - Logic', () => { `${logicFile1NameSplit[0]}-${logicFile1NameSplit[1]} ${logicFile1TitleSplit[0]} ${logicFile1DescriptionSplit[0]}` ); await searchPage.searchFiltersLogic.excludeInput.fill(`${logicFile1DescriptionSplit[1]}`); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(1); @@ -117,7 +117,7 @@ test.describe('Search - Filters - Logic', () => { test('[C699503] Filter with Exact phrase', async ({ searchPage }) => { await searchPage.searchFilters.logicFilter.click(); await searchPage.searchFiltersLogic.matchExactInput.fill(logicFile1.name); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(1); @@ -126,7 +126,7 @@ test.describe('Search - Filters - Logic', () => { await searchPage.searchFilters.logicFilter.click(); await searchPage.searchFiltersLogic.matchExactInput.fill(logicFile1.title); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(1); @@ -135,7 +135,7 @@ test.describe('Search - Filters - Logic', () => { await searchPage.searchFilters.logicFilter.click(); await searchPage.searchFiltersLogic.matchExactInput.fill(logicFile1.description); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(1); @@ -151,7 +151,7 @@ test.describe('Search - Filters - Logic', () => { await searchPage.searchFiltersLogic.matchAnyInput.fill(`${logicFile1NameSplit[0]} ${logicFile1TitleSplit[2]}`); await searchPage.searchFiltersLogic.excludeInput.fill(`${logicFile1NameSplit[3]}`); await searchPage.searchFiltersLogic.matchExactInput.fill(`${logicFile2NameSplit[1]}-${logicFile2NameSplit[2]}-${logicFile2NameSplit[3]}`); - await searchPage.searchFiltersLogic.applyButton.click(); + await searchPage.searchFilters.menuCardApply.click(); await searchPage.dataTable.progressBarWaitForReload(); expect(await searchPage.dataTable.getRowsCount()).toBe(1); diff --git a/projects/aca-playwright-shared/src/api/api-client-factory.ts b/projects/aca-playwright-shared/src/api/api-client-factory.ts index 7d3106d15..c9cbe99ba 100644 --- a/projects/aca-playwright-shared/src/api/api-client-factory.ts +++ b/projects/aca-playwright-shared/src/api/api-client-factory.ts @@ -40,7 +40,8 @@ import { FavoritesApi, TrashcanApi, PersonEntry, - CommentsApi + CommentsApi, + CategoriesApi } from '@alfresco/js-api'; import { ActionTypes, Rule } from './rules-api'; import { users } from '../base-config'; @@ -86,6 +87,7 @@ export class ApiClientFactory { public trashCan: TrashcanApi; public commentsApi: CommentsApi; public queriesApi: QueriesApi; + public categoriesApi: CategoriesApi; constructor() { this.alfrescoApi = new AlfrescoApi(config); @@ -110,6 +112,7 @@ export class ApiClientFactory { this.trashCan = new TrashcanApi(this.alfrescoApi); this.commentsApi = new CommentsApi(this.alfrescoApi); this.queriesApi = new QueriesApi(this.alfrescoApi); + this.categoriesApi = new CategoriesApi(this.alfrescoApi); return this; } diff --git a/projects/aca-playwright-shared/src/api/categories-api.ts b/projects/aca-playwright-shared/src/api/categories-api.ts new file mode 100644 index 000000000..9f0fd96ae --- /dev/null +++ b/projects/aca-playwright-shared/src/api/categories-api.ts @@ -0,0 +1,75 @@ +/*! + * Copyright © 2005-2024 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 { ApiClientFactory } from './api-client-factory'; +import { CategoryEntry, CategoryBody, CategoryQuery, CategoryPaging, CategoryLinkBody } from '@alfresco/js-api'; + +export class CategoriesApi { + private apiService: ApiClientFactory; + + constructor() { + this.apiService = new ApiClientFactory(); + } + + static async initialize(userName: string, password?: string): Promise { + const classObj = new CategoriesApi(); + await classObj.apiService.setUpAcaBackend(userName, password); + return classObj; + } + + async createCategory(categoryId: string, categoryBodyCreate: CategoryBody[], opts?: CategoryQuery): Promise { + try { + return await this.apiService.categoriesApi.createSubcategories(categoryId, categoryBodyCreate, opts); + } catch (error) { + console.error(error); + return null; + } + } + + async deleteCategory(categoryId: string): Promise { + if (categoryId === null) { + console.log('categoryId is null, skipping deletion'); + return; + } + + try { + await this.apiService.categoriesApi.deleteCategory(categoryId); + } catch (error) { + console.error(`${this.constructor.name} ${this.deleteCategory.name}: ${error}`); + } + } + + async linkNodeToCategory( + nodeId: string, + categoryLinkBodyCreate: CategoryLinkBody[], + opts?: CategoryQuery + ): Promise { + try { + return await this.apiService.categoriesApi.linkNodeToCategory(nodeId, categoryLinkBodyCreate, opts); + } catch (error) { + console.error(`${this.constructor.name} ${this.linkNodeToCategory.name}: ${error}`); + return null; + } + } +} diff --git a/projects/aca-playwright-shared/src/api/index.ts b/projects/aca-playwright-shared/src/api/index.ts index 7bd3c5188..f1d643465 100644 --- a/projects/aca-playwright-shared/src/api/index.ts +++ b/projects/aca-playwright-shared/src/api/index.ts @@ -34,3 +34,4 @@ export * from './node-content-tree'; export * from './search-api'; export * from './trashcan-api'; export * from './queries-api'; +export * from './categories-api'; diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters.component.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters.component.ts index 411703e12..10c758698 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters.component.ts @@ -44,4 +44,5 @@ export class SearchFilters extends BaseComponent { public menuCardClose = this.page.locator('.adf-search-filter-title-action'); public menuCardClear = this.page.locator('#cancel-filter-button'); public menuCardApply = this.page.locator('#apply-filter-button'); + public dropdownOptions = this.page.locator(`mat-option`); } \ No newline at end of file diff --git a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-logic.component.ts b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-logic.component.ts index 3a8c97f68..b4567c9a5 100644 --- a/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-logic.component.ts +++ b/projects/aca-playwright-shared/src/page-objects/components/search/search-filters/search-filters-logic.component.ts @@ -36,5 +36,4 @@ export class SearchFiltersLogic extends BaseComponent { public matchAnyInput = this.getChild(`[placeholder$='Results will match any words entered here']`); public excludeInput = this.getChild(`[placeholder$='Results will exclude matches with these words']`); public matchExactInput = this.getChild(`[placeholder$='Results will match this entire phrase']`); - public applyButton = this.page.locator('#apply-filter-button'); }