diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts
index 64c4972cfa..e3eeb64dfe 100644
--- a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts
+++ b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts
@@ -196,6 +196,24 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
visitNode(this._fakeBase);
}
+ private __sanitizeMetaAttribute(name: string, value: string, httpEquiv: string) {
+ if (name === 'charset')
+ return 'utf-8';
+
+ if (httpEquiv.toLowerCase() !== 'content-type' || name !== 'content')
+ return value;
+
+ const [type, ...params] = value.split(';');
+ if (type !== 'text/html' || params.length <= 0)
+ return value;
+
+ const charsetParamIdx = params.findIndex(param => param.trim().startsWith('charset='));
+ if (charsetParamIdx > -1)
+ params[charsetParamIdx] = 'charset=utf-8';
+
+ return `${type}; ${params.join('; ')}`;
+ }
+
private _sanitizeUrl(url: string): string {
if (url.startsWith('javascript:'))
return '';
@@ -420,7 +438,9 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
if (nodeName === 'IFRAME' && (name === 'src' || name === 'sandbox'))
continue;
let value = element.attributes[i].value;
- if (name === 'src' && (nodeName === 'IMG'))
+ if (nodeName === 'META')
+ value = this.__sanitizeMetaAttribute(name, value, (node as HTMLMetaElement).httpEquiv);
+ else if (name === 'src' && (nodeName === 'IMG'))
value = this._sanitizeUrl(value);
else if (name === 'srcset' && (nodeName === 'IMG'))
value = this._sanitizeSrcSet(value);
diff --git a/tests/snapshotter.spec.ts b/tests/snapshotter.spec.ts
index 485cd13c25..9b8a16e0b7 100644
--- a/tests/snapshotter.spec.ts
+++ b/tests/snapshotter.spec.ts
@@ -103,6 +103,20 @@ it.describe('snapshots', () => {
expect(distillSnapshot(snapshot)).toBe('hi');
});
+ it('should replace meta charset attr that specifies charset', async ({ page, server, toImpl, snapshotter }) => {
+ await page.goto(server.EMPTY_PAGE);
+ await page.setContent('');
+ const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');
+ expect(distillSnapshot(snapshot)).toBe('');
+ });
+
+ it('should replace meta content attr that specifies charset', async ({ page, server, toImpl, snapshotter }) => {
+ await page.goto(server.EMPTY_PAGE);
+ await page.setContent('');
+ const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');
+ expect(distillSnapshot(snapshot)).toBe('');
+ });
+
it('should respect subresource CSSOM change', async ({ page, server, toImpl, snapshotter }) => {
await page.goto(server.EMPTY_PAGE);
await page.route('**/style.css', route => {