chore: make NodeSnapshot type recursive and more (#30619)
Also, deviceDescriptors are now imported with ESM import instead of require()
This commit is contained in:
parent
4b5ecd2d79
commit
cf3ff6531a
|
|
@ -15,7 +15,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
import type { Devices } from './types';
|
||||||
* @type {import('./types').Devices}
|
|
||||||
*/
|
import deviceDescriptorsSource from './deviceDescriptorsSource.json';
|
||||||
module.exports = require("./deviceDescriptorsSource.json")
|
|
||||||
|
export const deviceDescriptors = deviceDescriptorsSource as Devices;
|
||||||
|
|
@ -26,7 +26,7 @@ import { Dispatcher } from './dispatcher';
|
||||||
import { yazl, yauzl } from '../../zipBundle';
|
import { yazl, yauzl } from '../../zipBundle';
|
||||||
import { ZipFile } from '../../utils/zipFile';
|
import { ZipFile } from '../../utils/zipFile';
|
||||||
import type * as har from '@trace/har';
|
import type * as har from '@trace/har';
|
||||||
import type { HeadersArray, Devices } from '../types';
|
import type { HeadersArray } from '../types';
|
||||||
import { JsonPipeDispatcher } from '../dispatchers/jsonPipeDispatcher';
|
import { JsonPipeDispatcher } from '../dispatchers/jsonPipeDispatcher';
|
||||||
import { WebSocketTransport } from '../transport';
|
import { WebSocketTransport } from '../transport';
|
||||||
import { SocksInterceptor } from '../socksInterceptor';
|
import { SocksInterceptor } from '../socksInterceptor';
|
||||||
|
|
@ -40,6 +40,7 @@ import type http from 'http';
|
||||||
import type { Playwright } from '../playwright';
|
import type { Playwright } from '../playwright';
|
||||||
import { SdkObject } from '../../server/instrumentation';
|
import { SdkObject } from '../../server/instrumentation';
|
||||||
import { serializeClientSideCallMetadata } from '../../utils';
|
import { serializeClientSideCallMetadata } from '../../utils';
|
||||||
|
import { deviceDescriptors as descriptors } from '../deviceDescriptors';
|
||||||
|
|
||||||
export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.LocalUtilsChannel, RootDispatcher> implements channels.LocalUtilsChannel {
|
export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.LocalUtilsChannel, RootDispatcher> implements channels.LocalUtilsChannel {
|
||||||
_type_LocalUtils: boolean;
|
_type_LocalUtils: boolean;
|
||||||
|
|
@ -53,7 +54,6 @@ export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.
|
||||||
|
|
||||||
constructor(scope: RootDispatcher, playwright: Playwright) {
|
constructor(scope: RootDispatcher, playwright: Playwright) {
|
||||||
const localUtils = new SdkObject(playwright, 'localUtils', 'localUtils');
|
const localUtils = new SdkObject(playwright, 'localUtils', 'localUtils');
|
||||||
const descriptors = require('../deviceDescriptors') as Devices;
|
|
||||||
const deviceDescriptors = Object.entries(descriptors)
|
const deviceDescriptors = Object.entries(descriptors)
|
||||||
.map(([name, descriptor]) => ({ name, descriptor }));
|
.map(([name, descriptor]) => ({ name, descriptor }));
|
||||||
super(scope, localUtils, 'LocalUtils', {
|
super(scope, localUtils, 'LocalUtils', {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import type { Action } from './recorderActions';
|
||||||
import type { MouseClickOptions } from './utils';
|
import type { MouseClickOptions } from './utils';
|
||||||
import { toModifiers } from './utils';
|
import { toModifiers } from './utils';
|
||||||
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
||||||
const deviceDescriptors = require('../deviceDescriptorsSource.json');
|
import { deviceDescriptors } from '../deviceDescriptors';
|
||||||
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
||||||
|
|
||||||
type CSharpLanguageMode = 'library' | 'mstest' | 'nunit';
|
type CSharpLanguageMode = 'library' | 'mstest' | 'nunit';
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import type { ActionInContext } from './codeGenerator';
|
||||||
import type { Action } from './recorderActions';
|
import type { Action } from './recorderActions';
|
||||||
import type { MouseClickOptions } from './utils';
|
import type { MouseClickOptions } from './utils';
|
||||||
import { toModifiers } from './utils';
|
import { toModifiers } from './utils';
|
||||||
const deviceDescriptors = require('../deviceDescriptorsSource.json');
|
import { deviceDescriptors } from '../deviceDescriptors';
|
||||||
import { JavaScriptFormatter } from './javascript';
|
import { JavaScriptFormatter } from './javascript';
|
||||||
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
||||||
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import type { ActionInContext } from './codeGenerator';
|
||||||
import type { Action } from './recorderActions';
|
import type { Action } from './recorderActions';
|
||||||
import type { MouseClickOptions } from './utils';
|
import type { MouseClickOptions } from './utils';
|
||||||
import { toModifiers } from './utils';
|
import { toModifiers } from './utils';
|
||||||
const deviceDescriptors = require('../deviceDescriptorsSource.json');
|
import { deviceDescriptors } from '../deviceDescriptors';
|
||||||
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
import { escapeWithQuotes } from '../../utils/isomorphic/stringUtils';
|
||||||
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import type { Action } from './recorderActions';
|
||||||
import type { MouseClickOptions } from './utils';
|
import type { MouseClickOptions } from './utils';
|
||||||
import { toModifiers } from './utils';
|
import { toModifiers } from './utils';
|
||||||
import { escapeWithQuotes, toSnakeCase } from '../../utils/isomorphic/stringUtils';
|
import { escapeWithQuotes, toSnakeCase } from '../../utils/isomorphic/stringUtils';
|
||||||
const deviceDescriptors = require('../deviceDescriptorsSource.json');
|
import { deviceDescriptors } from '../deviceDescriptors';
|
||||||
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
||||||
|
|
||||||
export class PythonLanguageGenerator implements LanguageGenerator {
|
export class PythonLanguageGenerator implements LanguageGenerator {
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
|
||||||
return checkAndReturn(result);
|
return checkAndReturn(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
const visitStyleSheet = (sheet: CSSStyleSheet) => {
|
const visitStyleSheet = (sheet: CSSStyleSheet): { equals: boolean, n: NodeSnapshot } => {
|
||||||
const data = ensureCachedData(sheet);
|
const data = ensureCachedData(sheet);
|
||||||
const oldCSSText = data.cssText;
|
const oldCSSText = data.cssText;
|
||||||
const cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet, true /* forceText */)!;
|
const cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet, true /* forceText */)!;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,15 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { FrameSnapshot, NodeSnapshot, RenderedFrameSnapshot, ResourceSnapshot } from '@trace/snapshot';
|
import type { FrameSnapshot, NodeNameAttributesChildNodesSnapshot, NodeSnapshot, RenderedFrameSnapshot, ResourceSnapshot, SubtreeReferenceSnapshot } from '@trace/snapshot';
|
||||||
|
|
||||||
|
function isNodeNameAttributesChildNodesSnapshot(n: NodeSnapshot): n is NodeNameAttributesChildNodesSnapshot {
|
||||||
|
return Array.isArray(n) && typeof n[0] === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSubtreeReferenceSnapshot(n: NodeSnapshot): n is SubtreeReferenceSnapshot {
|
||||||
|
return Array.isArray(n) && Array.isArray(n[0]);
|
||||||
|
}
|
||||||
|
|
||||||
export class SnapshotRenderer {
|
export class SnapshotRenderer {
|
||||||
private _snapshots: FrameSnapshot[];
|
private _snapshots: FrameSnapshot[];
|
||||||
|
|
@ -54,7 +62,7 @@ export class SnapshotRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(n as any)._string) {
|
if (!(n as any)._string) {
|
||||||
if (Array.isArray(n[0])) {
|
if (isSubtreeReferenceSnapshot(n)) {
|
||||||
// Node reference.
|
// Node reference.
|
||||||
const referenceIndex = snapshotIndex - n[0][0];
|
const referenceIndex = snapshotIndex - n[0][0];
|
||||||
if (referenceIndex >= 0 && referenceIndex <= snapshotIndex) {
|
if (referenceIndex >= 0 && referenceIndex <= snapshotIndex) {
|
||||||
|
|
@ -63,12 +71,13 @@ export class SnapshotRenderer {
|
||||||
if (nodeIndex >= 0 && nodeIndex < nodes.length)
|
if (nodeIndex >= 0 && nodeIndex < nodes.length)
|
||||||
(n as any)._string = visit(nodes[nodeIndex], referenceIndex, parentTag, parentAttrs);
|
(n as any)._string = visit(nodes[nodeIndex], referenceIndex, parentTag, parentAttrs);
|
||||||
}
|
}
|
||||||
} else if (typeof n[0] === 'string') {
|
} else if (isNodeNameAttributesChildNodesSnapshot(n)) {
|
||||||
|
const [name, nodeAttrs, ...children] = n;
|
||||||
// Element node.
|
// Element node.
|
||||||
// Note that <noscript> will not be rendered by default in the trace viewer, because
|
// Note that <noscript> will not be rendered by default in the trace viewer, because
|
||||||
// JS is enabled. So rename it to <x-noscript>.
|
// JS is enabled. So rename it to <x-noscript>.
|
||||||
const nodeName = n[0] === 'NOSCRIPT' ? 'X-NOSCRIPT' : n[0];
|
const nodeName = name === 'NOSCRIPT' ? 'X-NOSCRIPT' : name;
|
||||||
const attrs = Object.entries(n[1] || {});
|
const attrs = Object.entries(nodeAttrs || {});
|
||||||
const builder: string[] = [];
|
const builder: string[] = [];
|
||||||
builder.push('<', nodeName);
|
builder.push('<', nodeName);
|
||||||
const kCurrentSrcAttribute = '__playwright_current_src__';
|
const kCurrentSrcAttribute = '__playwright_current_src__';
|
||||||
|
|
@ -101,8 +110,8 @@ export class SnapshotRenderer {
|
||||||
builder.push(' ', attrName, '="', escapeAttribute(attrValue), '"');
|
builder.push(' ', attrName, '="', escapeAttribute(attrValue), '"');
|
||||||
}
|
}
|
||||||
builder.push('>');
|
builder.push('>');
|
||||||
for (let i = 2; i < n.length; i++)
|
for (const child of children)
|
||||||
builder.push(visit(n[i], snapshotIndex, nodeName, attrs));
|
builder.push(visit(child, snapshotIndex, nodeName, attrs));
|
||||||
if (!autoClosing.has(nodeName))
|
if (!autoClosing.has(nodeName))
|
||||||
builder.push('</', nodeName, '>');
|
builder.push('</', nodeName, '>');
|
||||||
(n as any)._string = builder.join('');
|
(n as any)._string = builder.join('');
|
||||||
|
|
@ -200,9 +209,10 @@ function snapshotNodes(snapshot: FrameSnapshot): NodeSnapshot[] {
|
||||||
const visit = (n: NodeSnapshot) => {
|
const visit = (n: NodeSnapshot) => {
|
||||||
if (typeof n === 'string') {
|
if (typeof n === 'string') {
|
||||||
nodes.push(n);
|
nodes.push(n);
|
||||||
} else if (typeof n[0] === 'string') {
|
} else if (isNodeNameAttributesChildNodesSnapshot(n)) {
|
||||||
for (let i = 2; i < n.length; i++)
|
const [,, ...children] = n;
|
||||||
visit(n[i]);
|
for (const child of children)
|
||||||
|
visit(child);
|
||||||
nodes.push(n);
|
nodes.push(n);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,18 @@ import type { Entry as HAREntry } from './har';
|
||||||
|
|
||||||
export type ResourceSnapshot = HAREntry;
|
export type ResourceSnapshot = HAREntry;
|
||||||
|
|
||||||
export type NodeSnapshot =
|
// Text node.
|
||||||
// Text node.
|
export type TextNodeSnapshot = string;
|
||||||
string |
|
// Subtree reference, "x snapshots ago, node #y". Could point to a text node.
|
||||||
// Subtree reference, "x snapshots ago, node #y". Could point to a text node.
|
// Only nodes that are not references are counted, starting from zero, using post-order traversal.
|
||||||
// Only nodes that are not references are counted, starting from zero, using post-order traversal.
|
export type SubtreeReferenceSnapshot = [ [number, number] ];
|
||||||
[ [number, number] ] |
|
// Node name, and optional attributes and child nodes.
|
||||||
// Just node name.
|
export type NodeNameAttributesChildNodesSnapshot = [ string ] | [ string, Record<string, string>, ...NodeSnapshot[] ];
|
||||||
[ string ] |
|
|
||||||
// Node name, attributes, child nodes.
|
|
||||||
// Unfortunately, we cannot make this type definition recursive, therefore "any".
|
|
||||||
[ string, { [attr: string]: string }, ...any ];
|
|
||||||
|
|
||||||
|
export type NodeSnapshot =
|
||||||
|
TextNodeSnapshot |
|
||||||
|
SubtreeReferenceSnapshot |
|
||||||
|
NodeNameAttributesChildNodesSnapshot;
|
||||||
|
|
||||||
export type ResourceOverride = {
|
export type ResourceOverride = {
|
||||||
url: string,
|
url: string,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const devices = require('../../packages/playwright-core/lib/server/deviceDescriptors');
|
const devices = require('../../packages/playwright-core/lib/server/deviceDescriptorsSource.json');
|
||||||
const md = require('../markdown');
|
const md = require('../markdown');
|
||||||
const docs = require('../doclint/documentation');
|
const docs = require('../doclint/documentation');
|
||||||
const PROJECT_DIR = path.join(__dirname, '..', '..');
|
const PROJECT_DIR = path.join(__dirname, '..', '..');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue