playwriter 0.0.29 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,117 @@
1
+ # Styles API Reference
2
+
3
+ The getStylesForLocator function inspects CSS styles applied to an element, similar to browser DevTools "Styles" panel.
4
+
5
+ ## Types
6
+
7
+ ```ts
8
+ import type { CDPSession } from './cdp-session.js';
9
+ import type { Locator } from 'playwright-core';
10
+ export interface StyleSource {
11
+ url: string;
12
+ line: number;
13
+ column: number;
14
+ }
15
+ export type StyleDeclarations = Record<string, string>;
16
+ export interface StyleRule {
17
+ selector: string;
18
+ source: StyleSource | null;
19
+ origin: 'regular' | 'user-agent' | 'injected' | 'inspector';
20
+ declarations: StyleDeclarations;
21
+ inheritedFrom: string | null;
22
+ }
23
+ export interface StylesResult {
24
+ element: string;
25
+ inlineStyle: StyleDeclarations | null;
26
+ rules: StyleRule[];
27
+ }
28
+ export declare function getStylesForLocator({ locator, cdp, includeUserAgentStyles, }: {
29
+ locator: Locator;
30
+ cdp: CDPSession;
31
+ includeUserAgentStyles?: boolean;
32
+ }): Promise<StylesResult>;
33
+ export declare function formatStylesAsText(styles: StylesResult): string;
34
+ ```
35
+
36
+ ## Examples
37
+
38
+ ```ts
39
+ import { page, getStylesForLocator, formatStylesAsText, console } from './debugger-examples-types.js'
40
+
41
+ // Example: Get styles for an element and display them
42
+ async function getElementStyles() {
43
+ const loc = page.locator('.my-button')
44
+ const styles = await getStylesForLocator({ locator: loc })
45
+ console.log(formatStylesAsText(styles))
46
+ }
47
+
48
+ // Example: Inspect computed styles for a specific element
49
+ async function inspectButtonStyles() {
50
+ const button = page.getByRole('button', { name: 'Submit' })
51
+ const styles = await getStylesForLocator({ locator: button })
52
+
53
+ console.log('Element:', styles.element)
54
+
55
+ if (styles.inlineStyle) {
56
+ console.log('Inline styles:', styles.inlineStyle)
57
+ }
58
+
59
+ for (const rule of styles.rules) {
60
+ console.log(`${rule.selector}: ${JSON.stringify(rule.declarations)}`)
61
+ if (rule.source) {
62
+ console.log(` Source: ${rule.source.url}:${rule.source.line}`)
63
+ }
64
+ }
65
+ }
66
+
67
+ // Example: Include browser default (user-agent) styles
68
+ async function getStylesWithUserAgent() {
69
+ const loc = page.locator('input[type="text"]')
70
+ const styles = await getStylesForLocator({
71
+ locator: loc,
72
+ includeUserAgentStyles: true,
73
+ })
74
+ console.log(formatStylesAsText(styles))
75
+ }
76
+
77
+ // Example: Find where a CSS property is defined
78
+ async function findPropertySource() {
79
+ const loc = page.locator('.card')
80
+ const styles = await getStylesForLocator({ locator: loc })
81
+
82
+ const backgroundRule = styles.rules.find((r) => 'background-color' in r.declarations)
83
+ if (backgroundRule) {
84
+ console.log('background-color defined by:', backgroundRule.selector)
85
+ if (backgroundRule.source) {
86
+ console.log(` at ${backgroundRule.source.url}:${backgroundRule.source.line}`)
87
+ }
88
+ }
89
+ }
90
+
91
+ // Example: Check inherited styles
92
+ async function checkInheritedStyles() {
93
+ const loc = page.locator('.nested-text')
94
+ const styles = await getStylesForLocator({ locator: loc })
95
+
96
+ const inheritedRules = styles.rules.filter((r) => r.inheritedFrom)
97
+ for (const rule of inheritedRules) {
98
+ console.log(`Inherited from ${rule.inheritedFrom}: ${rule.selector}`)
99
+ console.log(' Properties:', rule.declarations)
100
+ }
101
+ }
102
+
103
+ // Example: Compare styles between two elements
104
+ async function compareStyles() {
105
+ const primary = await getStylesForLocator({ locator: page.locator('.btn-primary') })
106
+ const secondary = await getStylesForLocator({ locator: page.locator('.btn-secondary') })
107
+
108
+ console.log('Primary button:')
109
+ console.log(formatStylesAsText(primary))
110
+
111
+ console.log('Secondary button:')
112
+ console.log(formatStylesAsText(secondary))
113
+ }
114
+
115
+ export { getElementStyles, inspectButtonStyles, getStylesWithUserAgent, findPropertySource, checkInheritedStyles, compareStyles }
116
+
117
+ ```
@@ -0,0 +1,8 @@
1
+ declare function getElementStyles(): Promise<void>;
2
+ declare function inspectButtonStyles(): Promise<void>;
3
+ declare function getStylesWithUserAgent(): Promise<void>;
4
+ declare function findPropertySource(): Promise<void>;
5
+ declare function checkInheritedStyles(): Promise<void>;
6
+ declare function compareStyles(): Promise<void>;
7
+ export { getElementStyles, inspectButtonStyles, getStylesWithUserAgent, findPropertySource, checkInheritedStyles, compareStyles };
8
+ //# sourceMappingURL=styles-examples.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles-examples.d.ts","sourceRoot":"","sources":["../src/styles-examples.ts"],"names":[],"mappings":"AAGA,iBAAe,gBAAgB,kBAI9B;AAGD,iBAAe,mBAAmB,kBAgBjC;AAGD,iBAAe,sBAAsB,kBAOpC;AAGD,iBAAe,kBAAkB,kBAWhC;AAGD,iBAAe,oBAAoB,kBASlC;AAGD,iBAAe,aAAa,kBAS3B;AAED,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,CAAA"}
@@ -0,0 +1,64 @@
1
+ import { page, getStylesForLocator, formatStylesAsText, console } from './debugger-examples-types.js';
2
+ // Example: Get styles for an element and display them
3
+ async function getElementStyles() {
4
+ const loc = page.locator('.my-button');
5
+ const styles = await getStylesForLocator({ locator: loc });
6
+ console.log(formatStylesAsText(styles));
7
+ }
8
+ // Example: Inspect computed styles for a specific element
9
+ async function inspectButtonStyles() {
10
+ const button = page.getByRole('button', { name: 'Submit' });
11
+ const styles = await getStylesForLocator({ locator: button });
12
+ console.log('Element:', styles.element);
13
+ if (styles.inlineStyle) {
14
+ console.log('Inline styles:', styles.inlineStyle);
15
+ }
16
+ for (const rule of styles.rules) {
17
+ console.log(`${rule.selector}: ${JSON.stringify(rule.declarations)}`);
18
+ if (rule.source) {
19
+ console.log(` Source: ${rule.source.url}:${rule.source.line}`);
20
+ }
21
+ }
22
+ }
23
+ // Example: Include browser default (user-agent) styles
24
+ async function getStylesWithUserAgent() {
25
+ const loc = page.locator('input[type="text"]');
26
+ const styles = await getStylesForLocator({
27
+ locator: loc,
28
+ includeUserAgentStyles: true,
29
+ });
30
+ console.log(formatStylesAsText(styles));
31
+ }
32
+ // Example: Find where a CSS property is defined
33
+ async function findPropertySource() {
34
+ const loc = page.locator('.card');
35
+ const styles = await getStylesForLocator({ locator: loc });
36
+ const backgroundRule = styles.rules.find((r) => 'background-color' in r.declarations);
37
+ if (backgroundRule) {
38
+ console.log('background-color defined by:', backgroundRule.selector);
39
+ if (backgroundRule.source) {
40
+ console.log(` at ${backgroundRule.source.url}:${backgroundRule.source.line}`);
41
+ }
42
+ }
43
+ }
44
+ // Example: Check inherited styles
45
+ async function checkInheritedStyles() {
46
+ const loc = page.locator('.nested-text');
47
+ const styles = await getStylesForLocator({ locator: loc });
48
+ const inheritedRules = styles.rules.filter((r) => r.inheritedFrom);
49
+ for (const rule of inheritedRules) {
50
+ console.log(`Inherited from ${rule.inheritedFrom}: ${rule.selector}`);
51
+ console.log(' Properties:', rule.declarations);
52
+ }
53
+ }
54
+ // Example: Compare styles between two elements
55
+ async function compareStyles() {
56
+ const primary = await getStylesForLocator({ locator: page.locator('.btn-primary') });
57
+ const secondary = await getStylesForLocator({ locator: page.locator('.btn-secondary') });
58
+ console.log('Primary button:');
59
+ console.log(formatStylesAsText(primary));
60
+ console.log('Secondary button:');
61
+ console.log(formatStylesAsText(secondary));
62
+ }
63
+ export { getElementStyles, inspectButtonStyles, getStylesWithUserAgent, findPropertySource, checkInheritedStyles, compareStyles };
64
+ //# sourceMappingURL=styles-examples.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles-examples.js","sourceRoot":"","sources":["../src/styles-examples.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "playwriter",
3
3
  "description": "",
4
- "version": "0.0.29",
4
+ "version": "0.0.32",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "repository": "https://github.com/remorses/playwriter",
9
9
  "scripts": {
10
- "build": "rm -rf dist *.tsbuildinfo && mkdir dist && cp src/resource.md src/prompt.md src/debugger-examples.ts dist/ && bun scripts/build-selector-generator.ts && bun scripts/build-bippy.ts && tsc",
10
+ "build": "rm -rf dist *.tsbuildinfo && mkdir dist && bun scripts/build-selector-generator.ts && bun scripts/build-bippy.ts && tsc && bun scripts/build-resources.ts",
11
11
  "prepublishOnly": "pnpm build",
12
12
  "watch": "tsc -w",
13
13
  "typecheck": "tsc --noEmit",
package/src/cdp-relay.ts CHANGED
@@ -271,14 +271,17 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
271
271
  const contextCreatedPromise = new Promise<void>((resolve) => {
272
272
  const handler = ({ event }: { event: CDPEventBase }) => {
273
273
  if (event.method === 'Runtime.executionContextCreated' && event.sessionId === sessionId) {
274
- clearTimeout(timeout)
275
- emitter.off('cdp:event', handler)
276
- resolve()
274
+ const params = event.params as Protocol.Runtime.ExecutionContextCreatedEvent | undefined
275
+ if (params?.context?.auxData?.isDefault === true) {
276
+ clearTimeout(timeout)
277
+ emitter.off('cdp:event', handler)
278
+ resolve()
279
+ }
277
280
  }
278
281
  }
279
282
  const timeout = setTimeout(() => {
280
283
  emitter.off('cdp:event', handler)
281
- logger?.log(chalk.yellow(`IMPORTANT: Runtime.enable timed out waiting for executionContextCreated (sessionId: ${sessionId}). This may cause pages to not be visible immediately.`))
284
+ logger?.log(chalk.yellow(`IMPORTANT: Runtime.enable timed out waiting for main frame executionContextCreated (sessionId: ${sessionId}). This may cause pages to not be visible immediately.`))
282
285
  resolve()
283
286
  }, 3000)
284
287
  emitter.on('cdp:event', handler)
@@ -1,10 +1,13 @@
1
- import type { Page } from 'playwright-core'
1
+ import type { Page, Locator } from 'playwright-core'
2
2
  import type { CDPSession } from './cdp-session.js'
3
3
  import type { Debugger } from './debugger.js'
4
4
  import type { Editor } from './editor.js'
5
+ import type { StylesResult } from './styles.js'
5
6
 
6
7
  export declare const page: Page
7
8
  export declare const getCDPSession: (options: { page: Page }) => Promise<CDPSession>
8
9
  export declare const createDebugger: (options: { cdp: CDPSession }) => Debugger
9
10
  export declare const createEditor: (options: { cdp: CDPSession }) => Editor
11
+ export declare const getStylesForLocator: (options: { locator: Locator; includeUserAgentStyles?: boolean }) => Promise<StylesResult>
12
+ export declare const formatStylesAsText: (styles: StylesResult) => string
10
13
  export declare const console: { log: (...args: unknown[]) => void }
package/src/mcp.ts CHANGED
@@ -431,72 +431,48 @@ const promptContent =
431
431
  fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'prompt.md'), 'utf-8') +
432
432
  `\n\nfor debugging internal playwriter errors, check playwriter relay server logs at: ${LOG_FILE_PATH}`
433
433
 
434
- server.resource('debugger-api', 'playwriter://debugger-api', { mimeType: 'text/plain' }, async () => {
434
+ server.resource('debugger-api', 'https://playwriter.dev/resources/debugger-api.md', { mimeType: 'text/plain' }, async () => {
435
435
  const packageJsonPath = require.resolve('playwriter/package.json')
436
- const distDir = path.join(path.dirname(packageJsonPath), 'dist')
437
-
438
- const debuggerTypes = fs
439
- .readFileSync(path.join(distDir, 'debugger.d.ts'), 'utf-8')
440
- .replace(/\/\/# sourceMappingURL=.*$/gm, '')
441
- .trim()
442
- const debuggerExamples = fs.readFileSync(path.join(distDir, 'debugger-examples.ts'), 'utf-8')
436
+ const packageDir = path.dirname(packageJsonPath)
437
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'debugger-api.md'), 'utf-8')
443
438
 
444
439
  return {
445
440
  contents: [
446
441
  {
447
- uri: 'playwriter://debugger-api',
448
- text: dedent`
449
- # Debugger API Reference
450
-
451
- ## Types
452
-
453
- \`\`\`ts
454
- ${debuggerTypes}
455
- \`\`\`
456
-
457
- ## Examples
458
-
459
- \`\`\`ts
460
- ${debuggerExamples}
461
- \`\`\`
462
- `,
442
+ uri: 'https://playwriter.dev/resources/debugger-api.md',
443
+ text: content,
463
444
  mimeType: 'text/plain',
464
445
  },
465
446
  ],
466
447
  }
467
448
  })
468
449
 
469
- server.resource('editor-api', 'playwriter://editor-api', { mimeType: 'text/plain' }, async () => {
450
+ server.resource('editor-api', 'https://playwriter.dev/resources/editor-api.md', { mimeType: 'text/plain' }, async () => {
470
451
  const packageJsonPath = require.resolve('playwriter/package.json')
471
- const distDir = path.join(path.dirname(packageJsonPath), 'dist')
472
-
473
- const editorTypes = fs
474
- .readFileSync(path.join(distDir, 'editor.d.ts'), 'utf-8')
475
- .replace(/\/\/# sourceMappingURL=.*$/gm, '')
476
- .trim()
477
- const editorExamples = fs.readFileSync(path.join(distDir, 'editor-examples.ts'), 'utf-8')
452
+ const packageDir = path.dirname(packageJsonPath)
453
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'editor-api.md'), 'utf-8')
478
454
 
479
455
  return {
480
456
  contents: [
481
457
  {
482
- uri: 'playwriter://editor-api',
483
- text: dedent`
484
- # Editor API Reference
485
-
486
- The Editor class provides a Claude Code-like interface for viewing and editing web page scripts at runtime.
487
-
488
- ## Types
489
-
490
- \`\`\`ts
491
- ${editorTypes}
492
- \`\`\`
458
+ uri: 'https://playwriter.dev/resources/editor-api.md',
459
+ text: content,
460
+ mimeType: 'text/plain',
461
+ },
462
+ ],
463
+ }
464
+ })
493
465
 
494
- ## Examples
466
+ server.resource('styles-api', 'https://playwriter.dev/resources/styles-api.md', { mimeType: 'text/plain' }, async () => {
467
+ const packageJsonPath = require.resolve('playwriter/package.json')
468
+ const packageDir = path.dirname(packageJsonPath)
469
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'styles-api.md'), 'utf-8')
495
470
 
496
- \`\`\`ts
497
- ${editorExamples}
498
- \`\`\`
499
- `,
471
+ return {
472
+ contents: [
473
+ {
474
+ uri: 'https://playwriter.dev/resources/styles-api.md',
475
+ text: content,
500
476
  mimeType: 'text/plain',
501
477
  },
502
478
  ],
@@ -839,13 +815,13 @@ server.tool(
839
815
  server.tool(
840
816
  'reset',
841
817
  dedent`
842
- Recreates the CDP connection and resets the browser/page/context. Use this when the MCP stops responding, you get connection errors, assertion failures, page closed, or timeout issues.
818
+ Recreates the CDP connection and resets the browser/page/context. Use this when the MCP stops responding, you get connection errors, if there are no pages in context, assertion failures, page closed, or other issues.
843
819
 
844
820
  After calling this tool, the page and context variables are automatically updated in the execution environment.
845
821
 
846
- IMPORTANT: this completely resets the execution context, removing any custom properties you may have added to the global scope AND clearing all keys from the \`state\` object. Only \`page\`, \`context\`, \`state\` (empty), \`console\`, and utility functions will remain.
822
+ This tools also removes any custom properties you may have added to the global scope AND clearing all keys from the \`state\` object. Only \`page\`, \`context\`, \`state\` (empty), \`console\`, and utility functions will remain.
847
823
 
848
- if playwright always returns all pages as about:blank urls and evaluate does not work you should aks the user to restart Chrome. This is a known Chrome bug.
824
+ if playwright always returns all pages as about:blank urls and evaluate does not work you should ask the user to restart Chrome. This is a known Chrome bug.
849
825
  `,
850
826
  {},
851
827
  async () => {
package/src/prompt.md CHANGED
@@ -95,82 +95,13 @@ you have access to some functions in addition to playwright methods:
95
95
  - `page`: the page object to create the session for
96
96
  - Returns: `{ send(method, params?), on(event, callback), off(event, callback) }`
97
97
  - Example: `const cdp = await getCDPSession({ page }); const metrics = await cdp.send('Page.getLayoutMetrics');`
98
- - `createDebugger({ cdp })`: creates a Debugger instance for setting breakpoints, stepping, and inspecting variables. Works with browser JS or Node.js (--inspect).
99
- - `cdp`: a CDPSession from `getCDPSession`
100
- - Methods: `enable()`, `setBreakpoint({ file, line, condition? })`, `deleteBreakpoint({ breakpointId })`, `listBreakpoints()`, `listScripts({ search? })`, `evaluate({ expression })`, `inspectLocalVariables()`, `getLocation()`, `stepOver()`, `stepInto()`, `stepOut()`, `resume()`, `isPaused()`, `setXHRBreakpoint({ url })`, `removeXHRBreakpoint({ url })`, `listXHRBreakpoints()`, `setBlackboxPatterns({ patterns })`, `addBlackboxPattern({ pattern })`, `removeBlackboxPattern({ pattern })`, `listBlackboxPatterns()`
101
- - Example:
102
- ```js
103
- const cdp = await getCDPSession({ page }); const dbg = createDebugger({ cdp }); await dbg.enable();
104
- console.log(dbg.listScripts({ search: 'app' }));
105
- await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 });
106
- // conditional breakpoint - only pause when userId is 123
107
- await dbg.setBreakpoint({ file: 'app.js', line: 50, condition: 'userId === 123' });
108
- // XHR breakpoint - pause when fetch/XHR URL contains '/api'
109
- await dbg.setXHRBreakpoint({ url: '/api' });
110
- // blackbox framework code when stepping
111
- await dbg.setBlackboxPatterns({ patterns: ['node_modules/'] });
112
- // user triggers the code, then:
113
- if (dbg.isPaused()) { console.log(await dbg.getLocation()); console.log(await dbg.inspectLocalVariables()); await dbg.resume(); }
114
- ```
115
- - `createEditor({ cdp })`: creates an Editor instance for viewing and live-editing page scripts and CSS stylesheets. Provides a Claude Code-like interface.
116
- - `cdp`: a CDPSession from `getCDPSession`
117
- - Methods: `enable()`, `list({ pattern? })`, `read({ url, offset?, limit? })`, `edit({ url, oldString, newString, dryRun? })`, `grep({ regex, pattern? })`, `write({ url, content, dryRun? })`
118
- - `pattern` parameter: regex to filter URLs (e.g. `/\.js/` for JS files, `/\.css/` for CSS files)
119
- - Inline scripts get `inline://` URLs, inline styles get `inline-css://` URLs - use grep() to find them by content
120
- - Example:
121
- ```js
122
- const cdp = await getCDPSession({ page }); const editor = createEditor({ cdp }); await editor.enable();
123
- // list all scripts and stylesheets
124
- console.log(editor.list());
125
- // list only JS files
126
- console.log(editor.list({ pattern: /\.js/ }));
127
- // list only CSS files
128
- console.log(editor.list({ pattern: /\.css/ }));
129
- // read a script with line numbers (like Claude Code Read tool)
130
- const { content, totalLines } = await editor.read({ url: 'https://example.com/app.js', offset: 0, limit: 50 });
131
- console.log(content);
132
- // edit a script (like Claude Code Edit tool) - exact string replacement
133
- await editor.edit({ url: 'https://example.com/app.js', oldString: 'DEBUG = false', newString: 'DEBUG = true' });
134
- // edit CSS
135
- await editor.edit({ url: 'https://example.com/styles.css', oldString: 'color: red', newString: 'color: blue' });
136
- // search across all scripts (like Grep) - useful for finding inline scripts
137
- const matches = await editor.grep({ regex: /myFunction/ });
138
- if (matches.length > 0) { await editor.edit({ url: matches[0].url, oldString: 'return false', newString: 'return true' }); }
139
- // search only in CSS files
140
- const cssMatches = await editor.grep({ regex: /background-color/, pattern: /\.css/ });
141
- ```
142
- - `getStylesForLocator({ locator, includeUserAgentStyles? })`: gets the CSS styles applied to an element, similar to browser DevTools "Styles" panel.
143
- - `locator`: a Playwright Locator for the element to inspect
144
- - `includeUserAgentStyles`: (optional, default: false) include browser default styles
145
- - Returns: `StylesResult` object with:
146
- - `element`: string description of the element (e.g. `div#main.container`)
147
- - `inlineStyle`: object of `{ property: value }` inline styles, or null
148
- - `rules`: array of CSS rules that apply to this element, each with:
149
- - `selector`: the CSS selector that matched
150
- - `source`: `{ url, line, column }` location in the stylesheet, or null
151
- - `origin`: `"regular"` | `"user-agent"` | `"injected"` | `"inspector"`
152
- - `declarations`: object of `{ property: value }` (values include `!important` if applicable)
153
- - `inheritedFrom`: element description if inherited (e.g. `body`), or null for direct matches
154
- - Example:
155
- ```js
156
- const loc = page.locator('.my-button');
157
- const styles = await getStylesForLocator({ locator: loc });
158
- console.log(formatStylesAsText(styles));
159
- ```
160
- - `formatStylesAsText(styles)`: formats a `StylesResult` object as human-readable text. Use this to display styles in a readable format.
98
+ - `createDebugger({ cdp })`: creates a Debugger instance for setting breakpoints, stepping, and inspecting variables. Read the `https://playwriter.dev/resources/debugger-api.md` resource for full API docs and examples.
99
+ - `createEditor({ cdp })`: creates an Editor instance for viewing and live-editing page scripts and CSS stylesheets. Read the `https://playwriter.dev/resources/editor-api.md` resource for full API docs and examples.
100
+ - `getStylesForLocator({ locator })`: gets the CSS styles applied to an element, similar to browser DevTools "Styles" panel. Read the `https://playwriter.dev/resources/styles-api.md` resource for full API docs and examples.
161
101
  - `getReactSource({ locator })`: gets the React component source location (file, line, column) for an element.
162
102
  - `locator`: a Playwright Locator or ElementHandle for the element to inspect
163
103
  - Returns: `{ fileName, lineNumber, columnNumber, componentName }` or `null` if not found
164
- - **Important**: Only works on **local dev servers** (localhost with Vite, Next.js, CRA in dev mode). Production builds strip source info. The JSX transform must have `development: true` to include `_debugSource`.
165
- - Example:
166
- ```js
167
- const loc = page.locator('.my-component');
168
- const source = await getReactSource({ locator: loc });
169
- if (source) {
170
- console.log(`Component: ${source.componentName}`);
171
- console.log(`File: ${source.fileName}:${source.lineNumber}:${source.columnNumber}`);
172
- }
173
- ```
104
+ - **Important**: Only works on **local dev servers** (localhost with Vite, Next.js, CRA in dev mode). Production builds strip source info.
174
105
 
175
106
  example:
176
107
 
@@ -0,0 +1,77 @@
1
+ import { page, getStylesForLocator, formatStylesAsText, console } from './debugger-examples-types.js'
2
+
3
+ // Example: Get styles for an element and display them
4
+ async function getElementStyles() {
5
+ const loc = page.locator('.my-button')
6
+ const styles = await getStylesForLocator({ locator: loc })
7
+ console.log(formatStylesAsText(styles))
8
+ }
9
+
10
+ // Example: Inspect computed styles for a specific element
11
+ async function inspectButtonStyles() {
12
+ const button = page.getByRole('button', { name: 'Submit' })
13
+ const styles = await getStylesForLocator({ locator: button })
14
+
15
+ console.log('Element:', styles.element)
16
+
17
+ if (styles.inlineStyle) {
18
+ console.log('Inline styles:', styles.inlineStyle)
19
+ }
20
+
21
+ for (const rule of styles.rules) {
22
+ console.log(`${rule.selector}: ${JSON.stringify(rule.declarations)}`)
23
+ if (rule.source) {
24
+ console.log(` Source: ${rule.source.url}:${rule.source.line}`)
25
+ }
26
+ }
27
+ }
28
+
29
+ // Example: Include browser default (user-agent) styles
30
+ async function getStylesWithUserAgent() {
31
+ const loc = page.locator('input[type="text"]')
32
+ const styles = await getStylesForLocator({
33
+ locator: loc,
34
+ includeUserAgentStyles: true,
35
+ })
36
+ console.log(formatStylesAsText(styles))
37
+ }
38
+
39
+ // Example: Find where a CSS property is defined
40
+ async function findPropertySource() {
41
+ const loc = page.locator('.card')
42
+ const styles = await getStylesForLocator({ locator: loc })
43
+
44
+ const backgroundRule = styles.rules.find((r) => 'background-color' in r.declarations)
45
+ if (backgroundRule) {
46
+ console.log('background-color defined by:', backgroundRule.selector)
47
+ if (backgroundRule.source) {
48
+ console.log(` at ${backgroundRule.source.url}:${backgroundRule.source.line}`)
49
+ }
50
+ }
51
+ }
52
+
53
+ // Example: Check inherited styles
54
+ async function checkInheritedStyles() {
55
+ const loc = page.locator('.nested-text')
56
+ const styles = await getStylesForLocator({ locator: loc })
57
+
58
+ const inheritedRules = styles.rules.filter((r) => r.inheritedFrom)
59
+ for (const rule of inheritedRules) {
60
+ console.log(`Inherited from ${rule.inheritedFrom}: ${rule.selector}`)
61
+ console.log(' Properties:', rule.declarations)
62
+ }
63
+ }
64
+
65
+ // Example: Compare styles between two elements
66
+ async function compareStyles() {
67
+ const primary = await getStylesForLocator({ locator: page.locator('.btn-primary') })
68
+ const secondary = await getStylesForLocator({ locator: page.locator('.btn-secondary') })
69
+
70
+ console.log('Primary button:')
71
+ console.log(formatStylesAsText(primary))
72
+
73
+ console.log('Secondary button:')
74
+ console.log(formatStylesAsText(secondary))
75
+ }
76
+
77
+ export { getElementStyles, inspectButtonStyles, getStylesWithUserAgent, findPropertySource, checkInheritedStyles, compareStyles }
@@ -1,66 +0,0 @@
1
- import { page, getCDPSession, createDebugger, console } from './debugger-examples-types.js'
2
-
3
- // Example: List available scripts and set a breakpoint
4
- async function listScriptsAndSetBreakpoint() {
5
- const cdp = await getCDPSession({ page })
6
- const dbg = createDebugger({ cdp })
7
- await dbg.enable()
8
-
9
- const scripts = await dbg.listScripts({ search: 'app' })
10
- console.log(scripts)
11
-
12
- if (scripts.length > 0) {
13
- const bpId = await dbg.setBreakpoint({ file: scripts[0].url, line: 100 })
14
- console.log('Breakpoint set:', bpId)
15
- }
16
- }
17
-
18
- // Example: Inspect state when paused at a breakpoint
19
- async function inspectWhenPaused() {
20
- const cdp = await getCDPSession({ page })
21
- const dbg = createDebugger({ cdp })
22
- await dbg.enable()
23
-
24
- if (dbg.isPaused()) {
25
- const loc = await dbg.getLocation()
26
- console.log('Paused at:', loc.url, 'line', loc.lineNumber)
27
- console.log('Source:', loc.sourceContext)
28
-
29
- const vars = await dbg.inspectLocalVariables()
30
- console.log('Variables:', vars)
31
-
32
- const result = await dbg.evaluate({ expression: 'myVar.length' })
33
- console.log('myVar.length =', result.value)
34
-
35
- await dbg.stepOver()
36
- }
37
- }
38
-
39
- // Example: Step through code
40
- async function stepThroughCode() {
41
- const cdp = await getCDPSession({ page })
42
- const dbg = createDebugger({ cdp })
43
- await dbg.enable()
44
-
45
- await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 })
46
-
47
- if (dbg.isPaused()) {
48
- await dbg.stepOver()
49
- await dbg.stepInto()
50
- await dbg.stepOut()
51
- await dbg.resume()
52
- }
53
- }
54
-
55
- // Example: Cleanup all breakpoints
56
- async function cleanupBreakpoints() {
57
- const cdp = await getCDPSession({ page })
58
- const dbg = createDebugger({ cdp })
59
-
60
- const breakpoints = dbg.listBreakpoints()
61
- for (const bp of breakpoints) {
62
- await dbg.deleteBreakpoint({ breakpointId: bp.id })
63
- }
64
- }
65
-
66
- export { listScriptsAndSetBreakpoint, inspectWhenPaused, stepThroughCode, cleanupBreakpoints }