Skip to content

Commit

Permalink
feat: e2e coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinderoubaix committed Jul 27, 2023
1 parent ecfeeb7 commit 04eee32
Show file tree
Hide file tree
Showing 25 changed files with 1,060 additions and 335 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,21 @@ jobs:
git commit -a -m v${{ inputs.version }}
git tag v${{ inputs.version }}
git show HEAD
- run: npm run build:ci
- run: npm run format:check
- run: npm run lint
- run: npx playwright install --with-deps
- run: npm run test
- run: npm run build:coverage
- run: npm run e2e
- uses: codecov/codecov-action@v3
with:
file: core/coverage/lcov.info
flags: unit
- uses: codecov/codecov-action@v3
with:
file: e2e/coverage/lcov.info
flags: e2e
- run: npm run build:ci
- run: npm run lint
- if: inputs.docPublish
uses: actions/checkout@v3
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ playwright-report/
test-results/
.svelte-kit/
dist.tar.gz
.nyc_output/
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ node_modules
dist
.angular
coverage/
.nyc_output/
playwright-report/
test-results/
.svelte-kit/
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# AgnosUI: A Versatile Frontend Widget Library for CSS Bootstrap Design

[![Build Status](https://github.com/AmadeusITGroup/AgnosUI/workflows/ci/badge.svg?branch=master)](https://github.com/AmadeusITGroup/AgnosUI/actions)
[![codecov](https://codecov.io/gh/AmadeusITGroup/AgnosUI/branch/master/graph/badge.svg)](https://codecov.io/gh/AmadeusITGroup/AgnosUI)

## Introduction

AgnosUI is a powerful library of widgets designed specifically for the [CSS Bootstrap design](https://getbootstrap.com/). Inspired by the success of [ng-bootstrap](https://ng-bootstrap.github.io/#/home), AgnosUI takes the concept a step further by offering widgets that can seamlessly integrate with any front-end framework of your choice. With support for popular frameworks like [Angular](https://angular.io/), [React](https://react.dev/), and [Svelte](https://svelte.dev/), AgnosUI allows you to effortlessly create consistent and visually appealing UI components across your projects.
Expand Down
13 changes: 11 additions & 2 deletions angular/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"builder": "ngx-build-plus:browser",
"options": {
"outputPath": "dist/demo",
"index": "demo/src/index.html",
Expand Down Expand Up @@ -55,12 +55,16 @@
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
},
"coverage": {
"sourceMap": true,
"extraWebpackConfig": "./demo/coverage.webpack.js"
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "ngx-build-plus:dev-server",
"configurations": {
"production": {
"servePath": "/angular/samples",
Expand All @@ -69,6 +73,11 @@
"development": {
"servePath": "/angular/samples",
"browserTarget": "demo:build:development"
},
"coverage": {
"servePath": "/angular/samples",
"browserTarget": "demo:build:coverage",
"extraWebpackConfig": "./demo/coverage.webpack.js"
}
},
"defaultConfiguration": "development"
Expand Down
15 changes: 15 additions & 0 deletions angular/demo/coverage.webpack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
module: {
rules: [
{
test: /\.(js|ts)$/,
loader: 'coverage-istanbul-loader',
options: {esModules: true},
enforce: 'post',
// eslint-disable-next-line @typescript-eslint/no-var-requires
include: [require('path').join(__dirname, '..', 'lib', 'src'), require('path').join(__dirname, '..', '..', 'core')],
exclude: [/\.(e2e|spec|po)\.ts$/, /node_modules/, /(ngfactory|ngstyle)\.js/],
},
],
},
};
4 changes: 4 additions & 0 deletions angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"scripts": {
"ng": "ng",
"dev": "ng serve",
"dev:coverage": "ng serve --configuration coverage",
"build": "npm run build:lib && npm run build:demo",
"build:lib": "ng build lib",
"build:demo": "ng build demo",
"build:copy": "node ../demo/scripts/copy.mjs angular",
"build:coverage": "ng build demo --configuration coverage",
"watch": "ng build --watch --configuration development",
"preview": "node ./scripts/preview.cjs dist/demo --port 4200 --single",
"tdd": "npm run test:lib --watch",
Expand Down Expand Up @@ -37,13 +39,15 @@
"@angular/compiler-cli": "^16.1.3",
"@types/jasmine": "^4.3.5",
"@types/webpack-env": "^1.18.1",
"coverage-istanbul-loader": "^3.0.5",
"jasmine-core": "^5.0.1",
"karma": "^6.4.2",
"karma-chrome-launcher": "^3.2.0",
"karma-coverage": "^2.2.1",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"ng-packagr": "^16.1.0",
"ngx-build-plus": "^16.0.0",
"raw-loader": "^4.0.2",
"sirv-cli": "^2.0.2",
"typescript": "~5.1.6"
Expand Down
1 change: 1 addition & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"dev": "vite dev -c vite.config.ts",
"build": "npm run build:demo && npm run svelte-check",
"build:coverage": "npm run build",
"build:demo": "vite build -c vite.config.ts",
"preview": "vite preview -c vite.config.ts",
"svelte-check": "svelte-check"
Expand Down
2 changes: 1 addition & 1 deletion e2e/alert/alert.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AlertPO} from '@agnos-ui/page-objects';
import {expect, test} from '@playwright/test';
import {expect, test} from '../fixture';
import {AlertDemoPO} from '../demo-po/alert.po';

test.describe(`Alert tests`, () => {
Expand Down
15 changes: 15 additions & 0 deletions e2e/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {test as base} from '@playwright/test';
import {promises as fs} from 'fs';
import path from 'path';
import {v4 as uuidv4} from 'uuid';

export const test = base.extend({});
test.afterEach(async ({page}) => {
const coverage: string = await page.evaluate(() => {
return JSON.stringify((window as any).__coverage__);
});
if (coverage) {
await fs.writeFile(path.join(__dirname, '.nyc_output', `${uuidv4()}.json`), coverage);
}
});
export {expect} from '@playwright/test';
2 changes: 1 addition & 1 deletion e2e/focustrack/focustrack.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {test, expect} from '@playwright/test';
import {expect, test} from '../fixture';
import {FocusTrackPO} from '../demo-po/focustrack.po';

type PromiseValue<T> = T extends Promise<infer U> ? U : never;
Expand Down
28 changes: 28 additions & 0 deletions e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import NYC from 'nyc';
import {promises as fs} from 'fs';
import {rm} from 'fs/promises';
import path from 'path';

async function globalSetup() {
console.log('Cleaning up coverage folders...');
const nycDir = path.join('e2e', '.nyc_output');
const reportDir = path.join('e2e', 'coverage');
await rm(nycDir, {recursive: true, force: true});
await fs.mkdir(nycDir);
await rm(reportDir, {recursive: true, force: true});
await fs.mkdir(reportDir);
console.log('Coverage setup ready !');
const nycInstance = new NYC({
cwd: __dirname,
['report-dir']: reportDir,
reporter: ['lcov', 'json', 'text-summary'],
extension: ['.ts', '.tsx', '.svelte'],
});
return async () => {
console.log('Saving coverage report...');
await nycInstance.report();
console.log('Coverage report saved !');
};
}

export default globalSetup;
52 changes: 33 additions & 19 deletions e2e/modal/modal.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expect, test} from '@playwright/test';
import {expect, test} from '../fixture';
import {ModalDefaultDemoModalPO, ModalDemoPO, ModalStackDemoModalPO} from '../demo-po/modal.po';

test.describe.parallel(`Modal tests`, () => {
Expand All @@ -7,24 +7,38 @@ test.describe.parallel(`Modal tests`, () => {
const modalPO = new ModalDefaultDemoModalPO(page, 0);
await page.goto('#/modal/default');
await modalDemoPO.locatorRoot.waitFor();
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorCloseButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You clicked on the close button');
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorYesButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You answered the question with "Yes"');
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorNoButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You answered the question with "No"');
await test.step('open modal and click on close', async () => {
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorCloseButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You clicked on the close button');
});
await test.step('open modal and click on yes', async () => {
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorYesButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You answered the question with "Yes"');
});
await test.step('open modal and click on no', async () => {
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorNoButton().click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You answered the question with "No"');
});
await test.step('open modal and click on backdrop', async () => {
await modalDemoPO.locatorLaunchDemoModalButton().click();
expect(modalPO.locatorTitle()).toContainText('Save changes');
expect(modalPO.locatorBody()).toContainText('Do you want to save your changes?');
await modalPO.locatorRoot.click();
await modalPO.locatorRoot.waitFor({state: 'hidden'});
await expect(modalDemoPO.locatorMessage()).toContainText('You clicked outside the modal');
});
});

test(`Modal stack`, async ({page}) => {
Expand Down
2 changes: 1 addition & 1 deletion e2e/pagination/pagination.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expect, test} from '@playwright/test';
import {expect, test} from '../fixture';
import {PaginationPO} from '@agnos-ui/page-objects';
import {PaginationDemoPO} from '../demo-po/pagination.po';

Expand Down
120 changes: 84 additions & 36 deletions e2e/rating/rating.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expect, test} from '@playwright/test';
import {expect, test} from '../fixture';
import {RatingPO} from '@agnos-ui/page-objects';
import {RatingDemoPO} from '../demo-po/rating.po';

Expand All @@ -20,41 +20,89 @@ test.describe.parallel(`Rating tests`, () => {
await page.goto('#/rating/default');
await ratingPO.locatorRoot.waitFor();

let expectedState: State = {
rootClasses: ['d-inline-flex', 'au-rating'],
min: '0',
max: '10',
value: '3',
text: '3 out of 10',
disabled: null,
readonly: null,
stars: ['★', '★', '★', '☆', '☆', '☆', '☆', '☆', '☆', '☆'],
classes: createArray(10, ['au-rating-star']),
};

expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 3, hovered: 0, left: 0});

const star = ratingPO.locatorStar(4);

await star.hover();
expectedState = {
...expectedState,
value: '5',
text: '5 out of 10',
stars: ['★', '★', '★', '★', '★', '☆', '☆', '☆', '☆', '☆'],
};
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 3, hovered: 5, left: 0});
expect(await ratingPO.state()).toEqual(expectedState);

await star.click();
expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 5, hovered: 5, left: 0});

await page.locator('body').hover(); // Leave the first rating

expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 5, hovered: 5, left: 5});
await test.step('click interactions', async () => {
let expectedState: State = {
rootClasses: ['d-inline-flex', 'au-rating'],
min: '0',
max: '10',
value: '3',
text: '3 out of 10',
disabled: null,
readonly: null,
stars: ['★', '★', '★', '☆', '☆', '☆', '☆', '☆', '☆', '☆'],
classes: createArray(10, ['au-rating-star']),
};

expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 3, hovered: 0, left: 0});

const star = ratingPO.locatorStar(4);

await star.hover();
expectedState = {
...expectedState,
value: '5',
text: '5 out of 10',
stars: ['★', '★', '★', '★', '★', '☆', '☆', '☆', '☆', '☆'],
};
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 3, hovered: 5, left: 0});
expect(await ratingPO.state()).toEqual(expectedState);

await star.click();
expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 5, hovered: 5, left: 0});

await page.locator('body').hover(); // Leave the first rating

expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 5, hovered: 5, left: 5});

await star.click();
await page.locator('body').hover(); // Leave the first rating
expectedState = {
...expectedState,
value: '0',
text: '0 out of 10',
stars: ['☆', '☆', '☆', '☆', '☆', '☆', '☆', '☆', '☆', '☆'],
};
expect(await ratingPO.state()).toEqual(expectedState);
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: 0, hovered: 5, left: 5});
});
await test.step('keyboard interactions', async () => {
await ratingPO.locatorRoot.focus();
const expectValue = async (value: number) => {
expect(await ratingPO.state()).toEqual({
rootClasses: ['d-inline-flex', 'au-rating'],
min: '0',
max: '10',
value: value.toString(),
text: `${value} out of 10`,
disabled: null,
readonly: null,
stars: createArray(value, '★').concat(createArray(10 - value, '☆')),
classes: createArray(10, ['au-rating-star']),
});
expect(await ratingDemoPO.defaultRatingDemoState()).toEqual({rating: value, hovered: 5, left: 5});
};
await page.keyboard.press('ArrowRight');
await expectValue(1);
await page.keyboard.press('ArrowUp');
await expectValue(2);
await page.keyboard.press('ArrowLeft');
await expectValue(1);
await page.keyboard.press('ArrowDown');
await expectValue(0);
await page.keyboard.press('End');
await expectValue(10);
await page.keyboard.press('Home');
await expectValue(0);
await page.keyboard.press('PageUp');
await expectValue(10);
await page.keyboard.press('PageDown');
await expectValue(0);
await page.keyboard.press('a');
await expectValue(0);
});
});

test(`Read only`, async ({page}) => {
Expand Down
Loading

0 comments on commit 04eee32

Please sign in to comment.