Skip to content

Enable Speedometer to use an external config.json file #515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 55 commits into from
Aug 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
2747124
initial test
flashdesignory May 8, 2025
f0f3d93
temp
flashdesignory May 9, 2025
43a9646
another checkin
flashdesignory May 9, 2025
075f8ff
simplify
flashdesignory May 9, 2025
be099ff
fix e2e
flashdesignory May 9, 2025
0c73ade
fix up stuff
flashdesignory May 9, 2025
0c63bc0
fix remote runner
flashdesignory May 9, 2025
7d3145b
enable config suite by default
flashdesignory May 9, 2025
84983e0
remove console
flashdesignory May 9, 2025
17fadf7
changes
flashdesignory May 9, 2025
bdd87d4
use params
flashdesignory May 13, 2025
7c9c69e
rename configUrl to config
flashdesignory May 13, 2025
4707d5f
remove Suites and Tags
flashdesignory May 13, 2025
efb87d2
feedback
flashdesignory May 14, 2025
7c724d9
fix e2e config param
flashdesignory May 14, 2025
fba0a2c
remove console
flashdesignory May 14, 2025
4743a1b
fix it up
flashdesignory May 14, 2025
e6ea8b9
allowlist
flashdesignory May 20, 2025
4de58a8
remove comment
flashdesignory Jun 2, 2025
89ca145
run format
flashdesignory Jun 2, 2025
0f511fe
add comment
flashdesignory Jun 28, 2025
6cc6414
cleanup catch in params
flashdesignory Jun 28, 2025
2a85323
rename _containsAllowedUrl to _isAllowedUrl and pass in url directly
flashdesignory Jun 28, 2025
2a03314
add basic validation to the init function
flashdesignory Jun 28, 2025
516d684
simplify suite.disabled assignment
flashdesignory Jun 28, 2025
8c9fd21
simplify suite.disabled assignment p2
flashdesignory Jun 28, 2025
6f8ef3e
rename _suites and _tags params
flashdesignory Jun 28, 2025
a807894
cleanup _isAllowedUrl method
flashdesignory Jun 28, 2025
81925af
run format
flashdesignory Jun 28, 2025
e701c2d
check readyState
flashdesignory Jun 29, 2025
6f08e6f
run format
flashdesignory Jun 29, 2025
8cd8ccb
add default tag
flashdesignory Jul 14, 2025
0764667
Merge branch 'main' into core/config
flashdesignory Jul 14, 2025
504ccc4
fix default suite in json
flashdesignory Jul 14, 2025
b95c47e
import dataProvider in developer-mode
flashdesignory Jul 14, 2025
af9d5a4
dynamic import
flashdesignory Jul 14, 2025
7a67c8c
Merge branch 'main' into core/config
flashdesignory Jul 15, 2025
368e9b7
run format
flashdesignory Jul 15, 2025
c6075c1
use disallowed domains
flashdesignory Jul 15, 2025
8f7c95b
remove emojis
flashdesignory Jul 16, 2025
113116f
throw error if suite entry is invalid
flashdesignory Jul 16, 2025
890fcb4
validate json url
flashdesignory Jul 16, 2025
289114f
check window location instead of config location
flashdesignory Jul 16, 2025
1d8f45e
add variation
flashdesignory Jul 16, 2025
2e5f751
check variations of domains
flashdesignory Jul 18, 2025
b59adc0
run format
flashdesignory Jul 18, 2025
9a37879
rename dataProvider to benchmarkConfigurator
flashdesignory Jul 18, 2025
7e235e5
Merge branch 'main' into core/config
flashdesignory Aug 6, 2025
08af823
re-add dart workload
flashdesignory Aug 6, 2025
bcdbe1e
use private vars
flashdesignory Aug 6, 2025
eb8c8fa
rename tests.mjs file
flashdesignory Aug 6, 2025
52d10bf
remove json extension check
flashdesignory Aug 20, 2025
ad81b73
move multiple declarations into new lines
flashdesignory Aug 20, 2025
c010903
add _reportError method
flashdesignory Aug 20, 2025
530759c
remove default tag from config.json
flashdesignory Aug 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions resources/benchmark-configurator.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// example url for local testing:
// http://localhost:8080/?developerMode=true&config=http://localhost:8080/resources/config.json
// since the json doesn't contain a default suite, dismiss warning popups and select from the developerMenu
import { defaultSuites } from "./default-tests.mjs";
import { params } from "./shared/params.mjs";

const DEFAULT_TAGS = ["all", "default", "experimental"];
const DISALLOWED_DOMAINS = ["browserbench.org"];
export class BenchmarkConfigurator {
#tags = new Set(DEFAULT_TAGS);
#suites = [];

get tags() {
return this.#tags;
}

get suites() {
return this.#suites;
}

/**
* Checks if a given string is a valid URL, supporting both absolute and relative paths.
*
* This function attempts to construct a URL object. For relative paths, it uses
* a dummy base URL to allow the URL constructor to parse them successfully.
*
* @param {string} url The URL string to validate.
* @returns {boolean} True if the URL is valid (absolute or relative), false otherwise.
*/
_isValidUrl(url) {
if (typeof url !== "string" || url.length === 0)
return false;

try {
new URL(url, "http://www.example.com");
return true;
} catch (error) {
return false;
}
}

/**
* Reports an error by showing an alert and logging a message to the console.
* @private
* @param {string} message The error message to display.
* @param {object} [debugInfo] An optional object containing additional debug information.
*/
_reportError(message, debugInfo) {
alert(message);
console.error(message, debugInfo);
}

_freezeSuites() {
Object.freeze(this.#suites);
this.#suites.forEach((suite) => {
if (!suite.tags)
suite.tags = [];
if (suite.url.startsWith("experimental/"))
suite.tags.unshift("all", "experimental");
else
suite.tags.unshift("all");
suite.enabled = suite.tags.includes("default");
Object.freeze(suite.tags);
Object.freeze(suite.steps);
});
}

_freezeTags() {
Object.freeze(this.#tags);
}

async init() {
if (params.config) {
try {
const benchmarkUrl = new URL(window.location);
if (DISALLOWED_DOMAINS.some((domain) => benchmarkUrl.hostname.endsWith(domain))) {
console.warn("Configuration fetch not allowed. Loading default suites.");
this._loadDefaultSuites();
return;
}

const response = await fetch(params.config);

if (!response.ok)
throw new Error(`Could not fetch config: ${response.status}`);

const config = await response.json();

if (!config || !Array.isArray(config.suites))
throw new Error("Could not find a valid config structure!");

config.suites.flatMap((suite) => suite.tags || []).forEach((tag) => this.#tags.add(tag));
config.suites.forEach((suite) => {
if (suite && suite.url && this._isValidUrl(suite.url))
this.#suites.push(suite);
else
throw new Error("Invalid suite data");
});
} catch (error) {
console.warn(`Error loading custom configuration: ${error.message}. Loading default suites.`);
this._loadDefaultSuites();
}
} else {
this._loadDefaultSuites();
}

this._freezeTags();
this._freezeSuites();
}

_loadDefaultSuites() {
defaultSuites.flatMap((suite) => suite.tags).forEach((tag) => this.#tags.add(tag));
defaultSuites.forEach((suite) => this.#suites.push(suite));
}

enableSuites(names, tags) {
if (names?.length) {
const lowerCaseNames = names.map((each) => each.toLowerCase());
this.#suites.forEach((suite) => {
suite.enabled = lowerCaseNames.includes(suite.name.toLowerCase());
});
} else if (tags?.length) {
tags.forEach((tag) => {
if (!this.#tags.has(tag))
console.error(`Unknown Suites tag: "${tag}"`);
});
const tagsSet = new Set(tags);
this.#suites.forEach((suite) => {
suite.enabled = suite.tags.some((tag) => tagsSet.has(tag));
});
} else {
console.warn("Neither names nor tags provided. Enabling all default suites.");
this.#suites.forEach((suite) => {
suite.enabled = suite.tags.includes("default");
});
}
if (this.#suites.some((suite) => suite.enabled))
return;

if (names?.length) {
this._reportError(`Suites "${names}" does not match any Suite. No tests to run.`, {
providedNames: names,
validNames: this.#suites.map((each) => each.name),
});
} else if (tags?.length) {
this._reportError(`Tags "${tags}" does not match any Suite. No tests to run.`, {
providedTags: tags,
validTags: Array.from(this.#tags),
});
}
}
}

const benchmarkConfigurator = new BenchmarkConfigurator();
await benchmarkConfigurator.init();

export { benchmarkConfigurator };
13 changes: 13 additions & 0 deletions resources/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"suites": [
{
"name": "NewsSite-PostMessage",
"url": "resources/newssite/news-next/dist/index.html",
"tags": ["newssite", "language"],
"type": "remote",
"config": {
"name": "default"
}
}
]
}
Loading
Loading