Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/npm_and_yarn/dompurify-2.5.4
Browse files Browse the repository at this point in the history
  • Loading branch information
louis-bompart authored Oct 15, 2024
2 parents b331d11 + cd723ed commit 6a1f899
Show file tree
Hide file tree
Showing 32 changed files with 2,407 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/e2e-certifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: 'End-to-end certifier'

on:
workflow_dispatch:
inputs:
environment:
description: The environment in which to run the job
default: dev
region:
description: The region in which to run the job
default: us-east-1
package:
description: The package name
job:
description: The name of the job (as defined in the deployment config)

jobs:
test-job:
runs-on: ubuntu-24.04
steps:
- name: Deploy JSUI beta version on Netlify
run: curl --request POST https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_BUILD_HOOK_ID }}

- name: Checkout repository
uses: actions/checkout@v2

- name: Install test dependencies
working-directory: ${{ github.workspace }}/playwright
run: |
npm install
npx playwright install --with-deps
- name: Run tests
working-directory: ${{ github.workspace }}/playwright
run: npx playwright test
3 changes: 3 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
# Prevent PRs that only modify dependencies from notifying everyone
package.json @ghost
yarn.lock @ghost

# Owners for the Playwright end-to-end test directory
playwright/ @coveo/search-qa
3 changes: 3 additions & 0 deletions playwright/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
playwright-report/
test-results/
7 changes: 7 additions & 0 deletions playwright/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('prettier').Config} */
module.exports = {
printWidth: 120,
tabWidth: 4,
singleQuote: true,
bracketSpacing: false,
};
85 changes: 85 additions & 0 deletions playwright/e2e/breadcrumb.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {test, expect} from '@playwright/test';
import {pageURL} from '../utils/utils';
import {isUaSearchEvent} from '../utils/requests';
import {DynamicFacetSelectors, BreadcrumbSelectors} from '../utils/selectors';

let facetTitle, facetField, facetValue;
test.describe('Breadcrumb', async () => {
test.beforeEach(async ({page}) => {
await page.goto(pageURL('DynamicFacets'));
facetValue = await DynamicFacetSelectors(page).facetValue.first().textContent();
facetTitle = await DynamicFacetSelectors(page).facet.getAttribute('data-title');
facetField = await DynamicFacetSelectors(page).facet.getAttribute('data-field');
await DynamicFacetSelectors(page).facetCheckbox.first().click();
});

test('with one facet value', async ({page}) => {
const breadcrumbList = await BreadcrumbSelectors(page).breadcrumbItemRow.first().textContent();
expect(breadcrumbList).toEqual(`${facetTitle}:${facetValue}Clear`);

const uaRequest = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause == 'breadcrumbFacet' &&
request.postDataJSON()[0]?.actionType == 'breadcrumb' &&
request.postDataJSON()[0]?.customData.facetTitle == facetTitle &&
request.postDataJSON()[0]?.customData.facetField == facetField,
{timeout: 10_000},
);
await BreadcrumbSelectors(page).breadcrumbClearFacet.first().click();
await uaRequest;
});

test('with multiple facet value', async ({page}) => {
await page.waitForLoadState('networkidle');
const uaRequest = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause == 'breadcrumbFacet' &&
request.postDataJSON()[0]?.actionType == 'breadcrumb' &&
request.postDataJSON()[0]?.customData.facetTitle == facetTitle &&
request.postDataJSON()[0]?.customData.facetField == facetField,
);

const facetValue_2 = await DynamicFacetSelectors(page).facetValue.locator('nth=1').textContent();
await DynamicFacetSelectors(page).facetCheckbox.locator('nth=1').click();
await expect(BreadcrumbSelectors(page).breadcrumbDynamicFacetValue.locator('nth=1')).toBeVisible();

// Validate Breadcrumb list
const breadcrumbList = await BreadcrumbSelectors(page).breadcrumbItemRow.first().textContent();
expect(breadcrumbList).toEqual(`${facetTitle}:${facetValue}Clear${facetValue_2}Clear`);

await BreadcrumbSelectors(page).breadcrumbClearFacet.first().click();
await uaRequest;

await BreadcrumbSelectors(page).breadcrumbClearFacet.first().click();
await uaRequest;
});

test('with facetValue of multiple facet', async ({page}) => {
await page.waitForLoadState('networkidle');
await DynamicFacetSelectors(page, '@year').facetCheckbox.first().click();
await expect(BreadcrumbSelectors(page).breadcrumbItemRow.locator('nth=1')).toBeVisible();

// Validate breadcrumb value
const facetTitle_2 = await DynamicFacetSelectors(page, '@year').facet.getAttribute('data-title');
const facetValue_2 = await DynamicFacetSelectors(page, '@year').facetValue.first().textContent();

const breadcrumbList = await BreadcrumbSelectors(page).breadcrumbItemRow.first().textContent();
expect(breadcrumbList).toEqual(`${facetTitle}:${facetValue}Clear`);

const breadcrumbList_2 = await BreadcrumbSelectors(page).breadcrumbItemRow.locator('nth=1').textContent();
expect(breadcrumbList_2).toEqual(`${facetTitle_2}:${facetValue_2}Clear`);
});

test('breadcrumb clear all facets', async ({page}) => {
const uaRequest = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause == 'breadcrumbResetAll' &&
request.postDataJSON()[0]?.actionType == 'breadcrumb',
);
await BreadcrumbSelectors(page).breadcrumbClearAll.click();
await uaRequest;
});
});
58 changes: 58 additions & 0 deletions playwright/e2e/didYouMean.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {test, expect} from '@playwright/test';
import {pageURL} from '../utils/utils';
import {isUaSearchEvent} from '../utils/requests';
import {SearchboxSelectors} from '../utils/selectors';

test.describe('Did you mean', () => {
test('Did you mean automatic', async ({page}) => {
const query = 'tets';
await page.goto(pageURL('00_standardSP4automated_1'));
await SearchboxSelectors(page).searchboxInput.first().fill(query);
const uaRequestSearchQuery = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'searchboxSubmit' &&
request.postDataJSON()[0]?.actionType === 'search box' &&
request.postDataJSON()[0]?.queryText === query,
{timeout: 5_000},
);
const uaRequestDidYouMeanAutomatic = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'didyoumeanAutomatic' &&
request.postDataJSON()[0]?.actionType === 'misc',
{timeout: 5_000},
);
await SearchboxSelectors(page).searchboxIcon.click();
await uaRequestSearchQuery;
await uaRequestDidYouMeanAutomatic;
});

test('Did you mean click', async ({page}) => {
const query = 'testt';
await page.goto(pageURL('00_standardSP4automated_1'));
await SearchboxSelectors(page).searchboxInput.first().fill(query);
const uaRequestSearchQuery = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'searchboxSubmit' &&
request.postDataJSON()[0]?.actionType === 'search box' &&
request.postDataJSON()[0]?.queryText === query,
{timeout: 5_000},
);
await SearchboxSelectors(page).searchboxIcon.click();
await uaRequestSearchQuery;
await expect(page.getByText('Did you mean: test')).toBeVisible();

const uaRequestDidYouMeanAutomatic = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'didyoumeanClick' &&
request.postDataJSON()[0]?.actionType === 'misc' &&
request.postDataJSON()[0]?.queryText === 'test',
{timeout: 5_000},
);
await page.getByRole('button', {name: 'test'}).click();
await uaRequestDidYouMeanAutomatic;
});
});
38 changes: 38 additions & 0 deletions playwright/e2e/documentField.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {test, expect} from '@playwright/test';
import {pageURL} from '../utils/utils';
import {isUaSearchEvent} from '../utils/requests';
import {DocumentFieldSelectors, SearchboxSelectors} from '../utils/selectors';

test.describe('Document FieldValue', async () => {
test.beforeEach(async ({page}) => {
await page.goto(pageURL('00_standardSP4automated_1'));
});

test('Select document field value', async ({page}) => {
const query = '@filetype=="lithiummessage"';

await page.locator('div.coveo-tab-section a[data-caption="Lithium"]').click();
await SearchboxSelectors(page).searchboxInput.fill(query);
const uaRequestSearchQuery = page.waitForRequest(
(request) => isUaSearchEvent(request) && request.postDataJSON()[0]?.actionCause == 'searchboxSubmit',
);
await SearchboxSelectors(page).searchboxIcon.click();
await uaRequestSearchQuery;

const docFieldValue = await DocumentFieldSelectors(page).fieldValue.first().textContent();
const uaRequestDocFieldValue = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause == 'documentField' &&
request.postDataJSON()[0]?.customData.facetValue == docFieldValue?.toLowerCase(),
);
await DocumentFieldSelectors(page).fieldValue.first().click();
await uaRequestDocFieldValue;

await expect(page.getByTitle(`${docFieldValue}`, {exact: true})).toBeChecked();
expect(await page.getByLabel('Remove inclusion filter on').textContent()).toEqual(`${docFieldValue}Clear`);

await DocumentFieldSelectors(page).fieldValue.first().click();
await expect(page.getByTitle(`${docFieldValue}`, {exact: true})).not.toBeChecked();
});
});
121 changes: 121 additions & 0 deletions playwright/e2e/dynamicCategoryFacet.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {test, expect} from '@playwright/test';
import {pageURL} from '../utils/utils';
import {isUaCustomEvent, isUaSearchEvent} from '../utils/requests';
import {DynamicCategoryFacetSelects, BreadcrumbSelectors} from '../utils/selectors';

const defaultFacetNumberOfValues = 5;
let facetValue_Level1, breadcrumbList;

test.describe('Dynamic Category Facet', () => {
test.beforeEach(async ({page}) => {
await page.goto(pageURL('DynamicFacets'));
await page.waitForLoadState('networkidle');
});
test('Should select the parent-child level, and clear selection', async ({page}) => {
// Select parent level
facetValue_Level1 = await DynamicCategoryFacetSelects(page).valueL1.first().textContent();
const uaRequestDNE_first = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'facetSelect' &&
request.postDataJSON()[0]?.actionType === 'dynamicFacet' &&
request.postDataJSON()[0]?.customData.facetValue === facetValue_Level1 &&
request.postDataJSON()[0]?.facetState[0].facetType === 'hierarchical' &&
request.postDataJSON()[0]?.facetState[0].valuePosition === 1,
{timeout: 5_000},
);

await DynamicCategoryFacetSelects(page).valueL1.first().click();
await uaRequestDNE_first;

// Validate breadcrumb
breadcrumbList = await BreadcrumbSelectors(page).breadcrumbItemRow.first().textContent();
expect(breadcrumbList).toEqual(`Categories:${facetValue_Level1}Clear`);

// Select 1st child level
const facetValue_Level2 = await DynamicCategoryFacetSelects(page).valueL2.first().textContent();
const uaRequestDNE_second = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'facetSelect' &&
request.postDataJSON()[0]?.actionType === 'dynamicFacet' &&
request.postDataJSON()[0]?.customData.facetValue ===
`${facetValue_Level1};${facetValue_Level2}` &&
request.postDataJSON()[0]?.facetState[0].facetType === 'hierarchical' &&
request.postDataJSON()[0]?.facetState[0].valuePosition === 1,
{timeout: 5_000},
);
await DynamicCategoryFacetSelects(page).valueL2.first().click();
await uaRequestDNE_second;
// Validate breadcrumb
breadcrumbList = await BreadcrumbSelectors(page).breadcrumbItemRow.first().textContent();
expect(breadcrumbList).toEqual(`Categories:${facetValue_Level1} / ${facetValue_Level2}Clear`);

// Validate ClearAll
const uaRequestClearAll = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'facetClearAll' &&
request.postDataJSON()[0]?.actionType === 'dynamicFacet',
{timeout: 5_000},
);
await DynamicCategoryFacetSelects(page).clearAllCategory.click();
await uaRequestClearAll;
// Validate breadcrumb
await expect(BreadcrumbSelectors(page).breadcrumbItemRow.first()).not.toBeVisible();
});

test('Show more Show less First level', async ({page}) => {
// Default state
const allValue_Level1 = await DynamicCategoryFacetSelects(page).valueL1.count();
expect(allValue_Level1).toEqual(defaultFacetNumberOfValues);

// Click Show More
const uaRequestShowMore = page.waitForRequest(
(request) =>
isUaCustomEvent(request) &&
request.postDataJSON()?.actionCause === 'showMoreFacetResults' &&
request.postDataJSON()?.actionType === 'dynamicFacet',
);
await DynamicCategoryFacetSelects(page).showMore.click();
await uaRequestShowMore;
await expect(DynamicCategoryFacetSelects(page).showLess).toBeVisible();
expect(await DynamicCategoryFacetSelects(page).valueL1.count()).toEqual(7);

// Click Show Less
const uaRequestShowLess = page.waitForRequest(
(request) =>
isUaCustomEvent(request) &&
request.postDataJSON()?.actionCause === 'showLessFacetResults' &&
request.postDataJSON()?.actionType === 'dynamicFacet',
);
await DynamicCategoryFacetSelects(page).showLess.click();
await uaRequestShowLess;
await expect(DynamicCategoryFacetSelects(page).showMore).toBeVisible();
await expect(DynamicCategoryFacetSelects(page).showLess).not.toBeVisible();
expect(await DynamicCategoryFacetSelects(page).valueL1.count()).toEqual(defaultFacetNumberOfValues);
});

test('Show more Show less 2nd level', async ({page}) => {
const uaRequestSelect = page.waitForRequest(
(request) =>
isUaSearchEvent(request) &&
request.postDataJSON()[0]?.actionCause === 'facetSelect' &&
request.postDataJSON()[0]?.actionType === 'dynamicFacet',
{timeout: 5_000},
);
await DynamicCategoryFacetSelects(page).valueL1.first().click();
await uaRequestSelect;
expect(await DynamicCategoryFacetSelects(page).valueL2.count()).toEqual(defaultFacetNumberOfValues);

// Show more test
await DynamicCategoryFacetSelects(page).showMore.click();
await expect(DynamicCategoryFacetSelects(page).showLess).toBeVisible();
expect(await DynamicCategoryFacetSelects(page).valueL2.count()).toEqual(defaultFacetNumberOfValues * 2);

// Show less test
await DynamicCategoryFacetSelects(page).showLess.click();
await expect(DynamicCategoryFacetSelects(page).showLess).not.toBeVisible();
expect(await DynamicCategoryFacetSelects(page).valueL2.count()).toEqual(defaultFacetNumberOfValues);
});
});
Loading

0 comments on commit 6a1f899

Please sign in to comment.