Generic checklist for reviewing DevTools CLs (your own before upload, or someone else's on Gerrit). Covers test correctness (tautological/vacuous tests, cleanup, leaks), code clarity, CL hygiene, and points to the specialized skills to consult for imports, UI, testing, strings, models, and verification. Use when asked to review a CL, a diff, a patch, or to self-review before `git cl upload`.
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
This checklist comes from recurring reviewer feedback on landed DevTools CLs. Use it for self-review before upload and for reviewing other people's CLs.
read_file to inspect enclosing classes/functions/tests and
search_files to verify callers or conventions across the repository.git diff origin/main...HEAD (or git show HEAD for a
single-commit branch). To learn about the branch and upload workflow, see the
devtools-version-control skill.)]}' line from each response to get JSON:
git cl diff (for the current branch), or fetch the patch set.curl -s https://chromium-review.googlesource.com/changes/devtools%2Fdevtools-frontend~<CL_NUMBER>/comments | tail -n +2.../changes/devtools%2Fdevtools-frontend~<CL_NUMBER>/messagesLoad the skill or .agents/rules/ files that match what the diff touches, and apply their rules:
| If the diff touches… | Load skill or rules |
|---|---|
Any import statement, or a new cross-module dependency | devtools-imports |
UI.Widget, lit-html views, components, CSS | ui-widgets |
| Reviewing UI and widgets (`front_end/(panels | ui)/**/*.{ts,css}`) |
| Migration of legacy imperative DOM to widgets or Lit | ui-eng-vision-orchestrator (and its sub-skills) |
| New or changed tests: choosing unit, API, or E2E | devtools-testing-guidance |
Reviewing tests (*.test.ts, test/**, front_end/testing/**) | .agents/rules/tests/*.md |
Tests that use describeWithEnvironment or describeWithMockConnection, or foundation modules | foundation-test-migration |
Ported Chromium web tests (web_tests/http/tests/devtools) | migrate-chromium-test |
Flaky or disabled tests, or it.skip / it.skipOnPlatforms | fix-tests |
| Rendering user-controlled strings (URLs, names, console text) | devtools-unicode-escaping |
front_end/models/*, BUILD.gn, devtools_grd_files.gni, entrypoints | devtools-model-management |
| Reviewing foundation, models, and build configs (`front_end/(core | models |
Merging modules or consolidating BUILD.gn | merging-devtools-module |
Settings registrations and descriptors | devtools-setting-migration |
Stack traces, source maps, DebuggerWorkspaceBinding | devtools-source-maps |
| Building, running tests, or lint | devtools-verification |
foo.ts, foo-meta.ts), GN visibility and dependency edges,
strict core -> models -> ui -> panels layering, SettingDescriptor
placement in the lowest layer where used, public widget/component APIs
(DEFAULT_VIEW input/output contracts), CDP protocol contracts, and test
validity..agents/rules/.Check these guards before reporting any finding (including general review findings):
@SomeEvent=${handler} bindings on <devtools-widget> (or a
widget's element):
@SomeEvent=${handler} as "never fires" or "lowercased
by the HTML parser" when the child widget class is built with
Common.ObjectWrapper.eventMixin(...) on top of UI.Widget.Widget /
UI.Widget.VBox / UI.Widget.HBox:
eventMixin.dispatchEventToListeners (front_end/core/common/Object.ts)
also calls this.dispatchDOMEvent(new CustomEvent(eventType, {detail: eventData[0]})),
and Widget.dispatchDOMEvent dispatches it on widget.element (which
is the <devtools-widget> host element when instantiated with widget()).@, ., and ? binding names by
reading the original template strings (attrNames[] in
front_end/third_party/lit/lib/lit.js), not the lowercased attribute
names from the HTML parser. So @PaintProfilerRequested registers
addEventListener('PaintProfilerRequested', ...), and event.detail
carries the first payload argument.Common.ObjectWrapper.ObjectWrapper directly
or holds one by composition instead of eventMixin on UI.Widget (it
has no dispatchDOMEvent, so no DOM CustomEvent is fired).new CustomEvent(...) in Object.ts does not set
bubbles: true).@SomeEvent handler reads (event as any).data instead of
(event as CustomEvent<T>).detail.html template whitespace (front_end/ui/lit/strip-whitespace.ts):
html templates from ui/lit/lit.js.
DevTools' custom html tag strips \n\s* outside <...> tags at
runtime..css.js imports in <style>${styles}</style>:
*.css.js default imports into <style>
in Lit templates. Generated .css.js files export plain CSS strings, not
CSSStyleSheet objects.DOM.undo that
calls removeSection() directly, followed by an assertion that the section
was removed), the test checks the mock and nothing else. Mock the boundary
instead (for example, have the CDP stub emit CSSModel.Events.StyleSheetChanged)
and let production code react to it.initialize) that skip the code path under
test. These tests pass because nothing happens.assert.isNull(pane.node()) right after pane.setNodeForTest(null). Each
assertion should verify the behavior that the test name describes.Foo.test.ts should exercise
Foo. Move logic-only tests to the model's test file (for example,
CSSMatchedStyles.test.ts). Otherwise, render the UI and assert on the DOM.<body> of the main frame.devtools-testing-guidance.aria-labels must match the
actual strings, for example "Show user agent shadow DOM" and not "User agent
shadow DOM". Check that the setting being toggled actually affects the
scenario.beforeEach singleton creation with a cleanup in afterEach
(for example, CSSWorkspaceBinding.removeInstance() or
WorkspaceImpl.removeInstance()) so that state does not leak between tests.try { … } finally { clock.restore(); }, or use the
sandbox or cleanup that the test runner provides. Keep the scope of fake
timers small.restore() first. Sinon
throws Attempted to wrap … which is already wrapped when the object is the
same instance.if (!stub.called) … in a test that stubs the method only once).TextUtils.TextRange.TextRange.fromObject(...) directly instead of going
through rule.style.range.constructor.Bug: or Fixed: trailer, or Bug: None. Keep lines under 72
characters.(13/16)).devtools-verification.ChromeDevTools/devtools-frontend
82e99f9
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.