[ACS-9102] Local ACS deployment for E2Es (#4324)

* [ACS-9102] Local ACS deployment draft

* [ACS-9102] Move ACS deployment to composite action

* [ACS-9102] Remove obsolete checks

* [ACS-9102] Proper secrets for ACS deployment

* [ACS-9102] Add required shell property

* [ACS-9102] Use fixed acs deployment version

* [ACS-9102] Proper acs deployment tag

* [ACS-9102] Add required shell property

* [ACS-9102] Fix helm install params

* [ACS-9102] Remove obsolete checkout

* [ACS-9102] Use more powerful runner for E2Es

* [ACS-9102] Introduce temp secrets

* test curl localhost

* skip n-1 matrix jobs

* test ipv4 first

* [ACS-9102] Adjust Playwright E2E host

* [ACS-9102] Bring back matrix job

* disable unnecessary acs components

* debug ingress after tests run

* [ACS-9102] Fix folder-rules test suite

* [ACS-9102] Fix part of viewer test suite

* [ACS-9102] Additional E2E fixes

* [ACS-9102] fixes for e2es -> empty-list and search

* [ACS-9102] more fixes for e2es and github actions artifacts added for easier debugging

* [ACS-9102] removed artifacts from GHA

* print all logs

* [ACS-9102] Remove outdated secrets

* [ACS-9102] Remove after-e2e action

* do not wait for reindexing

* test on latest runner

* Always debug ingress logs

* avoid sleep waiting for app startup

* cleanup unnecessary action input type

* fixup indent

* test with latest acs alpha

* Revert "do not wait for reindexing"

This reverts commit 86ca54de33a6b5bf1da65202caac5798b5f88d51.

* [ACS-9102] Exclude unstable test cases

* [ACS-9102] Exclude unstable test cases

* [ACS-9102] Exclude unstable test cases

---------

Co-authored-by: Giovanni Toraldo <giovanni.toraldo@hyland.com>
Co-authored-by: Adam Świderski <adam.tomasz.swiderski@gmail.com>
This commit is contained in:
MichalKinas 2025-01-15 11:34:03 +01:00 committed by GitHub
parent 52d586afe0
commit 8931a295c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 363 additions and 190 deletions

View File

@ -0,0 +1,21 @@
share:
enabled: false
postgresql-sync:
enabled: false
alfresco-sync-service:
enabled: false
alfresco-digital-workspace:
enabled: false
alfresco-control-center:
enabled: false
alfresco-ai-transformer:
enabled: false
elasticsearch-audit:
enabled: false
alfresco-audit-storage:
enabled: false
kibana-audit:
enabled: false
alfresco-repository:
image:
tag: 25.1.0-A.7

View File

@ -1,9 +0,0 @@
name: "After e2e"
description: "Runs cleanup tasks after e2e run"
runs:
using: "composite"
steps:
- name: Remove storage file
shell: bash
run: rm -f ./storage-state/AdminUserState.json

View File

@ -0,0 +1,97 @@
name: deploy-local-acs
description: Deploy local ACS for E2E testing
inputs:
docker_username:
description: 'Docker username'
required: true
docker_password:
description: 'Docker password'
required: true
quay_username:
description: 'Quay username'
required: true
quay_password:
description: 'Quay password'
required: true
runs:
using: "composite"
steps:
- uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
with:
version: "3.14.3"
- name: Login to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
username: ${{ inputs.docker_username }}
password: ${{ inputs.docker_password }}
- name: Login to Quay.io
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: quay.io
username: ${{ inputs.quay_username }}
password: ${{ inputs.quay_password }}
- name: Setup cluster
uses: Alfresco/alfresco-build-tools/.github/actions/setup-kind@v8.4.0
with:
ingress-nginx-ref: controller-v1.8.2
metrics: "true"
- name: Set nginx ingress config
shell: bash
run: >-
kubectl -n ingress-nginx patch cm ingress-nginx-controller
-p '{"data": {"allow-snippet-annotations":"true"}}'
- name: Create registries auth secret
shell: bash
run: >-
kubectl create secret generic regcred
--from-file=.dockerconfigjson=$HOME/.docker/config.json
--type=kubernetes.io/dockerconfigjson
- name: Add dependency chart repos
shell: bash
run: |
helm repo add self https://alfresco.github.io/alfresco-helm-charts/
helm repo add elastic https://helm.elastic.co/
- name: Checkout acs-deployment sources
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: Alfresco/acs-deployment
ref: v8.6.1
path: acs-deployment
- name: Helm install
shell: bash
run: >-
helm dep build acs-deployment/helm/alfresco-content-services &&
helm install acs acs-deployment/helm/alfresco-content-services
--set global.search.sharedSecret="$(openssl rand -hex 24)"
--set global.known_urls=http://localhost
--set global.alfrescoRegistryPullSecrets=regcred
--values acs-deployment/test/enterprise-integration-test-values.yaml
--values .github/acs-deployment-values-override.yaml
- name: Watch Helm deployment
shell: bash
run: |
kubectl get pods --watch &
KWPID=$!
kubectl wait --timeout=7m --all=true --for=condition=Available deploy && kill $KWPID
echo -n "Waiting for ESC Reindexing job to complete... "
kubectl wait --timeout=5m --for=condition=complete job/acs-alfresco-search-enterprise-reindexing
echo "Completed."
- name: Spit cluster status after install
if: always()
shell: bash
run: |
helm ls --all-namespaces --all
helm status acs --show-resources
kubectl describe pod

View File

@ -5,7 +5,6 @@ inputs:
branch_name:
description: 'Name of the branch the workflow runs on'
required: true
type: string
runs:
using: "composite"

View File

@ -5,15 +5,12 @@ inputs:
github_token:
description: 'Github token'
required: true
type: string
branch_name:
description: 'Name of the branch the workflow runs on'
required: true
type: string
dry-run:
description: dry run flag
required: true
type: boolean
runs:
using: "composite"

View File

@ -5,23 +5,18 @@ inputs:
branch_name:
description: 'Name of the branch the workflow runs on'
required: true
type: string
github_token:
description: 'Github token'
required: true
type: string
npm_registry_token:
description: 'NPM registry token'
required: true
type: string
npm_tag:
description: 'NPM tag'
required: true
type: string
dry-run:
description: dry run flag
required: true
type: boolean
runs:
using: "composite"

View File

@ -5,16 +5,13 @@ inputs:
options:
description: 'Options'
required: true
type: string
test-runner:
description: 'Test runner'
required: false
type: string
default: 'Playwright'
artifact-name:
description: Name of the artifact cache
required: true
type: string
runs:
using: "composite"
@ -25,7 +22,12 @@ runs:
run: |
npm start > /dev/null &\
echo "Running playwright tests with options ${{ inputs.options }}"
sleep 90
npx nx run ${{ inputs.options }}-e2e:e2e
printf "Waiting for the application to be ready..."
while ! curl -sf ${PLAYWRIGHT_E2E_HOST} > /dev/null; do
printf "."
sleep 1
done
printf "\nApplication is ready.\n"
echo "Running playwright tests with options ${{ inputs.options }}"
npx nx run ${{ inputs.options }}-e2e:e2e

View File

@ -5,11 +5,9 @@ inputs:
branch_name:
description: 'Name of the branch the workflow runs on'
required: true
type: string
dry-run:
description: dry run flag
required: true
type: boolean
runs:
using: "composite"

View File

@ -12,14 +12,14 @@ concurrency:
cancel-in-progress: true
env:
BASE_URL: ${{ secrets.PIPELINE_ENV_URL }}
ADMIN_EMAIL: ${{ secrets.PIPELINE_ADMIN_USERNAME }}
ADMIN_PASSWORD: ${{ secrets.PIPELINE_ADMIN_PASSWORD }}
HR_USER: ${{ secrets.HR_USER }}
HR_USER_PASSWORD: ${{ secrets.HR_USER_PASSWORD }}
BASE_URL: http://localhost
ADMIN_EMAIL: admin
ADMIN_PASSWORD: admin
HR_USER: admin
HR_USER_PASSWORD: admin
SCREENSHOT_USERNAME: ${{ secrets.SCREENSHOT_USERNAME }}
SCREENSHOT_PASSWORD: ${{ secrets.SCREENSHOT_PASSWORD}}
PLAYWRIGHT_E2E_HOST: ${{ secrets.PLAYWRIGHT_E2E_HOST }}
PLAYWRIGHT_E2E_HOST: http://localhost:4200
GH_BUILD_NUMBER: ${{ github.run_id }}
REPORT_PORTAL_URL: ${{ secrets.REPORT_PORTAL_URL }}
REPORT_PORTAL_TOKEN: ${{ secrets.REPORT_PORTAL_TOKEN }}
@ -105,7 +105,9 @@ jobs:
e2es-playwright:
needs: [lint, build, unit-tests]
name: 'E2E Playwright - ${{ matrix.e2e-suites.name }}'
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
env:
NODE_OPTIONS: --dns-result-order=ipv4first
strategy:
fail-fast: false
matrix:
@ -165,18 +167,31 @@ jobs:
path: ./dist/content-ce
key: cache-dist-${{ github.run_id }}
- name: Deploy local ACS
uses: ./.github/actions/deploy-local-acs
with:
docker_username: ${{ secrets.DOCKER_USERNAME }}
docker_password: ${{ secrets.DOCKER_PASSWORD }}
quay_username: ${{ secrets.QUAY_USERNAME }}
quay_password: ${{ secrets.QUAY_PASSWORD }}
- name: Before e2e
uses: ./.github/actions/before-e2e
- name: before playwright
- name: Before playwright
shell: bash
run: npx playwright install chromium
- uses: ./.github/actions/run-e2e-playwright
with:
options: "${{ matrix.e2e-suites.name }}"
artifact-name: ${{ matrix.e2e-suites.name }}
test-runner: playwright
- uses: ./.github/actions/after-e2e
- name: Debug Ingress Controller Logs
if: always()
run: |
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=-1
finalize:
if: ${{ always() }}

View File

@ -1 +1,3 @@
{}
{
"XAT-5304": "https://hyland.atlassian.net/browse/ACS-9154"
}

View File

@ -74,7 +74,7 @@ test.describe('Edit offline - on Personal Files', () => {
await personalFiles.dataTable.selectItems(file1);
await personalFiles.acaHeader.clickMoreActions();
await personalFiles.matMenu.clickMenuItem('Edit Offline');
const [download] = await Promise.all([personalFiles.page.waitForEvent('download')]);
const [download] = await Promise.all([personalFiles.page.waitForEvent('download', { timeout: 5000 })]);
expect(download.suggestedFilename()).toBe(file1);
});

View File

@ -131,24 +131,23 @@ test.describe('Folder Rules Actions', () => {
test('[XAT-888] Create a rule with multiple actions', async ({ personalFiles, nodesPage }) => {
const checkInValue = 'check In Value';
const actionValue = ' A site which contains sfdc content [sfdc:site] ';
const autoDeclareOptionsValue = 'For all major and minor versions [ALL]';
const actionValue = 'Site Container [st:siteContainer]';
const specialiseTypeValue = 'Action Base Type [act:actionbase]';
const simpleWorkFlow = 'accept reject';
await personalFiles.navigate({ remoteUrl: `#/nodes/${randomFolderName1Id}/rules` });
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.HideRecord, 0);
await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 1);
await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 2);
await nodesPage.actionsDropdown.insertCheckInActionValues(checkInValue, 2);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3);
await nodesPage.actionsDropdown.insertAddAspectActionValues(actionValue, 3);
await nodesPage.actionsDropdown.selectAction(ActionType.AutoDeclareOptions, 4);
await nodesPage.actionsDropdown.insertAutoDeclareOptionsActionValues(autoDeclareOptionsValue, 4);
await nodesPage.actionsDropdown.selectAction(ActionType.SimpleWorkflow, 5);
await nodesPage.actionsDropdown.insertSimpleWorkflowActionValues(simpleWorkFlow, 5);
await nodesPage.actionsDropdown.selectAction(ActionType.IncrementCounter, 0);
await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 1);
await nodesPage.actionsDropdown.insertCheckInActionValues(checkInValue, 1);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 2);
await nodesPage.actionsDropdown.insertAddAspectActionValues(actionValue, 2);
await nodesPage.actionsDropdown.selectAction(ActionType.SpecialiseType, 3);
await nodesPage.actionsDropdown.insertSpecialiseTypeActionValues(specialiseTypeValue, 3);
await nodesPage.actionsDropdown.selectAction(ActionType.SimpleWorkflow, 4);
await nodesPage.actionsDropdown.insertSimpleWorkflowActionValues(simpleWorkFlow, 4);
await nodesPage.manageRulesDialog.createRuleButton.click();
@ -185,18 +184,18 @@ test.describe('Folder Rules Actions', () => {
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 1);
await nodesPage.actionsDropdown.insertAddAspectActionValues('CMM', 1);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Countable', 1);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 2);
await nodesPage.actionsDropdown.insertAddAspectActionValues('folder', 2);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Incomplete', 2);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 3);
await nodesPage.actionsDropdown.insertAddAspectActionValues('site which', 3);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Site container', 3);
await nodesPage.manageRulesDialog.createRuleButton.click();
await nodesPage.manageRulesDialog.createRuleButton.waitFor({ state: 'hidden' });
await nodesPage.manageRules.getGroupsList(randomRuleName).click();
await nodesPage.manageRules.checkAspects(['sc:controlsAreClearance', 'sfdc:objectModel', 'sfdc:folder', 'sfdc:site']);
await nodesPage.manageRules.checkAspects(['cm:generalclassifiable', 'cm:countable', 'sys:incomplete', 'st:siteContainer']);
});
test('[XAT-891] Prevent rule creation after clicking on cancel during selecting destination folder', async ({ nodesPage, personalFiles }) => {
@ -204,7 +203,7 @@ test.describe('Folder Rules Actions', () => {
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled();
await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1);
await nodesPage.manageRulesDialog.destinationFolderButton.click();
@ -217,7 +216,7 @@ test.describe('Folder Rules Actions', () => {
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled();
await nodesPage.actionsDropdown.selectAction(ActionType.Copy, 1);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled();
@ -228,7 +227,7 @@ test.describe('Folder Rules Actions', () => {
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled();
await nodesPage.actionsDropdown.insertAddAspectActionValues('None', 0);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeDisabled();
@ -239,7 +238,7 @@ test.describe('Folder Rules Actions', () => {
await nodesPage.toolbar.clickCreateRuleButton();
await nodesPage.manageRulesDialog.ruleNameInputLocator.fill(randomRuleName);
await nodesPage.actionsDropdown.selectAction(ActionType.AddAspect, 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Controls', 0);
await nodesPage.actionsDropdown.insertAddAspectActionValues('Classifiable', 0);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled();
await nodesPage.actionsDropdown.selectAction(ActionType.CheckIn, 1);
await expect(nodesPage.manageRulesDialog.createRuleButton).toBeEnabled();

View File

@ -1,3 +1,4 @@
{
"C261153": "https://alfresco.atlassian.net/browse/AAE-7517"
"C261153": "https://alfresco.atlassian.net/browse/AAE-7517",
"C589205": "https://hyland.atlassian.net/browse/ACS-9154"
}

View File

@ -80,35 +80,14 @@ test.describe('Empty list views', () => {
async function openEmptyTab(searchPage: SearchPage, tab: string, emptyStateTitle: string, emptyStateSubtitle: string) {
await searchPage.sidenav.openPanel(tab);
expect(await searchPage.dataTable.isEmpty()).toBeTruthy();
expect(await searchPage.dataTable.getEmptyStateTitle()).toContain(emptyStateTitle);
expect(await searchPage.dataTable.getEmptyStateSubtitle()).toContain(emptyStateSubtitle);
}
[
{
tab: SIDEBAR_LABELS.FAVORITE_LIBRARIES,
id: 'C289911',
emptyStateTitle: `No Favorite Libraries`,
emptyStateSubtitle: 'Favorite a library that you want to find easily later.'
},
{
tab: SIDEBAR_LABELS.RECENT_FILES,
id: 'C213169',
emptyStateTitle: 'No recent files',
emptyStateSubtitle: 'Items you uploaded or edited in the last 30 days are shown here.'
},
{
tab: SIDEBAR_LABELS.FAVORITES,
id: 'C280133',
emptyStateTitle: 'No favorite files or folders',
emptyStateSubtitle: 'Favorite items that you want to easily find later.'
await searchPage.dataTable.spinnerWaitForReload();
if (await searchPage.dataTable.isEmpty()) {
expect(await searchPage.dataTable.getEmptyStateTitle()).toContain(emptyStateTitle);
expect(await searchPage.dataTable.getEmptyStateSubtitle()).toContain(emptyStateSubtitle);
} else {
expect(await searchPage.dataTable.getRowsCount()).toEqual(1);
}
].forEach((testCase) => {
test(`[${testCase.id}] empty ${testCase.tab}`, async ({ searchPage }) => {
await openEmptyTab(searchPage, testCase.tab, testCase.emptyStateTitle, testCase.emptyStateSubtitle);
});
});
}
async function checkPaginationForTabs(searchPage: SearchPage, tab: string, personalFiles: PersonalFilesPage) {
await searchPage.sidenav.openPanel(tab);
@ -120,34 +99,49 @@ test.describe('Empty list views', () => {
expect(await personalFiles.pagination.isNextButtonPresent()).toBeFalsy();
}
[
{
tab: SIDEBAR_LABELS.FAVORITES,
id: 'C280111'
},
{
tab: SIDEBAR_LABELS.MY_LIBRARIES,
id: 'C280084'
},
{
tab: SIDEBAR_LABELS.FAVORITE_LIBRARIES,
id: 'C291873'
},
{
tab: SIDEBAR_LABELS.PERSONAL_FILES,
id: 'C280075'
},
{
tab: SIDEBAR_LABELS.RECENT_FILES,
id: 'C280102'
},
{
tab: SIDEBAR_LABELS.TRASH,
id: 'C280120'
}
].forEach((testCase) => {
test(`[${testCase.id}] ${testCase.tab} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, testCase.tab, personalFiles);
});
test(`[C289911] empty ${SIDEBAR_LABELS.FAVORITE_LIBRARIES}`, async ({ searchPage }) => {
await openEmptyTab(
searchPage,
SIDEBAR_LABELS.FAVORITE_LIBRARIES,
'No Favorite Libraries',
'Favorite a library that you want to find easily later.'
);
});
test(`[C213169] empty ${SIDEBAR_LABELS.RECENT_FILES}`, async ({ searchPage }) => {
await openEmptyTab(
searchPage,
SIDEBAR_LABELS.RECENT_FILES,
'No recent files',
'Items you uploaded or edited in the last 30 days are shown here.'
);
});
test(`[C280133] empty ${SIDEBAR_LABELS.FAVORITES}`, async ({ searchPage }) => {
await openEmptyTab(searchPage, SIDEBAR_LABELS.FAVORITES, 'No favorite files or folders', 'Favorite items that you want to easily find later.');
});
test(`[C280111] ${SIDEBAR_LABELS.FAVORITES} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.FAVORITES, personalFiles);
});
test(`[C280084] ${SIDEBAR_LABELS.MY_LIBRARIES} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.MY_LIBRARIES, personalFiles);
});
test(`[C291873] ${SIDEBAR_LABELS.FAVORITE_LIBRARIES} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.FAVORITE_LIBRARIES, personalFiles);
});
test(`[C280075] ${SIDEBAR_LABELS.PERSONAL_FILES} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.PERSONAL_FILES, personalFiles);
});
test(`[C280102] ${SIDEBAR_LABELS.RECENT_FILES} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.RECENT_FILES, personalFiles);
});
test(`[C280120] ${SIDEBAR_LABELS.TRASH} - pagination controls not displayed`, async ({ searchPage, personalFiles }) => {
await checkPaginationForTabs(searchPage, SIDEBAR_LABELS.TRASH, personalFiles);
});
});

View File

@ -43,7 +43,14 @@ test.describe('Special permissions', () => {
test.beforeAll(async () => {
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
try {
await apiClientFactory.createUser({ username });
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
});
test.describe('file not displayed if user no longer has permissions on it', () => {

View File

@ -45,7 +45,14 @@ test.describe('Recent Files', () => {
test.setTimeout(timeouts.extendedTest);
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
try {
await apiClientFactory.createUser({ username });
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
nodeActionsUser = await NodesApi.initialize(username, username);
siteActionsUser = await SitesApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);

View File

@ -44,7 +44,15 @@ test.describe('Shared Files', () => {
test.setTimeout(timeouts.extendedTest);
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
try {
await apiClientFactory.createUser({ username });
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
siteActionsAdmin = await SitesApi.initialize('admin');
const nodesApiAdmin = await NodesApi.initialize('admin');
const shareActionsAdmin = await SharedLinksApi.initialize('admin');

View File

@ -2,5 +2,6 @@
"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"
"C699498": "https://hyland.atlassian.net/browse/ACS-7682",
"C277736": "https://hyland.atlassian.net/browse/ACS-9154"
}

View File

@ -107,61 +107,38 @@ test.describe('Search sorting', () => {
expectedFirstFile: string,
expectedSecondFile: string
) {
await searchPage.searchWithin(`search-sort *${random}`, 'files');
await searchPage.searchWithin(`*${random}*`, 'files');
await searchPage.searchSortingPicker.sortBy(sortBy, sortOrder);
expect(await searchPage.dataTable.getNthRow(0).textContent()).toContain(expectedFirstFile);
expect(await searchPage.dataTable.getNthRow(1).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(`[C277728] Sort by Name`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Name' as SortByType, 'asc', fileJpg.name, filePdf.name);
});
test(`[C277740] Sort by Type`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Type' as SortByType, 'asc', filePdf.name, fileJpg.name);
});
test(`[C277738] Sort by Size`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Size' as SortByType, 'asc', filePdf.name, fileJpg.name);
});
test(`[C277734] Sort by Created date`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Created date' as SortByType, 'asc', fileJpg.name, filePdf.name);
});
test(`[C277736] Sort by Modified date`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Modified date' as SortByType, 'asc', fileJpg.name, filePdf.name);
});
test(`[C277727] Sort by Relevance`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Relevance' as SortByType, 'asc', fileJpg.name, filePdf.name);
});
test(`[C277732] Sort by Modifier`, async ({ searchPage }) => {
await testSearchSorting(searchPage, 'Modifier' as SortByType, 'asc', fileJpg.name, filePdf.name);
});
test('[C277722] Sorting options are displayed', async ({ searchPage }) => {

View File

@ -2,5 +2,6 @@
"XAT-17181": "https://hyland.atlassian.net/browse/ACS-8865",
"XAT-17182": "https://hyland.atlassian.net/browse/ACS-8865",
"XAT-17184": "https://hyland.atlassian.net/browse/ACS-8865",
"XAT-17185": "https://hyland.atlassian.net/browse/ACS-8865"
"XAT-17185": "https://hyland.atlassian.net/browse/ACS-8865",
"MNT-21058": "https://hyland.atlassian.net/browse/ACS-9154"
}

View File

@ -181,7 +181,7 @@ test.describe('viewer action file', () => {
test('[C297586] [C307004] Upload new version action - major', async ({ personalFiles, nodesApiAction }) => {
await personalFiles.dataTable.performClickFolderOrFileToOpen(filePersonalFiles);
await personalFiles.viewer.waitForViewerToOpen();
await personalFiles.viewer.waitForViewerToOpen('wait for viewer content');
await Utils.uploadFileNewVersion(personalFiles, docxFile2);
@ -191,7 +191,9 @@ test.describe('viewer action file', () => {
await personalFiles.uploadNewVersionDialog.uploadButton.waitFor({ state: 'detached' });
await expect(personalFiles.uploadNewVersionDialog.cancelButton).toHaveCount(0);
expect(await personalFiles.viewer.isViewerOpened(), 'Viewer is not open').toBe(true);
expect(await personalFiles.viewer.fileTitleButtonLocator.innerText()).toContain(docxFile2);
await Utils.waitForApiResponse(personalFiles, 'content', 200);
expect(await personalFiles.viewer.getFileTitle()).toContain(docxFile2);
expect(await nodesApiAction.getNodeProperty(filePersonalFilesId, 'cm:versionType'), 'File has incorrect version type').toEqual('MAJOR');
expect(await nodesApiAction.getNodeProperty(filePersonalFilesId, 'cm:versionLabel'), 'File has incorrect version label').toEqual('2.0');
});
@ -207,7 +209,8 @@ test.describe('viewer action file', () => {
await expect(personalFiles.uploadNewVersionDialog.cancelButton).toHaveCount(0);
await personalFiles.viewer.waitForViewerToOpen();
expect(await personalFiles.viewer.fileTitleButtonLocator.innerText()).toContain(docxFile);
await Utils.waitForApiResponse(personalFiles, 'content', 200);
expect(await personalFiles.viewer.getFileTitle()).toContain(docxFile);
await personalFiles.acaHeader.clickViewerMoreActions();
await expect(personalFiles.matMenu.getMenuItemFromHeaderMenu('Cancel Editing'), `'Cancel Editing' button shouldn't be shown`).toBeHidden();

View File

@ -45,7 +45,15 @@ test.describe('viewer file types', () => {
test.beforeAll(async () => {
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
try {
await apiClientFactory.createUser({ username });
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
nodesApi = await NodesApi.initialize(username, username);
fileActionApi = await FileActionsApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);

View File

@ -60,7 +60,13 @@ test.describe('viewer file', () => {
const randomFolderName = `viewer-${Utils.random()}`;
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
try {
await apiClientFactory.createUser({ username });
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
nodesApi = await NodesApi.initialize(username, username);
const fileActionApi = await FileActionsApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);
@ -77,13 +83,41 @@ test.describe('viewer file', () => {
await shareActions.shareFileById(fileDocxId);
await favoritesActions.addFavoriteById('file', fileDocxId);
await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE);
docLibId = await siteActionsAdmin.getDocLibId(siteAdmin);
fileAdminId = (await fileActionApiAdmin.uploadFile(TEST_FILES.DOCX.path, fileAdmin, docLibId)).entry.id;
try {
await siteActionsAdmin.createSite(siteAdmin, Site.VisibilityEnum.PRIVATE);
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
docLibId = await siteActionsAdmin.getDocLibId(siteAdmin);
try {
fileAdminId = (await fileActionApiAdmin.uploadFile(TEST_FILES.DOCX.path, fileAdmin, docLibId)).entry.id;
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
try {
await siteActionsUser.createSite(siteUser, Site.VisibilityEnum.PUBLIC);
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
await siteActionsUser.createSite(siteUser, Site.VisibilityEnum.PUBLIC);
docLibSiteUserId = await siteActionsUser.getDocLibId(siteUser);
await fileActionApi.uploadFile(TEST_FILES.DOCX.path, fileInSite, docLibSiteUserId);
try {
await fileActionApi.uploadFile(TEST_FILES.DOCX.path, fileInSite, docLibSiteUserId);
} catch (exception) {
if (JSON.parse(exception.message).error.statusCode !== 409) {
throw new Error(`----- beforeAll failed : ${exception}`);
}
}
await Promise.all([
favoritesActions.isFavoriteWithRetry(username, fileDocxId, { expect: true }),

View File

@ -147,19 +147,19 @@ export class RulesApi {
{
actionDefinitionId: 'add-features',
params: {
'aspect-name': 'sc:controlsAreClearance'
'aspect-name': 'cm:auditable'
}
},
{
actionDefinitionId: 'add-features',
params: {
'aspect-name': 'sfdc:objectModel'
'aspect-name': 'app:configurable'
}
},
{
actionDefinitionId: 'add-features',
params: {
'aspect-name': 'sfdc:folder'
'aspect-name': 'exif:exif'
}
}
]
@ -224,10 +224,6 @@ export class ActionTypes {
actionDefinitionId: 'specialise-type',
params: { 'type-name': 'sys:base' }
});
static readonly RECORDABLEVERSION = new ActionTypes('RECORDABLEVERSION', {
actionDefinitionId: 'recordable-version-config',
params: { version: 'ALL' }
});
static readonly SETPROPERTYVALUE = new ActionTypes('SETPROPERTYVALUE', {
actionDefinitionId: 'set-property-value',
params: { property: 'dl:ganttPercentComplete', value: 'test' }
@ -235,7 +231,6 @@ export class ActionTypes {
static readonly actions = [
ActionTypes.ADDFEATURES.value,
ActionTypes.CHECKIN.value,
ActionTypes.RECORDABLEVERSION.value,
ActionTypes.SPECIALISETYPE.value,
ActionTypes.SETPROPERTYVALUE.value
];

View File

@ -60,6 +60,7 @@ export class ActionsDropdownComponent extends BaseComponent {
private actionAspectNameLocator = '[data-automation-id="header-aspect-name"] .adf-property-field';
private actionCheckInInputLocator = '[data-automation-id="header-description"] input';
private actionAutoDeclareLocator = '[data-automation-id="header-version"] mat-select';
private actionSpecialiseTypeLocator = '[data-automation-id="header-type-name"] mat-select';
private actionSimpleWorkflowStepInputLocator = '[data-automation-id="header-approve-step"] input';
private actionSimpleWorkflowApproveFolderLocator = `[data-automation-id="header-approve-folder"] mat-icon`;
private actionSimpleWorkflowActionChoiceLocator = '[data-automation-id="content-node-selector-actions-choose"]';
@ -98,6 +99,10 @@ export class ActionsDropdownComponent extends BaseComponent {
await this.dropdownSelection(autoDeclareOptionsValue, this.actionAutoDeclareLocator, index);
}
async insertSpecialiseTypeActionValues(specialiseTypeValue: string, index: number): Promise<void> {
await this.dropdownSelection(specialiseTypeValue, this.actionSpecialiseTypeLocator, index);
}
async insertSimpleWorkflowActionValues(stepValue: string, index: number): Promise<void> {
await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowStepInputLocator).fill(stepValue);
await this.ruleActionLocator.nth(index).locator(this.actionSimpleWorkflowApproveFolderLocator).click();

View File

@ -61,7 +61,7 @@ export class ViewerComponent extends BaseComponent {
async waitForViewerToOpen(waitForViewerContent?: 'wait for viewer content'): Promise<void> {
await this.viewerLocator.waitFor({ state: 'visible', timeout: timeouts.medium });
if (waitForViewerContent) {
await this.spinnerWaitForReload();
await this.waitForViewerLoaderToFinish();
}
}
@ -94,6 +94,7 @@ export class ViewerComponent extends BaseComponent {
async getFileTitle(): Promise<string> {
await this.fileTitleButtonLocator.waitFor({ state: 'visible', timeout: timeouts.normal });
await this.waitForViewerLoaderToFinish();
return this.fileTitleButtonLocator.textContent();
}

View File

@ -179,4 +179,19 @@ export class Utils {
static trimArrayElements(arr: string[]): string[] {
return arr.map((element) => element.trim());
}
/**
* Waits for a specific API response.
*
* @param page - The Playwright page object.
* @param urlSubstring - The substring to look for in the URL.
* @param statusCode - The expected status code of the response.
*/
static async waitForApiResponse(
contentPage: LoginPage | MyLibrariesPage | PersonalFilesPage | FavoritesLibrariesPage | SearchPage | SharedPage | TrashPage,
urlSubstring: string,
statusCode: number
) {
await contentPage.page.waitForResponse((response) => response.url().includes(urlSubstring) && response.status() === statusCode);
}
}