Skip to content

Commit 3955b03

Browse files
ergunshDevtools-frontend LUCI CQ
authored andcommitted
[Animations] Render animation selector in computed style widget
Before this CL, when the source of a property was an animation style; we were showing the selector as `element.style`. This CL updates it to show the animation's name correctly. Bug: 349566291 Change-Id: I65df388edba022e9274c8cb23ede000a75eea53d Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6170708 Auto-Submit: Ergün Erdoğmuş <[email protected]> Commit-Queue: Changhao Han <[email protected]> Reviewed-by: Changhao Han <[email protected]>
1 parent 0c31a7d commit 3955b03

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

front_end/panels/elements/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ ts_library("unittests") {
156156
"CSSRuleValidator.test.ts",
157157
"ClassesPaneWidget.test.ts",
158158
"ComputedStyleModel.test.ts",
159+
"ComputedStyleWidget.test.ts",
159160
"DOMLinkifier.test.ts",
160161
"ElementStatePaneWidget.test.ts",
161162
"ElementsPanel.test.ts",
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2023 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
import * as SDK from '../../core/sdk/sdk.js';
5+
import type * as Protocol from '../../generated/protocol.js';
6+
import {describeWithMockConnection} from '../../testing/MockConnection.js';
7+
import type * as TreeOutline from '../../ui/components/tree_outline/tree_outline.js';
8+
9+
import * as Elements from './elements.js';
10+
11+
async function waitForTraceElement(treeOutline: TreeOutline.TreeOutline.TreeOutline<unknown>): Promise<HTMLElement> {
12+
const element = treeOutline.shadowRoot?.querySelector('devtools-computed-style-trace');
13+
if (element) {
14+
return element;
15+
}
16+
17+
return new Promise<HTMLElement>(resolve => {
18+
requestAnimationFrame(async () => {
19+
const result = await waitForTraceElement(treeOutline);
20+
resolve(result);
21+
});
22+
});
23+
}
24+
25+
describeWithMockConnection('ComputedStyleWidget', () => {
26+
let computedStyleWidget: Elements.ComputedStyleWidget.ComputedStyleWidget;
27+
afterEach(() => {
28+
computedStyleWidget.detach();
29+
});
30+
31+
describe('trace element', () => {
32+
function createComputedStyleWidgetForTest(
33+
cssStyleDeclarationType: SDK.CSSStyleDeclaration.Type, cssStyleDeclarationName?: string,
34+
parentRule?: SDK.CSSRule.CSSRule): Elements.ComputedStyleWidget.ComputedStyleWidget {
35+
const node = sinon.createStubInstance(SDK.DOMModel.DOMNode);
36+
node.id = 1 as Protocol.DOM.NodeId;
37+
38+
const stubCSSStyle = {
39+
styleSheetId: 'STYLE_SHEET_ID' as Protocol.CSS.StyleSheetId,
40+
cssProperties: [{
41+
name: 'color',
42+
value: 'red',
43+
disabled: false,
44+
implicit: false,
45+
longhandProperties: [],
46+
range: {startLine: 1, startColumn: 4, endLine: 1, endColumn: 20},
47+
text: 'color: red;',
48+
}],
49+
shorthandEntries: [],
50+
} as Protocol.CSS.CSSStyle;
51+
52+
const cssMatchedStyles = sinon.createStubInstance(SDK.CSSMatchedStyles.CSSMatchedStyles, {
53+
node,
54+
propertyState: SDK.CSSMatchedStyles.PropertyState.ACTIVE,
55+
nodeStyles: [
56+
new SDK.CSSStyleDeclaration.CSSStyleDeclaration(
57+
{} as SDK.CSSModel.CSSModel, parentRule ?? null, stubCSSStyle, cssStyleDeclarationType,
58+
cssStyleDeclarationName),
59+
]
60+
});
61+
62+
const computedStyleModel = sinon.createStubInstance(Elements.ComputedStyleModel.ComputedStyleModel, {
63+
fetchComputedStyle: Promise.resolve({node, computedStyle: new Map([['color', 'red']])}),
64+
cssModel: sinon.createStubInstance(
65+
SDK.CSSModel.CSSModel, {cachedMatchedCascadeForNode: Promise.resolve(cssMatchedStyles)}),
66+
node,
67+
});
68+
const computedStyleWidget = new Elements.ComputedStyleWidget.ComputedStyleWidget(computedStyleModel);
69+
computedStyleWidget.markAsRoot();
70+
computedStyleWidget.show(document.body);
71+
72+
return computedStyleWidget;
73+
}
74+
75+
it('renders trace element with correct selector for declarations coming from animations', async () => {
76+
computedStyleWidget =
77+
createComputedStyleWidgetForTest(SDK.CSSStyleDeclaration.Type.Animation, '--animation-name');
78+
79+
computedStyleWidget.update();
80+
await computedStyleWidget.updateComplete;
81+
82+
const treeOutline = computedStyleWidget.contentElement.querySelector('devtools-tree-outline') as
83+
TreeOutline.TreeOutline.TreeOutline<unknown>;
84+
await treeOutline.expandRecursively(2);
85+
86+
const traceElement = await waitForTraceElement(treeOutline);
87+
const traceSelector = traceElement.shadowRoot?.querySelector('.trace-selector');
88+
assert.strictEqual(traceSelector?.textContent, '--animation-name animation');
89+
});
90+
91+
it('renders trace element with correct selector for declarations coming from WAAPI animations', async () => {
92+
computedStyleWidget = createComputedStyleWidgetForTest(SDK.CSSStyleDeclaration.Type.Animation);
93+
94+
computedStyleWidget.update();
95+
await computedStyleWidget.updateComplete;
96+
97+
const treeOutline = computedStyleWidget.contentElement.querySelector('devtools-tree-outline') as
98+
TreeOutline.TreeOutline.TreeOutline<unknown>;
99+
await treeOutline.expandRecursively(2);
100+
101+
const traceElement = await waitForTraceElement(treeOutline);
102+
const traceSelector = traceElement.shadowRoot?.querySelector('.trace-selector');
103+
assert.strictEqual(traceSelector?.textContent, 'animation style');
104+
});
105+
106+
it('renders trace element with correct selector for declarations transitions', async () => {
107+
computedStyleWidget = createComputedStyleWidgetForTest(SDK.CSSStyleDeclaration.Type.Transition);
108+
109+
computedStyleWidget.update();
110+
await computedStyleWidget.updateComplete;
111+
112+
const treeOutline = computedStyleWidget.contentElement.querySelector('devtools-tree-outline') as
113+
TreeOutline.TreeOutline.TreeOutline<unknown>;
114+
await treeOutline.expandRecursively(2);
115+
116+
const traceElement = await waitForTraceElement(treeOutline);
117+
const traceSelector = traceElement.shadowRoot?.querySelector('.trace-selector');
118+
assert.strictEqual(traceSelector?.textContent, 'transitions style');
119+
});
120+
121+
it('renders trace element with correct selector for declarations coming from CSS rules', async () => {
122+
computedStyleWidget = createComputedStyleWidgetForTest(
123+
SDK.CSSStyleDeclaration.Type.Regular, undefined,
124+
SDK.CSSRule.CSSStyleRule.createDummyRule({} as SDK.CSSModel.CSSModel, '.container'));
125+
126+
computedStyleWidget.update();
127+
await computedStyleWidget.updateComplete;
128+
129+
const treeOutline = computedStyleWidget.contentElement.querySelector('devtools-tree-outline') as
130+
TreeOutline.TreeOutline.TreeOutline<unknown>;
131+
await treeOutline.expandRecursively(5);
132+
133+
const traceElement = await waitForTraceElement(treeOutline);
134+
const traceSelector = traceElement.shadowRoot?.querySelector('.trace-selector');
135+
assert.strictEqual(traceSelector?.textContent, '.container');
136+
});
137+
138+
it('renders trace element with correct selector for declarations coming from inline styles', async () => {
139+
computedStyleWidget = createComputedStyleWidgetForTest(SDK.CSSStyleDeclaration.Type.Inline);
140+
141+
computedStyleWidget.update();
142+
await computedStyleWidget.updateComplete;
143+
144+
const treeOutline = computedStyleWidget.contentElement.querySelector('devtools-tree-outline') as
145+
TreeOutline.TreeOutline.TreeOutline<unknown>;
146+
await treeOutline.expandRecursively(5);
147+
148+
const traceElement = await waitForTraceElement(treeOutline);
149+
const traceSelector = traceElement.shadowRoot?.querySelector('.trace-selector');
150+
assert.strictEqual(traceSelector?.textContent, 'element.style');
151+
});
152+
});
153+
});

front_end/panels/elements/ComputedStyleWidget.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,19 @@ const createTraceElement =
158158
if (rule) {
159159
ruleOriginNode = StylePropertiesSection.createRuleOriginNode(matchedStyles, linkifier, rule);
160160
}
161+
162+
let selector = 'element.style';
163+
if (rule) {
164+
selector = rule.selectorText();
165+
} else if (property.ownerStyle.type === SDK.CSSStyleDeclaration.Type.Animation) {
166+
selector = property.ownerStyle.animationName() ? `${property.ownerStyle.animationName()} animation` :
167+
'animation style';
168+
} else if (property.ownerStyle.type === SDK.CSSStyleDeclaration.Type.Transition) {
169+
selector = 'transitions style';
170+
}
171+
161172
trace.data = {
162-
selector: rule ? rule.selectorText() : 'element.style',
173+
selector,
163174
active: !isPropertyOverloaded,
164175
onNavigateToSource: navigateToSource.bind(null, property),
165176
ruleOriginNode,

front_end/ui/legacy/ThrottledWidget.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export class ThrottledWidget extends VBox {
3434
});
3535
}
3636

37+
override get updateComplete(): Promise<boolean> {
38+
return this.updateThrottler.processCompleted?.then(result => Boolean(result)) || Promise.resolve(false);
39+
}
40+
3741
override wasShown(): void {
3842
super.wasShown();
3943
if (this.updateWhenVisible) {

0 commit comments

Comments
 (0)