Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
ceckoslab committed Dec 28, 2023
0 parents commit 3dc5226
Show file tree
Hide file tree
Showing 14 changed files with 2,663 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[*]
end_of_line = lf
insert_final_newline = true

[*.js]
indent_style = space
indent_size = 2
114 changes: 114 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{
"env": {
"browser": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 8
},
"globals": {
"console": false,
"unescape": false
},
"rules": {
//
// Rules that were enabled by default in pre-1.0 eslint
// https://github.com/eslint/eslint/blob/master/docs/user-guide/migrating-to-1.0.0.md
// re-enable all the ones we are not specifically disabling
//
"no-alert": 2,
"no-array-constructor": 2,
"no-caller": 2,
"no-catch-shadow": 2,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-implied-eval": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": 2,
"no-lone-blocks": 2,
"no-loop-func": 2,
"no-multi-str": 2,
"no-native-reassign": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-new-wrappers": 2,
"no-octal-escape": 2,
"no-process-exit": 2,
"no-proto": 2,
"no-return-assign": 2,
"no-script-url": 2,
"no-sequences": 2,
"no-shadow": 2,
"no-shadow-restricted-names": 2,
"no-spaced-func": 2,
"no-undef-init": 2,
"no-unused-expressions": 2,
"no-use-before-define": [2, { "functions": false }],
"no-with": 2,
"comma-spacing": 2,
"curly": [2, "all"],
"eol-last": 2,
"no-extra-parens": [2, "functions"],
"eqeqeq": 2,
"new-parens": 2,
"semi": 2,
"space-infix-ops": 2,
"yoda": [2, "never"],

//
// Changes over defaults
//
"keyword-spacing": 2,
"no-mixed-spaces-and-tabs": [2, true],
"quotes": [2, "double", "avoid-escape"],
"dot-notation": [2, {"allowKeywords": true}],
"space-unary-ops": 1,
"key-spacing": [1, {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
"no-empty": 2,
"brace-style": [1, "stroustrup", { "allowSingleLine": true }],
"semi-spacing": [2, {"before": false, "after": true}],
"indent": [2, 2, {"VariableDeclarator": 0, "MemberExpression": "off", "CallExpression": {"arguments": "off"}, "SwitchCase": 1}],
"space-before-function-paren": [2, "never"],
"no-trailing-spaces": [2, { "skipBlankLines": false }],
"linebreak-style": [2, "unix"],
"comma-dangle": [2, "never"],
"operator-linebreak": [2, "after"],
"space-in-parens": [2, "never"],
"no-debugger": "error",

//
// To enable soon
//

//"require-jsdoc": "error",
//"valid-jsdoc": "error",

//
// Disabled rules
//

// We have a lot of variables in underscore_casing
"camelcase": 0,

// Not ready for strict-mode yet
"strict": 0,

// We have some functions like BOOMR_check_doc_domain or BOOMR.
"new-cap": 0,

// We use console.log for debugging
"no-console": 0,

// We use _s in a couple places for internal vars
"no-underscore-dangle": 0,

// We delete some global vars for compat with older IE versions
"no-delete-var": 0,

// We use spaces for alignment in many places
"no-multi-spaces": 0
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
**/.DS_Store
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript"]
}
83 changes: 83 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# INP Measure - Puppeteer

Very experimental and still in a proof of concept stage but it does the trick.

Utilizes the source code available the [Web Vitals](https://github.com/GoogleChrome/web-vitals) library.

## Configure

Tweak the following lines in `index.js`:

```
// TODO, Change here to the element you would like Puppeteer to interact with.
const elementToInteractWith = "### ADD THE CSS SELECTOR HERE ###";
// TODO, Change here to the url you would like to load in Puppeteer.
const navigateTo = "https://www.example.com/";
```

## How to run?

1. From the root folder of the project run `npm init`
2. Run `node index.js`

When we run the project a browser will open and we will observe a simulation of user journey.

When INP gets triggered we will see similar output in the terminal:
```
Running on the original page.
Failed to load resource: the server responded with a status of 404 ()
Failed to load resource: the server responded with a status of 404 ()
Unsupported namespace or locale
inp: 264
```

## Measure many times after a change:

We have a shell script that can run a simulation multiple times. At the moment we run a simulation 10 times.

Try:

```
./run.sh
```

## Override resources:

In `index.js` we have a code fragment that looks like this:

```
// Add event listener to intercept requests
page.on("request", (interceptedRequest) => {
// Check if the request is for the resource you want to override
if (interceptedRequest.url().endsWith("example-js-of-interest.js")) {
console.log("Intercepted and overriding: " + interceptedRequest.url());
// Create a response from a local file
const overrideContent = fs.readFileSync(path.join(__dirname, "overrides", "example-js-of-interest.js"), "utf8");
interceptedRequest.respond({
status: 200,
contentType: "application/javascript; charset=utf-8",
body: overrideContent
});
return;
}
// Allow all other requests to continue normally
interceptedRequest.continue();
});
```

This allows us to load from filesystem our own version of some of the frontend files.

## CPU throttling:

In `DeviceEmulation.js` tweak:
```
page.emulateCPUThrottling(4)
```

## User-Agent string and screen size emulation:

Tweak parameters in `DeviceEmulation.js`.

133 changes: 133 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
const fs = require("fs");
const path = require("path");

const puppeteer = require("puppeteer");
const { PuppeteerScreenRecorder } = require("puppeteer-screen-recorder");

const recording = false;

const Cookies = require("./src/Cookies");
const CWV = require("./src/CWV");
const DeviceEmulation = require("./src/DeviceEmulation");

// TODO, Change here to the element you would like Puppeteer to interact with.
const elementToInteractWith = "### ADD THE CSS SELECTOR HERE ###";

// TODO, Change here to the url you would like to load in Puppeteer.
const navigateTo = "https://www.example.com/";

var args = process.argv.slice(2);

let experiment = 0;

if (args[0]) {
const paramParts = args[0].split("=");

if (paramParts[0] === "experiment") {
experiment = parseInt(paramParts[1]);
}
}

if (experiment === 0) {
console.log("Running on the original page.");
}
else {
console.log("Running experiment {" + experiment + "} on a modified page.");
}

(async() => {
const browser = await puppeteer.launch({ headless: false });

const page = await browser.newPage();

if (recording) {
// Configure the screen recorder
const recorder = new PuppeteerScreenRecorder(page, {
followNewTab: true,
fps: 30,
videoFrame: {
width: 1080,
height: 2400
}
// Other configurations
});

await recorder.start("output.mp4");
}

await DeviceEmulation.emulate(page);

// Listen for console events within the page and log them in Node.js context
page.on("console", (msg) => {
console.log(msg.text());
});

// Enable request interception
await page.setRequestInterception(true);

// Add event listener to intercept requests
page.on("request", (interceptedRequest) => {
// Check if the request is for the resource you want to override
if (interceptedRequest.url().endsWith("example-js-of-interest.js")) {
console.log("Intercepted and overriding: " + interceptedRequest.url());

// Create a response from a local file
const overrideContent = fs.readFileSync(path.join(__dirname, "overrides", "example-js-of-interest.js"), "utf8");
interceptedRequest.respond({
status: 200,
contentType: "application/javascript; charset=utf-8",
body: overrideContent
});
return;
}

// Allow all other requests to continue normally
interceptedRequest.continue();
});

// Navigate to the page
await page.goto(navigateTo);

await CWV.attachCWV_Lib(page);

await Cookies.setOptanonConsent(page);

// Wait for a specified timeout in milliseconds
await page.waitForTimeout(5000); // waits for 5 seconds

// Wait for the element to be present in the DOM
await page.waitForSelector(elementToInteractWith);

// Click the input input
await page.click(elementToInteractWith);
await page.focus(elementToInteractWith);

await page.waitForTimeout(5); // waits for 5 seconds

// Execute JS code after the timeout
await page.evaluateHandle(() => {
window.webVitals.getINP(function(info) {
if (info.value) {
console.log("inp: " + info.value);
}
else {
console.log("inp: not measured");
}
},
{
reportAllChanges: true
}
);
});

await page.waitForTimeout(5000); // waits for 5 seconds

if (recording) {
// Stop recording
await recorder.stop();
}

// You can close the browser after a timeout, or after some specific action
// that would ensure all metrics have been captured.
await browser.close();
})();
Empty file added overrides/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions overrides/example-js-of-interest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Override JS content
Loading

0 comments on commit 3dc5226

Please sign in to comment.