Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
class Streamer {
private _lastSnapshotNumber = 0;
private _staleStyleSheets = new Set<CSSStyleSheet>();
private _modifiedStyleSheets = new Set<CSSStyleSheet>();
private _readingStyleSheet = false; // To avoid invalidating due to our own reads.
private _fakeBase: HTMLBaseElement;
private _observer: MutationObserver;
Expand All @@ -105,6 +106,10 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
this._interceptNativeMethod(window.CSSGroupingRule.prototype, 'insertRule', invalidateCSSGroupingRule);
this._interceptNativeMethod(window.CSSGroupingRule.prototype, 'deleteRule', invalidateCSSGroupingRule);
this._interceptNativeGetter(window.CSSGroupingRule.prototype, 'cssRules', invalidateCSSGroupingRule);
this._interceptNativeSetter(window.StyleSheet.prototype, 'disabled', (sheet: StyleSheet) => {
if (sheet instanceof CSSStyleSheet)
this._invalidateStyleSheet(sheet as CSSStyleSheet);
});
this._interceptNativeAsyncMethod(window.CSSStyleSheet.prototype, 'replace', (sheet: CSSStyleSheet) => this._invalidateStyleSheet(sheet));

this._fakeBase = document.createElement('base');
Expand Down Expand Up @@ -191,6 +196,18 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
});
}

private _interceptNativeSetter(obj: any, prop: string, cb: (thisObj: any, result: any) => void) {
const descriptor = Object.getOwnPropertyDescriptor(obj, prop)!;
Object.defineProperty(obj, prop, {
...descriptor,
set: function(value: any) {
const result = descriptor.set!.call(this, value);
cb(this, value);
return result;
},
});
}

private _handleMutations(list: MutationRecord[]) {
for (const mutation of list)
ensureCachedData(mutation.target).attributesCached = undefined;
Expand All @@ -200,6 +217,8 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
if (this._readingStyleSheet)
return;
this._staleStyleSheets.add(sheet);
if (sheet.href !== null)
this._modifiedStyleSheets.add(sheet);
}

private _updateStyleElementStyleSheetTextIfNeeded(sheet: CSSStyleSheet, forceText?: boolean): string | undefined {
Expand Down Expand Up @@ -309,6 +328,8 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
private _getSheetText(sheet: CSSStyleSheet): string {
this._readingStyleSheet = true;
try {
if (sheet.disabled)
return '';
const rules: string[] = [];
for (const rule of sheet.cssRules)
rules.push(rule.cssText);
Expand Down Expand Up @@ -614,7 +635,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
collectionTime: 0,
};

for (const sheet of this._staleStyleSheets) {
for (const sheet of this._modifiedStyleSheets) {
if (sheet.href === null)
continue;
const content = this._updateLinkStyleSheetTextIfNeeded(sheet, snapshotNumber);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,24 @@ export class SnapshotRenderer {
let result = sameFrameResource ?? otherFrameResource;
if (result && method.toUpperCase() === 'GET') {
// Patch override if necessary.
for (const o of snapshot.resourceOverrides) {
if (url === o.url && o.sha1) {
result = {
...result,
response: {
...result.response,
content: {
...result.response.content,
_sha1: o.sha1,
}
},
};
break;
}
let override = snapshot.resourceOverrides.find(o => o.url === url);
if (override?.ref) {
// "ref" means use the same content as "ref" snapshots ago.
const index = this._index - override.ref;
if (index >= 0 && index < this._snapshots.length)
override = this._snapshots[index].resourceOverrides.find(o => o.url === url);
}
if (override?.sha1) {
result = {
...result,
response: {
...result.response,
content: {
...result.response.content,
_sha1: override.sha1,
}
},
};
}
}

Expand Down
7 changes: 7 additions & 0 deletions tests/library/trace-viewer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,8 @@ test('should respect CSSOM changes', async ({ runAndTrace, page, server }) => {
await page.goto(server.EMPTY_PAGE);
await page.setContent('<link rel="stylesheet" href="style.css"><button>Hello</button>');
await page.evaluate(() => { (document.styleSheets[0].cssRules[0] as any).style.color = 'blue'; });
await page.evaluate(() => '1 + 1');
await page.evaluate(() => { document.styleSheets[0].disabled = true; });
});

const frame1 = await traceViewer.snapshotFrame('Set content', 0);
Expand All @@ -2196,6 +2198,11 @@ test('should respect CSSOM changes', async ({ runAndTrace, page, server }) => {
await expect(frame6.locator('button')).toHaveCSS('color', 'rgb(255, 0, 0)');
const frame7 = await traceViewer.snapshotFrame('Evaluate', 4);
await expect(frame7.locator('button')).toHaveCSS('color', 'rgb(0, 0, 255)');
const frame8 = await traceViewer.snapshotFrame('Evaluate', 5);
await traceViewer.page.waitForTimeout(1000); // give it time to render wrong color
await expect(frame8.locator('button')).toHaveCSS('color', 'rgb(0, 0, 255)');
const frame9 = await traceViewer.snapshotFrame('Evaluate', 6);
await expect(frame9.locator('button')).toHaveCSS('color', 'rgb(0, 0, 0)');
});

test('should preserve custom doctype', async ({ runAndTrace, page }) => {
Expand Down
Loading