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');
}