├── tests ├── __init__.py └── energy_efficiency_carbon_percentiles.py ├── docker ├── build.ps1 ├── run.ps1 └── run-with-mounted-folder.ps1 ├── docs ├── README.md ├── tests │ ├── test-template.md │ ├── google-lighthouse-based.md │ ├── js-linting.md │ ├── css-linting.md │ ├── pa11y.md │ ├── a11y-statement.md │ ├── html-validate.md │ ├── webbkoll.md │ ├── standard.md │ ├── page-not-found.md │ ├── energy-efficiency.md │ └── http.md ├── thirdparty.md ├── getting-started-local.md ├── getting-started-github-actions.md ├── translation.md └── getting-started-docker.md ├── pa11y.json ├── locales ├── en │ └── LC_MESSAGES │ │ ├── 404.mo │ │ ├── css.mo │ │ ├── html.mo │ │ ├── software.mo │ │ ├── a11y_pa11y.mo │ │ ├── javascript.mo │ │ ├── lighthouse.mo │ │ ├── webperf-core.mo │ │ ├── a11y-statement.mo │ │ ├── email_validator.mo │ │ ├── http_validator.mo │ │ ├── standard-files.mo │ │ ├── energy_efficiency.mo │ │ ├── privacy_webbkollen.mo │ │ ├── tracking_validator.mo │ │ ├── performance_sitespeed_io.mo │ │ ├── performance_sitespeed_io.po │ │ ├── energy_efficiency.po │ │ ├── privacy_webbkollen.po │ │ ├── a11y_pa11y.po │ │ ├── 404.po │ │ ├── tracking_validator.po │ │ └── standard-files.po ├── sv │ └── LC_MESSAGES │ │ ├── 404.mo │ │ ├── css.mo │ │ ├── html.mo │ │ ├── software.mo │ │ ├── a11y_pa11y.mo │ │ ├── javascript.mo │ │ ├── lighthouse.mo │ │ ├── webperf-core.mo │ │ ├── a11y-statement.mo │ │ ├── email_validator.mo │ │ ├── http_validator.mo │ │ ├── standard-files.mo │ │ ├── energy_efficiency.mo │ │ ├── privacy_webbkollen.mo │ │ ├── tracking_validator.mo │ │ ├── performance_sitespeed_io.mo │ │ ├── performance_sitespeed_io.po │ │ ├── energy_efficiency.po │ │ ├── privacy_webbkollen.po │ │ ├── a11y_pa11y.po │ │ ├── 404.po │ │ ├── tracking_validator.po │ │ ├── standard-files.po │ │ └── a11y-statement.po └── gov │ └── LC_MESSAGES │ ├── 404.mo │ ├── css.mo │ ├── html.mo │ ├── a11y_pa11y.mo │ ├── lighthouse.mo │ ├── software.mo │ ├── webperf-core.mo │ ├── a11y-statement.mo │ ├── email_validator.mo │ ├── http_validator.mo │ ├── standard-files.mo │ ├── energy_efficiency.mo │ ├── privacy_webbkollen.mo │ ├── tracking_validator.mo │ ├── performance_sitespeed_io.mo │ ├── performance_sitespeed_io.po │ ├── energy_efficiency.po │ ├── privacy_webbkollen.po │ ├── a11y_pa11y.po │ ├── 404.po │ ├── tracking_validator.po │ └── standard-files.po ├── defaults ├── sites.json ├── settings.json └── a11y-overlays.json ├── pa11y-docker-config.json ├── .dockerignore ├── helpers ├── browser_helper.py ├── hash_helper.py ├── release_helper.py └── sitespeed_helper.py ├── requirements.txt ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── QUESTION.yml │ ├── FEATURE_IMPROVEMENT.yml │ └── BUG_REPORT.yml ├── release.yml ├── workflows │ ├── close-inactive-issues.yml │ ├── pylint.yml │ ├── update-docker.yml │ ├── prep-release.yml │ ├── create-release.yml │ ├── regression-test-webbkoll.yml │ ├── regression-test-translations.yml │ ├── manual-start-test.yml │ ├── regression-test-pa11y.yml │ ├── regression-test-standard-files.yml │ ├── codeql-analysis.yml │ ├── regression-test-software.yml │ ├── regression-test-energy-efficiency.yml │ ├── regression-test-http.yml │ ├── regression-test-email.yml │ ├── regression-test-404.yml │ ├── regression-test-lint-css.yml │ ├── regression-test-a11y-statement.yml │ ├── regression-test-lint-html.yml │ ├── regression-test-lint-js.yml │ └── regression-test-google-lighthouse-based.yml ├── PULL_REQUEST_TEMPLATE.md └── dependabot.yml ├── unittests ├── util │ └── httpserver.js └── data │ └── js │ └── color-modes.js ├── eslint.config.js ├── engines ├── utils.py ├── gov.py ├── sql.py └── sitespeed_result.py ├── LICENSE ├── chrome-cookies.cjs ├── package.json ├── .gitignore ├── Dockerfile ├── README.md └── chrome-custom.cjs /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docker/build.ps1: -------------------------------------------------------------------------------- 1 | CD .. 2 | docker build -t "webperf-core:latest" . 3 | CD docker -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documents README 2 | 3 | [Go to root README to get started](../README.md) -------------------------------------------------------------------------------- /pa11y.json: -------------------------------------------------------------------------------- 1 | { 2 | "chromeLaunchConfig": { 3 | "ignoreHTTPSErrors": false 4 | } 5 | } -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/404.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/404.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/css.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/css.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/404.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/404.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/css.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/css.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/html.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/html.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/404.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/404.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/css.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/css.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/html.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/html.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/html.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/html.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/software.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/software.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/software.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/software.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/a11y_pa11y.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/a11y_pa11y.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/javascript.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/javascript.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/lighthouse.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/lighthouse.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/a11y_pa11y.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/a11y_pa11y.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/lighthouse.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/lighthouse.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/software.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/software.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/a11y_pa11y.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/a11y_pa11y.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/javascript.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/javascript.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/lighthouse.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/lighthouse.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/webperf-core.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/webperf-core.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/webperf-core.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/webperf-core.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/webperf-core.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/webperf-core.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/a11y-statement.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/a11y-statement.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/email_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/email_validator.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/http_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/http_validator.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/standard-files.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/standard-files.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/a11y-statement.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/a11y-statement.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/email_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/email_validator.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/http_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/http_validator.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/standard-files.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/standard-files.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/a11y-statement.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/a11y-statement.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/email_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/email_validator.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/http_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/http_validator.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/standard-files.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/standard-files.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/energy_efficiency.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/energy_efficiency.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/privacy_webbkollen.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/privacy_webbkollen.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/tracking_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/tracking_validator.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/energy_efficiency.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/energy_efficiency.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/energy_efficiency.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/energy_efficiency.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/privacy_webbkollen.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/privacy_webbkollen.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/tracking_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/tracking_validator.mo -------------------------------------------------------------------------------- /defaults/sites.json: -------------------------------------------------------------------------------- 1 | { 2 | "sites": [ 3 | { 4 | "id": 0, 5 | "url": "https://webperf.se/" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/privacy_webbkollen.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/privacy_webbkollen.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/tracking_validator.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/tracking_validator.mo -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/performance_sitespeed_io.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/en/LC_MESSAGES/performance_sitespeed_io.mo -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/performance_sitespeed_io.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/gov/LC_MESSAGES/performance_sitespeed_io.mo -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/performance_sitespeed_io.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Webperf-se/webperf_core/HEAD/locales/sv/LC_MESSAGES/performance_sitespeed_io.mo -------------------------------------------------------------------------------- /pa11y-docker-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "chromeLaunchConfig": { 3 | "ignoreHTTPSErrors": false, 4 | "args": ["--no-sandbox", "--no-zygote", "--disable-gpu", "--disable-features=FedCm"] 5 | } 6 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | docs 4 | failures.log 5 | docker 6 | Dockerfile 7 | README.md 8 | LICENSE 9 | tmp 10 | cache 11 | node_modules 12 | geckodriver.log 13 | software-unknown-sources.json 14 | vnu.jar 15 | package-lock.json -------------------------------------------------------------------------------- /helpers/browser_helper.py: -------------------------------------------------------------------------------- 1 | from helpers.setting_helper import get_config 2 | 3 | def get_chromium_browser(): 4 | browser = get_config('tests.sitespeed.browser') 5 | if browser in ('chrome', 'edge'): 6 | return browser 7 | return 'chrome' 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.14.2 2 | lxml==6.0.2 3 | requests==2.32.5 4 | urllib3==2.6.0 5 | dnspython==2.8.0 6 | certifi==2025.10.5 7 | selenium==4.38.0 8 | IP2Location==8.11.0 9 | Pillow==11.3.0 10 | OpenCV-Python==4.12.0.88 11 | Numpy==2.2.4 12 | cryptography==46.0.3 13 | pylint==4.0.3 14 | packaging==25.0 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # TODO: We should try to automat creation of this. 2 | # - Look for sponsor links for projects listed in package.json 3 | # - Add tools /libraries that are very helpfull 4 | 5 | custom: [ 6 | "https://github.com/sitespeedio/sitespeed.io", 7 | "https://github.com/Webperf-se/webperf_core/blob/main/docs/CONTRIBUTING.md#funding" 8 | ] 9 | -------------------------------------------------------------------------------- /docker/run.ps1: -------------------------------------------------------------------------------- 1 | CD .. 2 | Write-Host "When docker has run an you are at bash inside container, you can run one of these commands:" 3 | Write-Host "python default.py -h" 4 | Write-Host "python default.py -i defaults/sites.json -r" 5 | Write-Host "python default.py -u https://webperf.se -t 26 -r" 6 | docker run -it --cpus="0.9" --shm-size=4g -e MAX_OLD_SPACE_SIZE=7000 --rm webperf-core:latest bash 7 | CD docker -------------------------------------------------------------------------------- /unittests/util/httpserver.js: -------------------------------------------------------------------------------- 1 | import handler from 'serve-handler'; 2 | import { createServer } from 'node:http'; 3 | 4 | let server; 5 | const port = 3000; 6 | 7 | export async function startServer() { 8 | server = createServer((request, response) => { 9 | return handler(request, response, { public: './unittests/data/' }); 10 | }); 11 | 12 | return server.listen(port, () => {}); 13 | } 14 | export async function stopServer() { 15 | return server.close(); 16 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/QUESTION.yml: -------------------------------------------------------------------------------- 1 | name: Question 2 | description: Ask a question about webperf_core 3 | labels: [question] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Ask a question about webperf_core 9 | - type: textarea 10 | id: your-question 11 | attributes: 12 | label: Your question 13 | description: You can also discuss it in the [webperf_core Slack channel](https://webperf.se/articles/webperf-pa-slack/). 14 | validations: 15 | required: true -------------------------------------------------------------------------------- /docker/run-with-mounted-folder.ps1: -------------------------------------------------------------------------------- 1 | CD .. 2 | Write-Host "When docker has run an you are at bash inside container, you can run one of these commands:" 3 | Write-Host "python default.py -h" 4 | Write-Host "python default.py -i defaults/sites.json -o reports/results.json -r" 5 | Write-Host "python default.py -u https://webperf.se -t 26 -o reports/webperf-se-t-26.json -r" 6 | New-Item -ItemType Directory -Force -Path "$(pwd)\reports\" 7 | docker run -it --mount src="$(pwd)\reports",target=/usr/src/runner/reports,type=bind --cpus="0.9" --shm-size=4g -e MAX_OLD_SPACE_SIZE=7000 --rm webperf-core:latest bash 8 | CD docker -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_IMPROVEMENT.yml: -------------------------------------------------------------------------------- 1 | name: New feature or improvement 2 | description: Suggest a new feature or something that can be improved 3 | labels: [enhancement] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Suggest a new feature or something that can be improved 9 | - type: textarea 10 | id: your-idea 11 | attributes: 12 | label: Feature/improvement 13 | description: You can also discuss new features/improvements in the [webperf_core Slack channel](https://webperf.se/articles/webperf-pa-slack/). 14 | validations: 15 | required: true -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes 3 | 4 | changelog: 5 | exclude: 6 | labels: 7 | - ignore-for-release 8 | - documentation 9 | categories: 10 | - title: Breaking Changes 🛠 11 | labels: 12 | - Semver-Major 13 | - breaking-change 14 | - title: Exciting New Features 🎉 15 | labels: 16 | - Semver-Minor 17 | - enhancement 18 | - title: Bug Fixes 19 | labels: 20 | - bug 21 | - title: Other Changes 22 | labels: 23 | - "*" 24 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | 3 | export default [ 4 | { 5 | languageOptions: { 6 | globals: { 7 | node: true, 8 | es6: true, 9 | URL: "readonly" 10 | }, 11 | parserOptions: { 12 | ecmaVersion: 'latest', 13 | sourceType: 'module' 14 | } 15 | }, 16 | rules: { 17 | 'require-atomic-updates': 0, 18 | 'no-extra-semi': 0, 19 | 'no-mixed-spaces-and-tabs': 0, 20 | 'unicorn/filename-case': 0, 21 | 'unicorn/prevent-abbreviations': 0, 22 | 'unicorn/no-array-reduce': 0, 23 | 'unicorn/prefer-spread': 0 24 | }, 25 | }, 26 | { 27 | ignores: ["unittests/*"] 28 | }, 29 | js.configs.recommended 30 | ]; 31 | -------------------------------------------------------------------------------- /helpers/hash_helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import base64 4 | import hashlib 5 | 6 | def create_sha256_hash(data): 7 | """ 8 | Creates a SHA-256 hash of the given data and returns it in base64 encoded format. 9 | 10 | This function first creates a SHA-256 hash of the input data. It then encodes this hash 11 | using base64 encoding and returns the result as a string. 12 | 13 | Parameters: 14 | data (bytes): The data to be hashed. This should be in bytes format. 15 | 16 | Returns: 17 | str: The base64 encoded SHA-256 hash of the input data. 18 | """ 19 | sha_signature = hashlib.sha256(data).digest() 20 | base64_encoded_sha_signature = base64.b64encode(sha_signature).decode() 21 | return base64_encoded_sha_signature 22 | -------------------------------------------------------------------------------- /.github/workflows/close-inactive-issues.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v10 14 | with: 15 | days-before-issue-stale: 150 16 | days-before-issue-close: 14 17 | stale-issue-label: "stale" 18 | stale-issue-message: "This issue is stale because it has been open for 150 days with no activity." 19 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." 20 | days-before-pr-stale: -1 21 | days-before-pr-close: -1 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: Pylint 2 | on: 3 | push: 4 | paths: 5 | - '**.py' 6 | - '**pylint.yml' 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | python-version: ["3.10", "3.13"] 13 | steps: 14 | - uses: actions/checkout@v6 15 | - name: Set up Python ${{ matrix.python-version }} 16 | uses: actions/setup-python@v6 17 | with: 18 | python-version: ${{ matrix.python-version }} 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install -r requirements.txt 23 | pip install pylint 24 | - name: Analysing the code with pylint 25 | run: | 26 | pylint $(git ls-files '*.py') --generated-members json,ssl,datetime --disable C0114 --errors-only 27 | -------------------------------------------------------------------------------- /engines/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | def use_item(current_index, skip, take): 5 | """ 6 | Determines whether an item at a given index should be used based on the skip and 7 | take parameters. 8 | 9 | Parameters: 10 | current_index (int): The index of the current item. 11 | skip (int): The number of items to skip. 12 | take (int): The number of items to take after skipping. If -1, takes all items. 13 | 14 | Returns: 15 | bool: True if the item should be used, False otherwise. 16 | 17 | The function returns False if the current index is less than the number of items to skip or 18 | if the current index is greater than or 19 | equal to the sum of the skip and take parameters (unless take is -1). 20 | Otherwise, it returns True. 21 | """ 22 | if skip > 0 and current_index < skip: 23 | return False 24 | 25 | if take != -1 and current_index >= (skip + take): 26 | return False 27 | 28 | return True 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Your checklist for a pull request to webperf_core 2 | Please review the [guidelines for contributing](/docs/CONTRIBUTING.md) to this repository. 3 | 4 | - [ ] I'm making a big change or adding functionality so I've already opened an issue proposing the change to other contributors (Or discussed it in [WebPerf Slack channel](https://webperf.se/articles/webperf-pa-slack/)), so I got feedback on the idea before took the time to write precious code 5 | - [ ] Check that your change/fix has corresponding regression tests (if applicable) 6 | - [ ] Validated that all regression tests pass (if applicable) 7 | - [ ] Squash commits so it looks sane 8 | - [ ] Update the documentation (if applicable) 9 | - [ ] Used labels for better release notes (if applicable) 10 | - `breaking-change` - For breaking changes 11 | - `enhancement` - For highlighted features 12 | - `bug` - For highlighted features 13 | 14 | 15 | 16 | 17 | ### Description 18 | Please describe your pull request and tell us the fix # 19 | 20 | Thank you for making webperf_core even better! 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Webperf.se 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for python 9 | - package-ecosystem: "pip" # See documentation for possible values 10 | directory: "/" # Location of package manifests 11 | schedule: 12 | interval: "weekly" 13 | # Maintain dependencies for GitHub Actions 14 | - package-ecosystem: "github-actions" 15 | # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) 16 | directory: "/" 17 | schedule: 18 | interval: "weekly" 19 | # Maintain dependencies for node 20 | - package-ecosystem: "npm" # See documentation for possible values 21 | directory: "/" # Location of package manifests 22 | schedule: 23 | interval: "weekly" 24 | -------------------------------------------------------------------------------- /chrome-cookies.cjs: -------------------------------------------------------------------------------- 1 | /* 2 | * USED FOR SITESPEED TEST (TO collect cookies set after a visit)!!! 3 | */ 4 | module.exports = async function (context, commands) { 5 | try { 6 | cdpClient = commands.cdp.engineDelegate.getCDPClient() 7 | // https://chromedevtools.github.io/devtools-protocol/tot/Storage/#method-getCookies 8 | bodyResult = await cdpClient.send('Storage.getCookies'); 9 | context.log.info('COOKIES:START:', bodyResult, 'COOKIES:END'); 10 | } catch (err) { 11 | // We probably used firefox... right now we don't have good way of catching cookies 12 | try { 13 | // tmp = await commands.js.run('return typeof document !== "undefined"'); 14 | // tmp = await commands.js.run('return typeof document.cookie !== "undefined"'); 15 | // str_cookies = await commands.js.run('return typeof document !== "undefined" && typeof document.cookie !== "undefined" ? [document.cookie] : []'); 16 | 17 | 18 | 19 | context.log.info('COOKIES:START:', {}, 'COOKIES:END'); 20 | } catch (err2) { 21 | context.log.info('COOKIES:START:', {}, 'COOKIES:END'); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /docs/tests/test-template.md: -------------------------------------------------------------------------------- 1 | # Test Header 2 | 3 | Add small description of what this test is. 4 | 5 | ## What is being tested? 6 | 7 | This section has not been written yet. 8 | 9 | ## How are rating being calculated? 10 | 11 | This section has not been written yet. 12 | 13 | ## Read more 14 | 15 | Links to other sources where you can test or read more 16 | 17 | ## How to setup? 18 | 19 | This section has not been written yet. 20 | 21 | ### Prerequirements 22 | 23 | * Fork this repository 24 | Is the website required to be public because we use external service? 25 | 26 | ### Setup with GitHub Actions 27 | 28 | This section has not been written yet. 29 | Read more on the [general page for github actions](../getting-started-github-actions.md). 30 | 31 | ### Setup Locally 32 | 33 | This section has not been written yet. 34 | * Follow [general local setup steps for this repository](../getting-started-local.md) 35 | 36 | #### Using NPM package 37 | 38 | This section has not been written yet. 39 | 40 | #### Using Docker image 41 | 42 | This section has not been written yet. 43 | 44 | #### Using service? 45 | 46 | This section has not been written yet. 47 | 48 | ## FAQ 49 | 50 | No frequently asked questions yet :) 51 | 52 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/performance_sitespeed_io.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-01-09 22:00+0200\n" 9 | "PO-Revision-Date: 2021-06-19 20:30+0200\n" 10 | "Last-Translator: marcus \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 15 - Performance (Sitespeed.io)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- The website is really fast!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- The website is fast.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- About average speed.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- The website is quite slow.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- The website is very slow!\n" 35 | 36 | msgid "TEXT_REVIEW_LOAD_TIME" 37 | msgstr "- Loading time: {}\n" 38 | 39 | msgid "TEXT_REVIEW_LOAD_TIME_SECONDS" 40 | msgstr "- Loading time: 0.{} sec\n" 41 | 42 | msgid "TEXT_REVIEW_NUMBER_OF_REQUESTS" 43 | msgstr "- Number of requests: {}" -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/performance_sitespeed_io.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-01-09 22:00+0200\n" 9 | "PO-Revision-Date: 2021-06-19 20:30+0200\n" 10 | "Last-Translator: marcus \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 15 - Performance (Sitespeed.io)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- The website is really fast!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- The website is fast.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- About average speed.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- The website is quite slow.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- The website is very slow!\n" 35 | 36 | msgid "TEXT_REVIEW_LOAD_TIME" 37 | msgstr "- Loading time: {}\n" 38 | 39 | msgid "TEXT_REVIEW_LOAD_TIME_SECONDS" 40 | msgstr "- Loading time: 0.{} sec\n" 41 | 42 | msgid "TEXT_REVIEW_NUMBER_OF_REQUESTS" 43 | msgstr "- Number of requests: {}" -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/performance_sitespeed_io.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 22:00+0200\n" 9 | "PO-Revision-Date: 2021-06-19 20:30+0200\n" 10 | "Last-Translator: marcus \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 15 - Prestanda (Sitespeed.io)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- Webbplatsen laddar in mycket snabbt!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- Webbplatsen är snabb.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- Genomsnittlig hastighet.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- Webbplatsen är ganska långsam.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- Webbplatsen är väldigt långsam!\n" 35 | 36 | msgid "TEXT_REVIEW_LOAD_TIME" 37 | msgstr "- Laddtid: {}\n" 38 | 39 | msgid "TEXT_REVIEW_LOAD_TIME_SECONDS" 40 | msgstr "- Laddtid: 0.{}s\n" 41 | 42 | msgid "TEXT_REVIEW_NUMBER_OF_REQUESTS" 43 | msgstr "- Antal förfrågningar: {} st" 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webperf_core", 3 | "version": "2025.12.1", 4 | "type": "module", 5 | "description": "You probably want to read the documentation available at homepage.", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/Webperf-se/webperf_core.git" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/Webperf-se/webperf_core/issues" 15 | }, 16 | "homepage": "https://github.com/Webperf-se/webperf_core/", 17 | "dependencies": { 18 | "@sitespeed.io/plugin": "1.0.0", 19 | "@sitespeed.io/plugin-lighthouse": "13.0.0", 20 | "pa11y": "9.0.1", 21 | "sitespeed.io": "38.6.0", 22 | "plugin-css": "2025.12.0", 23 | "plugin-html": "2025.12.0", 24 | "plugin-javascript": "2025.12.0", 25 | "plugin-pagenotfound": "2025.12.0", 26 | "plugin-accessibility-statement": "2025.12.0", 27 | "plugin-webperf-core": "2025.12.0" 28 | }, 29 | "devDependencies": { 30 | "eslint": "9.39.1", 31 | "serve": "14.2.5", 32 | "serve-handler": "6.1.6" 33 | }, 34 | "scripts": { 35 | "start-server": "serve unittests/data/", 36 | "stop-server": "sudo pkill serve", 37 | "lint": "eslint .", 38 | "lint:fix": "eslint . --fix" 39 | }, 40 | "engines": { 41 | "node": ">=20.x" 42 | } 43 | } -------------------------------------------------------------------------------- /docs/thirdparty.md: -------------------------------------------------------------------------------- 1 | # Third party extensions 2 | 3 | Here we will add all project we know about that use or extends webperf_core. 4 | Do you have project that you want to be added here? 5 | Let us know by [adding a GitHub issue](https://github.com/Webperf-se/webperf_core/issues/new/choose). 6 | 7 | ### Webperf.se 8 | 9 | Webperf.se is the origin of the webperf_core repository and the community. In [December 2019 Webperf.se open-sourced](https://webperf.se/articles/webperf-core/) the tests with the intention and expectation that more people would benefit from the benchmarking with the results publicly available at Webperf.se in their continuous improvements. 10 | 11 | * Author: [Marcus Österberg](https://github.com/marcusosterberg) 12 | * Github repo: [Webperf-se public repos](https://github.com/orgs/Webperf-se/repositories) 13 | 14 | ### Webperf Core Leaderboard 15 | 16 | Reads Webperf Core SQLite data onto a dashboard-like .NET 5.0 Blazor web page. 17 | 18 | * Author: [Johan Kronberg](https://github.com/krompaco/) 19 | * Github repo: [webperf-leaderboard](https://github.com/krompaco/webperf-leaderboard) 20 | 21 | ### Webperf Core Windows Sandbox 22 | > This repo will help you setup and use Windows Sandbox when working with webperf_core. Main goal is to make it safer, easier and faster to use webperf_core. 23 | 24 | * Author: [cockroacher](https://github.com/cockroacher) 25 | * Github repo: [webperf_core-windows-sandbox](https://github.com/cockroacher/webperf_core-windows-sandbox) -------------------------------------------------------------------------------- /docs/tests/google-lighthouse-based.md: -------------------------------------------------------------------------------- 1 | # Google Lighthouse based Tests 2 | [![Regression Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-google-lighthouse-based.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-google-lighthouse-based.yml) 3 | 4 | This is a general page for the lighthouse test that are using Google Lighthouse in the background. 5 | 6 | ## How to setup? 7 | 8 | This section has not been written yet. 9 | 10 | ### Prerequirements 11 | 12 | * Fork this repository 13 | 14 | ### Setup with GitHub Actions 15 | 16 | Read more on the [general page for github actions](../getting-started-github-actions.md). 17 | 18 | ### Setup Locally 19 | 20 | This section has not been written yet. 21 | * Follow [general local setup steps for this repository](../getting-started-local.md) 22 | 23 | You can run this test by letting webperf-core call Google API:s (googleapis.com) or install a local version on your system. 24 | Follow the instructions below depending on what you choose. 25 | 26 | #### Using NPM package 27 | 28 | Benefit of this option is that you can use it to test pre production urls like your AcceptanceTest environment. 29 | 30 | * Download and install Node.js (version 20.x) 31 | * Install NPM packages ( `npm install --omit=dev` ) 32 | 33 | ## Read more 34 | 35 | Links to other sources where you can test or read more 36 | * https://web.dev/ 37 | * https://pagespeed.web.dev/ 38 | 39 | 40 | ## FAQ 41 | 42 | No frequently asked questions yet :) 43 | -------------------------------------------------------------------------------- /docs/tests/js-linting.md: -------------------------------------------------------------------------------- 1 | # Javascript (JS) Validation 2 | This test is a JS linting test developed by the Webperf community. 3 | 4 | ## How are rating being calculated? 5 | *To be documented* 6 | 7 | As always, minimum rating are 1.0. 8 | 9 | ## How to setup? 10 | 11 | ### Prerequirements 12 | 13 | * Fork this repository 14 | 15 | ### Setup with GitHub Actions 16 | 17 | Read more on the [general page for github actions](../getting-started-github-actions.md). 18 | 19 | ### Setup Locally 20 | 21 | * Follow [general local setup steps for this repository](../getting-started-local.md) 22 | * It is highly recommended to set [general.cache.use](../settings-json.md) to `true` 23 | * It is highly recommended to set [general.cache.max-age](../settings-json.md) to at least 12 hours (Fail to do so may result in banning of service like github). 24 | * Depending on your preference, follow below NPM package or Docker image steps below. 25 | 26 | #### Using NPM package 27 | 28 | * Download and install Node.js (version 20.x) 29 | * Download and install Google Chrome browser 30 | * Install NPM packages ( `npm install --omit=dev` ) 31 | * Set [tests.sitespeed.docker.use](../settings-json.md) to `false` in your `settings.json` 32 | 33 | ##### Windows Specific 34 | 35 | * Allow node to connect through Windows firewall 36 | 37 | #### Using Docker image 38 | 39 | * Make sure Docker command is globally accessible on your system. 40 | * Set [tests.sitespeed.docker.use](../settings-json.md) to `true` in your `settings.json` 41 | 42 | ## FAQ 43 | 44 | No frequently asked questions yet :) -------------------------------------------------------------------------------- /docs/tests/css-linting.md: -------------------------------------------------------------------------------- 1 | # CSS Validation 2 | This test is a CSS linting test developed by the Webperf community. 3 | 4 | ## How are rating being calculated? 5 | *To be documented* 6 | 7 | As always, minimum rating are 1.0. 8 | 9 | ## How to setup? 10 | 11 | ### Prerequirements 12 | 13 | * Fork this repository 14 | 15 | ### Setup with GitHub Actions 16 | 17 | Read more on the [general page for github actions](../getting-started-github-actions.md). 18 | 19 | ### Setup Locally 20 | 21 | * Follow [general local setup steps for this repository](../getting-started-local.md) 22 | * It is highly recommended to set [general.cache.use](../settings-json.md) to `true` 23 | * It is highly recommended to set [general.cache.max-age](../settings-json.md) to at least 12 hours (Fail to do so may result in banning of service like github). 24 | * Depending on your preference, follow below NPM package or Docker image steps below. 25 | 26 | * Download and install Java (JDK 8 or above) 27 | 28 | #### Using NPM package 29 | 30 | * Download and install Node.js (version 20.x) 31 | * Download and install Google Chrome browser 32 | * Install NPM packages ( `npm install --omit=dev` ) 33 | * Set [tests.sitespeed.docker.use](../settings-json.md) to `false` in your `settings.json` 34 | 35 | ##### Windows Specific 36 | 37 | * Allow node to connect through Windows firewall 38 | 39 | #### Using Docker image 40 | 41 | * Make sure Docker command is globally accessible on your system. 42 | * Set [tests.sitespeed.docker.use](../settings-json.md) to `true` in your `settings.json` 43 | 44 | ## FAQ 45 | 46 | No frequently asked questions yet :) -------------------------------------------------------------------------------- /engines/gov.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import csv 3 | from helpers.models import SiteTests 4 | 5 | def write_tests(output_filename, site_tests, sites, _): 6 | """ 7 | Writes site test results to a CSV formated file from a given list of site tests. 8 | Compared to csv engine it is optimized for goverment reports and is missing some fields 9 | 10 | Args: 11 | output_filename (str): The name of the output file. 12 | site_tests (list): A list of site tests. 13 | sites (list) : A list of sites. 14 | _ : Unused parameter. 15 | 16 | Returns: 17 | None 18 | """ 19 | 20 | tmp_fieldnames = [] 21 | lst = ['type_of_test', 'data', 'rating', 'date' 22 | 'perf', 'sec', 'a11y', 'stand', 'perf'] 23 | 24 | standard_fieldnames = SiteTests.fieldnames() 25 | for fieldname in standard_fieldnames: 26 | if 'site_id' == fieldname: 27 | tmp_fieldnames.append('url') 28 | elif not any(fieldname in x for x in lst): 29 | tmp_fieldnames.append(fieldname) 30 | tmp_sites = dict(sites) 31 | 32 | with open(output_filename.replace('.gov', '.csv'), 33 | 'w', newline='', 34 | encoding='utf-8') as csvfile: 35 | writer = csv.DictWriter(csvfile, fieldnames=tmp_fieldnames) # pylint: disable=no-member 36 | 37 | 38 | writer.writeheader() 39 | for site_test in site_tests: 40 | site_url = tmp_sites.get(site_test['site_id']) 41 | 42 | writer.writerow({ 43 | 'url': site_url, 44 | 'report': (site_test['report'] + site_test['report_sec']) 45 | }) 46 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/energy_efficiency.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-02-06 23:14+0200\n" 9 | "PO-Revision-Date: 2021-12-12 10:08+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 22 - Energieffektivitet\n" 20 | 21 | msgid "TEXT_TRANSFER_SIZE" 22 | msgstr "- Nätverksstorlek: {0:.2f} {1}\n" 23 | 24 | msgid "TEXT_WEBSITE_IS_VERY_GOOD" 25 | msgstr "- Webbsidan genererar väldigt lite koldioxid!\n" 26 | 27 | msgid "TEXT_WEBSITE_IS_GOOD" 28 | msgstr "- Webbsidan genererar ganska lite koldioxid.\n" 29 | 30 | msgid "TEXT_WEBSITE_IS_OK" 31 | msgstr "- Genomsnittligt när det gäller koldioxid.\n" 32 | 33 | msgid "TEXT_WEBSITE_IS_BAD" 34 | msgstr "- Webbsidan genererar en hel del koldioxid :/\n" 35 | 36 | msgid "TEXT_WEBSITE_IS_VERY_BAD" 37 | msgstr "- Webbsidan är riktigt dålig! Skapar massor av koldioxid för varje sidvisning :(\n" 38 | 39 | msgid "TEXT_GRAMS_OF_CO2" 40 | msgstr "- Koldioxid per sidvisning: {} gram\n" 41 | 42 | msgid "TEXT_GREEN_ENERGY_TRUE" 43 | msgstr "- Webbplatsen verkar drivas med grön el.\n" 44 | 45 | msgid "TEXT_GREEN_ENERGY_FALSE" 46 | msgstr "- Kunde inte se ifall webbplatsen använder grön el.\n" 47 | 48 | msgid "TEXT_BETTER_THAN" 49 | msgstr "- Webbsidan är grönare än {0} % av testade webbplatser på webperf.se (Referens uppdaterad: {1}).\n" -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/energy_efficiency.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-02-06 23:14+0200\n" 9 | "PO-Revision-Date: 2021-12-12 10:08+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 22 - Energy efficiency\n" 20 | 21 | msgid "TEXT_TRANSFER_SIZE" 22 | msgstr "- Network transfer size: {0:.2f} {1}\n" 23 | 24 | msgid "TEXT_WEBSITE_IS_VERY_GOOD" 25 | msgstr "- Webpage generates very little carbon dioxide!\n" 26 | 27 | msgid "TEXT_WEBSITE_IS_GOOD" 28 | msgstr "- Webpage generates little carbon dioxide!\n" 29 | 30 | msgid "TEXT_WEBSITE_IS_OK" 31 | msgstr "- Average regarding carbon dioxide.\n" 32 | 33 | msgid "TEXT_WEBSITE_IS_BAD" 34 | msgstr "- The webpage generates more carbon dioxide than is preferable :/\n" 35 | 36 | msgid "TEXT_WEBSITE_IS_VERY_BAD" 37 | msgstr "- The website is generating a lot of carbon dioxide, for every pageview :(\n" 38 | 39 | msgid "TEXT_GRAMS_OF_CO2" 40 | msgstr "- Carbon dioxide per pageview: {} gram(s)\n" 41 | 42 | msgid "TEXT_GREEN_ENERGY_TRUE" 43 | msgstr "- The website seem to be on renewable energy!\n" 44 | 45 | msgid "TEXT_GREEN_ENERGY_FALSE" 46 | msgstr "- Could not verify if the website is using renewable energy.\n" 47 | 48 | msgid "TEXT_BETTER_THAN" 49 | msgstr "- More green than {0} % of the websites tested by webperf.se (Reference updated: {1}).\n" -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/energy_efficiency.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-02-06 23:14+0200\n" 9 | "PO-Revision-Date: 2021-12-12 10:08+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 22 - Energy efficiency\n" 20 | 21 | msgid "TEXT_TRANSFER_SIZE" 22 | msgstr "- Network transfer size: {0:.2f} {1}\n" 23 | 24 | msgid "TEXT_WEBSITE_IS_VERY_GOOD" 25 | msgstr "- Webpage generates very little carbon dioxide!\n" 26 | 27 | msgid "TEXT_WEBSITE_IS_GOOD" 28 | msgstr "- Webpage generates little carbon dioxide!\n" 29 | 30 | msgid "TEXT_WEBSITE_IS_OK" 31 | msgstr "- Average regarding carbon dioxide.\n" 32 | 33 | msgid "TEXT_WEBSITE_IS_BAD" 34 | msgstr "- The webpage generates more carbon dioxide than is preferable :/\n" 35 | 36 | msgid "TEXT_WEBSITE_IS_VERY_BAD" 37 | msgstr "- The website is generating a lot of carbon dioxide, for every pageview :(\n" 38 | 39 | msgid "TEXT_GRAMS_OF_CO2" 40 | msgstr "- Carbon dioxide per pageview: {} gram(s)\n" 41 | 42 | msgid "TEXT_GREEN_ENERGY_TRUE" 43 | msgstr "- The website seem to be on renewable energy!\n" 44 | 45 | msgid "TEXT_GREEN_ENERGY_FALSE" 46 | msgstr "- Could not verify if the website is using renewable energy.\n" 47 | 48 | msgid "TEXT_BETTER_THAN" 49 | msgstr "- More green than {0} % of the websites tested by webperf.se (Reference updated: {1}).\n" -------------------------------------------------------------------------------- /docs/tests/pa11y.md: -------------------------------------------------------------------------------- 1 | # Accessibility (Pa11y) 2 | [![Regression Test - Accessibility (Pa11y) Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-pa11y.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-pa11y.yml) 3 | 4 | Add small description of what this test is. 5 | 6 | ## What is being tested? 7 | 8 | It test accessibility on the specified url. 9 | Please note that automated accessibility test generally only find 20-30% of all errors. 10 | Even if this test is not finding anything you should still do a manuall check once in a while. 11 | 12 | ## How are rating being calculated? 13 | 14 | We are calculating rating based on: 15 | - Number of different error types 16 | - Number of total number of errors 17 | 18 | we are then combining the results. 19 | 20 | Math used are: 21 | - `rating_number_of_error_types = 5.0 - (number_of_error_types / 5.0)` 22 | - `rating_number_of_errors = 5.0 - ((number_of_errors / 2.0) / 5.0)` 23 | 24 | As always, minimum rating are 1.0. 25 | 26 | ## Read more 27 | 28 | * https://github.com/pa11y/pa11y 29 | 30 | ## How to setup? 31 | 32 | This section has not been written yet. 33 | 34 | ### Prerequirements 35 | 36 | * Fork this repository 37 | 38 | ### Setup with GitHub Actions 39 | 40 | Read more on the [general page for github actions](../getting-started-github-actions.md). 41 | 42 | ### Setup Locally 43 | 44 | * Follow [general local setup steps for this repository](../getting-started-local.md) 45 | * Download and install Node.js (version 20.x) 46 | * Download and install Google Chrome browser 47 | * Install NPM packages ( `npm install --omit=dev` ) 48 | 49 | ## FAQ 50 | 51 | No frequently asked questions yet :) 52 | 53 | -------------------------------------------------------------------------------- /defaults/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "general": { 3 | "dns": { 4 | "address": "8.8.8.8" 5 | }, 6 | "language": "en", 7 | "request": { 8 | "timeout": 60 9 | }, 10 | "review": { 11 | "show": false, 12 | "data": false, 13 | "details": false, 14 | "improve-only": true 15 | }, 16 | "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0", 17 | "cache": { 18 | "use": false, 19 | "folder": "cache", 20 | "max-age": 60 21 | } 22 | }, 23 | "github": { 24 | "api": { 25 | "key": "" 26 | } 27 | }, 28 | "tests": { 29 | "a11y-statement": { 30 | "max-nof-pages": 10 31 | }, 32 | "email": { 33 | "support": { 34 | "port25": false, 35 | "ipv6": false 36 | } 37 | }, 38 | "http": { 39 | "csp-only": false 40 | }, 41 | "sitespeed": { 42 | "browser": "chrome", 43 | "docker": { 44 | "use": false 45 | }, 46 | "timeout": 30, 47 | "mobile": false, 48 | "iterations": 2, 49 | "xvfb": false 50 | }, 51 | "software": { 52 | "advisory": { 53 | "path": "" 54 | }, 55 | "browser": "chrome", 56 | "stealth": { 57 | "use": true 58 | } 59 | }, 60 | "page-not-found": { 61 | "override-url": true 62 | }, 63 | "webbkoll": { 64 | "sleep": 20 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/privacy_webbkollen.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 20:45+0200\n" 9 | "PO-Revision-Date: 2021-06-16 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 20 - Privacy (Webbkollen)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- Webbplatsen är riktigt bra på integritet!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- Webbplatsen kan bli bättre, men är helt ok.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- Ok integritet men borde nog bli bättre.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- Dålig integritet.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- Riktigt dålig integritet för användarna!\n" 35 | 36 | msgid "TEXT_RESULT_NOT_READY" 37 | msgstr "Tjänsten är inte redo med ett resultat ännu, väntar ytterligare {0} sekunder\n" 38 | 39 | msgid "TEXT_REVIEW_CATEGORY_VERY_GOOD" 40 | msgstr " är bra!" 41 | 42 | msgid "TEXT_REVIEW_CATEGORY_IS_GOOD" 43 | msgstr " är bra, men har {0} varning(ar)." 44 | 45 | msgid "TEXT_REVIEW_CATEGORY_IS_OK" 46 | msgstr " är ok, men har {0} fel och {1} varning(ar)." 47 | 48 | msgid "TEXT_REVIEW_CATEGORY_IS_BAD" 49 | msgstr " är inte så bra." 50 | 51 | msgid "TEXT_REVIEW_CATEGORY_IS_VERY_BAD" 52 | msgstr " är dåligt." 53 | 54 | msgid "TEXT_REVIEW_GENERATED" 55 | msgstr "- Resultat skapat: {0} (Buffras 24h)\n" 56 | -------------------------------------------------------------------------------- /.github/workflows/update-docker.yml: -------------------------------------------------------------------------------- 1 | name: "Docker - Update to latest version(s)" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - '**update-docker.yml' 7 | - 'package.json' 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest] 14 | config: ["SOFTWARE_GITHUB_ADADVISORY_DATABASE_PATH=advisory_database"] 15 | steps: 16 | - name: Check out repository code 17 | uses: actions/checkout@v6 18 | - name: Setup python 19 | uses: actions/setup-python@v6 20 | with: 21 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 22 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 23 | - name: Setup dependencies using pip 24 | run: pip install -r requirements.txt 25 | - name: Ensure up to date Dockerfile 26 | run: python .github/workflows/verify_result.py -d ${{ matrix.config }},GITHUB_API_KEY=${{ secrets.GITHUB_TOKEN }} 27 | - name: Build the Docker image 28 | run: docker build -t "webperf-core:latest" . 29 | - name: Create pull request 30 | uses: peter-evans/create-pull-request@v7 31 | with: 32 | commit-message: Updating Dockerfile with latest browsers 33 | branch: dockerfile-latest-browsers 34 | title: Updating Dockerfile to latest browsers 35 | body: | 36 | This pull request is used to make it easier to keep the Dockerfile up to date. 37 | 38 | Following files may be touched: 39 | - Dockerfile 40 | assignees: 7h3Rabbit 41 | reviewers: 7h3Rabbit 42 | add-paths: | 43 | Dockerfile 44 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/privacy_webbkollen.po: -------------------------------------------------------------------------------- 1 | # English (default). 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 20:45+0200\n" 9 | "PO-Revision-Date: 2021-06-16 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 20 - Privacy (Webbkollen)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- The website is great on privacy!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- The site could be better, but is pretty good.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- About average privacy settings, but should get better.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- Rather poor on user privacy.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- Very bad privacy!\n" 35 | 36 | msgid "TEXT_RESULT_NOT_READY" 37 | msgstr "The service is not yet ready with a result, waiting another {0} seconds\n" 38 | 39 | msgid "TEXT_REVIEW_CATEGORY_VERY_GOOD" 40 | msgstr " is good!" 41 | 42 | msgid "TEXT_REVIEW_CATEGORY_IS_GOOD" 43 | msgstr " is good, but with {0} warning(s)." 44 | 45 | msgid "TEXT_REVIEW_CATEGORY_IS_OK" 46 | msgstr " is ok, with {0} error(s) and {1} warning(s)." 47 | 48 | msgid "TEXT_REVIEW_CATEGORY_IS_BAD" 49 | msgstr " is not that good." 50 | 51 | msgid "TEXT_REVIEW_CATEGORY_IS_VERY_BAD" 52 | msgstr " is pretty bad." 53 | 54 | msgid "TEXT_REVIEW_GENERATED" 55 | msgstr "- Result generated: {0} (Cached for 24 hours)\n" 56 | -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/privacy_webbkollen.po: -------------------------------------------------------------------------------- 1 | # English (default). 2 | # Copyright (C) 2020 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 20:45+0200\n" 9 | "PO-Revision-Date: 2021-06-16 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 20 - Privacy (Webbkollen)\n" 20 | 21 | msgid "TEXT_REVIEW_VERY_GOOD" 22 | msgstr "- The website is great on privacy!\n" 23 | 24 | msgid "TEXT_REVIEW_IS_GOOD" 25 | msgstr "- The site could be better, but is pretty good.\n" 26 | 27 | msgid "TEXT_REVIEW_IS_OK" 28 | msgstr "- About average privacy settings, but should get better.\n" 29 | 30 | msgid "TEXT_REVIEW_IS_BAD" 31 | msgstr "- Rather poor on user privacy.\n" 32 | 33 | msgid "TEXT_REVIEW_IS_VERY_BAD" 34 | msgstr "- Very bad privacy!\n" 35 | 36 | msgid "TEXT_RESULT_NOT_READY" 37 | msgstr "The service is not yet ready with a result, waiting another {0} seconds\n" 38 | 39 | msgid "TEXT_REVIEW_CATEGORY_VERY_GOOD" 40 | msgstr " is good!" 41 | 42 | msgid "TEXT_REVIEW_CATEGORY_IS_GOOD" 43 | msgstr " is good, but with {0} warning(s)." 44 | 45 | msgid "TEXT_REVIEW_CATEGORY_IS_OK" 46 | msgstr " is ok, with {0} error(s) and {1} warning(s)." 47 | 48 | msgid "TEXT_REVIEW_CATEGORY_IS_BAD" 49 | msgstr " is not that good." 50 | 51 | msgid "TEXT_REVIEW_CATEGORY_IS_VERY_BAD" 52 | msgstr " is pretty bad." 53 | 54 | msgid "TEXT_REVIEW_GENERATED" 55 | msgstr "- Result generated: {0} (Cached for 24 hours)\n" 56 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/a11y_pa11y.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2022 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 10:45+0200\n" 9 | "PO-Revision-Date: 2022-02-18 17:15+0200\n" 10 | "Last-Translator: Mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | msgid "TEXT_RUNNING_TEST" 18 | msgstr "## Test: 18 - Tillgänglighet (Pa11y)\n" 19 | 20 | msgid "TEXT_REVIEW_A11Y_VERY_GOOD" 21 | msgstr "- Webbplatsen har inga uppenbara fel inom tillgänglighet! Bra, men gör manuella undersökningar för säkerhets skull!\n" 22 | 23 | msgid "TEXT_REVIEW_A11Y_IS_GOOD" 24 | msgstr "- Webbplatsen kan bli mer tillgänglig, men är ganska ok.\n" 25 | 26 | msgid "TEXT_REVIEW_A11Y_IS_OK" 27 | msgstr "- Genomsnittlig tillgänglighet men kan bli bättre på automatiska tester.\n" 28 | 29 | msgid "TEXT_REVIEW_A11Y_IS_BAD" 30 | msgstr "- Webbplatsen är dålig på tillgänglighet för funktions­nedsatta personer.\n" 31 | 32 | msgid "TEXT_REVIEW_A11Y_IS_VERY_BAD" 33 | msgstr "- Väldigt dålig tillgänglighet!\n" 34 | 35 | msgid "TEXT_REVIEW_A11Y_NUMBER_OF_PROBLEMS" 36 | msgstr "- Antal tillgänglighets­problem: {} st" 37 | 38 | msgid "TEXT_REVIEW_A11Y_TOO_MANY_PROBLEMS" 39 | msgstr "- Info: För många unika problem för att lista alla.\n" 40 | 41 | msgid "TEXT_REVIEW_A11Y_PROBLEMS" 42 | msgstr "\n##### Problem:\n" 43 | 44 | msgid "TEXT_REVIEW_ERRORS_ITEM" 45 | msgstr " - {0} (totalt {1} st)\n" 46 | 47 | msgid "TEXT_REVIEW_RATING_GROUPED" 48 | msgstr "- Antal grupperade fel: {0}" 49 | 50 | msgid "TEXT_REVIEW_RATING_ITEMS" 51 | msgstr "- Antal fel: {0}" -------------------------------------------------------------------------------- /defaults/a11y-overlays.json: -------------------------------------------------------------------------------- 1 | { 2 | "overlays": [ 3 | { 4 | "name": "AccessiBe", 5 | "description": "Sometimes referred to as Accessiway?", 6 | "website": "https://accessibe.com", 7 | "urls": [ 8 | { 9 | "url": "https://acsbapp.com/" 10 | }, 11 | { 12 | "url": "https://cdn.acsbapp.com" 13 | }, 14 | { 15 | "url": "https://accesswidget-log-receiver.acsbapp.com/" 16 | } 17 | ] 18 | }, 19 | { 20 | "name": "EqualWeb", 21 | "description": "", 22 | "website": "https://www.equalweb.com", 23 | "urls": [ 24 | { 25 | "url": "https://aacdn.nagich.com/" 26 | }, 27 | { 28 | "url": "https://ocr.nagich.com/" 29 | } 30 | ] 31 | }, 32 | { 33 | "name": "UserWay", 34 | "description": "", 35 | "website": "https://userway.org", 36 | "urls": [ 37 | { 38 | "url": "https://cdn.userway.org/" 39 | }, 40 | { 41 | "url": "https://api.userway.org/" 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "AudioEye", 47 | "description": "", 48 | "website": "https://www.audioeye.com", 49 | "urls": [ 50 | { 51 | "url": "https://wsmcdn.audioeye.com/" 52 | }, 53 | { 54 | "url": "https://wsv3cdn.audioeye.com/" 55 | } 56 | ] 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /docs/tests/a11y-statement.md: -------------------------------------------------------------------------------- 1 | # Accessibility Statement 2 | [![Regression Test - Accessibility Statement Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-a11y-statement.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-a11y-statement.yml) 3 | 4 | Add small description of what this test is. 5 | 6 | ## What is being tested? 7 | 8 | This test looks for and rates your accessibility statement. 9 | This test is currently calibrated only for swedish. 10 | 11 | It rates on many "shall" statements from the [Swedish Agency for Digital Government](https://digg.se/kunskap-och-stod/digital-tillganglighet/skapa-en-tillganglighetsredogorelse) 12 | 13 | ## How are rating being calculated? 14 | 15 | We are calculating rating based on: 16 | - IF we can find an accessibility statement. 17 | - On what link depth we find the accessibility statement. 18 | - IF we can find "helt förenlig", "delvis förenlig" or "inte förenlig" 19 | - IF we can find valid/correct [notification function url to DIGG](https://www.digg.se/tdosanmalan) 20 | - IF we can find unreasonably burdensome accommodation 21 | - IF we can find evaluation method used to validate accessibility 22 | - IF we can find when accessibility statement was updated and WHEN 23 | 24 | ## Read more 25 | 26 | * https://digg.se/kunskap-och-stod/digital-tillganglighet/skapa-en-tillganglighetsredogorelse 27 | 28 | ## How to setup? 29 | 30 | This section has not been written yet. 31 | 32 | ### Prerequirements 33 | 34 | * Fork this repository 35 | 36 | ### Setup with GitHub Actions 37 | 38 | Read more on the [general page for github actions](../getting-started-github-actions.md). 39 | 40 | ### Setup Locally 41 | 42 | * Follow [general local setup steps for this repository](../getting-started-local.md) 43 | 44 | ## FAQ 45 | 46 | No frequently asked questions yet :) 47 | 48 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/a11y_pa11y.po: -------------------------------------------------------------------------------- 1 | # English 2 | # Copyright (C) 2022 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 10:45+0200\n" 9 | "PO-Revision-Date: 2022-02-18 17:15+0200\n" 10 | "Last-Translator: Mattias \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | msgid "TEXT_RUNNING_TEST" 18 | msgstr "## Test: 18 - Accessibility (Pa11y)\n" 19 | 20 | msgid "TEXT_REVIEW_A11Y_VERY_GOOD" 21 | msgstr "- The website do not have any apparent issues with accessibility!\n" 22 | 23 | msgid "TEXT_REVIEW_A11Y_IS_GOOD" 24 | msgstr "- The website can be more accessible, but is rather good!\n" 25 | 26 | msgid "TEXT_REVIEW_A11Y_IS_OK" 27 | msgstr "- The accessibility is about average, but needs to get better.\n" 28 | 29 | msgid "TEXT_REVIEW_A11Y_IS_BAD" 30 | msgstr "- The website is quite bad at accessibility and sucks for disabled people!\n" 31 | 32 | msgid "TEXT_REVIEW_A11Y_IS_VERY_BAD" 33 | msgstr "- The accessibility is really bad! Probably both for disabled people and everyone of us when we need some accessibility!\n" 34 | 35 | msgid "TEXT_REVIEW_A11Y_NUMBER_OF_PROBLEMS" 36 | msgstr "- Number of problems with accessibility: {}" 37 | 38 | msgid "TEXT_REVIEW_A11Y_TOO_MANY_PROBLEMS" 39 | msgstr "- Info: Too many unique problems to list them all.\n" 40 | 41 | msgid "TEXT_REVIEW_A11Y_PROBLEMS" 42 | msgstr "\n##### Problems:\n" 43 | 44 | msgid "TEXT_REVIEW_ERRORS_ITEM" 45 | msgstr " - {0} (number of issues of this type: {1})\n" 46 | 47 | msgid "TEXT_REVIEW_RATING_GROUPED" 48 | msgstr "- Number of types of issues: {0}" 49 | 50 | msgid "TEXT_REVIEW_RATING_ITEMS" 51 | msgstr "- Number of issues: {0}" -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/a11y_pa11y.po: -------------------------------------------------------------------------------- 1 | # English 2 | # Copyright (C) 2022 WebPerf 3 | # FIRST AUTHOR , 2020. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2020-12-12 10:45+0200\n" 9 | "PO-Revision-Date: 2022-02-18 17:15+0200\n" 10 | "Last-Translator: Mattias \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | msgid "TEXT_RUNNING_TEST" 18 | msgstr "## Test: 18 - Accessibility (Pa11y)\n" 19 | 20 | msgid "TEXT_REVIEW_A11Y_VERY_GOOD" 21 | msgstr "- The website do not have any apparent issues with accessibility!\n" 22 | 23 | msgid "TEXT_REVIEW_A11Y_IS_GOOD" 24 | msgstr "- The website can be more accessible, but is rather good!\n" 25 | 26 | msgid "TEXT_REVIEW_A11Y_IS_OK" 27 | msgstr "- The accessibility is about average, but needs to get better.\n" 28 | 29 | msgid "TEXT_REVIEW_A11Y_IS_BAD" 30 | msgstr "- The website is quite bad at accessibility and sucks for disabled people!\n" 31 | 32 | msgid "TEXT_REVIEW_A11Y_IS_VERY_BAD" 33 | msgstr "- The accessibility is really bad! Probably both for disabled people and everyone of us when we need some accessibility!\n" 34 | 35 | msgid "TEXT_REVIEW_A11Y_NUMBER_OF_PROBLEMS" 36 | msgstr "- Number of problems with accessibility: {}" 37 | 38 | msgid "TEXT_REVIEW_A11Y_TOO_MANY_PROBLEMS" 39 | msgstr "- Info: Too many unique problems to list them all.\n" 40 | 41 | msgid "TEXT_REVIEW_A11Y_PROBLEMS" 42 | msgstr "\n##### Problems:\n" 43 | 44 | msgid "TEXT_REVIEW_ERRORS_ITEM" 45 | msgstr " - {0} (number of issues of this type: {1})\n" 46 | 47 | msgid "TEXT_REVIEW_RATING_GROUPED" 48 | msgstr "- Number of types of issues: {0}" 49 | 50 | msgid "TEXT_REVIEW_RATING_ITEMS" 51 | msgstr "- Number of issues: {0}" -------------------------------------------------------------------------------- /docs/tests/html-validate.md: -------------------------------------------------------------------------------- 1 | # HTML 2 | 3 | This test is validating all used HTML on the url specified. Making use of the [html-validate](https://html-validate.org/) 4 | 5 | ## Differences compared to vanilla html-validate 6 | We are using 7 | * the built-in preset: ``--preset standard`` 8 | * sitespeed to visit the website 9 | * sitespeed's HAR file to identify HTML files used during the visit 10 | * all files whose mimetype contains 'html' 11 | 12 | ## How are rating being calculated? 13 | 14 | We are calculating rating based on: 15 | - Number of different error types 16 | - Number of total number of errors 17 | 18 | we are then combining the results. 19 | 20 | Math used are: 21 | - `rating_number_of_error_types = 5.0 - (number_of_error_types / 5.0)` 22 | - `rating_number_of_errors = 5.0 - ((number_of_errors / 2.0) / 5.0)` 23 | 24 | As always, minimum rating are 1.0. 25 | 26 | ## Read more 27 | 28 | ## How to setup? 29 | 30 | ### Prerequirements 31 | 32 | * Fork this repository 33 | 34 | ### Setup with GitHub Actions 35 | 36 | Read more on the [general page for github actions](../getting-started-github-actions.md). 37 | 38 | ### Setup Locally 39 | 40 | * Follow [general local setup steps for this repository](../getting-started-local.md) 41 | * It is highly recommended to set [general.cache.use](../settings-json.md) to `true` 42 | * It is highly recommended to set [general.cache.max-age](../settings-json.md) to at least 12 hours (Fail to do so may result in banning of service like github). 43 | * Depending on your preference, follow below NPM package or Docker image steps below. 44 | 45 | ##### Windows Specific 46 | 47 | * Allow node to connect through Windows firewall 48 | 49 | #### Using Docker image 50 | 51 | * Make sure Docker command is globally accessible on your system. 52 | * Set [tests.sitespeed.docker.use](../settings-json.md) to `true` in your `settings.json` 53 | 54 | ## FAQ 55 | 56 | No frequently asked questions yet :) 57 | -------------------------------------------------------------------------------- /docs/tests/webbkoll.md: -------------------------------------------------------------------------------- 1 | # Users’ integrity test against Webbkoll, provided by 5july.net 2 | [![Regression Test - Integrity & Security (Webbkoll) Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-webbkoll.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-webbkoll.yml) 3 | 4 | This test is using Webbkoll provided by 5july.net to show how you handle user security and integrity. 5 | 6 | ## What is being tested? 7 | 8 | We are currently using below sections of Webbkoll report: 9 | 10 | * HTTPS by default 11 | * HTTP Strict Transport Security (HSTS) 12 | * Content Security Policy 13 | * Reporting (CSP, Certificate Transparency, Network Error Logging) 14 | * Referrer Policy 15 | * Subresource Integrity (SRI) 16 | * HTTP headers 17 | * Cookies 18 | 19 | ## How are rating being calculated? 20 | 21 | We are currently giving you 5 in rating by for every section above if there is no error or warning. 22 | We give you 1 in rating if failed the section (getting a big red X, meaning error). 23 | We are giving you 2.5 in rating if you have warning on the section level. 24 | 25 | In addition to above we will give you following penelty: 26 | * for every small error we will lower the rating by 0.5 27 | * for every small warning we will lower the rating by 0.25. 28 | 29 | Lowest rating is as always 1.0 30 | 31 | ## Read more 32 | 33 | * https://webbkoll.5july.net/ 34 | 35 | ## How to setup? 36 | 37 | ### Prerequirements 38 | 39 | * Fork this repository 40 | * As we are using external service ( https://webbkoll.5july.net/ ) your site needs to be publicly available and the machine running 41 | this test needs to be able to access external service. 42 | 43 | ### Setup with GitHub Actions 44 | 45 | Read more on the [general page for github actions](../getting-started-github-actions.md). 46 | 47 | ### Setup Locally 48 | 49 | * Follow [general local setup steps for this repository](../getting-started-local.md) 50 | 51 | ## FAQ 52 | 53 | No frequently asked questions yet :) 54 | 55 | -------------------------------------------------------------------------------- /.github/workflows/prep-release.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/simbo/changes-since-last-release-action 2 | name: Prepare Release 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - "**software-full.json" 10 | - "Dockerfile" 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v6 17 | with: 18 | fetch-depth: 0 # [!] we need to checkout with tags and commit history 19 | - name: Setup python 20 | uses: actions/setup-python@v6 21 | with: 22 | python-version: "3.x" # Version range or exact version of a Python version to use, using SemVer's version range syntax 23 | architecture: "x64" # optional x64 or x86. Defaults to x64 if not specified 24 | - name: Setup dependencies using pip 25 | run: pip install -r requirements.txt 26 | - name: 📋 Get Commits since last Release 27 | id: changes 28 | uses: simbo/changes-since-last-release-action@v1.0.1 29 | with: 30 | line-prefix: "* " 31 | include-hashes: false 32 | - name: Generate new release version 33 | id: newversion 34 | run: python default.py --prepare-release "${{ steps.changes.outputs.last-tag }}" 35 | - name: Create pull request 36 | uses: peter-evans/create-pull-request@v7 37 | with: 38 | commit-message: Updated version in package.json to latest 39 | branch: update-version-in-package-json 40 | title: "Prepare release - ${{ env.NEW_VERSION }}" 41 | body: | 42 | Approving this PR triggers creation of a new release. 43 | 44 | Changes since ${{ steps.changes.outputs.last-tag }}: 45 | ${{ steps.changes.outputs.log }} 46 | assignees: cockroacher,marcusosterberg 47 | reviewers: cockroacher,marcusosterberg 48 | labels: ignore-for-release 49 | add-paths: | 50 | package.json 51 | -------------------------------------------------------------------------------- /docs/tests/standard.md: -------------------------------------------------------------------------------- 1 | # Standard files 2 | [![Regression Test - Standard files Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-standard-files.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-standard-files.yml) 3 | 4 | Add small description of what this test is. 5 | 6 | ## What is being tested? 7 | 8 | ### Robots.txt 9 | 10 | * Ensure /robots.txt has no `` element 11 | * Ensure /robots.txt has one or more of the following content: 12 | * `allow` 13 | * `disallow` 14 | * `user-agent` 15 | 16 | ### Sitemap 17 | 18 | * Checks if sitemap are referenced in robots.txt and seem to have correct formating. 19 | * Ensure sitemaps has one or more of the following content: 20 | * `www.sitemaps.org/schemas/sitemap/` 21 | * ` /etc/sudoers.d/tc 38 | 39 | # https://github.com/puppeteer/puppeteer/issues/8148#issuecomment-1397528849 40 | RUN Xvfb -ac :99 -screen 0 1280x1024x16 & export DISPLAY=:99 41 | 42 | RUN npm install -g node-gyp puppeteer-core npm-check-updates 43 | 44 | # If own settings.json exists it will overwrite the default 45 | COPY . /usr/src/runner 46 | 47 | # Use same parameters phantomas 48 | COPY pa11y-docker-config.json /usr/src/runner/pa11y.json 49 | 50 | RUN chown --recursive sitespeedio:sitespeedio /usr/src/runner 51 | 52 | RUN python3 -m pip install -r requirements.txt --break-system-packages && \ 53 | python3 -m pip install --upgrade pip --break-system-packages && \ 54 | python3 -m pip install --upgrade setuptools --break-system-packages && \ 55 | python3 -m pip install pyssim Pillow image --break-system-packages 56 | 57 | # Run everything after as non-privileged user. 58 | USER sitespeedio 59 | 60 | RUN npm install --omit=dev 61 | 62 | RUN python3 default.py --setting tests.sitespeed.xvfb=true --save-setting settings.json 63 | 64 | ENTRYPOINT [] 65 | 66 | CMD ["python3", "default.py -h"] 67 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-standard-files.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Standard files Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-energy-efficiency.yml' 19 | - '**regression-test-google-lighthouse-based.yml' 20 | - '**regression-test-html.yml' 21 | - '**regression-test-http.yml' 22 | - '**regression-test-lint-css.yml' 23 | - '**regression-test-pa11y.yml' 24 | - '**regression-test-sitespeed-browsertime-har.yml' 25 | - '**regression-test-sitespeed.yml' 26 | - '**regression-test-software.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest, windows-latest] 36 | version: [9] 37 | steps: 38 | - name: Check out repository code 39 | uses: actions/checkout@v6 40 | - name: Setup python 41 | uses: actions/setup-python@v6 42 | with: 43 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 44 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 45 | - name: Setup dependencies using pip 46 | run: pip install -r requirements.txt 47 | - if: ${{ matrix.os == 'ubuntu-latest' }} 48 | name: RUNNING TEST - LINUX 49 | run: | 50 | python default.py -t ${{ matrix.version }} -r -i defaults/sites.json -o data/testresult-${{ matrix.version }}.json 51 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 52 | - if: ${{ matrix.os == 'windows-latest' }} 53 | name: RUNNING TEST - WINDOWS 54 | run: | 55 | python default.py -t ${{ matrix.version }} -r -i defaults\sites.json -o data\testresult-${{ matrix.version }}.json 56 | python .github\workflows\verify_result.py -t ${{ matrix.version }} 57 | -------------------------------------------------------------------------------- /docs/tests/page-not-found.md: -------------------------------------------------------------------------------- 1 | # 404 (Page not Found) 2 | [![Regression Test - 404 (Page not Found) Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-404.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-404.yml) 3 | 4 | This test is checking if you have set up a 404 (page not found) page correctly. 5 | We are doing this by calling a random url on your domain and verifying following: 6 | - HTTP Status Code is 404 7 | - The resource returned is HTML 8 | - The HTML has a `title` element 9 | - The HTML has a `h1` element header 10 | - Text content are more then 150 chars 11 | - One or more of the following strings exist on page (only swedish for now) 12 | - saknas 13 | - finns inte 14 | - inga resultat 15 | - inte hittas 16 | - inte hitta 17 | - kunde inte 18 | - kunde ej 19 | - hittades inte 20 | - hittar inte 21 | - hittade vi inte 22 | - hittar vi inte 23 | - hittades tyvärr inte 24 | - tagits bort 25 | - fel adress 26 | - trasig 27 | - inte hitta 28 | - ej hitta 29 | - ingen sida 30 | - borttagen 31 | - flyttad 32 | - inga resultat 33 | - inte tillgänglig 34 | - inte sidan 35 | - kontrollera adressen 36 | - kommit utanför 37 | - gick fel 38 | - blev något fel 39 | - kan inte nås 40 | - gammal sida 41 | - hoppsan 42 | - finns inte 43 | - finns ej 44 | - byggt om 45 | - inte finns 46 | - inte fungera 47 | - ursäkta 48 | - uppstått ett fel 49 | - gick fel 50 | 51 | ## How are rating being calculated? 52 | 53 | You can get 1-5 in rating for every section: 54 | - HTTP Status Code is 404 55 | - The resource returned is HTML 56 | - The HTML has a `title` element 57 | - The HTML has a `h1` element header 58 | - Text content are more then 150 chars 59 | - One or more of the following strings exist on page 60 | 61 | They are then combined. 62 | 63 | ## Read more 64 | 65 | Links to other sources where you can test or read more 66 | 67 | ## How to setup? 68 | 69 | ### Prerequirements 70 | 71 | * Fork this repository 72 | * As we are using external service ( https://validator.w3.org/nu/ ) your site needs to be publicly available and the machine running 73 | this test needs to be able to access external service. 74 | 75 | ### Setup with GitHub Actions 76 | 77 | Read more on the [general page for github actions](../getting-started-github-actions.md). 78 | 79 | ### Setup Locally 80 | 81 | * Follow [general local setup steps for this repository](../getting-started-local.md) 82 | 83 | ## FAQ 84 | 85 | No frequently asked questions yet :) 86 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL (Security and Code Quality)" 13 | on: 14 | push: 15 | paths-ignore: 16 | - '**.md' 17 | - '**software-full.json' 18 | - '**software-sources.json' 19 | - '**update-software.yml' 20 | - '**update_software_helper.py' 21 | - '**software-rules.json' 22 | #on: [ push, pull_request ] 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: windows-latest 27 | #runs-on: windows-2019 28 | permissions: 29 | actions: read 30 | contents: read 31 | security-events: write 32 | 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | language: [ 'python', 'javascript' ] 37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 38 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v6 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v4 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v4 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v4 -------------------------------------------------------------------------------- /docs/tests/energy-efficiency.md: -------------------------------------------------------------------------------- 1 | # Energy Efficiency 2 | [![Regression Test - Energy Efficiency Test](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-energy-efficiency.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-energy-efficiency.yml) 3 | 4 | Aim for this test is to start discussion regarding website impact on climate and environment. 5 | It is not perfect but hopefully a start. 6 | 7 | ## What is being tested? 8 | 9 | We are giving websites a relative rating depending on the impact they would have _IF_ they had the same visitor count and technical solution. 10 | We are doing this by taking the weight of the url in KiB and calculating a value from this. 11 | We then compare that value with a reference values and gives you a rating. 12 | The reference values represents the percentile for all urls checked by Webperf.se. 13 | This is updated manually and you can see when it was done latet by looking at the date in top of [/tests/energy_efficiency_carbon_percentiles.py](../../tests/energy_efficiency_carbon_percentiles.py). 14 | 15 | If you know any other way we could automatically compare impact on climate and environment a certain url has, *PLEASE* let us know :) 16 | 17 | ## How are rating being calculated? 18 | 19 | This section has not been written yet. 20 | 21 | ## Read more 22 | 23 | * https://www.websitecarbon.com/ 24 | * https://www.thegreenwebfoundation.org/ 25 | 26 | ## How to setup? 27 | 28 | This test is using Sitespeed.io in the background 29 | so please follow instructions on page about [Sitespeed.io Based Test](./sitespeed.md) 30 | 31 | ### How to update carbon percentile reference? 32 | 33 | Below are the steps that you need to do to calculate a new carbon percentile reference file. 34 | As you can read above, this are required if you want to have a up to date reference regarding carbon footprint. 35 | It is also needed if you want to have your own reference to rate against, for example your own websites last year or your closes competition. 36 | 37 | #### Create new baseline 38 | You do this by running Energy efficiency against a list of all sites you want to compare against. 39 | For example: 40 | ``` 41 | python default.py -i kommuner.webprf -t 22 -o data\carbon-references-kommuner.json 42 | ``` 43 | 44 | #### Calculate new percentiles 45 | You now have a baseline to create your carbon percentiles from. 46 | You do this by running `python default.py --update-carbon `. 47 | We recommend running it as follows: 48 | ``` 49 | default.py --update-carbon data\carbon-references-kommuner.json 50 | ``` 51 | 52 | For webperf-core will now have updated `tests\energy_efficiency_carbon_percentiles.py` to use your new percentiles. 53 | 54 | ## FAQ 55 | 56 | No frequently asked questions yet :) 57 | 58 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/404.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # Marcus J Österberg , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-04-27 12:00\n" 8 | "PO-Revision-Date: 2025-05-09 23:00\n" 9 | "Last-Translator: Marcus J Österberg \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | msgid "has-unexpected-404-response (unresolved)" 32 | msgstr "Har oväntat 404-svar ({0})" 33 | 34 | msgid "has-unexpected-404-response (resolved)" 35 | msgstr "Har korrekt 404-svar (löst)" 36 | 37 | msgid "no-valid-title-found (unresolved)" 38 | msgstr "Ingen giltig titel hittades ({0})" 39 | 40 | msgid "no-valid-title-found (resolved)" 41 | msgstr "Giltig titel hittad (löst)" 42 | 43 | msgid "no-valid-h1-found (unresolved)" 44 | msgstr "Ingen giltig h1 hittades ({0})" 45 | 46 | msgid "no-valid-h1-found (resolved)" 47 | msgstr "Korrekt h1 hittades (löst)" 48 | 49 | msgid "no-valid-text-found (unresolved)" 50 | msgstr "ingen-giltig-text-hittad ({0})" 51 | 52 | msgid "no-valid-text-found (resolved)" 53 | msgstr "ingen-giltig-text-hittad (löst)" 54 | 55 | msgid "invalid-text-found (unresolved)" 56 | msgstr "ogiltig-text-hittad ({0})" 57 | 58 | msgid "invalid-text-found (resolved)" 59 | msgstr "ogiltig-text-hittad (löst)" 60 | 61 | msgid "no-valid-response-status-code (unresolved)" 62 | msgstr "Felaktig svarskod ({0})" 63 | 64 | msgid "no-valid-response-status-code (resolved)" 65 | msgstr "Korrekt svarskod (löst)" 66 | 67 | msgid "no-unsupported-locale-use (unresolved)" 68 | msgstr "ingen-ickestödd-användning-av-språk ({0})" 69 | 70 | msgid "no-unsupported-locale-use (resolved)" 71 | msgstr "ingen-ickestödd-användning-av-språk (löst)" 72 | 73 | msgid "no-valid-not-found-text-in-body (unresolved)" 74 | msgstr "ingen-giltig-inte-hittad-text-i-innehåll ({0})" 75 | 76 | msgid "no-valid-not-found-text-in-body (resolved)" 77 | msgstr "ingen-giltig-inte-hittad-text-i-innehåll (löst)" 78 | 79 | msgid "no-network (unresolved)" 80 | msgstr "Inget nätverk ({0})" 81 | 82 | msgid "no-network (resolved)" 83 | msgstr "Nätverk fungerar (löst)" 84 | -------------------------------------------------------------------------------- /unittests/data/js/color-modes.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) 3 | * Copyright 2011-2025 The Bootstrap Authors 4 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 5 | */ 6 | 7 | (() => { 8 | 'use strict' 9 | 10 | const getStoredTheme = () => localStorage.getItem('theme') 11 | const setStoredTheme = theme => localStorage.setItem('theme', theme) 12 | 13 | const getPreferredTheme = () => { 14 | const storedTheme = getStoredTheme() 15 | if (storedTheme) { 16 | return storedTheme 17 | } 18 | 19 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 20 | } 21 | 22 | const setTheme = theme => { 23 | if (theme === 'auto') { 24 | document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) 25 | } else { 26 | document.documentElement.setAttribute('data-bs-theme', theme) 27 | } 28 | } 29 | 30 | setTheme(getPreferredTheme()) 31 | 32 | const showActiveTheme = (theme, focus = false) => { 33 | const themeSwitcher = document.querySelector('#bd-theme') 34 | 35 | if (!themeSwitcher) { 36 | return 37 | } 38 | 39 | const themeSwitcherText = document.querySelector('#bd-theme-text') 40 | const activeThemeIcon = document.querySelector('.theme-icon-active use') 41 | const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) 42 | const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href') 43 | 44 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 45 | element.classList.remove('active') 46 | element.setAttribute('aria-pressed', 'false') 47 | }) 48 | 49 | btnToActive.classList.add('active') 50 | btnToActive.setAttribute('aria-pressed', 'true') 51 | activeThemeIcon.setAttribute('href', svgOfActiveBtn) 52 | const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})` 53 | themeSwitcher.setAttribute('aria-label', themeSwitcherLabel) 54 | 55 | if (focus) { 56 | themeSwitcher.focus() 57 | } 58 | } 59 | 60 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 61 | const storedTheme = getStoredTheme() 62 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 63 | setTheme(getPreferredTheme()) 64 | } 65 | }) 66 | 67 | window.addEventListener('DOMContentLoaded', () => { 68 | showActiveTheme(getPreferredTheme()) 69 | 70 | document.querySelectorAll('[data-bs-theme-value]') 71 | .forEach(toggle => { 72 | toggle.addEventListener('click', () => { 73 | const theme = toggle.getAttribute('data-bs-theme-value') 74 | setStoredTheme(theme) 75 | setTheme(theme) 76 | showActiveTheme(theme, true) 77 | }) 78 | }) 79 | }) 80 | })() 81 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | labels: [bug] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for reporting issues back to webperf_core! 8 | - type: input 9 | id: url 10 | attributes: 11 | label: URL 12 | description: What URL did you run webperf_core on? If you can't share your URL please make a minimial repro to a public location (e.g. https://glitch.com/, http://jsbin.com/, etc) 13 | placeholder: https://example.com 14 | validations: 15 | required: true 16 | - type: input 17 | id: version 18 | attributes: 19 | label: Webperf_core version 20 | description: What WebPerf_core version did you run webperf_core on? 21 | validations: 22 | required: true 23 | - type: checkboxes 24 | id: environment 25 | attributes: 26 | label: What environment are you running? 27 | description: You can read more about them at [Getting started](https://github.com/Webperf-se/webperf_core/blob/main/docs/getting-started.md). 28 | options: 29 | - label: Using GitHub Actions 30 | required: false 31 | - label: Using Docker Image from Dock Hub 32 | required: false 33 | - label: Local machine 34 | required: false 35 | - label: Other, please describe your environment in How to reproduce. 36 | required: false 37 | - type: checkboxes 38 | id: duplicate 39 | attributes: 40 | label: Has anyone else reported it already? 41 | description: Please double check that this issue has not been reported already in [Issues](https://github.com/Webperf-se/webperf_core/issues). 42 | options: 43 | - label: No, there are no other issues related to this in [Issues](https://github.com/Webperf-se/webperf_core/issues). 44 | required: true 45 | - type: textarea 46 | id: ebehavior 47 | attributes: 48 | label: Expected Behavior 49 | description: A brief description of what you expected to happen 50 | validations: 51 | required: true 52 | - type: textarea 53 | id: abehavior 54 | attributes: 55 | label: Actual Behavior. 56 | description: A brief description of what actually happened 57 | validations: 58 | required: true 59 | - type: textarea 60 | id: how-to-reproduce 61 | attributes: 62 | label: How to reproduce 63 | description: Please copy and paste how you run so we can reproduce. This will be automatically formatted into code, so no need for backticks. 64 | render: shell 65 | validations: 66 | required: true 67 | - type: textarea 68 | id: logs 69 | attributes: 70 | label: Log output 71 | description: Please copy and paste the full log output from your test (please DO NOT take a screenshot of the log output). This will be automatically formatted into code, so no need for backticks. 72 | render: shell 73 | validations: 74 | required: false -------------------------------------------------------------------------------- /.github/workflows/regression-test-software.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Software Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-sources.json' 8 | - '**update-software.yml' 9 | - 'Dockerfile' 10 | - '**regression-test-404.yml' 11 | - '**regression-test-a11y-statement.yml' 12 | - '**regression-test-css.yml' 13 | - '**regression-test-docker-image.yml' 14 | - '**regression-test-email.yml' 15 | - '**regression-test-energy-efficiency.yml' 16 | - '**regression-test-google-lighthouse-based.yml' 17 | - '**regression-test-html.yml' 18 | - '**regression-test-http.yml' 19 | - '**regression-test-lint-css.yml' 20 | - '**regression-test-pa11y.yml' 21 | - '**regression-test-sitespeed-browsertime-har.yml' 22 | - '**regression-test-sitespeed.yml' 23 | - '**regression-test-standard-files.yml' 24 | - '**regression-test-tracking.yml' 25 | - '**regression-test-translations.yml' 26 | - '**regression-test-webbkoll.yml' 27 | jobs: 28 | build: 29 | runs-on: ${{ matrix.os }} 30 | strategy: 31 | matrix: 32 | os: [ubuntu-latest] #, windows-latest] 33 | version: [25] 34 | config: ['SITESPEED_USE_DOCKER=False'] 35 | steps: 36 | - name: Check out repository code 37 | uses: actions/checkout@v6 38 | - name: Setup python 39 | uses: actions/setup-python@v6 40 | with: 41 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 42 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 43 | - name: Setup dependencies using pip 44 | run: pip install -r requirements.txt 45 | - name: Setup Node.js (v4 version 20.x) 46 | uses: actions/setup-node@v6 47 | with: 48 | node-version: '20.x' 49 | - if: ${{ matrix.os == 'ubuntu-latest' }} 50 | shell: bash 51 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 52 | run: | 53 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 54 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 55 | sudo apt-get update 56 | sudo apt-get --only-upgrade install google-chrome-stable 57 | google-chrome --version 58 | - name: Setup npm packages 59 | run: npm install 60 | timeout-minutes: 30 61 | - name: Start local HTTP server 62 | run: (npm run start-server&) 63 | - if: ${{ matrix.os == 'ubuntu-latest' }} 64 | name: RUNNING TEST - LINUX 65 | run: | 66 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 67 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 68 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/404.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # FIRST AUTHOR , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-04-27 12:00\n" 8 | "PO-Revision-Date: 2025-04-27 12:00\n" 9 | "Last-Translator: Mattias \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | msgid "has-unexpected-404-response (unresolved)" 32 | msgstr "Page not found, has unexpected 404 response ({0})" 33 | 34 | msgid "has-unexpected-404-response (resolved)" 35 | msgstr "Page not found, has expected 404 response (resolved)" 36 | 37 | msgid "no-valid-title-found (unresolved)" 38 | msgstr "Page not found, no valid title found ({0})" 39 | 40 | msgid "no-valid-title-found (resolved)" 41 | msgstr "Page not found, valid title found (resolved)" 42 | 43 | msgid "no-valid-h1-found (unresolved)" 44 | msgstr "Page not found, no valid h1 header found ({0})" 45 | 46 | msgid "no-valid-h1-found (resolved)" 47 | msgstr "Page not found, valid h1 header found (resolved)" 48 | 49 | msgid "no-valid-text-found (unresolved)" 50 | msgstr "Page not found, no valid text found ({0})" 51 | 52 | msgid "no-valid-text-found (resolved)" 53 | msgstr "Page not found, valid text found (resolved)" 54 | 55 | msgid "invalid-text-found (unresolved)" 56 | msgstr "Page not found, invalid text found ({0})" 57 | 58 | msgid "invalid-text-found (resolved)" 59 | msgstr "Page not found, valid text found (resolved)" 60 | 61 | msgid "no-valid-response-status-code (unresolved)" 62 | msgstr "Page not found, no valid 404 response status code used ({0})" 63 | 64 | msgid "no-valid-response-status-code (resolved)" 65 | msgstr "Page not found, valid 404 response status code used (resolved)" 66 | 67 | msgid "no-unsupported-locale-use (unresolved)" 68 | msgstr "Page not found, unsupported locale used ({0})" 69 | 70 | msgid "no-unsupported-locale-use (resolved)" 71 | msgstr "Page not found, used supported locale (resolved)" 72 | 73 | msgid "no-valid-not-found-text-in-body (unresolved)" 74 | msgstr "Page not found, no valid body text found, may because it is too short ({0})" 75 | 76 | msgid "no-valid-not-found-text-in-body (resolved)" 77 | msgstr "Page not found, valid body text found (resolved)" 78 | 79 | msgid "no-network (unresolved)" 80 | msgstr "Page not found, no network ({0})" 81 | 82 | msgid "no-network (resolved)" 83 | msgstr "Page not found, network is usable (resolved)" 84 | -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/404.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # FIRST AUTHOR , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-04-27 12:00\n" 8 | "PO-Revision-Date: 2025-04-27 12:00\n" 9 | "Last-Translator: Mattias \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | msgid "has-unexpected-404-response (unresolved)" 32 | msgstr "Page not found, has unexpected 404 response ({0})" 33 | 34 | msgid "has-unexpected-404-response (resolved)" 35 | msgstr "Page not found, has expected 404 response (resolved)" 36 | 37 | msgid "no-valid-title-found (unresolved)" 38 | msgstr "Page not found, no valid title found ({0})" 39 | 40 | msgid "no-valid-title-found (resolved)" 41 | msgstr "Page not found, valid title found (resolved)" 42 | 43 | msgid "no-valid-h1-found (unresolved)" 44 | msgstr "Page not found, no valid h1 header found ({0})" 45 | 46 | msgid "no-valid-h1-found (resolved)" 47 | msgstr "Page not found, valid h1 header found (resolved)" 48 | 49 | msgid "no-valid-text-found (unresolved)" 50 | msgstr "Page not found, no valid text found ({0})" 51 | 52 | msgid "no-valid-text-found (resolved)" 53 | msgstr "Page not found, valid text found (resolved)" 54 | 55 | msgid "invalid-text-found (unresolved)" 56 | msgstr "Page not found, invalid text found ({0})" 57 | 58 | msgid "invalid-text-found (resolved)" 59 | msgstr "Page not found, valid text found (resolved)" 60 | 61 | msgid "no-valid-response-status-code (unresolved)" 62 | msgstr "Page not found, no valid 404 response status code used ({0})" 63 | 64 | msgid "no-valid-response-status-code (resolved)" 65 | msgstr "Page not found, valid 404 response status code used (resolved)" 66 | 67 | msgid "no-unsupported-locale-use (unresolved)" 68 | msgstr "Page not found, unsupported locale used ({0})" 69 | 70 | msgid "no-unsupported-locale-use (resolved)" 71 | msgstr "Page not found, used supported locale (resolved)" 72 | 73 | msgid "no-valid-not-found-text-in-body (unresolved)" 74 | msgstr "Page not found, no valid body text found, may because it is too short ({0})" 75 | 76 | msgid "no-valid-not-found-text-in-body (resolved)" 77 | msgstr "Page not found, valid body text found (resolved)" 78 | 79 | msgid "no-network (unresolved)" 80 | msgstr "Page not found, no network ({0})" 81 | 82 | msgid "no-network (resolved)" 83 | msgstr "Page not found, network is usable (resolved)" 84 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-energy-efficiency.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Energy Efficiency Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-google-lighthouse-based.yml' 19 | - '**regression-test-html.yml' 20 | - '**regression-test-http.yml' 21 | - '**regression-test-lint-css.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest] #, windows-latest] 36 | config: ['SITESPEED_USE_DOCKER=False'] 37 | version: [22] 38 | steps: 39 | - name: Check out repository code 40 | uses: actions/checkout@v6 41 | - name: Setup python 42 | uses: actions/setup-python@v6 43 | with: 44 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 45 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 46 | - name: Setup dependencies using pip 47 | run: pip install -r requirements.txt 48 | - name: Setup Node.js (v4 version 20.x) 49 | uses: actions/setup-node@v6 50 | with: 51 | node-version: '20.x' 52 | - if: ${{ matrix.os == 'ubuntu-latest' }} 53 | shell: bash 54 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 55 | run: | 56 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 57 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 58 | sudo apt-get update 59 | sudo apt-get --only-upgrade install google-chrome-stable 60 | google-chrome --version 61 | - name: Setup npm packages 62 | run: npm install 63 | timeout-minutes: 30 64 | - name: Start local HTTP server 65 | run: (npm run start-server&) 66 | - if: ${{ matrix.os == 'ubuntu-latest' }} 67 | name: RUNNING TEST - LINUX 68 | run: | 69 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 70 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 71 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-http.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - HTTP & Network Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-energy-efficiency.yml' 19 | - '**regression-test-google-lighthouse-based.yml' 20 | - '**regression-test-html.yml' 21 | - '**regression-test-lint-css.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest] #, windows-latest] 36 | config: ['CSP_ONLY=False', 'CSP_ONLY=True'] 37 | version: [21] 38 | steps: 39 | - name: Check out repository code 40 | uses: actions/checkout@v6 41 | - name: Setup python 42 | uses: actions/setup-python@v6 43 | with: 44 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 45 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 46 | - name: Setup dependencies using pip 47 | run: pip install -r requirements.txt 48 | - name: Setup Node.js (v4 version 20.x) 49 | uses: actions/setup-node@v6 50 | with: 51 | node-version: '20.x' 52 | - if: ${{ matrix.os == 'ubuntu-latest' }} 53 | shell: bash 54 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 55 | run: | 56 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 57 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 58 | sudo apt-get update 59 | sudo apt-get --only-upgrade install google-chrome-stable 60 | google-chrome --version 61 | - name: Setup npm packages 62 | run: npm install 63 | timeout-minutes: 30 64 | - name: Start local HTTP server 65 | run: (npm run start-server&) 66 | - if: ${{ matrix.os == 'ubuntu-latest' }} 67 | name: RUNNING TEST - LINUX 68 | run: | 69 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 70 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 71 | -------------------------------------------------------------------------------- /docs/tests/http.md: -------------------------------------------------------------------------------- 1 | # HTTP & Network 2 | [![Regression Test - HTTP & Network](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-http.yml/badge.svg)](https://github.com/Webperf-se/webperf_core/actions/workflows/regression-test-http.yml) 3 | 4 | Add small description of what this test is. 5 | 6 | 7 | ## What is being tested? 8 | 9 | ### HTTP to HTTPS redirect 10 | 11 | Checks if HTTP requests are redirected to HTTPS. 12 | A common misstake is to forget to force this redirect for root domain if www. subdomain is used. 13 | Also checks for HSTS support. 14 | 15 | ### TLS support 16 | 17 | Checks for Secure encryption support 18 | * Checks for TLS 1.3 support 19 | * Checks for TLS 1.2 support 20 | 21 | Checks for Insecure encryption support 22 | * Checks for TLS 1.1 support 23 | * Checks for TLS 1.0 support 24 | * Checks if certificate used match website domain 25 | 26 | ### HTTP protocol support 27 | 28 | * Checks for HTTP/1.1 support 29 | * Checks for HTTP/2 support 30 | * Checks for HTTP/3 support 31 | 32 | ### IPv6 and IPv4 support 33 | 34 | * Checks for IPv4 support 35 | * Checks for IPv6 support 36 | 37 | ### Content Security Policy (CSP) support 38 | 39 | * Checks for CSP support 40 | * Gives CSP recommendation if it could improve 0.75 or more in rating 41 | 42 | ## How are rating being calculated? 43 | 44 | This section has not been written yet. 45 | 46 | ## Read more 47 | 48 | Links to other sources where you can test or read more 49 | 50 | * https://www.ssllabs.com/ssltest/ 51 | * https://http3check.net/ 52 | 53 | ## How to setup? 54 | 55 | ### Prerequirements 56 | 57 | * Fork this repository 58 | 59 | ### Setup with GitHub Actions 60 | 61 | Read more on the [general page for github actions](../getting-started-github-actions.md). 62 | 63 | ### Setup Locally 64 | 65 | * Follow [general local setup steps for this repository](../getting-started-local.md) 66 | * It is highly recommended to set `cache_when_possible` to `True` and to set `cache_time_delta` to 67 | * It is highly recommended to set `cache_time_delta` to at least 12 hours (Fail to do so may result in banning of service like github). 68 | 69 | #### Using NPM package 70 | 71 | * Download and install Node.js (version 20.x) 72 | * Download and install Google Chrome browser 73 | * Download and install Mozilla Firefox browser 74 | * Install NPM packages ( `npm install --omit=dev` ) 75 | * Set `sitespeed_use_docker = False` in your `config.py` 76 | 77 | ##### Windows Specific 78 | 79 | * Allow node to connect through Windows firewall 80 | 81 | #### Using Docker image 82 | 83 | * Make sure Docker command is globally accessible on your system. 84 | * Set `sitespeed_use_docker = True` in your `config.py` 85 | 86 | ## FAQ 87 | 88 | ### How to get CSP recommendation for website 89 | Did you know you can get a CSP recommendation for all/part of your website? 90 | Do the following and webperf_core will give a CSP recommendation for more than 1 page. 91 | * Set `csp_only = True` in your `config.py` 92 | * Point webperf_core to your sitemap or your own list pages you want to test. 93 | 94 | Example, below will take first 25 items from sitemap: 95 | `python default.py -r -t 21 --input-take=25 -i https://nimbleinitiatives.com/sitemap.xml` 96 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-email.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Email (Beta) Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-energy-efficiency.yml' 18 | - '**regression-test-google-lighthouse-based.yml' 19 | - '**regression-test-html.yml' 20 | - '**regression-test-http.yml' 21 | - '**regression-test-lint-css.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest, windows-latest] 36 | version: [24] 37 | steps: 38 | - name: Check out repository code 39 | uses: actions/checkout@v6 40 | - name: Setup python 41 | uses: actions/setup-python@v6 42 | with: 43 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 44 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 45 | - name: Setup dependencies using pip 46 | run: pip install -r requirements.txt 47 | - if: ${{ matrix.os == 'ubuntu-latest' }} 48 | continue-on-error: true 49 | shell: bash 50 | env: 51 | IP2LOCATION_DOWNLOAD_URL: ${{ secrets.IP2LOCATION_DOWNLOAD_URL }} 52 | name: Download IP2LOCATION DB (Using repository secret) - Linux 53 | run: | 54 | mkdir -p data/ 55 | wget -q -O data/IP2LOCATION-LITE-DB1.IPV6.BIN $IP2LOCATION_DOWNLOAD_URL 56 | - if: ${{ matrix.os == 'windows-latest' }} 57 | continue-on-error: true 58 | shell: pwsh 59 | env: 60 | IP2LOCATION_DOWNLOAD_URL: ${{ secrets.IP2LOCATION_DOWNLOAD_URL }} 61 | name: Download IP2LOCATION DB (Using repository secret) - Windows 62 | run: Invoke-WebRequest -Uri ${env:IP2LOCATION_DOWNLOAD_URL} -OutFile data\IP2LOCATION-LITE-DB1.IPV6.BIN 63 | - if: ${{ matrix.os == 'ubuntu-latest' }} 64 | name: RUNNING TEST - LINUX 65 | run: | 66 | python default.py -t ${{ matrix.version }} -r -i defaults/sites.json -o data/testresult-${{ matrix.version }}.json 67 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 68 | - if: ${{ matrix.os == 'windows-latest' }} 69 | name: RUNNING TEST - WINDOWS 70 | run: | 71 | python default.py -t ${{ matrix.version }} -r -i defaults\sites.json -o data\testresult-${{ matrix.version }}.json 72 | python .github\workflows\verify_result.py -t ${{ matrix.version }} 73 | -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/tracking_validator.po: -------------------------------------------------------------------------------- 1 | # GOV English. 2 | # Copyright (C) 2023 WebPerf 3 | # FIRST AUTHOR , 2023. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2023-09-12 10:45+0200\n" 9 | "PO-Revision-Date: 2023-09-12 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: GOV English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 23 - Tracking and Privacy\r\n" 20 | 21 | msgid "TEXT_VISITOR_ANALYTICS_USED" 22 | msgstr " Visitor analytics used:\r\n" 23 | 24 | msgid "TEXT_TRACKING" 25 | msgstr "GOV-IGNORE" 26 | 27 | msgid "TEXT_TRACKING_FOUND_ALLOWED" 28 | msgstr "GOV-IGNORE" 29 | 30 | msgid "TEXT_TRACKING_FOUND" 31 | msgstr "GOV-IGNORE" 32 | 33 | msgid "TEXT_TRACKING_MAX_SHOWED" 34 | msgstr "GOV-IGNORE" 35 | 36 | msgid "TEXT_TRACKING_TOTAL_FOUND" 37 | msgstr "GOV-IGNORE" 38 | 39 | msgid "TEXT_TRACKING_REFERENCE" 40 | msgstr "{0} - Has references to {1}" 41 | 42 | msgid "TEXT_FINGERPRINTING" 43 | msgstr "GOV-IGNORE" 44 | 45 | msgid "TEXT_FINGERPRINTING_FOUND" 46 | msgstr "GOV-IGNORE" 47 | 48 | msgid "TEXT_FINGERPRINTING_MAX_SHOWED" 49 | msgstr "GOV-IGNORE" 50 | 51 | msgid "TEXT_FINGERPRINTING_TOTAL_FOUND" 52 | msgstr "GOV-IGNORE" 53 | 54 | msgid "TEXT_ADS" 55 | msgstr "GOV-IGNORE" 56 | 57 | msgid "TEXT_ADS_FOUND_ALLOWED" 58 | msgstr "GOV-IGNORE" 59 | 60 | msgid "TEXT_ADS_FOUND" 61 | msgstr "GOV-IGNORE" 62 | 63 | msgid "TEXT_ADS_MAX_SHOWED" 64 | msgstr "GOV-IGNORE" 65 | 66 | msgid "TEXT_ADS_TOTAL_FOUND" 67 | msgstr "GOV-IGNORE" 68 | 69 | msgid "TEXT_COOKIES_HAS_THIRDPARTY" 70 | msgstr "GOV-IGNORE" 71 | 72 | msgid "TEXT_COOKIE_HAS_OVER_1YEAR" 73 | msgstr "GOV-IGNORE" 74 | 75 | msgid "TEXT_COOKIE_HAS_OVER_9MONTH" 76 | msgstr "GOV-IGNORE" 77 | 78 | msgid "TEXT_COOKIE_HAS_OVER_6MONTH" 79 | msgstr "GOV-IGNORE" 80 | 81 | msgid "TEXT_COOKIE_HAS_OVER_3MONTH" 82 | msgstr "GOV-IGNORE" 83 | 84 | msgid "TEXT_COOKIE_NOT_SECURE" 85 | msgstr "GOV-IGNORE" 86 | 87 | msgid "TEXT_COOKIE_HAS_ANALYTICS_COOKIE" 88 | msgstr " - Using analytic cookie(s) without consent: {0}" 89 | 90 | msgid "TEXT_COOKIE_LESS_THEN_3MONTH" 91 | msgstr "GOV-IGNORE" 92 | 93 | msgid "TEXT_COOKIE_SECURE" 94 | msgstr "GOV-IGNORE" 95 | 96 | msgid "TEXT_COOKIE_NO_ANALYTICS_COOKIE" 97 | msgstr "GOV-IGNORE" 98 | 99 | msgid "TEXT_COOKIE" 100 | msgstr "- Cookies" 101 | 102 | msgid "TEXT_GDPR_COUNTRIES" 103 | msgstr "GOV-IGNORE" 104 | 105 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES" 106 | msgstr " - Countries lacking adequate level of data protection: {0}\r\n" 107 | 108 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES_REQUESTS" 109 | msgstr " - {0}, {1} request\r\n" 110 | 111 | msgid "TEXT_GDPR_PAGE_IN_SWEDEN" 112 | msgstr "GOV-IGNORE" 113 | 114 | msgid "TEXT_GDPR_True" 115 | msgstr "Yes" 116 | 117 | msgid "TEXT_GDPR_False" 118 | msgstr "No" 119 | 120 | msgid "TEXT_GDPR_HAS_POINTS" 121 | msgstr "- GDPR" 122 | 123 | msgid "TEXT_GDPR_NO_POINTS" 124 | msgstr "- GDPR" 125 | 126 | msgid "TEXT_GDPR_MAX_SHOWED" 127 | msgstr " - More than {0} requests found, filtering out the rest\r\n" 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The project goal is to help identify and improve the web over time, one improvment at a time. 2 | It tries to do this by giving you a weighted list of improvment you can (and probably should do) to your website. 3 | 4 | 5 | # Features 6 | 7 | * Run same test(s) used by [WebPerf.se](https://webperf.se/) without [WebPerf Premium](https://webperf.se/erbjudande/) 8 | * Verify that you have done the basics for your website in: 9 | * Security 10 | * User Integrity 11 | * Performance 12 | * Accessibility 13 | * Accessibility statement 14 | * SEO 15 | * Code Quality 16 | * Networking 17 | * World Wide Web Standards 18 | * Email Standards 19 | * Software being used 20 | * Validate new release before going into production 21 | * Test other/more pages then [WebPerf.se](https://webperf.se/) do 22 | 23 | 24 | # Getting Started 25 | 26 | Easiest setup for testing public websites are by using GitHub Actions 27 | but you can run this project in many ways and what you choose depends on your needs. 28 | 29 | [Read more about how to get started](./docs/getting-started.md) 30 | 31 | - [Using GitHub Actions](./docs/getting-started-github-actions.md) 32 | - [Using Local Machine](./docs/getting-started-local.md) 33 | - [Using Docker](./docs/getting-started-docker.md) 34 | 35 | 36 | # Tests 37 | 38 | Webperf Core consists of many different tests. [Read general information about our tests](./docs/tests/README.md) or go directly to a specific test below. 39 | 40 | * [Accessibility (Pa11y)](./docs/tests/pa11y.md) 41 | * [Website performance (SiteSpeed)](./docs/tests/sitespeed.md) 42 | * [Validate 404 page (by default checks for Swedish text, though)](./docs/tests/page-not-found.md) 43 | * [Security, data-protecting & Integrity (Webbkoll)](./docs/tests/webbkoll.md) 44 | * [Energy Efficiency](./docs/tests/energy-efficiency.md) 45 | * [Standard files](./docs/tests/standard.md) 46 | * [HTTP and Network](./docs/tests/http.md) 47 | * [Tracking & Integrity](./docs/tests/tracking.md) 48 | * [Email (Beta)](./docs/tests/email.md) 49 | * [Software](./docs/tests/software.md) 50 | * [Accessibility Statement (Alpha)](./docs/tests/a11y-statement.md) 51 | * [CSS (StyleLint)](./docs/tests/css-linting.md) 52 | * [HTML (html-validate)](./docs/tests/html-validate.md) 53 | * [Javascript (ESlint)](./docs/tests/js-linting.md) 54 | * [Accessibility, Best practice, Performance, SEO (Google Lighthouse)](./docs/tests/google-lighthouse.md) 55 | 56 | 57 | # Contribute 58 | 59 | Do you want to contribute? 60 | 61 | [Read more about how to contribute](./docs/CONTRIBUTING.md) 62 | 63 | 64 | # Need help? 65 | 66 | It is often worthwhile to google/dockduckgo the error messages you get. 67 | If you give up the search then you can always [check if someone on our Slack channel](https://webperf.se/articles/webperf-pa-slack/) have time to help you, 68 | but don’t forget to paste your error message directly in the first post. 69 | Or, if you think your error are common for more people than yourself, [post an issue here at Github](https://github.com/Webperf-se/webperf_core/issues/new/choose). 70 | 71 | 72 | # Third party 73 | 74 | Think this is cool and want to see more? 75 | Why not look at third parties. 76 | 77 | [Read more about third party](./docs/thirdparty.md) 78 | 79 | 80 | 81 | # Credits 82 | 83 | We could not do this without all help from contributors and other projects we use. 84 | 85 | [Read more about them under credits](./CREDITS.md) -------------------------------------------------------------------------------- /.github/workflows/regression-test-404.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - 404 (Page not Found) Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-a11y-statement.yml' 14 | - '**regression-test-css.yml' 15 | - '**regression-test-docker-image.yml' 16 | - '**regression-test-email.yml' 17 | - '**regression-test-energy-efficiency.yml' 18 | - '**regression-test-google-lighthouse-based.yml' 19 | - '**regression-test-html.yml' 20 | - '**regression-test-http.yml' 21 | - '**regression-test-lint-css.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | jobs: 29 | build: 30 | runs-on: ${{ matrix.os }} 31 | strategy: 32 | matrix: 33 | os: [ubuntu-latest] #, windows-latest] 34 | config: ['SITESPEED_USE_DOCKER=False'] 35 | version: [2] 36 | steps: 37 | - name: Check out repository code 38 | uses: actions/checkout@v6 39 | - name: Setup python 40 | uses: actions/setup-python@v6 41 | with: 42 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 43 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 44 | - name: Setup dependencies using pip 45 | run: pip install -r requirements.txt 46 | - name: Setup Node.js (v4 version 20.x) 47 | uses: actions/setup-node@v6 48 | with: 49 | node-version: '20.x' 50 | - if: ${{ matrix.os == 'ubuntu-latest' }} 51 | shell: bash 52 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 53 | run: | 54 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 55 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 56 | sudo apt-get update 57 | sudo apt-get --only-upgrade install google-chrome-stable 58 | google-chrome --version 59 | - name: Setup npm packages 60 | run: npm install 61 | timeout-minutes: 30 62 | - name: Start local HTTP server 63 | run: (npm run start-server&) 64 | - if: ${{ matrix.os == 'ubuntu-latest' }} 65 | name: RUNNING TEST - LINUX 66 | run: | 67 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 68 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 69 | # - if: ${{ matrix.os == 'windows-latest' }} 70 | # name: RUNNING TEST - WINDOWS 71 | # run: | 72 | # python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data\testresult-${{ matrix.version }}.json --setting tests.sitespeed.browser=edge --setting ${{ matrix.config }} 73 | # python .github\workflows\verify_result.py -t ${{ matrix.version }} 74 | -------------------------------------------------------------------------------- /helpers/release_helper.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import getopt 4 | from pathlib import Path 5 | import sys 6 | from datetime import datetime 7 | import packaging.version 8 | 9 | def get_new_version(last_version): 10 | """ 11 | Generates a new version number based on the current date and the last version number. 12 | 13 | Args: 14 | last_version (packaging.version.Version): The last version number. 15 | 16 | Returns: 17 | packaging.version.Version: The new version number. 18 | """ 19 | print('last_version', last_version) 20 | new_version = packaging.version.Version(f"{datetime.now().year}.{datetime.now().month}.0") 21 | if new_version <= last_version: 22 | if last_version.major != new_version.major: 23 | print('major new_version', new_version) 24 | return new_version 25 | if last_version.minor != new_version.minor: 26 | print('minor new_version', new_version) 27 | return new_version 28 | 29 | new_version = packaging.version.Version( 30 | f"{new_version.major}.{new_version.minor}.{(last_version.micro + 1)}") 31 | 32 | print('micro new_version', new_version) 33 | else: 34 | print('new_version', new_version) 35 | return new_version 36 | 37 | def set_new_release_version_in_env(argv): 38 | last_version = packaging.version.Version(argv) 39 | new_version= get_new_version(last_version) 40 | 41 | current_version = None 42 | base_directory = Path(os.path.dirname( 43 | os.path.realpath(__file__)) + os.path.sep).parent 44 | with open( 45 | f'{base_directory}{os.path.sep}package.json', 46 | encoding='utf-8' 47 | ) as json_input_file: 48 | package_info = json.load(json_input_file) 49 | if 'version' in package_info: 50 | current_version = packaging.version.Version(package_info['version']) 51 | 52 | if current_version != new_version: 53 | print(( 54 | 'last and current version(s) do not match' 55 | f'new version={new_version}', 56 | f'package.json version={current_version}' 57 | )) 58 | return 59 | 60 | env_file = os.getenv('GITHUB_ENV') 61 | with open(env_file, "a", encoding="utf-8") as myfile: 62 | myfile.write(f"NEW_VERSION={new_version}") 63 | 64 | 65 | def update_release_version(argv): 66 | last_version = packaging.version.Version(argv) 67 | package_info = None 68 | 69 | base_directory = Path(os.path.dirname( 70 | os.path.realpath(__file__)) + os.path.sep).parent 71 | with open( 72 | f'{base_directory}{os.path.sep}package.json', 73 | encoding='utf-8' 74 | ) as json_input_file: 75 | package_info = json.load(json_input_file) 76 | package_version = packaging.version.Version(package_info['version']) 77 | last_version = max(last_version, package_version) 78 | new_version= get_new_version(last_version) 79 | package_info['version'] = f'{new_version}' 80 | 81 | with open( 82 | f'{base_directory}{os.path.sep}package.json', 83 | 'w', 84 | encoding='utf-8' 85 | ) as json_output_file: 86 | json.dump(package_info, json_output_file, indent=2) 87 | 88 | env_file = os.getenv('GITHUB_ENV') 89 | with open(env_file, "a", encoding="utf-8") as myfile: 90 | myfile.write(f"NEW_VERSION={new_version}") 91 | 92 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-lint-css.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - CSS Linting Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-energy-efficiency.yml' 19 | - '**regression-test-google-lighthouse-based.yml' 20 | - '**regression-test-html.yml' 21 | - '**regression-test-http.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest] #, windows-latest] 36 | config: ['SITESPEED_USE_DOCKER=False'] 37 | version: [27] 38 | steps: 39 | - name: Check out repository code 40 | uses: actions/checkout@v6 41 | - name: Setup python 42 | uses: actions/setup-python@v6 43 | with: 44 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 45 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 46 | - name: Setup dependencies using pip 47 | run: pip install -r requirements.txt 48 | - name: Setup Node.js (v4 version 20.x) 49 | uses: actions/setup-node@v6 50 | with: 51 | node-version: '20.x' 52 | - if: ${{ matrix.os == 'ubuntu-latest' }} 53 | shell: bash 54 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 55 | run: | 56 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 57 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 58 | sudo apt-get update 59 | sudo apt-get --only-upgrade install google-chrome-stable 60 | google-chrome --version 61 | - name: Setup npm packages 62 | run: npm install 63 | timeout-minutes: 30 64 | - name: Start local HTTP server 65 | run: (npm run start-server&) 66 | - if: ${{ matrix.os == 'ubuntu-latest' }} 67 | name: RUNNING TEST - LINUX 68 | run: | 69 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 70 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 71 | # - if: ${{ matrix.os == 'windows-latest' }} 72 | # name: RUNNING TEST - WINDOWS 73 | # run: | 74 | # python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data\testresult-${{ matrix.version }}.json --setting tests.sitespeed.browser=edge --setting ${{ matrix.config }} 75 | # python .github\workflows\verify_result.py -t ${{ matrix.version }} 76 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-a11y-statement.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Accessibility Statement Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-css.yml' 15 | - '**regression-test-docker-image.yml' 16 | - '**regression-test-email.yml' 17 | - '**regression-test-energy-efficiency.yml' 18 | - '**regression-test-google-lighthouse-based.yml' 19 | - '**regression-test-html.yml' 20 | - '**regression-test-http.yml' 21 | - '**regression-test-lint-css.yml' 22 | - '**regression-test-pa11y.yml' 23 | - '**regression-test-sitespeed-browsertime-har.yml' 24 | - '**regression-test-sitespeed.yml' 25 | - '**regression-test-software.yml' 26 | - '**regression-test-standard-files.yml' 27 | - '**regression-test-tracking.yml' 28 | - '**regression-test-translations.yml' 29 | - '**regression-test-webbkoll.yml' 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ubuntu-latest] #, windows-latest] 36 | config: ['SITESPEED_USE_DOCKER=False'] 37 | version: [26] 38 | steps: 39 | - name: Check out repository code 40 | uses: actions/checkout@v6 41 | - name: Setup python 42 | uses: actions/setup-python@v6 43 | with: 44 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 45 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 46 | - name: Setup dependencies using pip 47 | run: pip install -r requirements.txt 48 | - name: Setup Node.js (v4 version 20.x) 49 | uses: actions/setup-node@v6 50 | with: 51 | node-version: '20.x' 52 | - if: ${{ matrix.os == 'ubuntu-latest' }} 53 | shell: bash 54 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 55 | run: | 56 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 57 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 58 | sudo apt-get update 59 | sudo apt-get --only-upgrade install google-chrome-stable 60 | google-chrome --version 61 | - name: Setup npm packages 62 | run: npm install 63 | timeout-minutes: 30 64 | - name: Start local HTTP server 65 | run: (npm run start-server&) 66 | - if: ${{ matrix.os == 'ubuntu-latest' }} 67 | name: RUNNING TEST - LINUX 68 | run: | 69 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 70 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 71 | # - if: ${{ matrix.os == 'windows-latest' }} 72 | # name: RUNNING TEST - WINDOWS 73 | # run: | 74 | # python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data\testresult-${{ matrix.version }}.json --setting tests.sitespeed.browser=edge --setting ${{ matrix.config }} 75 | # python .github\workflows\verify_result.py -t ${{ matrix.version }} 76 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-lint-html.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - HTML Linting Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-energy-efficiency.yml' 19 | - '**regression-test-google-lighthouse-based.yml' 20 | - '**regression-test-html.yml' 21 | - '**regression-test-http.yml' 22 | - '**regression-test-lint-css.yml' 23 | - '**regression-test-pa11y.yml' 24 | - '**regression-test-sitespeed-browsertime-har.yml' 25 | - '**regression-test-sitespeed.yml' 26 | - '**regression-test-software.yml' 27 | - '**regression-test-standard-files.yml' 28 | - '**regression-test-tracking.yml' 29 | - '**regression-test-translations.yml' 30 | - '**regression-test-webbkoll.yml' 31 | jobs: 32 | build: 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | matrix: 36 | os: [ubuntu-latest] #, windows-latest] 37 | config: ['SITESPEED_USE_DOCKER=False'] 38 | version: [28] 39 | steps: 40 | - name: Check out repository code 41 | uses: actions/checkout@v6 42 | - name: Setup python 43 | uses: actions/setup-python@v6 44 | with: 45 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 46 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 47 | - name: Setup dependencies using pip 48 | run: pip install -r requirements.txt 49 | - name: Setup Node.js (v4 version 20.x) 50 | uses: actions/setup-node@v6 51 | with: 52 | node-version: '20.x' 53 | - if: ${{ matrix.os == 'ubuntu-latest' }} 54 | shell: bash 55 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 56 | run: | 57 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 58 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 59 | sudo apt-get update 60 | sudo apt-get --only-upgrade install google-chrome-stable 61 | google-chrome --version 62 | - name: Setup npm packages 63 | run: npm install 64 | timeout-minutes: 30 65 | - name: Start local HTTP server 66 | run: (npm run start-server&) 67 | - if: ${{ matrix.os == 'ubuntu-latest' }} 68 | name: RUNNING TEST - LINUX 69 | run: | 70 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 71 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 72 | # - if: ${{ matrix.os == 'windows-latest' }} 73 | # name: RUNNING TEST - WINDOWS 74 | # run: | 75 | # python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data\testresult-${{ matrix.version }}.json --setting tests.sitespeed.browser=edge --setting ${{ matrix.config }} 76 | # python .github\workflows\verify_result.py -t ${{ matrix.version }} 77 | -------------------------------------------------------------------------------- /docs/getting-started-github-actions.md: -------------------------------------------------------------------------------- 1 | # Getting started with Github Actions 2 | 3 | The easiest way to set up webperf-core is by using GitHub Actions for public facing websites. 4 | 5 | If you want to test or verify private websites, you should consider one of the other methods. 6 | 7 | ## How to set up 8 | - [Fork webperf-core repository](https://github.com/Webperf-se/webperf_core/fork?fragment=1) 9 | - You may need to activate the workflow "Manual - Run test against url" in your new repository. 10 | - Remember to update your repository from time to time to receive updates. 11 | 12 | ### Manually trigger a new test 13 | 14 | 1. **Navigate to your GitHub repository**: Go to the main page of your repository (at https://github.com) where your GitHub Action is located. 15 | 16 | 2. **Go to the 'Actions' tab**: On the top of your repository page, you'll see several tabs like 'Code', 'Issues', 'Pull requests', etc. Click on the 'Actions' tab. 17 | 18 | 3. **Select the workflow**: You'll see a list of workflows on the left side of the screen. Click on the one you want to run manually. 19 | - Select "Manual - Run test against url" to run a specific test on your URL. 20 | 21 | 4. **Run workflow**: After selecting the workflow, you'll see a 'Run workflow' dropdown on the right side of the workflow. Click on it. 22 | 23 | 5. **Choose the branch**: A dropdown menu will appear where you can select the branch where your changes are. 24 | Usually, you'd choose the 'main' branch. 25 | - "Webpage url to test": Enter your URL here. 26 | - "Test to run, comma separated list of numbers": Choose which test or tests to run, separated by commas. [Here you can find a list of the testnumbers explained](tests/README.md). 27 | - "Setting general.review.details": If set to True, it will show a more detailed review when available. This is useful when it's time to actually fix some of the issues and not just track progress. 28 | - "Setting general.review.data": If set to True, it will include the test data as JSON, which is tech oriented and can be a useful tool for your IT department to help resolve any issues. 29 | - "Setting general.review.improve-only": If set to True, it will only display areas that can be improved. 30 | 31 | 6. **Trigger the workflow**: After selecting your branch, just click the 'Run workflow' button and you're good to go! Once the workflow is triggered, it may take a few minutes to complete. Some tests run quickly, while others take longer. Running multiple tests simultaneously can significantly increase the total runtime. 32 | 33 | And that's it! Your workflow should now be running successfully. You can later check the progress or result of the run by: 34 | 1. Clicking on it in the list on the main page under the 'Actions' tab. 35 | 2. Click the "Build"-button. 36 | 3. Expand the "Test [your test number] for [your URL]" section. 37 | 4. Your test results will be displayed there. 38 | 39 | Remember, it's all about trial and error, so don't worry if you don't get it right the first time. 40 | 41 | ## Update your fork 42 | You should update your fork regularly to ensure you have the latest changes. 43 | 1. Go to the main page of your webperf-core fork (https://github.com/[your username]/webperf_core) 44 | 2. Find the button "Sync fork" and press it. 45 | 3. When it opens it will tell you if your fork is out of date. 46 | 4. Press "Update branch". 47 | 5. Now your fork is updated. 48 | 6. Extra tip: If you don't plan to contribute to the code, go to 'Actions' and disable all workflows except "Manual - Run test against url". This will make the updates faster and easier. 49 | -------------------------------------------------------------------------------- /docs/translation.md: -------------------------------------------------------------------------------- 1 | # Translation 2 | 3 | The following is copied from Slack community threads,translated from Swedish. 4 | 5 | ## Create Your Own Copy of Our Repository 6 | 7 | - Sign up for a free account at [GitHub](https://github.com). 8 | - Sign in with your new account. 9 | - Go to [Webperf Core Repository](https://github.com/Webperf-se/webperf_core/). 10 | - Press the "Fork" button. 11 | 12 | You now have your own copy where you can make all your changes. 13 | 14 | When you are done with all the changes, 15 | go to the "Pull requests" tab and press the button to create a new pull request. 16 | Once you do that, we will receive a notification and review your suggested changes. 17 | 18 | ## General Information About Translation 19 | 20 | All help with writing texts is greatly appreciated! 😃 21 | 22 | No coding knowledge is required; everything can be done directly in the browser on GitHub. 🙂 23 | 24 | The following files need to be updated: 25 | - [404 Test (English)](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2F404.po) 26 | - [A11y Statement Test (English)](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2Fa11y-statement.po) 27 | - [CSS Test](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2Fcss.po) 28 | - [HTML Test (English)](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2Fhtml.po) 29 | - [Javascript Test](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2Fjavascript.po) 30 | - [Lighthouse Test](https://github.com/Webperf-se/webperf_core/blob/main/locales%2Fen%2FLC_MESSAGES%2Flighthouse.po) 31 | 32 | In this thread, I will explain for each text how you can figure out what text should be there. 33 | 34 | ### General Notes for `.po` Files 35 | The texts in each of the files above work as follows: 36 | There is a text for completed rules (resolved) and a text for rules that still need to be addressed (unresolved). 37 | The text between the two `"` on each line that starts with `msgstr` needs to be more understandable. 38 | 39 | On lines where the text in `msgstr` starts with the same text as `msgid`, it is completely untranslated. 40 | 41 | The first part of `msgid` before the space (in the second image circled in green) is the rule ID. 42 | This is useful for getting more information about what text makes sense to write. 43 | More on this in the text specific to each file. 44 | 45 | ### General Notes for All Tests 46 | All tests have language support. 47 | We start with English, but later they also need to be translated into Swedish. 48 | The difference between the English and Swedish files is that they are in different directories: 49 | `en` for English and `sv` for Swedish. 50 | 51 | ## Test-Specific Notes About Translation 52 | 53 | ### CSS Test 54 | For the CSS Test, you can find out more about the rule by visiting the Stylelint website at the following address: 55 | `https://stylelint.io/user-guide/rules/{rule-id}` 56 | 57 | Replace `{rule-id}` with the rule ID you want to get more information about. 58 | 59 | For example: 60 | For `unit-no-unknown`, the address is: 61 | [https://stylelint.io/user-guide/rules/unit-no-unknown](https://stylelint.io/user-guide/rules/unit-no-unknown). 62 | 63 | ### Javascript Test 64 | For the Javascript Test, the address is: 65 | `https://eslint.org/docs/latest/rules/{rule-id}` 66 | 67 | ### HTML Test 68 | For the HTML Test, the address is: 69 | [https://html-validate.org/rules/{rule-id}.html](https://html-validate.org/rules/{rule-id}.html) 70 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-lint-js.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - JS Linting Test" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-energy-efficiency.yml' 19 | - '**regression-test-google-lighthouse-based.yml' 20 | - '**regression-test-html.yml' 21 | - '**regression-test-http.yml' 22 | - '**regression-test-lint-css.yml' 23 | - '**regression-test-lint-html.yml' 24 | - '**regression-test-pa11y.yml' 25 | - '**regression-test-sitespeed-browsertime-har.yml' 26 | - '**regression-test-sitespeed.yml' 27 | - '**regression-test-software.yml' 28 | - '**regression-test-standard-files.yml' 29 | - '**regression-test-tracking.yml' 30 | - '**regression-test-translations.yml' 31 | - '**regression-test-webbkoll.yml' 32 | jobs: 33 | build: 34 | runs-on: ${{ matrix.os }} 35 | strategy: 36 | matrix: 37 | os: [ubuntu-latest] #, windows-latest] 38 | config: ['SITESPEED_USE_DOCKER=False'] 39 | version: [29] 40 | steps: 41 | - name: Check out repository code 42 | uses: actions/checkout@v6 43 | - name: Setup python 44 | uses: actions/setup-python@v6 45 | with: 46 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 47 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 48 | - name: Setup dependencies using pip 49 | run: pip install -r requirements.txt 50 | - name: Setup Node.js (v4 version 20.x) 51 | uses: actions/setup-node@v6 52 | with: 53 | node-version: '20.x' 54 | - if: ${{ matrix.os == 'ubuntu-latest' }} 55 | shell: bash 56 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 57 | run: | 58 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 59 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 60 | sudo apt-get update 61 | sudo apt-get --only-upgrade install google-chrome-stable 62 | google-chrome --version 63 | - name: Setup npm packages 64 | run: npm install 65 | timeout-minutes: 30 66 | - name: Start local HTTP server 67 | run: (npm run start-server&) 68 | - if: ${{ matrix.os == 'ubuntu-latest' }} 69 | name: RUNNING TEST - LINUX 70 | run: | 71 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting ${{ matrix.config }} --setting tests.sitespeed.xvfb=true 72 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 73 | # - if: ${{ matrix.os == 'windows-latest' }} 74 | # name: RUNNING TEST - WINDOWS 75 | # run: | 76 | # python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data\testresult-${{ matrix.version }}.json --setting tests.sitespeed.browser=edge --setting ${{ matrix.config }} 77 | # python .github\workflows\verify_result.py -t ${{ matrix.version }} 78 | -------------------------------------------------------------------------------- /engines/sitespeed_result.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | from pathlib import Path 4 | from urllib.parse import urlparse 5 | import re 6 | from engines.utils import use_item 7 | from helpers.setting_helper import get_config 8 | 9 | def get_url_from_file_content(input_filename): 10 | """ 11 | Extracts the URL from the content of a HAR file. 12 | 13 | The function opens the file and reads the first 1024 bytes. 14 | It then uses a regular expression to find the URL in the read data. 15 | If the file does not exist, it prints an error message and returns None. 16 | 17 | Parameters: 18 | input_filename (str): The path of the HAR file from which to extract the URL. 19 | 20 | Returns: 21 | str: The extracted URL. Returns None if the file does not exist or no URL is found. 22 | 23 | """ 24 | try: 25 | # No need to read all content, just read the first 1024 bytes as our url will be there 26 | # we are doing this for performance 27 | with open(input_filename, 'r', encoding='utf-8') as file: 28 | data = file.read(1024) 29 | regex = r"\"[_]{0,1}url\":[ ]{0,1}\"(?P[^\"]+)\"" 30 | matches = re.finditer(regex, data, re.MULTILINE) 31 | for _, match in enumerate(matches, start=1): 32 | return match.group('url') 33 | except OSError: 34 | print(f'Error. No such file or directory: {input_filename}') 35 | return None 36 | 37 | return None 38 | 39 | def read_sites_from_directory(directory, hostname_or_argument, input_skip, input_take): 40 | sites = [] 41 | 42 | hostname = hostname_or_argument 43 | if hostname_or_argument.endswith('.result'): 44 | tmp_url = hostname_or_argument[:hostname_or_argument.rfind('.result')] 45 | hostname = urlparse(tmp_url).hostname 46 | 47 | base_directory = Path(os.path.dirname( 48 | os.path.realpath(__file__)) + os.path.sep).parent 49 | 50 | # host_path = os.path.join(base_directory, directory, hostname) + os.path.sep 51 | host_path = directory 52 | 53 | if not os.path.exists(host_path): 54 | return sites 55 | 56 | dirs = os.listdir(host_path) 57 | 58 | urls = {} 59 | 60 | for file_name in dirs: 61 | if input_take != -1 and len(urls) >= input_take: 62 | break 63 | 64 | if not file_name.endswith('.har'): 65 | continue 66 | 67 | full_path = os.path.join( 68 | host_path, file_name) 69 | 70 | url = get_url_from_file_content(full_path) 71 | urls[url] = full_path 72 | 73 | current_index = 0 74 | for url, har_path in urls.items(): 75 | if use_item(current_index, input_skip, input_take): 76 | sites.append([har_path, url]) 77 | current_index += 1 78 | 79 | return sites 80 | 81 | def read_sites(hostname_or_argument, input_skip, input_take): 82 | """ 83 | Reads the sites from the cache directory based on the hostname or 84 | the argument that ends with '.result'. 85 | 86 | Parameters: 87 | hostname_or_argument (str): The hostname or the argument that ends with '.result'. 88 | input_skip (int): The number of items to skip from the start. 89 | input_take (int): The number of items to take after skipping. If -1, takes all items. 90 | 91 | Returns: 92 | list: A list of sites where each site is represented as a 93 | list containing the path to the HAR file and the URL. 94 | """ 95 | cache_folder = get_config('general.cache.folder') 96 | return read_sites_from_directory(cache_folder, hostname_or_argument, input_skip, input_take) 97 | -------------------------------------------------------------------------------- /.github/workflows/regression-test-google-lighthouse-based.yml: -------------------------------------------------------------------------------- 1 | name: "Regression Test - Google Lighthouse Based Test(s)" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - '**software-full.json' 8 | - '**software-sources.json' 9 | - '**update-software.yml' 10 | - '**update_software_helper.py' 11 | - '**software-rules.json' 12 | - 'Dockerfile' 13 | - '**regression-test-404.yml' 14 | - '**regression-test-a11y-statement.yml' 15 | - '**regression-test-css.yml' 16 | - '**regression-test-docker-image.yml' 17 | - '**regression-test-email.yml' 18 | - '**regression-test-html.yml' 19 | - '**regression-test-http.yml' 20 | - '**regression-test-lint-css.yml' 21 | - '**regression-test-pa11y.yml' 22 | - '**regression-test-sitespeed-browsertime-har.yml' 23 | - '**regression-test-sitespeed.yml' 24 | - '**regression-test-software.yml' 25 | - '**regression-test-standard-files.yml' 26 | - '**regression-test-tracking.yml' 27 | - '**regression-test-translations.yml' 28 | - '**regression-test-webbkoll.yml' 29 | jobs: 30 | build: 31 | runs-on: ${{ matrix.os }} 32 | strategy: 33 | matrix: 34 | os: [ubuntu-latest] 35 | version: [30] 36 | steps: 37 | - name: Check out repository code 38 | uses: actions/checkout@v6 39 | - name: Setup python 40 | uses: actions/setup-python@v6 41 | with: 42 | python-version: '3.13' # Version range or exact version of a Python version to use, using SemVer's version range syntax 43 | architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified 44 | - name: Setup dependencies using pip 45 | run: pip install -r requirements.txt 46 | - name: Setup Node.js (v4 version 20.x) 47 | uses: actions/setup-node@v6 48 | with: 49 | node-version: '20.x' 50 | - if: ${{ matrix.os == 'ubuntu-latest' }} 51 | shell: bash 52 | name: Setup Google Chrome browser (ONLY used for Sitespeed) 53 | run: | 54 | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - 55 | sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 56 | sudo apt-get update 57 | sudo apt-get --only-upgrade install google-chrome-stable 58 | google-chrome --version 59 | - name: Setup npm packages 60 | run: npm install 61 | timeout-minutes: 30 62 | - name: Start local HTTP server 63 | run: (npm run start-server&) 64 | - if: ${{ matrix.os == 'ubuntu-latest' }} 65 | name: RUNNING TEST - LINUX 66 | run: | 67 | python default.py -t ${{ matrix.version }} -r -u http://localhost:3000/ -o data/testresult-${{ matrix.version }}.json --setting tests.sitespeed.xvfb=true 68 | python .github/workflows/verify_result.py -t ${{ matrix.version }} 69 | - if: ${{ matrix.os == 'ubuntu-latest' && matrix.version == 1 }} 70 | name: RUNNING TEST - LINUX 71 | run: | 72 | node node_modules/sitespeed.io/bin/sitespeed.js -b chrome --xvfb --plugins.remove screenshot --plugins.remove html --plugins.remove metrics --browsertime.screenshot false --screenshot false --screenshotLCP false --browsertime.screenshotLCP false --chrome.cdp.performance false --browsertime.chrome.timeline false --videoParams.createFilmstrip false --visualMetrics false --visualMetricsPerceptual false --visualMetricsContentful false --browsertime.headless true --browsertime.chrome.includeResponseBodies all --utc true --browsertime.chrome.args ignore-certificate-errors -n 1 --plugins.add ../../../@sitespeed.io/plugin-lighthouse/index.js --plugins.add ../../../plugin-webperf-core/lib/index.js http://localhost:3000/?webperf-core-test-${{ matrix.version }} 73 | -------------------------------------------------------------------------------- /chrome-custom.cjs: -------------------------------------------------------------------------------- 1 | /* 2 | * USED FOR SITESPEED TEST (TO test real no javascript gain)!!! 3 | * Right now sitespeed doesn't support blocking specific content type so this is our workaround 4 | */ 5 | module.exports = async function (context, commands) { 6 | cdpClient = commands.cdp.engineDelegate.getCDPClient() 7 | await cdpClient.send('Fetch.enable', { 8 | patterns: [ 9 | { 10 | urlPattern: '*', 11 | resourceType: 'Document', 12 | requestStage: 'Response' 13 | } 14 | ] 15 | }); 16 | 17 | cdpClient.on('Fetch.requestPaused', async function (reqEvent) { 18 | if (reqEvent == undefined) { 19 | return 20 | } 21 | const requestId = reqEvent.requestId; 22 | let responseHeaders = reqEvent.responseHeaders || []; 23 | 24 | if ('webperf' in context.options) { 25 | for (var i = 1; i <= 9; i++) { 26 | const key = 'header0X'.replace('X', i); 27 | if (!(key in context.options.webperf)) { 28 | // context.log.warning("NO " + key + " OPTIONS"); 29 | continue; 30 | } 31 | pair = context.options.webperf[key].replaceAll('%20', ' ').split('='); 32 | const newServerHeader = { name: pair[0].replaceAll('%3D', '='), value: pair[1].replaceAll('%3D', '=') }; 33 | const foundHeaderIndex = responseHeaders.findIndex( 34 | h => h.name === pair[0].replaceAll('%3D', '=') 35 | ); 36 | if (foundHeaderIndex) { 37 | context.log.warning("ADDED HTTP HEADER: " + pair[0].replaceAll('%3D', '=') + " = " + pair[1].replaceAll('%3D', '=')); 38 | responseHeaders[foundHeaderIndex] = newServerHeader; 39 | } else { 40 | context.log.warning("OVERRITE HTTP HEADER: " + pair[0].replaceAll('%3D', '=') + " = " + pair[1].replaceAll('%3D', '=')); 41 | responseHeaders.push(newServerHeader); 42 | } 43 | } 44 | } else { 45 | context.log.warning("NO PLUGIN OPTIONS"); 46 | } 47 | 48 | reqEvent.responseHeaders = responseHeaders; 49 | // HACK: for some reason we cant get this to work, so we will use workaround by calling fulfillRequest instead 50 | // return cdpClient.send('Fetch.continueResponse', { 51 | // requestId: requestId, 52 | // responseCode: reqEvent.responseStatusCode, 53 | // responseHeaders: responseHeaders 54 | // }); 55 | 56 | bodyResult = await cdpClient.send('Fetch.getResponseBody', { 57 | requestId: requestId 58 | }); 59 | 60 | body = '' 61 | if (bodyResult.base64Encoded) { 62 | body = atob(bodyResult.body) 63 | } 64 | 65 | if ('webperf' in context.options) { 66 | for (var i = 1; i <= 9; i++) { 67 | const key = 'HTML0X'.replace('X', i); 68 | if (!(key in context.options.webperf)) { 69 | // context.log.warning("NO " + key + " OPTIONS"); 70 | continue; 71 | } 72 | pair = context.options.webperf[key].replaceAll('%20', ' ').split('='); 73 | context.log.warning("HTML CHANGED: " + pair[0].replaceAll('%3D', '=') + " = " + pair[1].replaceAll('%3D', '=')); 74 | body = body.replace(pair[0].replaceAll('%3D', '='), pair[1].replaceAll('%3D', '=')) 75 | } 76 | } else { 77 | context.log.warning("NO PLUGIN OPTIONS"); 78 | } 79 | 80 | 81 | return cdpClient.send('Fetch.fulfillRequest', { 82 | requestId: requestId, 83 | responseCode: reqEvent.responseStatusCode, 84 | responseHeaders: responseHeaders, 85 | body: bodyResult.body 86 | }); 87 | }); 88 | } 89 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/tracking_validator.po: -------------------------------------------------------------------------------- 1 | # English (default). 2 | # Copyright (C) 2022 WebPerf 3 | # FIRST AUTHOR , 2021. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-04-17 10:45+0200\n" 9 | "PO-Revision-Date: 2022-02-09 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: English \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 23 - Tracking and Privacy\r\n" 20 | 21 | msgid "TEXT_VISITOR_ANALYTICS_USED" 22 | msgstr " Visitor analytics used:\r\n" 23 | 24 | msgid "TEXT_TRACKING" 25 | msgstr "##### Tracking" 26 | 27 | msgid "TEXT_TRACKING_FOUND_ALLOWED" 28 | msgstr " - {0} - Tracking found, having {1} are allowed" 29 | 30 | msgid "TEXT_TRACKING_FOUND" 31 | msgstr " - {0} - Tracking found" 32 | 33 | msgid "TEXT_TRACKING_MAX_SHOWED" 34 | msgstr " - More than {0} requests found, filtering out the rest" 35 | 36 | msgid "TEXT_TRACKING_TOTAL_FOUND" 37 | msgstr " - A total of {0} tracking requests found.\n" 38 | 39 | msgid "TEXT_TRACKING_REFERENCE" 40 | msgstr "{0} - Has references to {1}" 41 | 42 | msgid "TEXT_FINGERPRINTING" 43 | msgstr "##### Fingerprinting/identifying technology" 44 | 45 | msgid "TEXT_FINGERPRINTING_FOUND" 46 | msgstr " - {0} - Fingerprinting/identifying found.\n" 47 | 48 | msgid "TEXT_FINGERPRINTING_MAX_SHOWED" 49 | msgstr " - More than {0} requests found, filtering out the rest." 50 | 51 | msgid "TEXT_FINGERPRINTING_TOTAL_FOUND" 52 | msgstr " - A total of {0} tracking requests found.\n" 53 | 54 | msgid "TEXT_ADS" 55 | msgstr "##### Ads" 56 | 57 | msgid "TEXT_ADS_FOUND_ALLOWED" 58 | msgstr " - {0} - Ad server request found, having {1} are allowed" 59 | 60 | msgid "TEXT_ADS_FOUND" 61 | msgstr " - {0} - Ad server request found" 62 | 63 | msgid "TEXT_ADS_MAX_SHOWED" 64 | msgstr " - More than {0} requests found, filtering out the rest" 65 | 66 | msgid "TEXT_ADS_TOTAL_FOUND" 67 | msgstr " - A total of {0} ad server requests found.\n" 68 | 69 | msgid "TEXT_COOKIES_HAS_THIRDPARTY" 70 | msgstr " - Thirdparty: {0}" 71 | 72 | msgid "TEXT_COOKIE_HAS_OVER_1YEAR" 73 | msgstr " - Valid over 1 year: {0}" 74 | 75 | msgid "TEXT_COOKIE_HAS_OVER_9MONTH" 76 | msgstr " - Valid over 9 months: {0}" 77 | 78 | msgid "TEXT_COOKIE_HAS_OVER_6MONTH" 79 | msgstr " - Valid over 6 months: {0}" 80 | 81 | msgid "TEXT_COOKIE_HAS_OVER_3MONTH" 82 | msgstr " - Valid over 3 months: {0}" 83 | 84 | msgid "TEXT_COOKIE_NOT_SECURE" 85 | msgstr " - No requirement for secure transfer: {0}" 86 | 87 | msgid "TEXT_COOKIE_HAS_ANALYTICS_COOKIE" 88 | msgstr " - Using analytic cookie(s) without consent: {0}" 89 | 90 | msgid "TEXT_COOKIE_LESS_THEN_3MONTH" 91 | msgstr " - Valid less than 3 months" 92 | 93 | msgid "TEXT_COOKIE_SECURE" 94 | msgstr " - Require secure transfer" 95 | 96 | msgid "TEXT_COOKIE_NO_ANALYTICS_COOKIE" 97 | msgstr " - Not using analytic cookies without consent" 98 | 99 | msgid "TEXT_COOKIE" 100 | msgstr "##### Cookies" 101 | 102 | msgid "TEXT_GDPR_COUNTRIES" 103 | msgstr " Number of countries: {0}\r\n" 104 | 105 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES" 106 | msgstr " Countries lacking adequate level of data protection: {0}\r\n" 107 | 108 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES_REQUESTS" 109 | msgstr " {0}, {1} request:\r\n" 110 | 111 | msgid "TEXT_GDPR_PAGE_IN_SWEDEN" 112 | msgstr " Page hosted in Sweden: {0}\r\n" 113 | 114 | msgid "TEXT_GDPR_True" 115 | msgstr "Yes" 116 | 117 | msgid "TEXT_GDPR_False" 118 | msgstr "No" 119 | 120 | msgid "TEXT_GDPR_HAS_POINTS" 121 | msgstr "##### GDPR and Schrems" 122 | 123 | msgid "TEXT_GDPR_NO_POINTS" 124 | msgstr "##### GDPR and Schrems" 125 | 126 | msgid "TEXT_GDPR_MAX_SHOWED" 127 | msgstr " - More than {0} requests found, filtering out the rest\r\n" 128 | 129 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/tracking_validator.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2022 WebPerf 3 | # FIRST AUTHOR , 2021. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2021-04-24 09:15+0200\n" 9 | "PO-Revision-Date: 2022-02-09 19:30+0200\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | msgid "TEXT_RUNNING_TEST" 19 | msgstr "## Test: 23 - Spårning och Integritet\r\n" 20 | 21 | msgid "TEXT_VISITOR_ANALYTICS_USED" 22 | msgstr " Besökaranalys används:\r\n" 23 | 24 | msgid "TEXT_TRACKING" 25 | msgstr "##### Spårning" 26 | 27 | msgid "TEXT_TRACKING_FOUND_ALLOWED" 28 | msgstr " - {0} - Spårning hittad, tillåtet att ha {1} st" 29 | 30 | msgid "TEXT_TRACKING_FOUND" 31 | msgstr " - {0} - Spårning hittad" 32 | 33 | msgid "TEXT_TRACKING_MAX_SHOWED" 34 | msgstr " - Fler än {0} spårnings­förfrågningar hittade, döljer resten" 35 | 36 | msgid "TEXT_TRACKING_TOTAL_FOUND" 37 | msgstr " - Hittade totalt {0} spårnings­förfrågningar.\n" 38 | 39 | msgid "TEXT_TRACKING_REFERENCE" 40 | msgstr "{0} - Har referens till {1}" 41 | 42 | msgid "TEXT_FINGERPRINTING" 43 | msgstr "##### Identifierings­tekniker" 44 | 45 | msgid "TEXT_FINGERPRINTING_FOUND" 46 | msgstr " - {0} - Identifierings­tekniker hittade.\n" 47 | 48 | msgid "TEXT_FINGERPRINTING_MAX_SHOWED" 49 | msgstr " - Hittade totalt {0} identifierings­förfrågningar" 50 | 51 | msgid "TEXT_FINGERPRINTING_TOTAL_FOUND" 52 | msgstr " - Hittade totalt {0} identifierings­förfrågningar.\n" 53 | 54 | msgid "TEXT_ADS" 55 | msgstr "##### Annonsörer" 56 | 57 | msgid "TEXT_ADS_FOUND_ALLOWED" 58 | msgstr " - {0} - Annonsörs­förfrågan hittad, tillåtet att ha {1} st" 59 | 60 | msgid "TEXT_ADS_FOUND" 61 | msgstr " - {0} - Annonsörs­förfrågan hittad" 62 | 63 | msgid "TEXT_ADS_MAX_SHOWED" 64 | msgstr " - Fler än {0} annonsörs­förfrågningar hittade, döljer resten" 65 | 66 | msgid "TEXT_ADS_TOTAL_FOUND" 67 | msgstr " - Hittade totalt {0} annonsörs­förfrågningar.\n" 68 | 69 | msgid "TEXT_COOKIES_HAS_THIRDPARTY" 70 | msgstr " - Tredjeparts­kakor: {0}" 71 | 72 | msgid "TEXT_COOKIE_HAS_OVER_1YEAR" 73 | msgstr " - Giltiga över 1 år: {0}" 74 | 75 | msgid "TEXT_COOKIE_HAS_OVER_9MONTH" 76 | msgstr " - Giltiga över 9 månader: {0}" 77 | 78 | msgid "TEXT_COOKIE_HAS_OVER_6MONTH" 79 | msgstr " - Giltiga över 6 månader: {0}" 80 | 81 | msgid "TEXT_COOKIE_HAS_OVER_3MONTH" 82 | msgstr " - Giltiga över 3 månader: {0}" 83 | 84 | msgid "TEXT_COOKIE_NOT_SECURE" 85 | msgstr " - Inget krav på säker överföring: {0}" 86 | 87 | msgid "TEXT_COOKIE_HAS_ANALYTICS_COOKIE" 88 | msgstr " - Använder analyskakor utan samtycke: {0}" 89 | 90 | msgid "TEXT_COOKIE_LESS_THEN_3MONTH" 91 | msgstr " - Giltighetstid är kortare än 3 månader" 92 | 93 | msgid "TEXT_COOKIE_SECURE" 94 | msgstr " - Kräver säker överföring" 95 | 96 | msgid "TEXT_COOKIE_NO_ANALYTICS_COOKIE" 97 | msgstr " - Använder ej analyskakor utan samtycke" 98 | 99 | msgid "TEXT_COOKIE" 100 | msgstr "##### Kakor" 101 | 102 | msgid "TEXT_GDPR_COUNTRIES" 103 | msgstr " Antal olika länder: {0}\r\n" 104 | 105 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES" 106 | msgstr " Länder utan adekvat nivå av dataskydd: {0}\r\n" 107 | 108 | msgid "TEXT_GDPR_NONE_COMPLIANT_COUNTRIES_REQUESTS" 109 | msgstr " {0}, {1} förfrågningar:\r\n" 110 | 111 | msgid "TEXT_GDPR_PAGE_IN_SWEDEN" 112 | msgstr " Sidan skickades från Sverige: {0}\r\n" 113 | 114 | msgid "TEXT_GDPR_True" 115 | msgstr "Ja" 116 | 117 | msgid "TEXT_GDPR_False" 118 | msgstr "Nej" 119 | 120 | msgid "TEXT_GDPR_HAS_POINTS" 121 | msgstr "##### Dataskyddsförordningen och Schrems II-domen" 122 | 123 | msgid "TEXT_GDPR_NO_POINTS" 124 | msgstr "##### Dataskyddsförordningen och Schrems II-domen" 125 | 126 | msgid "TEXT_GDPR_MAX_SHOWED" 127 | msgstr " - Fler än {0} förfrågningar hittade, döljer resten\r\n" 128 | -------------------------------------------------------------------------------- /docs/getting-started-docker.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Docker Desktop 2 | 3 | You can build an image and put in your local registry or use `webperfse/webperf-core`, both have all runtime dependencies installed and are good to go. 4 | 5 | Image is based on the [image set up by Sitespeed.io](https://github.com/sitespeedio/sitespeed.io). Great work, thanks! 6 | 7 | By default, [defaults/settings.json](settings-json.md), gets copied and used and should have sensible defaults that work well inside the container. 8 | 9 | If you add your own [settings.json](settings-json.md) it will take precedence when building the image. 10 | 11 | You might also want to acquire your own copy of `data/IP2LOCATION-LITE-DB1.IPV6.BIN` before building your image, it is required for the GDPR-related ratings. 12 | 13 | ## Use the public image with your custom files 14 | 15 | You can base your own image on `webperfse/webperf-core` or your own local version of it. It can be convenient to have your repo or folder outside of the original repo. 16 | 17 | For example you can hold your own copies of [settings.json](settings-json.md) and `defaults/sites.json` in this separate folder. 18 | 19 | This can make it easier to update image tag, or sync the original GitHub repository without having to re-apply your own changes. 20 | 21 | Put a `Dockerfile` in the new folder. Content example: 22 | 23 | ``` 24 | FROM webperfse/webperf-core:latest 25 | 26 | COPY settings.json /usr/src/runner/settings.json 27 | COPY defaults/sites.json /usr/src/runner/sites.json 28 | ``` 29 | 30 | Build it from your new folder: 31 | 32 | 33 | ``` 34 | docker build -t "my-own-webperf-runner:latest" . 35 | ``` 36 | 37 | When running, the `--shm-size` and `--cpus` parameters adjusts available resources for the container. The environment variable MAX_OLD_SPACE_SIZE is picked up by Node.js and should be set to give that runtime more memory to work with. 38 | 39 | What to set is dependent on the host machine's resources and the complexity of the web sites you test. MAX_OLD_SPACE_SIZE should in all situations be set lower than `--shm-size`. 40 | 41 | All mentioned parameters are standard Docker and Node.js settings. For the GitHub Action runner we use `--shm-size=4g -e MAX_OLD_SPACE_SIZE=3000` when regression testing the image. 42 | 43 | This starts the container: 44 | 45 | ``` 46 | docker run -it --cpus="0.9" --shm-size=4g -e MAX_OLD_SPACE_SIZE=3000 --rm my-own-webperf-runner:latest bash 47 | ``` 48 | 49 | Now you are at bash but with separate [settings.json](settings-json.md) and `defaults/sites.json` files _burnt into_ the image. 50 | 51 | If you have PowerShell we recommend you also copy the _*.ps1_-files from the _./docker_ folder and adjust them to fit the custom image. 52 | 53 | ## How to setup for building image locally 54 | 55 | - Install Docker Desktop or other software that let's you run `docker` commands. 56 | - [Set "Use Rosetta"](https://www.sitespeed.io/documentation/sitespeed.io/docker/#running-on-mac-m1-arm) if on Mac with ARM. 57 | - Build the image using command in [docker/build.ps1](../docker/build.ps1) or by running the ps1-script in PowerShell. This takes a while. 58 | - _Option 1:_ Start container using command in [docker/run.ps1](../docker/run.ps1) or by running the ps1-script in PowerShell. 59 | - _Option 2:_ Build the image using command in [docker/run-with-mounted-folder.ps1](../docker/run-with-mounted-folder.ps1) or by running the ps1-script in PowerShell - this allows for writing report files to folder on host machine. 60 | - When container is running and you are at bash you can run `python default.py -h` and start tests according to the documentation - all dependencies are already set up in the image. 61 | 62 | ## Change settings / configuration 63 | 64 | Easiest and fastest way is to use the `--setting` command that only change the setting for current run. 65 | You can list all available settings by writing `--setting ?`. 66 | 67 | If you want to change your settings in a more permanent way you can do so by creating a settings.json file. 68 | Read more about it at [settings.json](settings-json.md). 69 | 70 | ## Known issues 71 | 72 | Lighthouse tests sometimes fail reporting NO_NAVSTART - retrying usually works. Seems to be a somewhat often reported issue with Chrome/Lighthouse and Docker. -------------------------------------------------------------------------------- /tests/energy_efficiency_carbon_percentiles.py: -------------------------------------------------------------------------------- 1 | # This array was last generated with carbon-rating.py on 2025-01-09 2 | def get_generated_date(): 3 | """ 4 | Get the date when the data was generated. 5 | 6 | Returns: 7 | str: A string that represents the date when the data was generated. 8 | The date is in the format 'YYYY-MM-DD'. 9 | """ 10 | return '2025-01-09' 11 | 12 | def get_percentiles(): 13 | """ 14 | Get the precomputed percentiles of CO2 data. 15 | 16 | Returns: 17 | list: A list of precomputed percentiles of the CO2 data. 18 | The list contains 100 elements, 19 | each representing the percentile from 1 to 100. 20 | The percentiles are sorted in ascending order. 21 | The percentile values are floats. 22 | """ 23 | return [ 24 | 0.7195952818745981, 25 | 0.7706758259036811, 26 | 0.8246947915802244, 27 | 0.864793432929809, 28 | 0.9271062361625955, 29 | 0.9866173468456139, 30 | 1.0280096576667856, 31 | 1.061448940867814, 32 | 1.09573927227268, 33 | 1.1360545822188723, 34 | # 10 percentile 35 | 1.1699348951320163, 36 | 1.2147008457232498, 37 | 1.249170034221164, 38 | 1.2792559820437106, 39 | 1.3194955966393465, 40 | 1.3529217133346714, 41 | 1.3990941891606665, 42 | 1.4341873880397062, 43 | 1.4722503573893104, 44 | 1.502322656416567, 45 | # 20 percentile 46 | 1.539990389450267, 47 | 1.5687833671211266, 48 | 1.6170550083711275, 49 | 1.655786720460979, 50 | 1.697164996655192, 51 | 1.730082201379142, 52 | 1.767065420803125, 53 | 1.8008167694809147, 54 | 1.8281698474776464, 55 | 1.865497204635874, 56 | # 30 percentile 57 | 1.9010437557259574, 58 | 1.934970898957923, 59 | 1.9669621076763375, 60 | 2.0057327164213175, 61 | 2.0443316300736036, 62 | 2.0861144507727354, 63 | 2.1223484815534905, 64 | 2.1493408069397324, 65 | 2.1827582906514635, 66 | 2.2279277005960467, 67 | # 40 percentile 68 | 2.2698465993019283, 69 | 2.309275846820325, 70 | 2.3432775037933604, 71 | 2.383390396800218, 72 | 2.4359921304131857, 73 | 2.470044476021733, 74 | 2.5122664455035935, 75 | 2.5576627485840113, 76 | 2.5908547136852285, 77 | 2.630395345983561, 78 | # 50 percentile 79 | 2.6687325934208466, 80 | 2.7099887297773497, 81 | 2.7457207935567713, 82 | 2.786273944612406, 83 | 2.830521771501168, 84 | 2.8794038707949228, 85 | 2.9305072753503913, 86 | 2.9806218415672427, 87 | 3.0302468597396044, 88 | 3.0708806737285332, 89 | # 60 percentile 90 | 3.128674833484622, 91 | 3.197390320348181, 92 | 3.281886587732006, 93 | 3.353935443185177, 94 | 3.4110046734642236, 95 | 3.4930577582621942, 96 | 3.554626243976573, 97 | 3.6184129482993153, 98 | 3.69737528028402, 99 | 3.7618564816109137, 100 | # 70 percentile 101 | 3.833286559524969, 102 | 3.9153947217936858, 103 | 3.9854729661120554, 104 | 4.069211942387605, 105 | 4.137290469394648, 106 | 4.214598499869672, 107 | 4.30092180077848, 108 | 4.386039112462475, 109 | 4.5338635714594275, 110 | 4.658924154902808, 111 | # 80 percentile 112 | 4.761884975552838, 113 | 4.897171352176927, 114 | 5.009684617401868, 115 | 5.158261279351962, 116 | 5.325759560409118, 117 | 5.5755929450997845, 118 | 5.785922447958589, 119 | 6.070004807722104, 120 | 6.317559374117899, 121 | 6.665658417993342, 122 | # 90 percentile 123 | 6.954556294588348, 124 | 7.333459656625008, 125 | 7.856159684408294, 126 | 8.28457829550749, 127 | 9.075920278409493, 128 | 10.06626644719094, 129 | 11.618200617671459, 130 | 14.460188703512507, 131 | 18.25513119120255, 132 | 80.10806937437329 133 | ] 134 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/standard-files.po: -------------------------------------------------------------------------------- 1 | # Swedish 2 | # Copyright (C) 2025 WebPerf 3 | # FIRST AUTHOR , 2025. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2025-05-06 19:30\n" 9 | "PO-Revision-Date: 2025-05-06 19:30\n" 10 | "Last-Translator: mattias \n" 11 | "Language-Team: Swedish \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | # 17 | # Example(s): 18 | # Please note that msgid has to be unique in each file. 19 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 20 | 21 | msgid "rule-id (unresolved)" 22 | msgstr "Text som visas istället för msgid, visas för allvarlighetsnivåerna (kritisk, fel och varning)" 23 | 24 | msgid "rule-id (resolved)" 25 | msgstr "Text som visas istället för msgid, här unikt för allvarlighetsnivån löst" 26 | 27 | msgid "rule-id" 28 | msgstr "Text som visas istället för msgid, här oberoende av allvarlighetsnivå" 29 | 30 | # End of Examples 31 | 32 | 33 | msgid "no-duplicates-sitemap (unresolved)" 34 | msgstr "Sitemap, inga dubbletter av Url:er i är tillåtna ({0})" 35 | 36 | msgid "no-duplicates-sitemap (resolved)" 37 | msgstr "Sitemap, inga dubbletter av Url:er i är tillåtna (löst)" 38 | 39 | msgid "no-robots-txt (unresolved)" 40 | msgstr "robots.txt saknas, får inte laddas ner eller har inte förväntat innehåll ({0})" 41 | 42 | msgid "no-robots-txt (resolved)" 43 | msgstr "robots.txt saknas, får inte laddas ner eller har inte förväntat innehåll (löst)" 44 | 45 | msgid "no-sitemap-in-robots-txt (unresolved)" 46 | msgstr "Sitemap anges inte i robots.txt ({0})" 47 | 48 | msgid "no-sitemap-in-robots-txt (resolved)" 49 | msgstr "Sitemap anges inte i robots.txt (löst)" 50 | 51 | msgid "no-valid-sitemap-found (unresolved)" 52 | msgstr "Sitemap, ingen giltig sitemap hittades ({0})" 53 | 54 | msgid "no-valid-sitemap-found (resolved)" 55 | msgstr "Sitemap, ingen giltig sitemap hittades (löst)" 56 | 57 | msgid "no-same-domain-sitemap (unresolved)" 58 | msgstr "Sitemap, Url i måste använda samma domän som robots.txt ({0})" 59 | 60 | msgid "no-same-domain-sitemap (resolved)" 61 | msgstr "Sitemap, Url i måste använda samma domän som robots.txt (löst)" 62 | 63 | msgid "no-https-sitemap (unresolved)" 64 | msgstr "Sitemap, Url i måste börja med https:// ({0})" 65 | 66 | msgid "no-https-sitemap (resolved)" 67 | msgstr "Sitemap, Url i måste börja med https:// (löst)" 68 | 69 | msgid "no-unknown-types-sitemap (unresolved)" 70 | msgstr "Sitemap, listar annat än webbsidor ({0})" 71 | 72 | msgid "no-unknown-types-sitemap (resolved)" 73 | msgstr "Sitemap, listar annat än webbsidor (löst)" 74 | 75 | msgid "invalid-sitemap-too-large (unresolved)" 76 | msgstr "Sitemap, överskrider 50 000 objekt ({0})" 77 | 78 | msgid "invalid-sitemap-too-large (resolved)" 79 | msgstr "Sitemap, överskrider 50 000 objekt (löst)" 80 | 81 | msgid "no-items-sitemap (unresolved)" 82 | msgstr "Sitemap, har inga objekt ({0})" 83 | 84 | msgid "no-items-sitemap (resolved)" 85 | msgstr "Sitemap, har inga objekt (löst)" 86 | 87 | msgid "no-rss-feed (unresolved)" 88 | msgstr "Feed saknas i HTML:ens metadata ({0})" 89 | 90 | msgid "no-rss-feed (resolved)" 91 | msgstr "Feed saknas i HTML:ens metadata (löst)" 92 | 93 | msgid "no-security-txt (unresolved)" 94 | msgstr "security.txt saknas ({0})" 95 | 96 | msgid "no-security-txt (resolved)" 97 | msgstr "security.txt saknas (löst)" 98 | 99 | msgid "invalid-security-txt (unresolved)" 100 | msgstr "security.txt har felaktigt innehåll ({0})" 101 | 102 | msgid "invalid-security-txt (resolved)" 103 | msgstr "security.txt har felaktigt innehåll (löst)" 104 | 105 | msgid "no-security-txt-contact (unresolved)" 106 | msgstr "security.txt saknar nödvändig kontaktinformation ({0})" 107 | 108 | msgid "no-security-txt-contact (resolved)" 109 | msgstr "security.txt saknar nödvändig kontaktinformation (löst)" 110 | 111 | msgid "no-security-txt-expires (unresolved)" 112 | msgstr "security.txt kräver utgångsinformation (tillägg i utkast v10) saknas ({0})" 113 | 114 | msgid "no-security-txt-expires (resolved)" 115 | msgstr "security.txt kräver utgångsinformation (tillägg i utkast v10) saknas (löst)" 116 | 117 | msgid "no-network (unresolved)" 118 | msgstr "Test misslyckades, kunde inte nå webbplatsen ({0})" 119 | 120 | msgid "no-network (resolved)" 121 | msgstr "Test misslyckades, kunde inte nå webbplatsen (löst)" 122 | -------------------------------------------------------------------------------- /locales/en/LC_MESSAGES/standard-files.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # FIRST AUTHOR , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-05-06 19:30\n" 8 | "PO-Revision-Date: 2025-05-06 19:30\n" 9 | "Last-Translator: Your-Name-Here \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | 32 | msgid "no-duplicates-sitemap (unresolved)" 33 | msgstr "Sitemap, No duplicate Urls in allowed ({0})" 34 | 35 | msgid "no-duplicates-sitemap (resolved)" 36 | msgstr "Sitemap, No duplicate Urls in allowed (resolved)" 37 | 38 | msgid "no-robots-txt (unresolved)" 39 | msgstr "robots.txt is missing, not allowed to download or has not the expected content ({0})" 40 | 41 | msgid "no-robots-txt (resolved)" 42 | msgstr "robots.txt is missing, not allowed to download or has not the expected content (resolved)" 43 | 44 | msgid "no-sitemap-in-robots-txt (unresolved)" 45 | msgstr "Sitemap is not specified in robots.txt ({0})" 46 | 47 | msgid "no-sitemap-in-robots-txt (resolved)" 48 | msgstr "Sitemap is not specified in robots.txt (resolved)" 49 | 50 | msgid "no-valid-sitemap-found (unresolved)" 51 | msgstr "Sitemap, no valid sitemap found ({0})" 52 | 53 | msgid "no-valid-sitemap-found (resolved)" 54 | msgstr "Sitemap, no valid sitemap found (resolved)" 55 | 56 | msgid "no-same-domain-sitemap (unresolved)" 57 | msgstr "Sitemap, Url in must use same domain as robots.txt ({0})" 58 | 59 | msgid "no-same-domain-sitemap (resolved)" 60 | msgstr "Sitemap, Url in must use same domain as robots.txt (resolved)" 61 | 62 | msgid "no-https-sitemap (unresolved)" 63 | msgstr "Sitemap, Url in has to start with https:// ({0})" 64 | 65 | msgid "no-https-sitemap (resolved)" 66 | msgstr "Sitemap, Url in has to start with https:// (resolved)" 67 | 68 | msgid "no-unknown-types-sitemap (unresolved)" 69 | msgstr "Sitemap, lists other stuff then webpages ({0})" 70 | 71 | msgid "no-unknown-types-sitemap (resolved)" 72 | msgstr "Sitemap, lists other stuff then webpages (resolved)" 73 | 74 | msgid "invalid-sitemap-too-large (unresolved)" 75 | msgstr "Sitemap, is exceeding 50 000 items ({0})" 76 | 77 | msgid "invalid-sitemap-too-large (resolved)" 78 | msgstr "Sitemap, is exceeding 50 000 items (resolved)" 79 | 80 | msgid "no-items-sitemap (unresolved)" 81 | msgstr "Sitemap, has no items ({0})" 82 | 83 | msgid "no-items-sitemap (resolved)" 84 | msgstr "Sitemap, has no items (resolved)" 85 | 86 | msgid "no-rss-feed (unresolved)" 87 | msgstr "Feed is missing in the HTML's metadata ({0})" 88 | 89 | msgid "no-rss-feed (resolved)" 90 | msgstr "Feed is missing in the HTML's metadata (resolved)" 91 | 92 | msgid "no-security-txt (unresolved)" 93 | msgstr "security.txt is missing ({0})" 94 | 95 | msgid "no-security-txt (resolved)" 96 | msgstr "security.txt is missing (resolved)" 97 | 98 | msgid "invalid-security-txt (unresolved)" 99 | msgstr "security.txt has incorrect content ({0})" 100 | 101 | msgid "invalid-security-txt (resolved)" 102 | msgstr "security.txt has incorrect content (resolved)" 103 | 104 | msgid "no-security-txt-contact (unresolved)" 105 | msgstr "security.txt is missing the required contact info ({0})" 106 | 107 | msgid "no-security-txt-contact (resolved)" 108 | msgstr "security.txt is missing the required contact info (resolved)" 109 | 110 | msgid "no-security-txt-expires (unresolved)" 111 | msgstr "security.txt requires expiration information (added in draft v10) is missing ({0})" 112 | 113 | msgid "no-security-txt-expires (resolved)" 114 | msgstr "security.txt requires expiration information (added in draft v10) is missing (resolved)" 115 | 116 | msgid "no-network (unresolved)" 117 | msgstr "Test failed, unable to access website ({0})" 118 | 119 | msgid "no-network (resolved)" 120 | msgstr "Test failed, unable to access website (resolved)" 121 | -------------------------------------------------------------------------------- /locales/gov/LC_MESSAGES/standard-files.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # FIRST AUTHOR , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-05-06 19:30\n" 8 | "PO-Revision-Date: 2025-05-06 19:30\n" 9 | "Last-Translator: Your-Name-Here \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | 32 | msgid "no-duplicates-sitemap (unresolved)" 33 | msgstr "Sitemap, No duplicate Urls in allowed ({0})" 34 | 35 | msgid "no-duplicates-sitemap (resolved)" 36 | msgstr "Sitemap, No duplicate Urls in allowed (resolved)" 37 | 38 | msgid "no-robots-txt (unresolved)" 39 | msgstr "robots.txt is missing, not allowed to download or has not the expected content ({0})" 40 | 41 | msgid "no-robots-txt (resolved)" 42 | msgstr "robots.txt is missing, not allowed to download or has not the expected content (resolved)" 43 | 44 | msgid "no-sitemap-in-robots-txt (unresolved)" 45 | msgstr "Sitemap is not specified in robots.txt ({0})" 46 | 47 | msgid "no-sitemap-in-robots-txt (resolved)" 48 | msgstr "Sitemap is not specified in robots.txt (resolved)" 49 | 50 | msgid "no-valid-sitemap-found (unresolved)" 51 | msgstr "Sitemap, no valid sitemap found ({0})" 52 | 53 | msgid "no-valid-sitemap-found (resolved)" 54 | msgstr "Sitemap, no valid sitemap found (resolved)" 55 | 56 | msgid "no-same-domain-sitemap (unresolved)" 57 | msgstr "Sitemap, Url in must use same domain as robots.txt ({0})" 58 | 59 | msgid "no-same-domain-sitemap (resolved)" 60 | msgstr "Sitemap, Url in must use same domain as robots.txt (resolved)" 61 | 62 | msgid "no-https-sitemap (unresolved)" 63 | msgstr "Sitemap, Url in has to start with https:// ({0})" 64 | 65 | msgid "no-https-sitemap (resolved)" 66 | msgstr "Sitemap, Url in has to start with https:// (resolved)" 67 | 68 | msgid "no-unknown-types-sitemap (unresolved)" 69 | msgstr "Sitemap, lists other stuff then webpages ({0})" 70 | 71 | msgid "no-unknown-types-sitemap (resolved)" 72 | msgstr "Sitemap, lists other stuff then webpages (resolved)" 73 | 74 | msgid "invalid-sitemap-too-large (unresolved)" 75 | msgstr "Sitemap, is exceeding 50 000 items ({0})" 76 | 77 | msgid "invalid-sitemap-too-large (resolved)" 78 | msgstr "Sitemap, is exceeding 50 000 items (resolved)" 79 | 80 | msgid "no-items-sitemap (unresolved)" 81 | msgstr "Sitemap, has no items ({0})" 82 | 83 | msgid "no-items-sitemap (resolved)" 84 | msgstr "Sitemap, has no items (resolved)" 85 | 86 | msgid "no-rss-feed (unresolved)" 87 | msgstr "Feed is missing in the HTML's metadata ({0})" 88 | 89 | msgid "no-rss-feed (resolved)" 90 | msgstr "Feed is missing in the HTML's metadata (resolved)" 91 | 92 | msgid "no-security-txt (unresolved)" 93 | msgstr "security.txt is missing ({0})" 94 | 95 | msgid "no-security-txt (resolved)" 96 | msgstr "security.txt is missing (resolved)" 97 | 98 | msgid "invalid-security-txt (unresolved)" 99 | msgstr "security.txt has incorrect content ({0})" 100 | 101 | msgid "invalid-security-txt (resolved)" 102 | msgstr "security.txt has incorrect content (resolved)" 103 | 104 | msgid "no-security-txt-contact (unresolved)" 105 | msgstr "security.txt is missing the required contact info ({0})" 106 | 107 | msgid "no-security-txt-contact (resolved)" 108 | msgstr "security.txt is missing the required contact info (resolved)" 109 | 110 | msgid "no-security-txt-expires (unresolved)" 111 | msgstr "security.txt requires expiration information (added in draft v10) is missing ({0})" 112 | 113 | msgid "no-security-txt-expires (resolved)" 114 | msgstr "security.txt requires expiration information (added in draft v10) is missing (resolved)" 115 | 116 | msgid "no-network (unresolved)" 117 | msgstr "Test failed, unable to access website ({0})" 118 | 119 | msgid "no-network (resolved)" 120 | msgstr "Test failed, unable to access website (resolved)" 121 | -------------------------------------------------------------------------------- /locales/sv/LC_MESSAGES/a11y-statement.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 WebPerf 2 | # Marcus J Österberg , 2025. 3 | # 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: PACKAGE VERSION\n" 7 | "POT-Creation-Date: 2025-04-27 12:00\n" 8 | "PO-Revision-Date: 2025-05-09 23:00\n" 9 | "Last-Translator: Marcus J Österberg \n" 10 | "Language-Team: English \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | # 16 | # Example(s): 17 | # Please note that msgid has to be unique in each file. 18 | # {0} in msgstr will add the severity, one of (critical, error, warning, resolved). 19 | 20 | msgid "rule-id (unresolved)" 21 | msgstr "Text to show instead of msgid, showed for severity levels (critical, error and warning)" 22 | 23 | msgid "rule-id (resolved)" 24 | msgstr "Text to show instead of msgid, here unique on severity level resolved" 25 | 26 | msgid "rule-id" 27 | msgstr "Text to show instead of msgid, here independent of severity level" 28 | 29 | # End of Examples 30 | 31 | 32 | msgid "compatible-word-partly (unresolved)" 33 | msgstr "Anger själv att webbplats endast är delvis följsam ({0})" 34 | 35 | msgid "compatible-word-partly (resolved)" 36 | msgstr "Anger själv att webbplats endast är delvis följsam (löst)" 37 | 38 | msgid "no-network (unresolved)" 39 | msgstr "Inget nätverk ({0})" 40 | 41 | msgid "no-network (resolved)" 42 | msgstr "Inget nätverk (löst)" 43 | 44 | msgid "no-updated-date (unresolved)" 45 | msgstr "Inget uppdateringsdatum ({0})" 46 | 47 | msgid "no-updated-date (resolved)" 48 | msgstr "Uppdateringsdatum (löst)" 49 | 50 | msgid "updated-date-older-than-1years (unresolved)" 51 | msgstr "Uppdateringsdatum äldre än 1 år ({0})" 52 | 53 | msgid "updated-date-older-than-1years (resolved)" 54 | msgstr "Uppdateringsdatum äldre än 1 år (löst)" 55 | 56 | msgid "updated-date-older-than-2years (unresolved)" 57 | msgstr "Uppdateringsdatum äldre än 2 år ({0})" 58 | 59 | msgid "updated-date-older-than-2years (resolved)" 60 | msgstr "Uppdateringsdatum äldre än 2 år (löst)" 61 | 62 | msgid "updated-date-older-than-3years (unresolved)" 63 | msgstr "Uppdateringsdatum äldre än 3 år ({0})" 64 | 65 | msgid "updated-date-older-than-3years (resolved)" 66 | msgstr "Uppdateringsdatum äldre än 3 år (löst)" 67 | 68 | msgid "updated-date-older-than-4years (unresolved)" 69 | msgstr "Uppdateringsdatum äldre än 4 år ({0})" 70 | 71 | msgid "updated-date-older-than-4years (resolved)" 72 | msgstr "Uppdateringsdatum äldre än 4 år (löst)" 73 | 74 | msgid "updated-date-older-than-5years (unresolved)" 75 | msgstr "Uppdateringsdatum äldre än 5 år ({0})" 76 | 77 | msgid "updated-date-older-than-5years (resolved)" 78 | msgstr "Uppdateringsdatum äldre än 5 år (löst)" 79 | 80 | msgid "no-evaluation-method (unresolved)" 81 | msgstr "Anger ingen utvärderingsmetod ({0})" 82 | 83 | msgid "no-evaluation-method (resolved)" 84 | msgstr "Anger sin utvärderingsmetod (löst)" 85 | 86 | msgid "has-canonical-notification-function-link (unresolved)" 87 | msgstr "Har inte korrekt länk för anmälan ({0})" 88 | 89 | msgid "has-canonical-notification-function-link (resolved)" 90 | msgstr "Har korrekt länk för anmälan (löst)" 91 | 92 | msgid "has-old-notification-function-link (unresolved)" 93 | msgstr "Har en gammal länk för anmälan ({0})" 94 | 95 | msgid "has-old-notification-function-link (resolved)" 96 | msgstr "Har en gammal länk för anmälan (löst)" 97 | 98 | msgid "no-notification-function-link (unresolved)" 99 | msgstr "Ingen länk för anmälan-funktion ({0})" 100 | 101 | msgid "no-notification-function-link (resolved)" 102 | msgstr "Har länk för anmälan-funktion (löst)" 103 | 104 | msgid "compatible-word-not (unresolved)" 105 | msgstr "Anger själv att webbplats ej är kompatibel ({0})" 106 | 107 | msgid "compatible-word-not (resolved)" 108 | msgstr "Anger själv att webbplats ej är kompatibel (löst)" 109 | 110 | msgid "no-compatible-word (unresolved)" 111 | msgstr "Ingen text om följdsamhet hittades ({0})" 112 | 113 | msgid "no-compatible-word (resolved)" 114 | msgstr "Ingen text om följdsamhet hittades (löst)" 115 | 116 | msgid "has-unreasonably-burdensome-accommodation (unresolved)" 117 | msgstr "Hävdar oskäligt betungande anpassning ({0})" 118 | 119 | msgid "has-unreasonably-burdensome-accommodation (resolved)" 120 | msgstr "Hävdar oskäligt betungande anpassning (löst)" 121 | 122 | msgid "no-a11y-statement (unresolved)" 123 | msgstr "Ingen tillgänglighetsredogörelse hittades ({0})" 124 | 125 | msgid "no-a11y-statement (resolved)" 126 | msgstr "Tillgänglighetsredogörelse hittad (löst)" 127 | -------------------------------------------------------------------------------- /helpers/sitespeed_helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import urllib 5 | import urllib.parse 6 | 7 | from helpers.csp_helper import append_csp_data, default_csp_result_object 8 | from helpers.data_helper import append_domain_entry,\ 9 | append_domain_entry_with_key, has_domain_entry_with_key 10 | from helpers.http_header_helper import append_data_from_response_headers 11 | from helpers.sri_helper import append_sri_data 12 | 13 | def get_data_from_sitespeed(filename, org_domain): 14 | """ 15 | Extracts data from a HAR (HTTP Archive) file generated by SiteSpeed and 16 | updates a result dictionary. 17 | 18 | This function reads a HAR file and iterates over the entries in the log. 19 | For each entry, it extracts information such as the request URL, 20 | scheme, HTTP version, and server IP address. It also appends data 21 | from the response headers and MIME types. 22 | The extracted information is then added to the result dictionary 23 | under the appropriate categories. 24 | 25 | Parameters: 26 | filename (str): The name of the HAR file to be read. 27 | org_domain (str): The original domain for which the HAR file was generated. 28 | 29 | Returns: 30 | dict: The result dictionary updated with the extracted information. 31 | The dictionary also includes a 'visits' key which is set to 32 | 1 to indicate that the function has been called once for the given HAR file. 33 | """ 34 | result = { 35 | 'visits': 0, 36 | org_domain: default_csp_result_object(True) 37 | } 38 | 39 | if filename == '': 40 | result['failed'] = True 41 | return result 42 | 43 | if not os.path.exists(filename): 44 | result['failed'] = True 45 | return result 46 | 47 | # Fix for content having unallowed chars 48 | with open(filename, encoding='utf-8') as json_input_file: 49 | har_data = json.load(json_input_file) 50 | 51 | if 'log' in har_data: 52 | har_data = har_data['log'] 53 | 54 | # return zero visits if no entries 55 | if len(har_data["entries"]) == 0: 56 | result['failed'] = True 57 | return result 58 | 59 | for entry in har_data["entries"]: 60 | req = entry['request'] 61 | res = entry['response'] 62 | req_url = req['url'] 63 | 64 | o = urllib.parse.urlparse(req_url) 65 | req_domain = o.hostname 66 | 67 | if req_domain not in result: 68 | result[req_domain] = default_csp_result_object(False) 69 | 70 | append_domain_entry(req_domain, 'schemes', o.scheme.upper(), result) 71 | append_domain_entry(req_domain, 'urls', req_url, result) 72 | 73 | scheme = f'{o.scheme.lower()}:' 74 | if not has_domain_entry_with_key( 75 | org_domain, 76 | 'csp-findings', 77 | 'scheme-sources', 78 | scheme, result) and scheme != 'http:': 79 | append_domain_entry_with_key( 80 | org_domain, 81 | 'csp-findings', 82 | 'scheme-sources', 83 | scheme, 84 | result) 85 | 86 | if 'httpVersion' in req and req['httpVersion'] != '': 87 | http_version = req['httpVersion'].replace('h2', 'HTTP/2') 88 | http_version = http_version.replace('h3', 'HTTP/3') 89 | http_version = http_version.upper() 90 | append_domain_entry(req_domain, 'protocols', http_version, result) 91 | 92 | if 'httpVersion' in res and res['httpVersion'] != '': 93 | http_version = res['httpVersion'].replace('h2', 'HTTP/2') 94 | http_version = http_version.replace('h3', 'HTTP/3') 95 | http_version = http_version.upper() 96 | append_domain_entry(req_domain, 'protocols', http_version, result) 97 | 98 | if 'serverIPAddress' in entry: 99 | if ':' in entry['serverIPAddress']: 100 | append_domain_entry(req_domain, 'ip-versions', 'IPv6', result) 101 | else: 102 | append_domain_entry(req_domain, 'ip-versions', 'IPv4', result) 103 | 104 | append_data_from_response_headers( 105 | res['headers'], 106 | req_url, 107 | org_domain, 108 | req_domain, 109 | result) 110 | 111 | append_csp_data(req_url, req_domain, res, org_domain, result) 112 | append_sri_data(req_domain, res, result) 113 | 114 | result['visits'] = 1 115 | return result 116 | --------------------------------------------------------------------------------