Skip to content
54 changes: 32 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ Alternatively, you can use the test-all command to start the server and run the
npm run test-all
```

If you need to test only a certain component, you can specify its name in the test command:

```
npm run test Alert
```

### Testing Agate components

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:
Expand All @@ -34,6 +40,10 @@ npm run test -- --theme=agate
npm run test-all -- --theme=agate
```

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

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

## Testing on TV
Expand Down Expand Up @@ -127,8 +137,8 @@ Test results are compared to the optimum values which are stored in global varia

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

describe('Dropdown', () => {
const component = 'Dropdown';
Expand Down Expand Up @@ -187,21 +197,7 @@ describe('Dropdown', () => {
});
});

it('should have a good CLS', async () => {
await page.evaluateOnNewDocument(CLS);
await page.goto(`http://${serverAddr}/dropdown`);
await page.waitForSelector('#dropdown');
await page.focus('#dropdown');
await page.keyboard.down('Enter');

let actualCLS = await clsValue();

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

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

it('should have a good INP', async () => {
it('should have a good CLS and INP', async () => {
await page.goto(`http://${serverAddr}/dropdown`);
await page.addScriptTag({url: webVitalsURL});
await page.waitForSelector('#dropdown');
Expand All @@ -210,17 +206,31 @@ describe('Dropdown', () => {
await page.keyboard.down('Enter');
await new Promise(r => setTimeout(r, 100));

let inpValue;
let maxValue;

page.on("console", (msg) => {
inpValue = Number(msg.text());
TestResults.addResult({component: component, type: 'INP', actualValue: Math.round((inpValue + Number.EPSILON) * 1000) / 1000});
expect(inpValue).toBeLessThan(maxINP);
let jsonMsg = JSON.parse(msg.text());
if (jsonMsg.name === 'CLS') {
maxValue = maxCLS;
} else if (jsonMsg.name === 'INP') {
maxValue = maxINP;
}

TestResults.addResult({component: component, type: jsonMsg.name, actualValue: Math.round((Number(jsonMsg.value) + Number.EPSILON) * 1000) / 1000});
expect(Number(jsonMsg.value)).toBeLessThan(maxValue);
});

await page.evaluateHandle(() => {
webVitals.onINP(function (inp) {
console.log(inp.value); // eslint-disable-line no-console
console.log(JSON.stringify({"name": inp.name, "value": inp.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
}
);

webVitals.onCLS(function (cls) {
console.log(JSON.stringify({"name": cls.name, "value": cls.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
Expand Down
13 changes: 0 additions & 13 deletions performance/TraceModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,6 @@ const FPS = async () => {

const getAverageFPS = () => (window.FPSValues.reduce((a, b) => a + b, 0) / window.FPSValues.length) || 0;

const CLS = () => {
window.cls = 0;
new PerformanceObserver(entryList => {
let entries = entryList.getEntries() || [];
entries.forEach(e => {
if (!e.hadRecentInput) { // omit entries likely caused by user input
window.cls += e.value;
}
});
}).observe({type: 'layout-shift', buffered: true});
};

const PageLoadingMetrics = (filename) => {
const events = fs.readFileSync(filename, 'utf8');
const result = JSON.parse(events);
Expand All @@ -49,7 +37,6 @@ const PageLoadingMetrics = (filename) => {
};

module.exports = {
CLS,
FPS,
getAverageFPS,
PageLoadingMetrics
Expand Down
45 changes: 22 additions & 23 deletions performance/tests/agate/ArcPicker.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* global CPUThrottling, page, minFPS, maxCLS, stepNumber, maxDCL, maxFCP, maxINP, maxLCP, passRatio, serverAddr, targetEnv, webVitals, webVitalsURL */

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

describe('ArcPicker', () => {
const component = 'ArcPicker';
Expand Down Expand Up @@ -61,22 +61,7 @@ describe('ArcPicker', () => {
});
});

it('should have a good CLS', async () => {
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 actualCLS = await clsValue();

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

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

it('should have a good INP', async () => {
it('should have a good CLS and INP', async () => {
await page.goto(`http://${serverAddr}/arcPicker`);
await page.addScriptTag({url: webVitalsURL});
await page.waitForSelector('#arcPicker');
Expand All @@ -86,17 +71,31 @@ describe('ArcPicker', () => {
await page.keyboard.up('ArrowUp');
await new Promise(r => setTimeout(r, 200));

let inpValue;
let maxValue;

page.on("console", (msg) => {
inpValue = Number(msg.text());
TestResults.addResult({component: component, type: 'INP', actualValue: Math.round((inpValue + Number.EPSILON) * 1000) / 1000});
expect(inpValue).toBeLessThan(maxINP);
let jsonMsg = JSON.parse(msg.text());
if (jsonMsg.name === 'CLS') {
maxValue = maxCLS;
} else if (jsonMsg.name === 'INP') {
maxValue = maxINP;
}

TestResults.addResult({component: component, type: jsonMsg.name, actualValue: Math.round((Number(jsonMsg.value) + Number.EPSILON) * 1000) / 1000});
expect(Number(jsonMsg.value)).toBeLessThan(maxValue);
});

await page.evaluateHandle(() => {
webVitals.onINP(function (inp) {
console.log(inp.value); // eslint-disable-line no-console
console.log(JSON.stringify({"name": inp.name, "value": inp.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
}
);

webVitals.onCLS(function (cls) {
console.log(JSON.stringify({"name": cls.name, "value": cls.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
Expand Down
45 changes: 22 additions & 23 deletions performance/tests/agate/ArcSlider.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* global CPUThrottling, page, minFPS, maxCLS, stepNumber, maxDCL, maxFCP, maxINP, maxLCP, passRatio, serverAddr, targetEnv, webVitals, webVitalsURL */

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

describe('ArcSlider', () => {
const component = 'ArcSlider';
Expand Down Expand Up @@ -61,22 +61,7 @@ describe('ArcSlider', () => {
});
});

it('should have a good CLS', async () => {
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 actualCLS = await clsValue();

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

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

it('should have a good INP', async () => {
it('should have a good CLS and INP', async () => {
await page.goto(`http://${serverAddr}/arcSlider`);
await page.addScriptTag({url: webVitalsURL});
await page.waitForSelector('#arcSlider');
Expand All @@ -86,17 +71,31 @@ describe('ArcSlider', () => {
await page.keyboard.up('ArrowUp');
await new Promise(r => setTimeout(r, 200));

let inpValue;
let maxValue;

page.on("console", (msg) => {
inpValue = Number(msg.text());
TestResults.addResult({component: component, type: 'INP', actualValue: Math.round((inpValue + Number.EPSILON) * 1000) / 1000});
expect(inpValue).toBeLessThan(maxINP);
let jsonMsg = JSON.parse(msg.text());
if (jsonMsg.name === 'CLS') {
maxValue = maxCLS;
} else if (jsonMsg.name === 'INP') {
maxValue = maxINP;
}

TestResults.addResult({component: component, type: jsonMsg.name, actualValue: Math.round((Number(jsonMsg.value) + Number.EPSILON) * 1000) / 1000});
expect(Number(jsonMsg.value)).toBeLessThan(maxValue);
});

await page.evaluateHandle(() => {
webVitals.onINP(function (inp) {
console.log(inp.value); // eslint-disable-line no-console
console.log(JSON.stringify({"name": inp.name, "value": inp.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
}
);

webVitals.onCLS(function (cls) {
console.log(JSON.stringify({"name": cls.name, "value": cls.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
Expand Down
29 changes: 22 additions & 7 deletions performance/tests/agate/BodyText.test.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
/* global CPUThrottling, page, maxCLS, stepNumber, maxDCL, maxFCP, maxLCP, passRatio, serverAddr, targetEnv */
/* global CPUThrottling, page, maxCLS, stepNumber, maxDCL, maxFCP, maxLCP, passRatio, serverAddr, targetEnv, webVitals, webVitalsURL */

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

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

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

let actualCLS = await clsValue();
let clsValue;

TestResults.addResult({component: component, type: 'CLS', actualValue: Math.round((actualCLS + Number.EPSILON) * 1000) / 1000});
page.on("console", (msg) => {
let jsonMsg = JSON.parse(msg.text());

expect(actualCLS).toBeLessThan(maxCLS);
clsValue = Number(jsonMsg.value);
TestResults.addResult({component: component, type: 'CLS', actualValue: Math.round((clsValue + Number.EPSILON) * 1000) / 1000});
expect(clsValue).toBeLessThan(maxCLS);
});

await page.evaluateHandle(() => {
webVitals.onCLS(function (cls) {
console.log(JSON.stringify({"name": cls.name, "value": cls.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
}
);
});
await new Promise(r => setTimeout(r, 1000));
});

it('should have a good DCL, FCP and LCP', async () => {
Expand Down
45 changes: 22 additions & 23 deletions performance/tests/agate/Button.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* global CPUThrottling, page, minFPS, maxCLS, stepNumber, maxDCL, maxFCP, maxINP, maxLCP, passRatio, serverAddr, targetEnv, webVitals, webVitalsURL */

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

describe('Button', () => {
const component = 'Button';
Expand Down Expand Up @@ -61,22 +61,7 @@ describe('Button', () => {
});
});

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

let actualCLS = await clsValue();

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

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

it('should have a good INP', async () => {
it('should have a good CLS and INP', async () => {
await page.goto(`http://${serverAddr}/button`);
await page.addScriptTag({url: webVitalsURL});
await page.waitForSelector('#agate-button');
Expand All @@ -86,17 +71,31 @@ describe('Button', () => {
await page.keyboard.up('Enter');
await new Promise(r => setTimeout(r, 200));

let inpValue;
let maxValue;

page.on("console", (msg) => {
inpValue = Number(msg.text());
TestResults.addResult({component: component, type: 'INP', actualValue: Math.round((inpValue + Number.EPSILON) * 1000) / 1000});
expect(inpValue).toBeLessThan(maxINP);
let jsonMsg = JSON.parse(msg.text());
if (jsonMsg.name === 'CLS') {
maxValue = maxCLS;
} else if (jsonMsg.name === 'INP') {
maxValue = maxINP;
}

TestResults.addResult({component: component, type: jsonMsg.name, actualValue: Math.round((Number(jsonMsg.value) + Number.EPSILON) * 1000) / 1000});
expect(Number(jsonMsg.value)).toBeLessThan(maxValue);
});

await page.evaluateHandle(() => {
webVitals.onINP(function (inp) {
console.log(inp.value); // eslint-disable-line no-console
console.log(JSON.stringify({"name": inp.name, "value": inp.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
}
);

webVitals.onCLS(function (cls) {
console.log(JSON.stringify({"name": cls.name, "value": cls.value})); // eslint-disable-line no-console
},
{
reportAllChanges: true
Expand Down
Loading