Skip to content

Commit

Permalink
WRQ-4709 : Added performance tests for agate components (#79)
Browse files Browse the repository at this point in the history
* added performance tests for agate components

* code review fixes

* Solved lint errors. Added fallback script for serve

* minor update README

---------

Co-authored-by: Seungho Park <[email protected]>
  • Loading branch information
daniel-stoian-lgp and seunghoh authored Feb 1, 2024
1 parent 2017ac1 commit b001733
Show file tree
Hide file tree
Showing 91 changed files with 6,067 additions and 10 deletions.
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,32 @@ We utilize puppeteer to get chrome performance traces.

### Testing Sandstone components

Start the server with Sandstone components and run the test suite on it.
You can start the server and run the test suite on it separately. Sandstone is the default theme, so you can simply use:

```
npm run test-all -- --theme=sandstone
npm run serve
npm run test
```

Alternatively, you can use the test-all command to start the server and run the test suite together:

```
npm run serve-sandstone
npm run test -- --theme=sandstone
npm run test-all
```

### Testing Agate components

Start the server with Agate components and run the test suite on it.
```
npm run test-all -- --theme=agate
```
Start the server with Agate components and run the test suite on it. You can specify the theme by adding --theme=agate at the end of the command:

```
npm run serve-agate
npm run test -- --theme=agate
```

```
npm run test-all -- --theme=agate
```

On Windows OS you might need to install `cross-env` globally with `npm install -g cross-env`.

## Testing on TV
Expand All @@ -47,7 +52,6 @@ TV_IP=10.0.1.1 npm run test -- --target=TV --theme=sandstone
## CPU Throttling

You can simulate a low-end device with a CPU throttling option. 1 is no throttle, 2 is 2x slowdown.

See the [Puppeteer API docs](https://pptr.dev/api/puppeteer.page.emulatecputhrottling) for the detailed information.

Available commands are:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"author": "",
"main": "src/index.js",
"scripts": {
"serve": "cross-env REACT_APP_ENACT_THEME=sandstone enact serve",
"serve-sandstone": "cross-env REACT_APP_ENACT_THEME=sandstone enact serve",
"serve-agate": "cross-env REACT_APP_ENACT_THEME=agate enact serve",
"pack": "enact pack",
Expand Down
2 changes: 1 addition & 1 deletion performance/TraceModel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global requestAnimationFrame, PerformanceObserver */
/* global requestAnimationFrame */

const fs = require('fs');

Expand Down
139 changes: 139 additions & 0 deletions performance/tests/agate/ArcPicker.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* global CPUThrottling, page, minFPS, maxFID, maxCLS, stepNumber, maxDCL, maxFCP, maxLCP, passRatio, serverAddr, targetEnv */

const TestResults = require('../../TestResults');
const {CLS, FID, FPS, getAverageFPS, PageLoadingMetrics} = require('../../TraceModel');
const {clsValue, firstInputValue, getFileName, newPageMultiple} = require('../../utils');

describe('ArcPicker', () => {
const component = 'ArcPicker';
TestResults.newFile(component);

describe('click', () => {
it('animates', async () => {
await FPS();
await page.goto(`http://${serverAddr}/arcPicker`);
await page.waitForSelector('#arcPicker');
await page.click('#arcPicker'); // to move mouse on the button.
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();

const averageFPS = await getAverageFPS();
TestResults.addResult({component: component, type: 'FPS Click', actualValue: Math.round((averageFPS + Number.EPSILON) * 1000) / 1000});

expect(averageFPS).toBeGreaterThan(minFPS);
});
});

describe('keypress', () => {
it('animates', async () => {
await FPS();
await page.goto(`http://${serverAddr}/arcPicker`);
await page.waitForSelector('#arcPicker');
await page.focus('#arcPicker');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowUp');
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowUp');
await page.keyboard.down('ArrowDown');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowDown');
await page.keyboard.down('ArrowDown');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowDown');

const averageFPS = await getAverageFPS();
TestResults.addResult({component: component, type: 'FPS Keypress', actualValue: Math.round((averageFPS + Number.EPSILON) * 1000) / 1000});

expect(averageFPS).toBeGreaterThan(minFPS);
});
});

it('should have a good FID and CLS', async () => {
await page.evaluateOnNewDocument(FID);
await page.evaluateOnNewDocument(CLS);
await page.goto(`http://${serverAddr}/arcPicker`);
await page.waitForSelector('#arcPicker');
await page.focus('#arcPicker');
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 200));

let actualFirstInput = await firstInputValue();
let actualCLS = await clsValue();

TestResults.addResult({component: component, type: 'FID', actualValue: Math.round((actualFirstInput + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'CLS', actualValue: Math.round((actualCLS + Number.EPSILON) * 1000) / 1000});

expect(actualFirstInput).toBeLessThan(maxFID);
expect(actualCLS).toBeLessThan(maxCLS);
});

it('should have a good DCL, FCP and LCP', async () => {
const filename = getFileName(component);

let passContDCL = 0;
let passContFCP = 0;
let passContLCP = 0;
let avgDCL = 0;
let avgFCP = 0;
let avgLCP = 0;
for (let step = 0; step < stepNumber; step++) {
const arcPickerPage = targetEnv === 'TV' ? page : await newPageMultiple();
await arcPickerPage.emulateCPUThrottling(CPUThrottling);

await arcPickerPage.tracing.start({path: filename, screenshots: false});
await arcPickerPage.goto(`http://${serverAddr}/arcPicker`);
await arcPickerPage.waitForSelector('#arcPicker');
await new Promise(r => setTimeout(r, 200));

await arcPickerPage.tracing.stop();

const {actualDCL, actualFCP, actualLCP} = PageLoadingMetrics(filename);
avgDCL = avgDCL + actualDCL;
if (actualDCL < maxDCL) {
passContDCL += 1;
}

avgFCP = avgFCP + actualFCP;
if (actualFCP < maxFCP) {
passContFCP += 1;
}

avgLCP = avgLCP + actualLCP;
if (actualLCP < maxLCP) {
passContLCP += 1;
}

if (targetEnv === 'PC') await arcPickerPage.close();
}
avgDCL = avgDCL / stepNumber;
avgFCP = avgFCP / stepNumber;
avgLCP = avgLCP / stepNumber;

TestResults.addResult({component: component, type: 'DCL', actualValue: Math.round((avgDCL + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'FCP', actualValue: Math.round((avgFCP + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'LCP', actualValue: Math.round((avgLCP + Number.EPSILON) * 1000) / 1000});

expect(passContDCL).toBeGreaterThan(passRatio * stepNumber);
expect(avgDCL).toBeLessThan(maxDCL);

expect(passContFCP).toBeGreaterThan(passRatio * stepNumber);
expect(avgFCP).toBeLessThan(maxFCP);

expect(passContLCP).toBeGreaterThan(passRatio * stepNumber);
expect(avgLCP).toBeLessThan(maxLCP);
});
});

139 changes: 139 additions & 0 deletions performance/tests/agate/ArcSlider.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* global CPUThrottling, page, minFPS, maxFID, maxCLS, stepNumber, maxDCL, maxFCP, maxLCP, passRatio, serverAddr, targetEnv */

const TestResults = require('../../TestResults');
const {CLS, FID, FPS, getAverageFPS, PageLoadingMetrics} = require('../../TraceModel');
const {clsValue, firstInputValue, getFileName, newPageMultiple} = require('../../utils');

describe('ArcSlider', () => {
const component = 'ArcSlider';
TestResults.newFile(component);

describe('click', () => {
it('animates', async () => {
await FPS();
await page.goto(`http://${serverAddr}/arcSlider`);
await page.waitForSelector('#arcSlider');
await page.click('#arcSlider'); // to move mouse on the button.
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();
await page.mouse.down();
await new Promise(r => setTimeout(r, 100));
await page.mouse.up();

const averageFPS = await getAverageFPS();
TestResults.addResult({component: component, type: 'FPS Click', actualValue: Math.round((averageFPS + Number.EPSILON) * 1000) / 1000});

expect(averageFPS).toBeGreaterThan(minFPS);
});
});

describe('keypress', () => {
it('animates', async () => {
await FPS();
await page.goto(`http://${serverAddr}/arcSlider`);
await page.waitForSelector('#arcSlider');
await page.focus('#arcSlider');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowUp');
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowUp');
await page.keyboard.down('ArrowDown');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowDown');
await page.keyboard.down('ArrowDown');
await new Promise(r => setTimeout(r, 100));
await page.keyboard.up('ArrowDown');

const averageFPS = await getAverageFPS();
TestResults.addResult({component: component, type: 'FPS Keypress', actualValue: Math.round((averageFPS + Number.EPSILON) * 1000) / 1000});

expect(averageFPS).toBeGreaterThan(minFPS);
});
});

it('should have a good FID and CLS', async () => {
await page.evaluateOnNewDocument(FID);
await page.evaluateOnNewDocument(CLS);
await page.goto(`http://${serverAddr}/arcSlider`);
await page.waitForSelector('#arcSlider');
await page.focus('#arcSlider');
await page.keyboard.down('ArrowUp');
await new Promise(r => setTimeout(r, 200));

let actualFirstInput = await firstInputValue();
let actualCLS = await clsValue();

TestResults.addResult({component: component, type: 'FID', actualValue: Math.round((actualFirstInput + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'CLS', actualValue: Math.round((actualCLS + Number.EPSILON) * 1000) / 1000});

expect(actualFirstInput).toBeLessThan(maxFID);
expect(actualCLS).toBeLessThan(maxCLS);
});

it('should have a good DCL, FCP and LCP', async () => {
const filename = getFileName(component);

let passContDCL = 0;
let passContFCP = 0;
let passContLCP = 0;
let avgDCL = 0;
let avgFCP = 0;
let avgLCP = 0;
for (let step = 0; step < stepNumber; step++) {
const buttonPage = targetEnv === 'TV' ? page : await newPageMultiple();
await buttonPage.emulateCPUThrottling(CPUThrottling);

await buttonPage.tracing.start({path: filename, screenshots: false});
await buttonPage.goto(`http://${serverAddr}/arcSlider`);
await buttonPage.waitForSelector('#arcSlider');
await new Promise(r => setTimeout(r, 200));

await buttonPage.tracing.stop();

const {actualDCL, actualFCP, actualLCP} = PageLoadingMetrics(filename);
avgDCL = avgDCL + actualDCL;
if (actualDCL < maxDCL) {
passContDCL += 1;
}

avgFCP = avgFCP + actualFCP;
if (actualFCP < maxFCP) {
passContFCP += 1;
}

avgLCP = avgLCP + actualLCP;
if (actualLCP < maxLCP) {
passContLCP += 1;
}

if (targetEnv === 'PC') await buttonPage.close();
}
avgDCL = avgDCL / stepNumber;
avgFCP = avgFCP / stepNumber;
avgLCP = avgLCP / stepNumber;

TestResults.addResult({component: component, type: 'DCL', actualValue: Math.round((avgDCL + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'FCP', actualValue: Math.round((avgFCP + Number.EPSILON) * 1000) / 1000});
TestResults.addResult({component: component, type: 'LCP', actualValue: Math.round((avgLCP + Number.EPSILON) * 1000) / 1000});

expect(passContDCL).toBeGreaterThan(passRatio * stepNumber);
expect(avgDCL).toBeLessThan(maxDCL);

expect(passContFCP).toBeGreaterThan(passRatio * stepNumber);
expect(avgFCP).toBeLessThan(maxFCP);

expect(passContLCP).toBeGreaterThan(passRatio * stepNumber);
expect(avgLCP).toBeLessThan(maxLCP);
});
});

Loading

0 comments on commit b001733

Please sign in to comment.