원클릭으로
foundation-test-migration
// Migrating unit tests to foundation unit tests using TestUniverse and devtools_foundation_module. Use when moving tests away from DOM-heavy helpers like describeWithEnvironment or describeWithMockConnection.
// Migrating unit tests to foundation unit tests using TestUniverse and devtools_foundation_module. Use when moving tests away from DOM-heavy helpers like describeWithEnvironment or describeWithMockConnection.
MANDATORY: Activate this skill ANY TIME you need to build the project, run tests, or verify code health in DevTools. You MUST use this skill before executing commands like npm test, npm run build, autoninja, or linters, as it contains critical, repository-specific instructions on how to correctly format these commands, filter test runs, and interpret failures.
Use when managing branches, creating and uploading CLs, or handling stacked changes in the DevTools Gerrit-based workflow.
Conventions for importing code in Devtools to avoid build errors. Covers cross-module imports, internal imports, and the "import * as" requirement.
Workflow for merging a DevTools submodule into its parent module. Covers BUILD.gn consolidation and updating devtools_grd_files.gni.
Guidelines for building UI widgets using the MVP architecture in DevTools. Covers Widget lifecycle, lit-html views, and state management.
| name | foundation-test-migration |
| description | Migrating unit tests to foundation unit tests using TestUniverse and devtools_foundation_module. Use when moving tests away from DOM-heavy helpers like describeWithEnvironment or describeWithMockConnection. |
This skill provides guidance on migrating DevTools unit tests to the "foundation" pattern, which is lighter, avoids global singletons, and is compatible with both Node and Browser runtimes (Isomorphic).
Use this template for modules that should be platform-agnostic.
FileReader or layout metrics) or heavy DevTools dependencies. Use Universe to access services.TestUniverse is the preferred way to setup a DevTools-like environment for tests without global singletons.
Common.Settings.Settings.instance()).DevToolsContext to manage dependencies.Avoid describeWithEnvironment or describeWithMockConnection.
Instead, use standard describe and initialize environment hooks at the top-level describe block. Crucial: Without setupRuntimeHooks, tests creating SDK models will crash due to uninitialized experiments (e.g. capture-node-creation-stacks).
import {setupLocaleHooks} from '../../testing/LocaleHelpers.js';
import {setupSettingsHooks} from '../../testing/SettingsHelpers.js';
import {setupRuntimeHooks} from '../../testing/RuntimeHelpers.js';
import {TestUniverse} from '../../testing/TestUniverse.js';
describe('MyComponent', () => {
setupLocaleHooks();
setupSettingsHooks();
setupRuntimeHooks();
let universe: TestUniverse;
beforeEach(() => {
universe = new TestUniverse();
});
});
Instead of using SDK.TargetManager.TargetManager.instance(), use universe.targetManager. Use universe.createTarget() instead of the global createTarget.
// OLD
const target = createTarget();
const targetManager = SDK.TargetManager.TargetManager.instance();
// NEW
const target = universe.createTarget({url: urlString`http://example.com/`});
const targetManager = universe.targetManager;
If the test used describeWithMockConnection and global setMockConnectionResponseHandler to stub CDP traffic, you can migrate this by passing a MockCDPConnection to universe.createTarget(). This allows stubbing out CDP traffic scoped to a specific target tree rather than globally.
import {MockCDPConnection} from '../../testing/MockCDPConnection.js';
const cdpConnection = new MockCDPConnection([
{
method: 'Network.getResponseBody',
response: () => ({body: 'mocked body', base64Encoded: false}),
}
]);
const target = universe.createTarget({connection: cdpConnection});
[!TIP] Legacy Target URLs:
EnvironmentHelpers.createTarget()defaults tohttp://example.com/.TestUniverse.createTarget()defaults toabout:blank. If your test asserts against specific URLs, remember to pass the URL explicitly.
For large integration tests, you may encounter code that strictly calls SomeModule.instance() or uses complex legacy helpers (like createWorkspaceProject).
Do not use setUpEnvironment() as it will create disconnected singletons. Instead, wire the singletons to your TestUniverse and stub the globals to bridge legacy helpers:
beforeEach(async () => {
universe = new TestUniverse();
const {targetManager, workspace, settings} = universe;
// 1. Stub globals so legacy helpers use TestUniverse components
sinon.stub(Workspace.Workspace.WorkspaceImpl, 'instance').returns(workspace);
sinon.stub(SDK.TargetManager.TargetManager, 'instance').returns(targetManager);
sinon.stub(Common.Settings.Settings, 'instance').returns(settings);
// 2. Initialize interdependent singletons in the correct order
SDK.NetworkManager.MultitargetNetworkManager.instance({forceNew: true, targetManager});
// 3. Now safe to use legacy helpers that rely on the above instances
await createWorkspaceProject(urlString`file:///path/to/overrides`, [...]);
});
assert.deepEqual)Protocol requests/responses dynamically generated by Chrome (like Network conditions) can vary slightly (e.g., adding connectionType, urlPattern).
assert.deepEqual(rules, [{...}]) will flake if unrequested fields are present.sinon.spy() for handlers and assert with sinon.assert.calledOnceWithMatch:const emulateSpy = sinon.spy();
connection.setSuccessHandler('Network.emulateNetworkConditionsByRule', request => {
emulateSpy(request);
return {ruleIds: []};
});
// Matches only the fields you care about, ignoring extra protocol fields
sinon.assert.calledOnceWithMatch(emulateSpy, {
offline: false,
matchedNetworkConditions: [sinon.match({ downloadThroughput: 1000 })],
});
ReferenceError: FileReader is not defined)Foundation tests run in Node.js where window, FileReader, and certain DOM string encodings don't exist.
btoa(), Uint8Array).front_end/core/platform/api/HostRuntime.ts.If a test times out (5000ms exceeded), it is usually an unhandled promise caused by a missing singleton. Double-check the constructor of the failing manager to see which instance() it listens to, and ensure that dependent singleton was created first.
When a module and its tests are ready, update BUILD.gn:
devtools_module to devtools_foundation_module for both the module and its unittests.foundation_unittests target in the parent BUILD.gn.# front_end/my_module/BUILD.gn
devtools_foundation_module("my_module") {
sources = [ "MyModule.ts" ]
deps = [ "../../core/common:bundle" ]
}
devtools_foundation_module("unittests") {
testonly = true
sources = [ "MyModule.test.ts" ]
deps = [
":my_module",
"../../testing",
]
}
Foundation tests must pass in both Node.js and Browser runtimes.
npm test -- front_end/core/sdk/NetworkManager.test.ts --node-unit-tests
npm test -- front_end/core/sdk/NetworkManager.test.ts