Skip to main content

Writing A Scenario

To estimate the carbon footprint of your application, GreenFrame executes a Playwright scenario in a sandboxed container.

Your First Scenario

Create a JS file named as you wish - for instance, scenario.js. It should contain an async function expecting one argument: a page object. Since version 2.0.0, this function has to be exported using module.exports. (The import/export syntax is not supported yet)

./scenario.js
const scenario = async function (page) {
// Here interactions using the page object
};

module.exports = scenario;

Then, write user interactions as calls to the page object method. Every interaction returns a promise, so be sure to await them to run the scenario step by step.

Here is an example scenario:

./scenario.js
const scenario = async (page) => {
await page.goto('', { waitUntil: 'networkidle' }); // Go to the baseUrl
await page.waitForTimeout(3000); // Wait for 3 seconds
await page.scrollToElement('footer'); // Scroll to the footer (if present)
await page.waitForNetworkIdle(); // Wait every request has been answered as a normal user.
};

module.exports = scenario;

How to convert a 1.x scenario into a 2.x scenario

const scenario = [previous_code]

module.exports = scenario;

Default Scenario

The default scenario opens the URL and scrolls to the end of the page. You can use it as the basis for your scenario.

./scenario.js
const visit = async (page) => {
await page.goto('', { waitUntil: 'networkidle' });
await page.scrollToEnd();
};

module.exports = visit;

Adding Milestones

When you check the details of an analysis on the GreenFrame.io website, you may find it hard to relate a particular spike in the carbon footprint to a particular user interaction.

To help you understand what's going on, you can add milestones to your scenario. A milestone is a step that will be displayed in the analysis timeline.

Add a milestone by calling the page.addMilestone() method in your scenario:

./scenario.js
const scenario = async (page) => {
await page.goto('', { waitUntil: 'networkidle' });
await page.addMilestone('Go to solutions'); // here
await page.scrollToElement('#solutions'), await page.click('#solutions');
await page.waitForNetworkIdle();
await page.addMilestone('Go Back home'); // and here
await page.goto('', { waitUntil: 'networkidle' });
};

module.exports = scenario;

Milestone in the timeline

Using Environment Variables or External Library

In a scenario, you can import external module, either local JS files or npm libraries. This allows you to use advanced features of Playwright, specific code, or utility functions.

Here is an example of scenario using both external lib and environment variables to log in a website without hard-coding keys in the file :

./scenario.js
const { loginToWebSite } = require('externalLoginLibrary');
const login = process.env.ENV_VAR_LOGIN;
const password = process.env.ENV_VAR_PASSWORD;

const scenario = async (page) => {
await loginToWebSite(login, password);
await page.goto('', { waitUntil: 'networkidle' });
await page.scrollToEnd();
await page.waitForNetworkIdle();
};

module.exports = scenario;
  • To use an external local file, import it using require

    (The import/export syntax is not supported yet)

  • To use an external library, import it using require. It must be installed locally using your favorite package manager. For this, create a package.json file locally.

package.json
{
"name": "greenframe-myProject",
"description": "GreenFrame scenarios for myProject",
"version": "0.1.0",
"author": "Me",
"dependencies": {
"@playwright/test": "^1.30.0",
"externalLoginLibrary": "^0.1.0"
},
"license": "UNLICENSED"
}

Then, before runing greenframe, just run npm or yarn on this package.

~/myProject/yarn
~/myProject/greenframe analyze -C myConfiguration.yml
  • To use environment variables, you need to configure them using the envFile or the envVar option

    Check the Configuration File page for more details.

Playwright API

Check the PlayWright documentation on writing tests for more information.

Recording A Scenario

You can write scenarios by hand, or use the PlayWright Test Generator to generate a scenario based on a user session.

Custom Playwright Instance

GreenFrame's Playwright instance is tweaked in 2 ways:

  • To better replicate real user interactions (which are much slower than what a robot does), new methods were added and some existing methods were overridden.
  • To prevent malicious users from executing arbitrary shell scripts in the container, some methods were removed

Page Methods

The page object exposed in GreenFrame scenarios is the PlayWright page object augmented with a few methods improving the developer experience.

Here is a list of methods that only exists in GreenFrame's page object.

page.scrollToElement(selector)

Scroll smoothly to an element.

Example:

await page.scrollToElement('footer');

page.scrollToEnd()

Scroll smoothly to the end of the page.

Example:

await page.scrollToEnd();

page.waitForNetworkIdle([state, options])

This method waits until networkIdle.

  • This is syntactic sugar for page.waitForLoadState() where the state is fixed at networkidle

Playwright doc

await page.waitForNetworkIdle(); // The promise resolves after 'networkidle' event.

page.scrollByDistance(distance)

Scroll smoothly of the given offset in pixels

  • distance <number>: Distance of the smooth scroll. Can either be positive (go down) or negative (go up).

Example:

await page.scrollByDistance(100); // go down by 100px
await page.scrollByDistance(-100); // go up by 100px

page.addMilestone(milestone)

You can add milestones to a scenario. These milestones will be displayed on analysis graphs and allow you to understand which user actions perform this peak on graphs.

Example:

await page.addMilestone('Go to home');

The milestone name must be unique in your scenario.

Best practices to write a good scenario

To have good stability in your scenario and detect changes during development, it is important to keep in mind some best practices by using GreenFrame CLI.

The main goal is to be sure that GreenFrame CLI can track every network request, record every page rendering, and collect the same amount of data for each subsequent analysis.

Typically, if you click on a button while the server has not responded to the request yet, The GreenFrame CLI might not track the entire network traffic.

If your page hasn't been entirely loaded, your CPU Usage will also be underestimated.

Use { waitUntil: 'networkidle' } as often as possible

Avoid :

await page.goto('/path');
await page.waitForNavigation();

Prefer:

await page.goto('/path', { waitUntil: 'networkidle' });
await page.waitForNavigation({ waitUntil: 'networkidle' });

By default, a goto function will be resolved when the page has fired the load event.

The waitUntil with networkidle option force Playwright to resolve the function when no request has been opened in the last 500ms and all requests have been answered.

Whenever you want to be sure your network has been fully tracked, you can use the following custom function:

await page.waitForNetworkIdle();

Use waitForNavigation on Page Change

Most of the time your scenario will click on a button or a link to be redirected to another page. You can ensure that your navigation is terminated by using a Promise.all()

await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }),
page.click('a'),
]);

The following line will be resolved when both waitForNavigation and click functions have been resolved. It is important to put in first the waitForNavigation function because it will tell Playwright to be ready for a page change.