{"id":19935950,"url":"https://github.com/gaelgirodon/ecojourney","last_synced_at":"2025-03-01T12:19:38.205Z","repository":{"id":95469120,"uuid":"607367675","full_name":"GaelGirodon/ecojourney","owner":"GaelGirodon","description":"🚧 Ecojourney is an eco-design website audit tool focused on best practices over scoring","archived":false,"fork":false,"pushed_at":"2023-11-29T22:31:24.000Z","size":316,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-12T02:38:24.064Z","etag":null,"topics":["analysis","audit","best-practices","eco-design","green-it","lint","scan","web"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GaelGirodon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-02-27T20:58:33.000Z","updated_at":"2023-07-21T22:19:27.000Z","dependencies_parsed_at":"2023-11-29T23:25:00.206Z","dependency_job_id":"5bcbb819-71d0-4f5c-b05b-3967ae48f86a","html_url":"https://github.com/GaelGirodon/ecojourney","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GaelGirodon%2Fecojourney","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GaelGirodon%2Fecojourney/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GaelGirodon%2Fecojourney/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GaelGirodon%2Fecojourney/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GaelGirodon","download_url":"https://codeload.github.com/GaelGirodon/ecojourney/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241361984,"owners_count":19950482,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analysis","audit","best-practices","eco-design","green-it","lint","scan","web"],"created_at":"2024-11-12T23:22:45.305Z","updated_at":"2025-03-01T12:19:38.158Z","avatar_url":"https://github.com/GaelGirodon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ecojourney\n\n[![version](https://img.shields.io/github/package-json/v/GaelGirodon/ecojourney?style=flat-square)](https://github.com/GaelGirodon/ecojourney/releases/latest)\n[![license](https://img.shields.io/github/license/GaelGirodon/ecojourney?color=blue\u0026style=flat-square)](./LICENSE)\n[![build](https://img.shields.io/github/actions/workflow/status/GaelGirodon/ecojourney/main.yml?branch=main\u0026style=flat-square)](https://github.com/GaelGirodon/ecojourney/actions/workflows/main.yml)\n[![tests](https://img.shields.io/endpoint?style=flat-square\u0026url=https%3A%2F%2Fgist.githubusercontent.com%2FGaelGirodon%2Ffbde4d59b7dd3c4f2cc9c4fea3497ae1%2Fraw%2Fecojourney-junit-tests.json)](https://github.com/GaelGirodon/ecojourney/actions/workflows/main.yml)\n[![coverage](https://img.shields.io/endpoint?style=flat-square\u0026url=https%3A%2F%2Fgist.githubusercontent.com%2FGaelGirodon%2Ffbde4d59b7dd3c4f2cc9c4fea3497ae1%2Fraw%2Fecojourney-cobertura-coverage.json)](https://github.com/GaelGirodon/ecojourney/actions/workflows/main.yml)\n\n**Ecojourney** is an eco-design website audit tool\nfocused on best practices over scoring.\n\n\u003e 🚧 **Ecojourney is in alpha stage**  🚧\n\u003e\n\u003e _Everything is experimental and may change significantly at any time._\n\u003e\n\u003e The NPM package hasn't been published yet, but it can be installed from the\n\u003e tarball generated by the [`build`](https://github.com/GaelGirodon/ecojourney/actions)\n\u003e job. Download and extract the `tarball.zip` file, then run:\n\u003e\n\u003e ```shell\n\u003e npm i -g ecojourney-X.Y.Z.tgz\n\u003e ```\n\n## About\n\n_Ecojourney_ analyses a browsing scenario on a web application, collecting\nmetrics and issues about eco-design best practices.\n\nIt is made to help developers improve their web application by highlighting\nissues to fix in order to reduce its environmental impact, primarily on\nend-user devices and network infrastructures. But this is not enough to affirm\nthat a web application is environmental friendly: an _Ecojourney_ audit should\nbe completed by automated and manual source code analysis, server-side\napplication analysis (e.g. energy consumption metrology with Scaphandre), and\nshould come after a rigorous UX design process (to focus on simple and useful\nfeatures), Life-Cycle Assessments (ISO 14040 \u0026 14044), and more.\n\nUnder the hood, this tool is built to be modular, extensible (_coming soon!_),\nand it uses a carefully selected small set of NPM dependencies (8, including\ntransitive ones). Playwright is the main one, enabling cross-browser web\nautomation, device emulation, proxy support and more.\n\n_Ecojourney_ is inspired by these tools, sharing several similarities, but\ntrying to bring different features and/or various improvements:\n\n- [_Lighthouse_](https://github.com/GoogleChrome/lighthouse),\n  but focuses on eco-design (even if there's some overlap with performance) and\n  allows to analyse multiple pages and complex scenarios with a single run,\n- [_GreenIT Analysis_](https://github.com/cnumr/GreenIT-Analysis)\n  ([_CLI_](https://github.com/cnumr/GreenIT-Analysis-cli)),\n  but focuses on best practices over scoring and with a more refined API\n  and tooling,\n- [_EcoIndex_](https://github.com/cnumr/Ecoindex),\n  but focuses on best practices over scoring, with more metrics and\n  bundled as a CLI tool instead of a web service.\n\n## Quick start\n\n💻 **Make sure your computer meets the following requirements:**\n\n- **Node.js 18.x or newer**\n- **A web browser**: Google Chrome, Microsoft Edge\n  or a [Playwright supported browser](https://playwright.dev/docs/browsers)\n\n📦 **Install using `npm`:**\n\n```shell\nnpm i -g ecojourney\n```\n\n🌐 **Audit a single URL:**\n\n```shell\necojourney audit https://mywebsite.net\n```\n\n📄 **Initialise a manifest file and run it:**\n\n```shell\necojourney init mywebsite.yml\necojourney audit mywebsite.yml\n```\n\n## Installation\n\n**Ecojourney** is published as an NPM package and can be installed in various\nways as long as Node.js and your favorite package manager are installed on your\nworkstation.\n\nInstall and run globally:\n\n```shell\nnpm i ecojourney -g\necojourney [command]\n```\n\nInstall and run globally, using `npx`:\n\n```shell\nnpx ecojourney [command]\n```\n\nInstall as a dev dependency of your Node.js project (_recommended_):\n\n```shell\ncd my-project/\nnpm i ecojourney -D\n```\n\n- Run locally:\n\n```shell\nnpx ecojourney [command]\n```\n\n- Run locally, using a dedicated script in your `package.json` file:\n\n```json\n{\n  \"scripts\": {\n    \"ecojourney\": \"ecojourney audit ecojourney.yml\"\n  }\n}\n```\n\n```shell\nnpm run ecojourney\n```\n\n## Usage\n\nInitialise a manifest YAML file:\n\n```shell\necojourney init mywebsite.yml\n```\n\nEdit file content:\n\n- Define the browsing scenario to audit\n- Customise the configuration: browser, device, report formats, proxy, ...\n\nRun the audit:\n\n```shell\necojourney audit mywebsite.yml\n```\n\nSome configuration options can be overridden from the CLI or environment\nvariables:\n\n```shell\nexport ECOJOURNEY_AUDIT_BROWSER=\"msedge\"\necojourney audit mywebsite.yml --dry-run\n```\n\n### CLI\n\n_Ecojourney_ commands can be executed from a terminal:\n\n\u003c!-- \u003ccli\u003e --\u003e\n```shell\necojourney [options] [command]\n```\n\n**Global options**\n\n| Flags           | Description               | Environment variable |\n| --------------- | ------------------------- | -------------------- |\n| `-V, --version` | Output the version number |                      |\n| `-v, --verbose` | Enable verbose output     | `ECOJOURNEY_VERBOSE` |\n| `-h, --help`    | Display help for command  |                      |\n\n**Commands**\n\n| Name              | Usage              | Description                              |\n| ----------------- | ------------------ | ---------------------------------------- |\n| [`audit`](#audit) | `[options] \u003cpath\u003e` | Audit a website eco-design compliance    |\n| [`init`](#init)   | `[options] [path]` | Initialise a manifest file interactively |\n\n#### `audit`\n\nAudit a website eco-design compliance.\n\n```shell\necojourney audit [options] \u003cpath\u003e\n```\n\n**Arguments**\n\n| Name   | Description                                         | Required |\n| ------ | --------------------------------------------------- | :------: |\n| `path` | Path to the audit manifest file or website page URL |    ☑️     |\n\n**Options**\n\n| Flags                       | Description                                                      | Default     | Environment variable        |\n| --------------------------- | ---------------------------------------------------------------- | ----------- | --------------------------- |\n| `-b, --browser [browser]`   | Browser to run the audit with                                    | `chromium`  | `ECOJOURNEY_AUDIT_BROWSER`  |\n| `-l, --headless [headless]` | Run browser in headless mode                                     | `true`      | `ECOJOURNEY_AUDIT_HEADLESS` |\n| `-d, --device [device]`     | Simulate browser behavior for a specific device (e.g. Galaxy S8) |             | `ECOJOURNEY_AUDIT_DEVICE`   |\n| `-H, --header [headers...]` | Additional HTTP headers to be sent with every request            |             | `ECOJOURNEY_AUDIT_HEADERS`  |\n| `-t, --timeout [timeout]`   | Maximum time to wait for navigations or actions, in milliseconds |             | `ECOJOURNEY_AUDIT_TIMEOUT`  |\n| `-r, --retry [retry]`       | Number of retries in case of failure                             | `0`         | `ECOJOURNEY_AUDIT_RETRY`    |\n| `-o, --output [output]`     | Directory to write reports to                                    | `.`         | `ECOJOURNEY_AUDIT_OUTPUT`   |\n| `-f, --format [formats...]` | Output report formats                                            | `html,json` | `ECOJOURNEY_AUDIT_FORMAT`   |\n| `-s, --dry-run`             | Simulate the audit without actually running the browser          | `false`     | `ECOJOURNEY_AUDIT_DRY_RUN`  |\n| `-h, --help`                | Display help for command                                         |             |                             |\n\n#### `init`\n\nInitialise a manifest file interactively.\n\n```shell\necojourney init [options] [path]\n```\n\n**Arguments**\n\n| Name   | Description                                 | Required |\n| ------ | ------------------------------------------- | :------: |\n| `path` | Path to the audit manifest file to generate |    🔲     |\n\n**Options**\n\n| Flags        | Description              | Default | Environment variable |\n| ------------ | ------------------------ | ------- | -------------------- |\n| `-h, --help` | Display help for command |         |                      |\n\u003c!-- \u003c/cli\u003e --\u003e\n\n### Manifest\n\n\u003c!-- \u003cmanifest\u003e --\u003e\nThe manifest file allows to describe the audit scenario and configuration.\n\nIt can be easily and interactively initialised using the [`init`](#init)\ncommand. A [JSON schema](./src/audit/manifest/manifest.schema.json) is also\nprovided to enable code completion and validation in your IDE (using built-in\nJSON schema support for YAML files or via an extension).\n\n#### Example\n\n```yaml\n# Audited website description\nname: My website\ndescription: A website that must comply with eco-design best practices\nurl: https://mywebsite.net\n\n# Audit configuration (merged with CLI flags and environment variables)\nconfig: ...\n\n# Procedures allow to define reusable sequences of actions\nprocedures: ...\n\n# Actions allow to define the browsing scenario to run and audit\nactions:\n  # Start a scenario (allows to group page audit results)\n  - scenario: Browse blog posts\n  # Navigate to the posts index page\n  - goto: https://mywebsite.net/posts\n  - wait: main.posts\n  # Analyse the current page (including the previous navigation actions)\n  - page: Posts index\n  # Take a screenshot of the current page\n  - screenshot: posts-index.png\n  # Navigate to and audit the post page\n  - click: article.post\n  - wait: main.post\n  - page: Post\n  - screenshot: posts-single.png\n```\n\n#### Interpolation\n\nSome properties support injecting environment variables and procedure arguments\nusing the double curly braces `{{` and `}}` as delimiters. This is particularly\nuseful to avoid committing sensitive values such as user passwords.\n\n**Example:**\n\n```yaml\n# Fill a password input using a value set from an environment variable\n- fill: { selector: \"#password\", value: \"{{ env.PASSWORD }}\" }\n```\n\n#### Metadata\n\n```yaml\nname: My website\ndescription: A website that must comply with eco-design best practices\nurl: https://mywebsite.net\n```\n\n| Name          | Description                                               | Required |\n| ------------- | --------------------------------------------------------- | :------: |\n| `name`        | Name of the web application                               |    🔲     |\n| `description` | Description of the web application or of the current test |    🔲     |\n| `url`         | Main/root URL of the web application                      |    ☑️     |\n\n#### Configuration\n\nAudit configuration (merged with CLI flags and environment variables)\n\n```yaml\nconfig:\n  browser: \"chromium\"\n  headless: true\n  device: \"Galaxy S8\"\n  headers: {\"X-User\":\"user\"}\n  proxy:\n    server: \"http://myproxy.com:3128\"\n    bypass: \".com, chromium.org, .domain.com\"\n    username: \"username\"\n    password: \"password\"\n  timeout: 10000\n  retries: 3\n  output: \"./reports/\"\n  formats: [\"html\"]\n  influxdb:\n    url: \"http://localhost:8086\"\n    token: \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    org: \"my-org\"\n    bucket: \"my-bucket\"\n    prefix: \"eco_\"\n  dryRun: true\n  verbose: true\n```\n\n| Name         | Description                                                      | Type      | Default       | Values                                              |\n| ------------ | ---------------------------------------------------------------- | --------- | ------------- | --------------------------------------------------- |\n| `browser`    | Browser to run the audit with                                    | `string`  | `chromium`    | `msedge`, `chrome`, `chromium`, `firefox`, `webkit` |\n| `headless`   | Run browser in headless mode                                     | `boolean` | `true`        |                                                     |\n| `device`     | Simulate browser behavior for a specific device                  | `string`  |               |                                                     |\n| `headers`    | Additional HTTP headers to be sent with every request            | `object`  |               |                                                     |\n| `proxy`      | Network proxy settings                                           | `object`  |               |                                                     |\n| ∟ `server`   | Proxy to be used for all requests                                | `string`  |               |                                                     |\n| ∟ `bypass`   | Comma-separated domains to bypass proxy                          | `string`  |               |                                                     |\n| ∟ `username` | Username to use if HTTP proxy requires authentication            | `string`  |               |                                                     |\n| ∟ `password` | Password to use if HTTP proxy requires authentication            | `string`  |               |                                                     |\n| `timeout`    | Maximum time to wait for navigations or actions, in milliseconds | `integer` |               |                                                     |\n| `retries`    | Number of retries in case of failure                             | `integer` | `0`           |                                                     |\n| `output`     | Directory to write reports to                                    | `string`  | `.`           |                                                     |\n| `formats`    | Output report formats                                            | `array`   | `html,json`   | `html`, `json`, `influxdb`                          |\n| `influxdb`   | InfluxDB connection configuration                                | `object`  |               |                                                     |\n| ∟ `url`      | Base URL                                                         | `string`  |               |                                                     |\n| ∟ `token`    | Authentication token                                             | `string`  |               |                                                     |\n| ∟ `org`      | Destination organisation for writes                              | `string`  |               |                                                     |\n| ∟ `bucket`   | Destination bucket for writes                                    | `string`  |               |                                                     |\n| ∟ `prefix`   | Measurement name prefix                                          | `string`  | `ecojourney_` |                                                     |\n| `dryRun`     | Simulate the audit without actually running the browser          | `boolean` | `false`       |                                                     |\n| `verbose`    | Enable verbose output                                            | `boolean` | `false`       |                                                     |\n\n#### Actions\n\nActions allow to define the browsing scenario to run and audit.\n\n```yaml\nactions:\n  # Abbreviated syntax\n  - \u003cname\u003e: \u003cvalue1\u003e, \u003cvalue2\u003e\n  # Explicit syntax\n  - \u003cname\u003e:\n      \u003cproperty1\u003e: \u003cvalue1\u003e\n      \u003cproperty2\u003e: \u003cvalue2\u003e\n```\n\n##### `check`\n\nCheck or uncheck a checkbox or a radio button.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element and the state to set (`check` or `uncheck`, default to `check`)\n\n```yaml\n- check: \"input[name='remember'], check\"\n```\n\n**Explicit syntax**\n\n```yaml\n- check:\n    selector: \"input[name='remember']\"\n    state: \"check\"\n```\n\n| Property   | Type     | Description                                                 | Required |\n| ---------- | -------- | ----------------------------------------------------------- | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element          |    ☑️     |\n| `state`    | `string` | The state to set (`check` or `uncheck`, default to `check`) |    🔲     |\n\n##### `click`\n\nClick on an element.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element\n\n```yaml\n- click: \"button[type='submit']\"\n```\n\n**Explicit syntax**\n\n```yaml\n- click:\n    selector: \"button[type='submit']\"\n```\n\n| Property   | Type     | Description                                        | Required |\n| ---------- | -------- | -------------------------------------------------- | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element |    ☑️     |\n\n##### `fill`\n\nFill an input or a textarea with a text.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element and the value to set (supports templating)\n\n```yaml\n- fill: \"#search, Eco-design\"\n```\n\n**Explicit syntax**\n\n```yaml\n- fill:\n    selector: \"#search\"\n    value: \"Eco-design\"\n```\n\n| Property   | Type     | Description                                                              | Required |\n| ---------- | -------- | ------------------------------------------------------------------------ | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element (supports templating) |    ☑️     |\n| `value`    | `string` | The value to set (supports templating)                                   |    ☑️     |\n\n##### `goto`\n\nNavigate to the given URL.\n\n**Abbreviated syntax**\n\n_Argument:_ the target HTTP/HTTPS URL (supports templating)\n\n```yaml\n- goto: \"https://mywebsite.net/admin\"\n```\n\n**Explicit syntax**\n\n```yaml\n- goto:\n    url: \"https://mywebsite.net/admin\"\n```\n\n| Property | Type     | Description                                     | Required |\n| -------- | -------- | ----------------------------------------------- | :------: |\n| `url`    | `string` | The target HTTP/HTTPS URL (supports templating) |    ☑️     |\n\n##### `page`\n\nMark the current state as a stable page to analyse.\n\n**Abbreviated syntax**\n\n_Argument:_ the page name\n\n```yaml\n- page: \"Profile page\"\n```\n\n**Explicit syntax**\n\n```yaml\n- page:\n    name: \"Profile page\"\n```\n\n| Property | Type     | Description   | Required |\n| -------- | -------- | ------------- | :------: |\n| `name`   | `string` | The page name |    ☑️     |\n\n##### `procedure`\n\nExecute actions from a procedure.\n\n**Abbreviated syntax**\n\n_Argument:_ the procedure name\n\n```yaml\n- procedure: \"login\"\n```\n\n**Explicit syntax**\n\n```yaml\n- procedure:\n    name: \"login\"\n    args: {\"username\":\"admin\"}\n```\n\n| Property | Type     | Description         | Required |\n| -------- | -------- | ------------------- | :------: |\n| `name`   | `string` | The procedure name  |    ☑️     |\n| `args`   | `object` | Procedure arguments |    🔲     |\n\n##### `scenario`\n\nStart a scenario (allows to group page audit results).\n\n**Abbreviated syntax**\n\n_Argument:_ the scenario name\n\n```yaml\n- scenario: \"Browse my profile\"\n```\n\n**Explicit syntax**\n\n```yaml\n- scenario:\n    name: \"Browse my profile\"\n    newContext: false\n    exclude: false\n```\n\n| Property     | Type      | Description                                            | Required |\n| ------------ | --------- | ------------------------------------------------------ | :------: |\n| `name`       | `string`  | The scenario name                                      |    ☑️     |\n| `newContext` | `boolean` | Close the current context and create a new one         |    🔲     |\n| `exclude`    | `boolean` | Exclude this scenario from analysis (only run actions) |    🔲     |\n\n##### `screenshot`\n\nTake a screenshot of the current page.\n\n**Abbreviated syntax**\n\n_Argument:_ the file path to save the image to\n\n```yaml\n- screenshot: \"posts.png\"\n```\n\n**Explicit syntax**\n\n```yaml\n- screenshot:\n    path: \"posts.png\"\n```\n\n| Property | Type     | Description                        | Required |\n| -------- | -------- | ---------------------------------- | :------: |\n| `path`   | `string` | The file path to save the image to |    ☑️     |\n\n##### `scroll`\n\nScroll an element into view.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element\n\n```yaml\n- scroll: \"#footer\"\n```\n\n**Explicit syntax**\n\n```yaml\n- scroll:\n    selector: \"#footer\"\n```\n\n| Property   | Type     | Description                                        | Required |\n| ---------- | -------- | -------------------------------------------------- | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element |    ☑️     |\n\n##### `select`\n\nSelect option or options in select.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element and option(s) to select\n\n```yaml\n- select: \"select[name='lang'], fr\"\n```\n\n**Explicit syntax**\n\n```yaml\n- select:\n    selector: \"select[name='lang']\"\n    value: \"fr\"\n    values: [\"fr\",\"en\"]\n```\n\n| Property   | Type     | Description                                        | Required |\n| ---------- | -------- | -------------------------------------------------- | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element |    ☑️     |\n| `value`    | `string` | The option to select                               |    🔘     |\n| `values`   | `array`  | Options to select                                  |    🔘     |\n\n##### `upload`\n\nSelect input files for upload.\n\n**Abbreviated syntax**\n\n_Argument:_ the selector to use when resolving the DOM element and input file(s) to set\n\n```yaml\n- upload: \"input[name='file'], myfile.txt\"\n```\n\n**Explicit syntax**\n\n```yaml\n- upload:\n    selector: \"select[name='lang']\"\n    file: \"myfile.txt\"\n    files: [\"myfile1.txt\",\"myfile2.txt\"]\n```\n\n| Property   | Type     | Description                                        | Required |\n| ---------- | -------- | -------------------------------------------------- | :------: |\n| `selector` | `string` | The selector to use when resolving the DOM element |    ☑️     |\n| `file`     | `string` | The input file to set                              |    🔘     |\n| `files`    | `array`  | Input files to set                                 |    🔘     |\n\n##### `wait`\n\nWait for the required load state to be reached or for an element to be visible.\n\n**Abbreviated syntax**\n\n_Argument:_ the load state to wait for (`load`, `domcontentloaded`, `networkidle`)\n\n```yaml\n- wait: \"load\"\n```\n\n_Argument:_ the selector to use when resolving the DOM element\n\n```yaml\n- wait: \"main#container\"\n```\n\n**Explicit syntax**\n\n```yaml\n- wait:\n    state: \"load\"\n    selector: \"main#container\"\n```\n\n| Property   | Type     | Description                                        | Required |\n| ---------- | -------- | -------------------------------------------------- | :------: |\n| `state`    | `string` | The load state to wait for                         |    🔘     |\n| `selector` | `string` | The selector to use when resolving the DOM element |    🔘     |\n\n#### Procedures\n\nProcedures allow to define reusable sequences of actions.\n\nDefine a procedure with a unique name under the `procedures` key:\n\n```yaml\nprocedures:\n  # Log a user in using the login form page\n  login:\n    - page: \"Login page for {{ args.username }}\"\n    - fill: { selector: \"#username\", value: \"{{ args.username }}\" }\n    - fill: { selector: \"#password\", value: \"{{ args.password }}\" }\n    - click: button[type=\"submit\"]\n```\n\nCall it from the browsing scenario using the [`procedure`](#procedure) action:\n\n```yaml\nactions:\n  - ...\n  - procedure:\n      name: login\n      args: { username: user, password: \"{{ env.USER_PASSWORD }}\" }\n  - ...\n```\n\u003c!-- \u003c/manifest\u003e --\u003e\n\n### Report\n\nAudit results can be exported using various report formats that can be specified\nusing the `formats` CLI flag, environment variable or manifest configuration\nkey.\n\n#### HTML\n\nExport analysis results to an HTML report file.\n\n➡️ Recommended for simple analysis result visualisation\n\n#### JSON\n\nExport analysis results to a JSON report file.\n\n➡️ Recommended for further data analysis and visualisation\n\n#### InfluxDB\n\nWrite analysis results to an InfluxDB time-series database via 2 measurements:\n\n- `{prefix}issues`: number of issues by severity for each audit, scenario and\n  page, with analysis duration\n- `{prefix}measure`: main metrics for each audit, scenario and page\n\nPublished data is more or less the same as the data visible on the HTML report\nwithout opening collapsible elements, thus, some data (issues list, secondary\nmeasures, rules and metrics list, etc.) are not written because they doesn't fit\nwell in a TSDB or are not relevant enough to be worth tracking on a dashboard.\n\n➡️ Recommended to keep track of analysis results over time on a Grafana\ndashboard\n\n✔️ Don't forget to set a retention time for the target bucket to enable\nautomatic deletion of old data.\n\n### Continuous Integration\n\nAudits can be executed in CI environments:\n\n1. Use the Playwright Docker image in a Linux agent:\n   `mcr.microsoft.com/playwright`\n\n| Provider            | Configuration key                  |\n| ------------------- | ---------------------------------- |\n| **GitHub Actions**  | `jobs.\u003cjob_id\u003e.container`          |\n| **GitLab**          | `\u003cjob_id\u003e.image`                   |\n| **Azure Pipelines** | `container` or `jobs[*].container` |\n\n2. Install project dependencies, including _Ecojourney_:\n\n```shell\nnpm ci\n```\n\n3. Run the audit:\n\n```shell\nnpx ecojourney audit [...]\n```\n\n✔️ **Best practices:**\n\n- Running the audit on each commit is usually wasteful, it should preferably\n  be executed manually or on specific events (main branch, release, ...)\n- Don't forget to cache dependencies (Docker image, `node_modules` / NPM cache,\n  ...)\n\n## Analysers\n\nEach page from the browsing scenario is analysed by a list of analysers, each\none collecting metrics and identifying issues regarding eco-design best\npractices.\n\n\u003c!-- \u003canalysers\u003e --\u003e\n### Cache (`cache`)\n\nCheck cache headers\n\n#### Rules\n\n| Id                        | Name                    | Description                                                                                                                     |\n| ------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- |\n| `configure-cache-headers` | Configure cache headers | Configure cache headers on static resources to enable HTTP caching (Cache-Control with a large max-age, ETag and Last-Modified) |\n\n### Compression (`compression`)\n\nCheck compression\n\n#### Metrics\n\n| Id                            | Name                  | Description                                             |\n| ----------------------------- | --------------------- | ------------------------------------------------------- |\n| `compressible-requests-count` | Compressible requests | The number of requests that should be served compressed |\n\n#### Rules\n\n| Id                   | Name               | Description                                                                    |\n| -------------------- | ------------------ | ------------------------------------------------------------------------------ |\n| `enable-compression` | Enable compression | Configure HTTP compression to improve transfer speed and bandwidth utilisation |\n\n### Cookies (`cookies`)\n\nCheck cookies\n\n#### Rules\n\n| Id                              | Name                          | Description                                                 |\n| ------------------------------- | ----------------------------- | ----------------------------------------------------------- |\n| `optimise-cookies`              | Optimise cookies size         | Optimise cookies size and remove them when they are useless |\n| `no-cookie-for-static-resource` | No cookie for static resource | Host static resource on a domain without cookie             |\n\n### Errors (`errors`)\n\nCheck for request and page errors\n\n#### Metrics\n\n| Id                      | Name            | Description                   |\n| ----------------------- | --------------- | ----------------------------- |\n| `failed-requests-count` | Failed requests | The number of failed requests |\n| `errors-count`          | Errors          | The number of page errors     |\n\n#### Rules\n\n| Id          | Name      | Description                                                  |\n| ----------- | --------- | ------------------------------------------------------------ |\n| `fix-error` | Fix error | Fix code or request error as it consumes resources uselessly |\n\n### Fonts (`fonts`)\n\nCheck for fonts\n\n#### Metrics\n\n| Id                     | Name                | Description                      |\n| ---------------------- | ------------------- | -------------------------------- |\n| `external-fonts-count` | External fonts      | The number of external fonts     |\n| `external-fonts-size`  | External fonts size | The total size of external fonts |\n\n#### Rules\n\n| Id                   | Name               | Description                                                                                                         |\n| -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- |\n| `use-standard-fonts` | Use standard fonts | Use fonts already pre-installed on user terminals to avoid additional downloads, or at least optimise external font |\n\n### Global (`global`)\n\nGlobal metrics calculation and analysis\n\n#### Metrics\n\n| Id                          | Name                | Description                      |\n| --------------------------- | ------------------- | -------------------------------- |\n| `eco-index`                 | EcoIndex            | The EcoIndex                     |\n| `requests-count`            | Requests            | The number of HTTP requests      |\n| `responses-size`            | Responses size      | The total size of HTTP responses |\n| `dom-elements-count`        | DOM elements        | The number of DOM elements       |\n| `greenhouse-gases-emission` | 🌫️ GhG emission      | The greenhouse gases emission    |\n| `water-consumption`         | 💧 Water consumption | The water consumption            |\n| `redirections-count`        | Redirections        | The number of HTTP redirections  |\n| `domains-count`             | Domains             | The number of domains            |\n\n#### Rules\n\n| Id                      | Name                  | Description                                                                          |\n| ----------------------- | --------------------- | ------------------------------------------------------------------------------------ |\n| `reduce-requests-count` | Reduce requests count | Reduce the number of requests                                                        |\n| `reduce-responses-size` | Reduce responses size | Reduce the responses size                                                            |\n| `reduce-dom-size`       | Reduce DOM size       | Reduce the page complexity (and thus the number of elements in the DOM)              |\n| `avoid-redirections`    | Avoid redirections    | Avoid redirections as they increase response time and resource consumption uselessly |\n| `limit-domains-count`   | Limit domains count   | Limit the number of domains serving resources                                        |\n\n### Images (`images`)\n\nCheck images\n\n#### Metrics\n\n| Id                    | Name               | Description                     |\n| --------------------- | ------------------ | ------------------------------- |\n| `raster-images-count` | Raster images      | The number of raster images     |\n| `raster-images-size`  | Raster images size | The total size of raster images |\n| `vector-images-count` | Vector images      | The number of vector images     |\n| `vector-images-size`  | Vector images size | The total size of vector images |\n\n#### Rules\n\n| Id                          | Name                      | Description                                                                                                                                  |\n| --------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |\n| `optimise-image`            | Optimise image            | Replace raster images with CSS, font glyphs or vector images when possible, otherwise use the right format (WebP, AVIF, PNG) and compression |\n| `optimise-vector-image`     | Optimise vector image     | Optimise and minimise SVG images                                                                                                             |\n| `serve-right-sized-image`   | Serve right-sized image   | Serve pre-resized image instead of resizing browser-side                                                                                     |\n| `load-only-displayed-image` | Load only displayed image | Load image only if it is displayed                                                                                                           |\n\n### Plugins (`plugins`)\n\nCheck plugins\n\n#### Metrics\n\n| Id                     | Name           | Description                          |\n| ---------------------- | -------------- | ------------------------------------ |\n| `social-plugins-count` | Social plugins | The number of social plugin requests |\n\n#### Rules\n\n| Id                    | Name                | Description                                                                                    |\n| --------------------- | ------------------- | ---------------------------------------------------------------------------------------------- |\n| `avoid-social-plugin` | Avoid social plugin | Social network official plugins are usually heavy and intrusive, replace them with basic links |\n\n### Scripts (`scripts`)\n\nCheck scripts\n\n#### Metrics\n\n| Id                       | Name                  | Description                        |\n| ------------------------ | --------------------- | ---------------------------------- |\n| `external-scripts-count` | External scripts      | The number of external scripts     |\n| `external-scripts-size`  | External scripts size | The total size of external scripts |\n| `embedded-scripts-count` | Embedded scripts      | The number of embedded scripts     |\n| `embedded-scripts-size`  | Embedded scripts size | The total size of embedded scripts |\n\n#### Rules\n\n| Id                     | Name                 | Description                                                                                                                |\n| ---------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------- |\n| `externalise-script`   | Externalise script   | Avoid embedding script into the HTML page as it would be transferred each time the page is requested                       |\n| `minify-script`        | Minify script        | Reduce the size of the script by minifying JS code                                                                         |\n| `reduce-scripts-count` | Reduce scripts count | Reduce the number of scripts: combine them to reduce the number of requests                                                |\n| `reduce-script-size`   | Reduce script size   | Reduce the size of the script: use JS only when necessary, remove dead code using tree shaking, configure compression, ... |\n\n### Style sheets (`stylesheets`)\n\nCheck style sheets\n\n#### Metrics\n\n| Id                      | Name                 | Description                       |\n| ----------------------- | -------------------- | --------------------------------- |\n| `external-styles-count` | External styles      | The number of external styles     |\n| `external-styles-size`  | External styles size | The total size of external styles |\n| `embedded-styles-count` | Embedded styles      | The number of embedded styles     |\n| `embedded-styles-size`  | Embedded styles size | The total size of embedded styles |\n\n#### Rules\n\n| Id                    | Name                | Description                                                                                               |\n| --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------- |\n| `externalise-style`   | Externalise style   | Avoid embedding style sheet into the HTML page as it would be transferred each time the page is requested |\n| `minify-style`        | Minify style        | Reduce the size of the style sheet by minifying CSS code                                                  |\n| `provide-print-style` | Provide print style | Optimise styles for printing                                                                              |\n| `reduce-styles-count` | Reduce styles count | Reduce the number of style sheets to reduce the number of requests                                        |\n| `reduce-style-size`   | Reduce style size   | Reduce the size of the style sheet: optimise CSS, remove unused styles, configure compression, ...        |\n\u003c!-- \u003c/analysers\u003e --\u003e\n\n## License\n\n**Ecojourney** is licensed under the GNU General Public License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaelgirodon%2Fecojourney","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaelgirodon%2Fecojourney","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaelgirodon%2Fecojourney/lists"}