playwriter 0.0.30 → 0.0.33

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.30",
4
+ "version": "0.0.33",
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",
@@ -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
@@ -428,75 +428,51 @@ const server = new McpServer({
428
428
  })
429
429
 
430
430
  const promptContent =
431
- fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'prompt.md'), 'utf-8') +
431
+ fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', '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
  ],
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 }