[AAE-7160] Setup Playwright in ADF - Storybook testing (#7537)

* [AAE-7160] Setup Playwright in ADF - Storybook testing

* New test cases for groups component. Reorganize the files

* Add to package.json scripts - npm run playwright

* Change amount of workers

* Change workesr to 2
This commit is contained in:
MichalFidor 2022-03-07 08:36:55 +01:00 committed by GitHub
parent 25eaf9d024
commit a0c7631abb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1792 additions and 131 deletions

View File

@ -37,6 +37,10 @@ env:
- IDENTITY_ADMIN_EMAIL=$E2E_ADMIN_EMAIL_IDENTITY
- IDENTITY_ADMIN_PASSWORD=$E2E_ADMIN_PASSWORD_IDENTITY
- URL_HOST_ADF="http://localhost:4200"
#PLAYWRIGHT VARIABLES
- PLAYWRIGHT_WORKERS=2
- PLAYWRIGHT_STORYBOOK_E2E_HOST=http://localhost
- PLAYWRIGHT_STORYBOOK_E2E_PORT=4400
branches:
only:
@ -61,6 +65,8 @@ stages:
if: type = pull_request || (type = cron || type = api)
- name: "e2e Test"
if: type = pull_request || (type = cron || type = api)
- name: "Storybook Playwright Tests"
if: type = pull_request || (type = cron || type = api)
- name: "Release tag"
if: branch = master
- name: "Deprecate develop builds"
@ -168,6 +174,15 @@ jobs:
- ADF_VERSION=$(npm view @alfresco/adf-core@${TAG_NPM} version)
- ./scripts/travis/release/deprecate-develop-build.sh -v ${ADF_VERSION}
- stage: "Storybook Playwright Tests"
name: "Process Cloud"
before_script: ./scripts/ci/jobs/dbpci-before-playwright
script: ./scripts/travis/storybook-testing/storybook-test.sh
workspaces:
use:
- built_libs_cache
- built_demo_shell_cache
- stage: "e2e Test"
name: "Core"
before_script:

View File

@ -3,136 +3,136 @@
"language": "en",
"words": [
"activiti",
"CSRF",
"glyphicon",
"sharedlinks",
"fullscreen",
"sidenav",
"truthy",
"cryptodoc",
"mysites",
"afts",
"classlist",
"folderlink",
"filelink",
"datatable",
"repo",
"snackbar",
"promisify",
"xdescribe",
"unfavorite",
"devtools",
"gitter",
"jira",
"markdownlint",
"uploader",
"nginx",
"docx",
"SOLR",
"unshare",
"validators",
"pdfjs",
"exif",
"cardview",
"webm",
"keycodes",
"adhoc",
"swimlanes",
"datepicker",
"waypoints",
"waypoint",
"hotfix",
"typeahead",
"gridster",
"Collapsable",
"rowspan",
"typeahead",
"tabindex",
"afts",
"Arial",
"swsdp",
"Datetimepicker",
"mimetype",
"multiselect",
"arrowup",
"arrowdown",
"dialpad",
"backend",
"Unclaim",
"transclusion",
"transcluded",
"arrowup",
"auditable",
"taggable",
"datarow",
"datacolumn",
"textitem",
"boolitem",
"mapitem",
"selectitem",
"keyvaluepairsitem",
"boolitem",
"baseitem",
"checkboxes",
"tasklist",
"dateitem",
"webscript",
"minlength",
"doclib",
"fullname",
"firstname",
"lastname",
"userinfo",
"qshare",
"imgpreview",
"AUTHTYPE",
"ECMHOST",
"backend",
"baseitem",
"BASESHAREURL",
"booleanvisibility",
"booleanvisibilityprocess",
"boolitem",
"BPMHOST",
"OAUTHCONFIG",
"cardview",
"checkboxes",
"classlist",
"Collapsable",
"CONTEXTROOTBPM",
"CONTEXTROOTECM",
"DISABLECSRF",
"printf",
"mincount",
"listgrid",
"filesize",
"Theming",
"quicktime",
"Promise",
"Examinate",
"highlightable",
"Droppable",
"UPDATEPERMISSIONS",
"Whitespaces",
"keyvaluepairs",
"cryptodoc",
"CSRF",
"datacolumn",
"datarow",
"datatable",
"dateitem",
"datepicker",
"datetimeitem",
"floatitem",
"intitem",
"Datetimepicker",
"dbpci",
"DDTHH",
"MLTEXT",
"penta",
"BASESHAREURL",
"hardend",
"filedata",
"uncheck",
"subfolders",
"ECMBPM",
"processwithvariables",
"dropdownrestprocess",
"devops",
"mouseenter",
"starteventform",
"devtools",
"dialpad",
"DISABLECSRF",
"doclib",
"docx",
"dropdownrestprocess",
"Droppable",
"ECMBPM",
"ECMHOST",
"Examinate",
"exif",
"filedata",
"filelink",
"filesize",
"firstname",
"floatitem",
"folderlink",
"formtotestvalidations",
"requirednumbervisibility",
"numbervisibilityprocess",
"booleanvisibilityprocess",
"booleanvisibility",
"processparent",
"uploadfileform",
"processwithstarteventform",
"processstring",
"typeahed",
"fullname",
"fullscreen",
"gitter",
"glyphicon",
"gridster",
"hardend",
"highlightable",
"hotfix",
"imgpreview",
"intitem",
"jira",
"jsons",
"keycodes",
"keyvaluepairs",
"keyvaluepairsitem",
"lastname",
"listgrid",
"mapitem",
"markdownlint",
"mimetype",
"mincount",
"minlength",
"minmax",
"jsons",
"Inplace"
"Inplace",
"MLTEXT",
"mouseenter",
"multiselect",
"mysites",
"nginx",
"numbervisibilityprocess",
"OAUTHCONFIG",
"pdfjs",
"penta",
"printf",
"processparent",
"processstring",
"processwithstarteventform",
"processwithvariables",
"Promise",
"promisify",
"qshare",
"quicktime",
"repo",
"requirednumbervisibility",
"rowspan",
"selectitem",
"sharedlinks",
"sidenav",
"snackbar",
"SOLR",
"starteventform",
"subfolders",
"swimlanes",
"swsdp",
"tabindex",
"taggable",
"tasklist",
"textitem",
"Theming",
"transcluded",
"transclusion",
"truthy",
"typeahead",
"typeahed",
"uncheck",
"Unclaim",
"unfavorite",
"unshare",
"UPDATEPERMISSIONS",
"uploader",
"uploadfileform",
"userinfo",
"validators",
"waypoint",
"waypoints",
"webm",
"webscript",
"Whitespaces",
"xdescribe"
],
"dictionaries": [
"html",

View File

@ -0,0 +1,11 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export enum ComponentTitles {
processServicesCloud = 'process-services-cloud',
}

View File

@ -0,0 +1,31 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Locator, Page } from '@playwright/test';
import { PlaywrightBase } from '../playwright-base';
export abstract class BaseComponent extends PlaywrightBase {
private rootElement: string;
constructor(page: Page,rootElement: string) {
super(page);
this.rootElement = rootElement;
}
/**
* Method which should be used across the repository, while creating
* reference to elements, which are in root element of component.
* @param cssLocator css selector as String. Need to be in the tree under the root element
* @param options if you want to localize it by text, then provide an optional hasText
* @returns Locator object
*/
getChild(cssLocator: string, options?: { hasText: string | RegExp }): Locator {
return this.page.locator(`${this.rootElement} ${cssLocator}`, options);
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { BaseComponent } from '../base.component';
export class ErrorComponent extends BaseComponent {
private static rootElement = 'mat-error';
public content = this.getChild('');
constructor(page: Page) {
super(page, ErrorComponent.rootElement);
}
}

View File

@ -0,0 +1,11 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export * from './error.component';
export * from './listbox.component';
export * from './validation.component';

View File

@ -0,0 +1,20 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { BaseComponent } from '../base.component';
export class ListboxComponent extends BaseComponent {
private static rootElement = 'div[role=listbox]';
public allOptions = this.getChild('');
public oneOption = this.getChild('span >> span');
constructor(page: Page) {
super(page, ListboxComponent.rootElement);
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { BaseComponent } from '../base.component';
export class TooltipComponent extends BaseComponent {
private static rootElement = 'mat-tooltip-component';
public content = this.getChild('div');
constructor(page: Page) {
super(page, TooltipComponent.rootElement);
}
}

View File

@ -0,0 +1,10 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export * from './basic';
export * from './base.component';

View File

@ -0,0 +1,10 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export * from './components';
export * from './stories/base.storie';

View File

@ -0,0 +1,17 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
export abstract class PlaywrightBase {
public page: Page;
constructor(page: Page) {
this.page = page;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { timeouts } from '../../utils/timeouts';
import { ComponentTitles } from '../../models/component-titles.model';
import { PlaywrightBase } from '../playwright-base';
interface NavigateParameters { componentName: string; story: string };
export class BaseStories extends PlaywrightBase {
private rootComponentTitle: string;
constructor(page: Page, rootComponentTitle: ComponentTitles) {
super(page);
this.rootComponentTitle = rootComponentTitle;
}
async navigateTo({ componentName, story }: NavigateParameters): Promise<void> {
await this.page.goto(`/iframe.html?id=${this.rootComponentTitle}-components-${componentName}--${story}`, {
waitUntil: 'networkidle',
timeout: timeouts.large
});
}
}

View File

@ -0,0 +1,101 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { PlaywrightTestConfig, ReporterDescription, WebServerConfig } from '@playwright/test';
import { dotenvConfig } from '@alfresco/adf-cli/tooling';
import { paths } from './utils/paths';
import { timeouts } from './utils/timeouts';
import path from 'path';
export const getGlobalConfig = (): PlaywrightTestConfig => {
dotenvConfig();
const env = process.env;
const baseUrl = `${env.PLAYWRIGHT_STORYBOOK_E2E_HOST}:${env.PLAYWRIGHT_STORYBOOK_E2E_PORT}`;
let startCommand: string;
let report: ReporterDescription;
if (!!env.CI) {
startCommand = 'nx run stories:storybook';
report = ['html', { outputFolder: path.resolve(`../${paths.report}`), open: 'never' }];
} else {
startCommand = 'nx run stories:build-storybook && nx run stories:storybook';
report = ['html', { outputFolder: path.resolve(`../${paths.report}`), open: 'on-failure' }];
}
const webServer: WebServerConfig = {
command: startCommand,
// It's true, but watch on on localhost! If you'll have other app up and running then it'll use this app to run the tests.
// It won't check what application is currently running.
reuseExistingServer: true,
timeout: timeouts.webServer,
url: baseUrl
};
return {
timeout: timeouts.globalTest,
globalTimeout: timeouts.globalSpec,
testMatch: /.*\.e2e\.ts/,
expect: {
timeout: timeouts.large
},
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!env.CI,
/* Retry on CI only */
retries: env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: env.PLAYWRIGHT_WORKERS ? parseInt(env.PLAYWRIGHT_WORKERS, 0) : 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [['list'], report],
quiet: false,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
actionTimeout: 0,
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
headless: !!env.PLAYWRIGHT_HEADLESS ? (env.PLAYWRIGHT_HEADLESS === 'true') : !!env.CI,
ignoreHTTPSErrors: true,
bypassCSP: true,
browserName: 'chromium',
baseURL: baseUrl,
viewport: {
height: 900,
width: 1400
},
launchOptions: {
devtools: false,
args: [
'--disable-web-security',
'--no-sandbox'
]
}
},
projects: [
{
name: 'Process Services Cloud : People',
testMatch: /.people-cloud*\.e2e\.ts/
},
{
name: 'Process Services Cloud : Groups',
testMatch: /.groups-cloud*\.e2e\.ts/
}
],
webServer
};
};
export default getGlobalConfig();

View File

@ -0,0 +1,28 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { BaseComponent } from '../../page-object/components/base.component';
import { ErrorComponent, TooltipComponent, ListboxComponent } from '../../page-object/components/basic';
export class GroupComponent extends BaseComponent {
private static rootElement = 'adf-cloud-group';
public error = new ErrorComponent(this.page);
public tooltip = new TooltipComponent(this.page);
public listbox = new ListboxComponent(this.page);
public groupNaming = this.getChild('[data-automation-id="adf-cloud-group-chip-list"]');
public groupInput = this.getChild('[data-automation-id="adf-group-cloud-search-input"]');
constructor(page: Page, rootElement = GroupComponent.rootElement) {
super(page, rootElement);
}
public getUserLocator = (userName: string) => this.getChild(`[data-automation-id="adf-cloud-group-chip-${userName}"]`);
}

View File

@ -0,0 +1,28 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { Page } from '@playwright/test';
import { BaseComponent } from '../../page-object/components/base.component';
import { ErrorComponent, TooltipComponent, ListboxComponent } from '../../page-object/components/basic';
export class PeopleComponent extends BaseComponent {
private static rootElement = 'adf-cloud-people';
public error = new ErrorComponent(this.page);
public tooltip = new TooltipComponent(this.page);
public listbox = new ListboxComponent(this.page);
public usersNaming = this.getChild('[data-automation-id="adf-cloud-people-chip-list"]');
public usersInput = this.getChild('[data-automation-id="adf-people-cloud-search-input"]');
constructor(page: Page, rootElement = PeopleComponent.rootElement) {
super(page, rootElement);
}
public getUserLocator = (userName: 'userName1' | 'userName2') => this.getChild(`[data-automation-id="adf-people-cloud-chip-${userName}"]`);
}

View File

@ -0,0 +1,28 @@
/* eslint-disable brace-style */
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { test as base } from '@playwright/test';
import { BaseStories } from '../../page-object';
import { ComponentTitles } from '../../models/component-titles.model';
import { PeopleComponent } from '../components/people.component';
import { GroupComponent } from '../components/group.component';
interface Pages {
processServicesCloud: BaseStories;
peopleComponent: PeopleComponent;
groupComponent: GroupComponent;
}
export const test = base.extend<Pages>({
processServicesCloud: async ({ page }, use) => { await use(new BaseStories(page, ComponentTitles.processServicesCloud)); },
peopleComponent: async ({ page }, use) => { await use(new PeopleComponent(page)); },
groupComponent: async ({ page }, use) => { await use(new GroupComponent(page)); }
});
export { expect } from '@playwright/test';

View File

@ -0,0 +1,50 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { test, expect } from '../fixtures/page-initialization';
test.describe.configure({ mode: 'parallel' });
test.describe('Groups component stories tests', () => {
test('Valid Preselected Groups', async ({ processServicesCloud, groupComponent }) => {
const expectedUsersName = `
Mock Group 1 cancel
Mock Group 2 cancel
Mock Group 3 cancel
Mock Group 4 cancel
Mock Group 5
`;
await processServicesCloud.navigateTo({ componentName: 'group', story: 'valid-preselected-groups' });
await expect(groupComponent.groupNaming).toContainText(expectedUsersName);
});
test('Mandatory Preselected Groups', async ({ processServicesCloud, groupComponent }) => {
const expectedUsersName = `
Mock Group 1
Mock Group 2 cancel
Mock Group 3
`;
await processServicesCloud.navigateTo({ componentName: 'group', story: 'mandatory-preselected-groups' });
await expect.soft(groupComponent.groupNaming).toContainText(expectedUsersName);
await groupComponent.getUserLocator('Mock Group 1').hover();
await expect(groupComponent.tooltip.content).toContainText('Mandatory');
});
test('Invalid Preselected Groups', async ({ processServicesCloud, groupComponent }) => {
const expectedWarningMessage = 'warning No group found with the name invalid groups';
await processServicesCloud.navigateTo({ componentName: 'group', story: 'invalid-preselected-groups' });
await expect(groupComponent.error.content).toContainText(expectedWarningMessage);
});
});

View File

@ -0,0 +1,69 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
import { test, expect } from '../fixtures/page-initialization';
test.describe.configure({ mode: 'parallel' });
test.describe('People component stories tests', () => {
test('Valid Preselected Users', async ({ processServicesCloud, peopleComponent }) => {
const expectedUsersName = `
first-name-1 last-name-1 cancel
first-name-2 last-name-2 cancel
first-name-3 last-name-3 cancel
first-name-4 last-name-4 cancel
first-name-5 last-name-5
`;
await processServicesCloud.navigateTo({ componentName: 'people', story: 'valid-preselected-users' });
await expect(peopleComponent.usersNaming).toContainText(expectedUsersName);
});
test('Mandatory Preselected Users', async ({ processServicesCloud, peopleComponent }) => {
const expectedUsersName = `
first-name-1 last-name-1
first-name-2 last-name-2 cancel
`;
await processServicesCloud.navigateTo({ componentName: 'people', story: 'mandatory-preselected-users' });
await peopleComponent.getUserLocator('userName1').hover();
await expect.soft(peopleComponent.usersNaming).toContainText(expectedUsersName);
await expect(peopleComponent.tooltip.content).toContainText('Mandatory');
});
test('Invalid Preselected Users', async ({ processServicesCloud, peopleComponent }) => {
const expectedWarningMessage = 'warning No user found with the username invalid user';
await processServicesCloud.navigateTo({ componentName: 'people', story: 'invalid-preselected-users' });
await expect(peopleComponent.error.content).toContainText(expectedWarningMessage);
});
test('Excluded Users', async ({ processServicesCloud, peopleComponent }) => {
const expectedExcludedUsers = `
mocked-user-id-2
mocked-user-id-3
`;
await processServicesCloud.navigateTo({ componentName: 'people', story: 'excluded-users' });
await peopleComponent.usersInput.type('user');
await expect(peopleComponent.listbox.allOptions).not.toContainText(expectedExcludedUsers);
});
test('No Users', async ({ processServicesCloud, peopleComponent }) => {
const expectedInformation = 'No user found with the username user';
await processServicesCloud.navigateTo({ componentName: 'people', story: 'no-users' });
await peopleComponent.usersInput.type('user');
await expect(peopleComponent.listbox.oneOption).toContainText(expectedInformation);
});
});

View File

@ -0,0 +1,16 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
const rootFolder = 'e2e-output/playwright-data';
export const paths = {
rootFolder,
files: `${rootFolder}/downloads`,
report: `${rootFolder}/report`,
userStates: `${rootFolder}/user-states`
};

View File

@ -0,0 +1,17 @@
/*
* Copyright © 2005 - 2021 Alfresco Software, Ltd. All rights reserved.
*
* License rights for this program may be obtained from Alfresco Software, Ltd.
* pursuant to a written agreement and any use of this program without such an
* agreement is prohibited.
*/
export const timeouts = {
tiny: 500,
short: 1000,
medium: 5000,
large: 10000,
globalTest: 30 * 1000,
webServer: 120 * 1000,
globalSpec: 60 * 10 * 1000
};

1118
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,8 @@
"postbuild:ci": "node ./scripts/app-config-replace.js",
"06": "echo -------------------------------------------- Clean ----------------------------------------------",
"06s": "",
"clean": "rimraf dist node_modules lib/dist"
"clean": "rimraf dist node_modules lib/dist",
"playwright": "npx playwright test --config='e2e-playwright/playwright.config.ts'"
},
"repository": {
"type": "git",
@ -108,12 +109,18 @@
"devDependencies": {
"@angular-devkit/build-angular": "^0.1002.2",
"@angular-devkit/build-ng-packagr": "~0.1002.2",
"@angular-eslint/builder": "1.2.0",
"@angular-eslint/eslint-plugin": "1.2.0",
"@angular-eslint/eslint-plugin-template": "1.2.0",
"@angular-eslint/schematics": "1.2.0",
"@angular-eslint/template-parser": "1.2.0",
"@angular/cli": "^10.2.2",
"@angular/compiler-cli": "^10.0.12",
"@nrwl/schematics": "8.12.11",
"@nrwl/storybook": "^12.9.0",
"@nrwl/workspace": "^11.2.11",
"@paperist/types-remark": "0.1.3",
"@playwright/test": "^1.19.2",
"@storybook/addon-essentials": "~6.3.0",
"@storybook/angular": "~6.3.0",
"@storybook/builder-webpack5": "~6.3.0",
@ -125,6 +132,8 @@
"@types/pdfjs-dist": "^2.1.5",
"@types/request": "^2.48.5",
"@types/selenium-webdriver": "^4.0.11",
"@typescript-eslint/eslint-plugin": "4.3.0",
"@typescript-eslint/parser": "4.3.0",
"ajv-cli": "^4.2.0",
"codelyzer": "^6.0.1",
"commander": "6.2.1",
@ -132,6 +141,12 @@
"cspell": "^5.5.1",
"css-loader": "^5.2.6",
"dotenv": "^8.2.0",
"eslint": "^7.6.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsdoc": "30.7.6",
"eslint-plugin-prefer-arrow": "1.2.2",
"eslint-plugin-rxjs": "latest",
"eslint-plugin-unicorn": "latest",
"github-api": "^3.4.0",
"graphql": "^15.8.0",
"graphql-request": "^3.7.0",
@ -171,20 +186,7 @@
"tsconfig-paths": "^3.12.0",
"tslint": "6.1.3",
"typescript": "3.9.8",
"webdriver-manager": "12.1.8",
"eslint": "^7.6.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsdoc": "30.7.6",
"eslint-plugin-prefer-arrow": "1.2.2",
"@angular-eslint/builder": "1.2.0",
"@angular-eslint/eslint-plugin": "1.2.0",
"@angular-eslint/eslint-plugin-template": "1.2.0",
"@angular-eslint/schematics": "1.2.0",
"@angular-eslint/template-parser": "1.2.0",
"@typescript-eslint/eslint-plugin": "4.3.0",
"@typescript-eslint/parser": "4.3.0",
"eslint-plugin-unicorn": "latest",
"eslint-plugin-rxjs": "latest"
"webdriver-manager": "12.1.8"
},
"license": "Apache-2.0",
"bundlesize": [

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
# At the moment we only need to install chromium
npx playwright install chromium

View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Increase the max_user_watches
sudo sysctl -w fs.inotify.max_user_watches=524288
# Run Playwright Storybook Tests
npx playwright test --config='e2e-playwright/playwright.config.ts' || exit 1