tabwright 1.0.0 → 1.0.1
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.
- package/dist/aria-snapshot.d.ts +0 -1
- package/dist/aria-snapshot.js +9 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
- package/dist/bippy.js +1 -1
- package/dist/browser-config.d.ts +0 -1
- package/dist/browser-config.js +0 -1
- package/dist/browser-install.d.ts +0 -1
- package/dist/browser-install.js +0 -1
- package/dist/browser-launch.d.ts +0 -1
- package/dist/browser-launch.js +0 -1
- package/dist/builtin-capabilities.d.ts +0 -1
- package/dist/builtin-capabilities.js +0 -1
- package/dist/capability-agent-skill.d.ts +0 -1
- package/dist/capability-agent-skill.js +0 -1
- package/dist/capability-auth-state.d.ts +0 -1
- package/dist/capability-auth-state.js +0 -1
- package/dist/capability-auth.d.ts +0 -1
- package/dist/capability-auth.js +0 -1
- package/dist/capability-options.d.ts +0 -1
- package/dist/capability-options.js +0 -1
- package/dist/capability-package.d.ts +0 -1
- package/dist/capability-package.js +0 -1
- package/dist/capability-registry.d.ts +0 -1
- package/dist/capability-registry.js +0 -1
- package/dist/capability-runner.d.ts +0 -1
- package/dist/capability-runner.js +0 -1
- package/dist/capability-studio.d.ts +0 -1
- package/dist/capability-studio.js +0 -1
- package/dist/cdp-log.d.ts +0 -1
- package/dist/cdp-log.js +0 -1
- package/dist/cdp-relay.d.ts +0 -1
- package/dist/cdp-relay.js +0 -1
- package/dist/cdp-session.d.ts +0 -1
- package/dist/cdp-session.js +0 -1
- package/dist/cdp-types.d.ts +0 -1
- package/dist/cdp-types.js +0 -1
- package/dist/chrome-discovery.d.ts +0 -1
- package/dist/chrome-discovery.js +0 -1
- package/dist/clean-html.d.ts +0 -1
- package/dist/clean-html.js +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +9 -2
- package/dist/cloud-client.d.ts +0 -1
- package/dist/cloud-client.js +0 -1
- package/dist/create-logger.d.ts +0 -1
- package/dist/create-logger.js +0 -1
- package/dist/debugger-examples-types.d.ts +0 -1
- package/dist/debugger-examples-types.js +0 -1
- package/dist/debugger-examples.d.ts +0 -1
- package/dist/debugger-examples.js +0 -1
- package/dist/debugger.d.ts +0 -1
- package/dist/debugger.js +0 -1
- package/dist/diff-utils.d.ts +0 -1
- package/dist/diff-utils.js +0 -1
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +5 -7
- package/dist/editor-examples.d.ts +0 -1
- package/dist/editor-examples.js +0 -1
- package/dist/editor.d.ts +0 -1
- package/dist/editor.js +0 -1
- package/dist/env-compat.d.ts +0 -1
- package/dist/env-compat.js +0 -1
- package/dist/executor.d.ts +0 -1
- package/dist/executor.js +1 -2
- package/dist/extension/background.js +7 -3
- package/dist/extension/manifest.json +1 -1
- package/dist/ghost-browser.d.ts +0 -1
- package/dist/ghost-browser.js +0 -1
- package/dist/ghost-cursor-controller.d.ts +0 -1
- package/dist/ghost-cursor-controller.js +0 -1
- package/dist/ghost-cursor.d.ts +0 -1
- package/dist/ghost-cursor.js +0 -1
- package/dist/htmlrewrite.d.ts +0 -1
- package/dist/htmlrewrite.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/kill-port.d.ts +0 -1
- package/dist/kill-port.js +0 -1
- package/dist/kitty-graphics.d.ts +0 -1
- package/dist/kitty-graphics.js +0 -1
- package/dist/mcp.d.ts +0 -1
- package/dist/mcp.js +0 -1
- package/dist/package-paths.d.ts +0 -1
- package/dist/package-paths.js +0 -1
- package/dist/page-markdown.d.ts +0 -1
- package/dist/page-markdown.js +0 -1
- package/dist/performance-examples.d.ts +0 -1
- package/dist/performance-examples.js +0 -1
- package/dist/playwright-import.d.ts +0 -1
- package/dist/playwright-import.js +0 -1
- package/dist/product-paths.d.ts +0 -1
- package/dist/product-paths.js +0 -1
- package/dist/protocol.d.ts +0 -1
- package/dist/protocol.js +0 -1
- package/dist/react-source.d.ts +0 -1
- package/dist/react-source.js +0 -1
- package/dist/readability.js +1 -1
- package/dist/relay-client.d.ts +0 -1
- package/dist/relay-client.js +0 -1
- package/dist/relay-state.d.ts +0 -1
- package/dist/relay-state.js +0 -1
- package/dist/replay-ai-index.d.ts +0 -1
- package/dist/replay-ai-index.js +0 -1
- package/dist/replay-eval.d.ts +0 -1
- package/dist/replay-eval.js +0 -1
- package/dist/replay-handoff.d.ts +0 -1
- package/dist/replay-handoff.js +0 -1
- package/dist/replay-workflow-compiler.d.ts +0 -1
- package/dist/replay-workflow-compiler.js +0 -1
- package/dist/rrweb-recording-relay.d.ts +0 -1
- package/dist/rrweb-recording-relay.js +0 -1
- package/dist/rrweb-recording.d.ts +0 -1
- package/dist/rrweb-recording.js +0 -1
- package/dist/scoped-fs.d.ts +0 -1
- package/dist/scoped-fs.js +0 -1
- package/dist/selector-generator.js +1 -1
- package/dist/start-relay-server.d.ts +0 -1
- package/dist/start-relay-server.js +0 -1
- package/dist/styles-examples.d.ts +0 -1
- package/dist/styles-examples.js +0 -1
- package/dist/styles.d.ts +0 -1
- package/dist/styles.js +0 -1
- package/dist/tabwright-agent-skill.d.ts +0 -1
- package/dist/tabwright-agent-skill.js +0 -1
- package/dist/test-declarations.d.ts +0 -1
- package/dist/test-declarations.js +0 -1
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +2 -2
- package/dist/wait-for-page-load.d.ts +0 -1
- package/dist/wait-for-page-load.js +0 -1
- package/dist/workflow-capability.d.ts +0 -1
- package/dist/workflow-capability.js +0 -1
- package/package.json +9 -4
- package/readme.md +35 -0
- package/dist/aria-snapshot.d.ts.map +0 -1
- package/dist/aria-snapshot.js.map +0 -1
- package/dist/aria-snapshot.test.d.ts +0 -2
- package/dist/aria-snapshot.test.d.ts.map +0 -1
- package/dist/aria-snapshot.test.js +0 -270
- package/dist/aria-snapshot.test.js.map +0 -1
- package/dist/aria-snapshot.unit.test.d.ts +0 -2
- package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
- package/dist/aria-snapshot.unit.test.js +0 -542
- package/dist/aria-snapshot.unit.test.js.map +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
- package/dist/browser-config.d.ts.map +0 -1
- package/dist/browser-config.js.map +0 -1
- package/dist/browser-install.d.ts.map +0 -1
- package/dist/browser-install.js.map +0 -1
- package/dist/browser-launch.d.ts.map +0 -1
- package/dist/browser-launch.js.map +0 -1
- package/dist/builtin-capabilities.d.ts.map +0 -1
- package/dist/builtin-capabilities.js.map +0 -1
- package/dist/capability-agent-skill.d.ts.map +0 -1
- package/dist/capability-agent-skill.js.map +0 -1
- package/dist/capability-auth-state.d.ts.map +0 -1
- package/dist/capability-auth-state.js.map +0 -1
- package/dist/capability-auth.d.ts.map +0 -1
- package/dist/capability-auth.js.map +0 -1
- package/dist/capability-cli-confirmation.test.d.ts +0 -2
- package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
- package/dist/capability-cli-confirmation.test.js +0 -79
- package/dist/capability-cli-confirmation.test.js.map +0 -1
- package/dist/capability-options.d.ts.map +0 -1
- package/dist/capability-options.js.map +0 -1
- package/dist/capability-options.test.d.ts +0 -2
- package/dist/capability-options.test.d.ts.map +0 -1
- package/dist/capability-options.test.js +0 -81
- package/dist/capability-options.test.js.map +0 -1
- package/dist/capability-package.d.ts.map +0 -1
- package/dist/capability-package.js.map +0 -1
- package/dist/capability-package.test.d.ts +0 -2
- package/dist/capability-package.test.d.ts.map +0 -1
- package/dist/capability-package.test.js +0 -179
- package/dist/capability-package.test.js.map +0 -1
- package/dist/capability-registry.d.ts.map +0 -1
- package/dist/capability-registry.js.map +0 -1
- package/dist/capability-registry.test.d.ts +0 -2
- package/dist/capability-registry.test.d.ts.map +0 -1
- package/dist/capability-registry.test.js +0 -1683
- package/dist/capability-registry.test.js.map +0 -1
- package/dist/capability-runner.d.ts.map +0 -1
- package/dist/capability-runner.js.map +0 -1
- package/dist/capability-search-relevance.test.d.ts +0 -2
- package/dist/capability-search-relevance.test.d.ts.map +0 -1
- package/dist/capability-search-relevance.test.js +0 -67
- package/dist/capability-search-relevance.test.js.map +0 -1
- package/dist/capability-studio.d.ts.map +0 -1
- package/dist/capability-studio.js.map +0 -1
- package/dist/capability-studio.test.d.ts +0 -2
- package/dist/capability-studio.test.d.ts.map +0 -1
- package/dist/capability-studio.test.js +0 -41
- package/dist/capability-studio.test.js.map +0 -1
- package/dist/cdp-log.d.ts.map +0 -1
- package/dist/cdp-log.js.map +0 -1
- package/dist/cdp-log.test.d.ts +0 -2
- package/dist/cdp-log.test.d.ts.map +0 -1
- package/dist/cdp-log.test.js +0 -109
- package/dist/cdp-log.test.js.map +0 -1
- package/dist/cdp-relay.d.ts.map +0 -1
- package/dist/cdp-relay.js.map +0 -1
- package/dist/cdp-session.d.ts.map +0 -1
- package/dist/cdp-session.js.map +0 -1
- package/dist/cdp-types.d.ts.map +0 -1
- package/dist/cdp-types.js.map +0 -1
- package/dist/channel-owner-inspect.test.d.ts +0 -2
- package/dist/channel-owner-inspect.test.d.ts.map +0 -1
- package/dist/channel-owner-inspect.test.js +0 -75
- package/dist/channel-owner-inspect.test.js.map +0 -1
- package/dist/chrome-discovery.d.ts.map +0 -1
- package/dist/chrome-discovery.js.map +0 -1
- package/dist/chrome-discovery.test.d.ts +0 -2
- package/dist/chrome-discovery.test.d.ts.map +0 -1
- package/dist/chrome-discovery.test.js +0 -41
- package/dist/chrome-discovery.test.js.map +0 -1
- package/dist/clean-html.d.ts.map +0 -1
- package/dist/clean-html.js.map +0 -1
- package/dist/cli-help.test.d.ts +0 -2
- package/dist/cli-help.test.d.ts.map +0 -1
- package/dist/cli-help.test.js +0 -98
- package/dist/cli-help.test.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cloud-client.d.ts.map +0 -1
- package/dist/cloud-client.js.map +0 -1
- package/dist/create-logger.d.ts.map +0 -1
- package/dist/create-logger.js.map +0 -1
- package/dist/debugger-examples-types.d.ts.map +0 -1
- package/dist/debugger-examples-types.js.map +0 -1
- package/dist/debugger-examples.d.ts.map +0 -1
- package/dist/debugger-examples.js.map +0 -1
- package/dist/debugger.d.ts.map +0 -1
- package/dist/debugger.js.map +0 -1
- package/dist/diff-utils.d.ts.map +0 -1
- package/dist/diff-utils.js.map +0 -1
- package/dist/diff-utils.test.d.ts +0 -2
- package/dist/diff-utils.test.d.ts.map +0 -1
- package/dist/diff-utils.test.js +0 -137
- package/dist/diff-utils.test.js.map +0 -1
- package/dist/doctor.d.ts.map +0 -1
- package/dist/doctor.js.map +0 -1
- package/dist/doctor.test.d.ts +0 -2
- package/dist/doctor.test.d.ts.map +0 -1
- package/dist/doctor.test.js +0 -208
- package/dist/doctor.test.js.map +0 -1
- package/dist/editor-examples.d.ts.map +0 -1
- package/dist/editor-examples.js.map +0 -1
- package/dist/editor.d.ts.map +0 -1
- package/dist/editor.js.map +0 -1
- package/dist/env-compat.d.ts.map +0 -1
- package/dist/env-compat.js.map +0 -1
- package/dist/executor.d.ts.map +0 -1
- package/dist/executor.js.map +0 -1
- package/dist/executor.unit.test.d.ts +0 -2
- package/dist/executor.unit.test.d.ts.map +0 -1
- package/dist/executor.unit.test.js +0 -143
- package/dist/executor.unit.test.js.map +0 -1
- package/dist/extension-connection.test.d.ts +0 -2
- package/dist/extension-connection.test.d.ts.map +0 -1
- package/dist/extension-connection.test.js +0 -708
- package/dist/extension-connection.test.js.map +0 -1
- package/dist/extension-icon-warning.test.d.ts +0 -2
- package/dist/extension-icon-warning.test.d.ts.map +0 -1
- package/dist/extension-icon-warning.test.js +0 -33
- package/dist/extension-icon-warning.test.js.map +0 -1
- package/dist/ghost-browser.d.ts.map +0 -1
- package/dist/ghost-browser.js.map +0 -1
- package/dist/ghost-cursor-controller.d.ts.map +0 -1
- package/dist/ghost-cursor-controller.js.map +0 -1
- package/dist/ghost-cursor.d.ts.map +0 -1
- package/dist/ghost-cursor.js.map +0 -1
- package/dist/htmlrewrite.d.ts.map +0 -1
- package/dist/htmlrewrite.js.map +0 -1
- package/dist/htmlrewrite.test.d.ts +0 -2
- package/dist/htmlrewrite.test.d.ts.map +0 -1
- package/dist/htmlrewrite.test.js +0 -7975
- package/dist/htmlrewrite.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kill-port.d.ts.map +0 -1
- package/dist/kill-port.js.map +0 -1
- package/dist/kitty-graphics.d.ts.map +0 -1
- package/dist/kitty-graphics.js.map +0 -1
- package/dist/kitty-graphics.test.d.ts +0 -2
- package/dist/kitty-graphics.test.d.ts.map +0 -1
- package/dist/kitty-graphics.test.js +0 -125
- package/dist/kitty-graphics.test.js.map +0 -1
- package/dist/locator-selector.test.d.ts +0 -2
- package/dist/locator-selector.test.d.ts.map +0 -1
- package/dist/locator-selector.test.js +0 -98
- package/dist/locator-selector.test.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -20
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -56
- package/dist/mcp-client.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/on-mouse-action.test.d.ts +0 -2
- package/dist/on-mouse-action.test.d.ts.map +0 -1
- package/dist/on-mouse-action.test.js +0 -180
- package/dist/on-mouse-action.test.js.map +0 -1
- package/dist/options-page.test.d.ts +0 -2
- package/dist/options-page.test.d.ts.map +0 -1
- package/dist/options-page.test.js +0 -773
- package/dist/options-page.test.js.map +0 -1
- package/dist/package-paths.d.ts.map +0 -1
- package/dist/package-paths.js.map +0 -1
- package/dist/page-markdown.d.ts.map +0 -1
- package/dist/page-markdown.js.map +0 -1
- package/dist/performance-examples.d.ts.map +0 -1
- package/dist/performance-examples.js.map +0 -1
- package/dist/playwright-import.d.ts.map +0 -1
- package/dist/playwright-import.js.map +0 -1
- package/dist/popup-relocation.test.d.ts +0 -7
- package/dist/popup-relocation.test.d.ts.map +0 -1
- package/dist/popup-relocation.test.js +0 -139
- package/dist/popup-relocation.test.js.map +0 -1
- package/dist/product-paths.d.ts.map +0 -1
- package/dist/product-paths.js.map +0 -1
- package/dist/product-paths.test.d.ts +0 -2
- package/dist/product-paths.test.d.ts.map +0 -1
- package/dist/product-paths.test.js +0 -39
- package/dist/product-paths.test.js.map +0 -1
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js.map +0 -1
- package/dist/protocol.test.d.ts +0 -2
- package/dist/protocol.test.d.ts.map +0 -1
- package/dist/protocol.test.js +0 -31
- package/dist/protocol.test.js.map +0 -1
- package/dist/react-source.d.ts.map +0 -1
- package/dist/react-source.js.map +0 -1
- package/dist/relay-client.d.ts.map +0 -1
- package/dist/relay-client.js.map +0 -1
- package/dist/relay-client.test.d.ts +0 -2
- package/dist/relay-client.test.d.ts.map +0 -1
- package/dist/relay-client.test.js +0 -305
- package/dist/relay-client.test.js.map +0 -1
- package/dist/relay-core.test.d.ts +0 -2
- package/dist/relay-core.test.d.ts.map +0 -1
- package/dist/relay-core.test.js +0 -1427
- package/dist/relay-core.test.js.map +0 -1
- package/dist/relay-navigation.test.d.ts +0 -2
- package/dist/relay-navigation.test.d.ts.map +0 -1
- package/dist/relay-navigation.test.js +0 -661
- package/dist/relay-navigation.test.js.map +0 -1
- package/dist/relay-session.test.d.ts +0 -2
- package/dist/relay-session.test.d.ts.map +0 -1
- package/dist/relay-session.test.js +0 -1121
- package/dist/relay-session.test.js.map +0 -1
- package/dist/relay-state.d.ts.map +0 -1
- package/dist/relay-state.js.map +0 -1
- package/dist/relay-state.test.d.ts +0 -2
- package/dist/relay-state.test.d.ts.map +0 -1
- package/dist/relay-state.test.js +0 -594
- package/dist/relay-state.test.js.map +0 -1
- package/dist/replay-ai-index.d.ts.map +0 -1
- package/dist/replay-ai-index.js.map +0 -1
- package/dist/replay-ai-index.test.d.ts +0 -2
- package/dist/replay-ai-index.test.d.ts.map +0 -1
- package/dist/replay-ai-index.test.js +0 -255
- package/dist/replay-ai-index.test.js.map +0 -1
- package/dist/replay-cli.test.d.ts +0 -2
- package/dist/replay-cli.test.d.ts.map +0 -1
- package/dist/replay-cli.test.js +0 -275
- package/dist/replay-cli.test.js.map +0 -1
- package/dist/replay-eval.d.ts.map +0 -1
- package/dist/replay-eval.js.map +0 -1
- package/dist/replay-handoff.d.ts.map +0 -1
- package/dist/replay-handoff.js.map +0 -1
- package/dist/replay-handoff.test.d.ts +0 -2
- package/dist/replay-handoff.test.d.ts.map +0 -1
- package/dist/replay-handoff.test.js +0 -123
- package/dist/replay-handoff.test.js.map +0 -1
- package/dist/replay-workflow-compiler.d.ts.map +0 -1
- package/dist/replay-workflow-compiler.js.map +0 -1
- package/dist/replay-workflow-compiler.test.d.ts +0 -2
- package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
- package/dist/replay-workflow-compiler.test.js +0 -223
- package/dist/replay-workflow-compiler.test.js.map +0 -1
- package/dist/rrweb-recording-relay.d.ts.map +0 -1
- package/dist/rrweb-recording-relay.js.map +0 -1
- package/dist/rrweb-recording-relay.test.d.ts +0 -2
- package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
- package/dist/rrweb-recording-relay.test.js +0 -85
- package/dist/rrweb-recording-relay.test.js.map +0 -1
- package/dist/rrweb-recording.d.ts.map +0 -1
- package/dist/rrweb-recording.js.map +0 -1
- package/dist/scoped-fs.d.ts.map +0 -1
- package/dist/scoped-fs.js.map +0 -1
- package/dist/scoped-fs.test.d.ts +0 -5
- package/dist/scoped-fs.test.d.ts.map +0 -1
- package/dist/scoped-fs.test.js +0 -73
- package/dist/scoped-fs.test.js.map +0 -1
- package/dist/skill-stub.test.d.ts +0 -2
- package/dist/skill-stub.test.d.ts.map +0 -1
- package/dist/skill-stub.test.js +0 -22
- package/dist/skill-stub.test.js.map +0 -1
- package/dist/snapshot-tools.test.d.ts +0 -2
- package/dist/snapshot-tools.test.d.ts.map +0 -1
- package/dist/snapshot-tools.test.js +0 -856
- package/dist/snapshot-tools.test.js.map +0 -1
- package/dist/start-relay-server.d.ts.map +0 -1
- package/dist/start-relay-server.js.map +0 -1
- package/dist/styles-examples.d.ts.map +0 -1
- package/dist/styles-examples.js.map +0 -1
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js.map +0 -1
- package/dist/tabwright-agent-skill.d.ts.map +0 -1
- package/dist/tabwright-agent-skill.js.map +0 -1
- package/dist/tabwright-agent-skill.test.d.ts +0 -2
- package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
- package/dist/tabwright-agent-skill.test.js +0 -51
- package/dist/tabwright-agent-skill.test.js.map +0 -1
- package/dist/test-declarations.d.ts.map +0 -1
- package/dist/test-declarations.js.map +0 -1
- package/dist/test-utils.d.ts +0 -69
- package/dist/test-utils.d.ts.map +0 -1
- package/dist/test-utils.js +0 -448
- package/dist/test-utils.js.map +0 -1
- package/dist/test-utils.test.d.ts +0 -2
- package/dist/test-utils.test.d.ts.map +0 -1
- package/dist/test-utils.test.js +0 -55
- package/dist/test-utils.test.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/wait-for-page-load.d.ts.map +0 -1
- package/dist/wait-for-page-load.js.map +0 -1
- package/dist/workflow-capability.d.ts.map +0 -1
- package/dist/workflow-capability.js.map +0 -1
- package/dist/workflow-script-flow.test.d.ts +0 -2
- package/dist/workflow-script-flow.test.d.ts.map +0 -1
- package/dist/workflow-script-flow.test.js +0 -285
- package/dist/workflow-script-flow.test.js.map +0 -1
- package/src/__snapshots__/x.com.processed.html +0 -1003
- package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
- package/src/a11y-client.ts +0 -241
- package/src/aria-snapshot.test.ts +0 -311
- package/src/aria-snapshot.ts +0 -1681
- package/src/aria-snapshot.unit.test.ts +0 -615
- package/src/aria-snapshots/github-interactive.txt +0 -193
- package/src/aria-snapshots/github-raw.txt +0 -309
- package/src/aria-snapshots/hackernews-interactive.txt +0 -477
- package/src/aria-snapshots/hackernews-raw.txt +0 -428
- package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
- package/src/aria-snapshots/prosemirror-raw.txt +0 -145
- package/src/assets/aria-labels-hacker-news.png +0 -0
- package/src/assets/aria-labels-old-reddit.png +0 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
- package/src/assets/x.com.html +0 -32946
- package/src/browser-config.ts +0 -179
- package/src/browser-install.ts +0 -284
- package/src/browser-launch.ts +0 -75
- package/src/builtin-capabilities.ts +0 -2765
- package/src/capability-agent-skill.ts +0 -305
- package/src/capability-auth-state.ts +0 -197
- package/src/capability-auth.ts +0 -249
- package/src/capability-cli-confirmation.test.ts +0 -90
- package/src/capability-options.test.ts +0 -89
- package/src/capability-options.ts +0 -57
- package/src/capability-package.test.ts +0 -204
- package/src/capability-package.ts +0 -555
- package/src/capability-registry.test.ts +0 -1905
- package/src/capability-registry.ts +0 -1234
- package/src/capability-runner.ts +0 -801
- package/src/capability-search-relevance.test.ts +0 -73
- package/src/capability-studio.test.ts +0 -45
- package/src/capability-studio.ts +0 -641
- package/src/cdp-log.test.ts +0 -131
- package/src/cdp-log.ts +0 -112
- package/src/cdp-relay.ts +0 -2944
- package/src/cdp-session.ts +0 -77
- package/src/cdp-types.ts +0 -158
- package/src/channel-owner-inspect.test.ts +0 -94
- package/src/chrome-discovery.test.ts +0 -50
- package/src/chrome-discovery.ts +0 -220
- package/src/clean-html.ts +0 -141
- package/src/cli-help.test.ts +0 -123
- package/src/cli.ts +0 -3181
- package/src/cloud-client.ts +0 -179
- package/src/create-logger.ts +0 -38
- package/src/debugger-examples-types.ts +0 -16
- package/src/debugger-examples.ts +0 -66
- package/src/debugger.ts +0 -708
- package/src/diff-utils.test.ts +0 -152
- package/src/diff-utils.ts +0 -70
- package/src/doctor.test.ts +0 -244
- package/src/doctor.ts +0 -321
- package/src/editor-examples.ts +0 -158
- package/src/editor.ts +0 -426
- package/src/env-compat.ts +0 -28
- package/src/executor.ts +0 -1824
- package/src/executor.unit.test.ts +0 -168
- package/src/extension-connection.test.ts +0 -855
- package/src/extension-icon-warning.test.ts +0 -45
- package/src/ghost-browser.ts +0 -149
- package/src/ghost-cursor-client.ts +0 -494
- package/src/ghost-cursor-controller.ts +0 -129
- package/src/ghost-cursor.ts +0 -123
- package/src/htmlrewrite.test.ts +0 -8008
- package/src/htmlrewrite.ts +0 -390
- package/src/index.ts +0 -53
- package/src/kill-port.ts +0 -219
- package/src/kitty-graphics.test.ts +0 -139
- package/src/kitty-graphics.ts +0 -79
- package/src/locator-selector.test.ts +0 -119
- package/src/mcp-client.ts +0 -78
- package/src/mcp.ts +0 -629
- package/src/on-mouse-action.test.ts +0 -226
- package/src/options-page.test.ts +0 -839
- package/src/package-paths.ts +0 -38
- package/src/page-markdown.ts +0 -240
- package/src/performance-examples.ts +0 -186
- package/src/playwright-import.ts +0 -59
- package/src/popup-relocation.test.ts +0 -163
- package/src/product-paths.test.ts +0 -47
- package/src/product-paths.ts +0 -28
- package/src/protocol.test.ts +0 -52
- package/src/protocol.ts +0 -351
- package/src/react-source.ts +0 -379
- package/src/relay-client.test.ts +0 -375
- package/src/relay-client.ts +0 -572
- package/src/relay-core.test.ts +0 -1603
- package/src/relay-navigation.test.ts +0 -790
- package/src/relay-session.test.ts +0 -1375
- package/src/relay-state.test.ts +0 -729
- package/src/relay-state.ts +0 -561
- package/src/replay-ai-index.test.ts +0 -278
- package/src/replay-ai-index.ts +0 -872
- package/src/replay-cli.test.ts +0 -325
- package/src/replay-eval.ts +0 -1039
- package/src/replay-handoff.test.ts +0 -163
- package/src/replay-handoff.ts +0 -109
- package/src/replay-workflow-compiler.test.ts +0 -250
- package/src/replay-workflow-compiler.ts +0 -700
- package/src/resource.md +0 -409
- package/src/rrweb-recording-relay.test.ts +0 -99
- package/src/rrweb-recording-relay.ts +0 -400
- package/src/rrweb-recording.ts +0 -322
- package/src/scoped-fs.test.ts +0 -80
- package/src/scoped-fs.ts +0 -420
- package/src/skill-stub.test.ts +0 -24
- package/src/snapshot-tools.test.ts +0 -1017
- package/src/snapshots/hacker-news-accessibility-full.md +0 -81
- package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
- package/src/snapshots/page-markdown-output.txt +0 -16
- package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
- package/src/start-relay-server.ts +0 -69
- package/src/styles-examples.ts +0 -84
- package/src/styles.ts +0 -343
- package/src/tabwright-agent-skill.test.ts +0 -61
- package/src/tabwright-agent-skill.ts +0 -105
- package/src/test-declarations.ts +0 -13
- package/src/test-utils.test.ts +0 -70
- package/src/test-utils.ts +0 -566
- package/src/utils.ts +0 -78
- package/src/wait-for-page-load.ts +0 -198
- package/src/workflow-capability.ts +0 -417
- package/src/workflow-script-flow.test.ts +0 -388
|
@@ -1,1375 +0,0 @@
|
|
|
1
|
-
import { createMCPClient } from './mcp-client.js'
|
|
2
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
3
|
-
import { chromium } from '@xmorse/playwright-core'
|
|
4
|
-
import { getCdpUrl } from './utils.js'
|
|
5
|
-
import { getCDPSessionForPage } from './cdp-session.js'
|
|
6
|
-
import { Debugger } from './debugger.js'
|
|
7
|
-
import { Editor } from './editor.js'
|
|
8
|
-
import { PlaywrightExecutor } from './executor.js'
|
|
9
|
-
import {
|
|
10
|
-
setupTestContext,
|
|
11
|
-
cleanupTestContext,
|
|
12
|
-
getExtensionServiceWorker,
|
|
13
|
-
createSseServer,
|
|
14
|
-
safeCloseCDPBrowser,
|
|
15
|
-
type TestContext,
|
|
16
|
-
withTimeout,
|
|
17
|
-
js,
|
|
18
|
-
} from './test-utils.js'
|
|
19
|
-
import './test-declarations.js'
|
|
20
|
-
|
|
21
|
-
const TEST_PORT = 19993
|
|
22
|
-
|
|
23
|
-
// --- CDP Session Tests ---
|
|
24
|
-
|
|
25
|
-
describe('CDP Session Tests', () => {
|
|
26
|
-
let testCtx: TestContext | null = null
|
|
27
|
-
|
|
28
|
-
beforeAll(async () => {
|
|
29
|
-
testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'pw-cdp-test-', toggleExtension: true })
|
|
30
|
-
|
|
31
|
-
const serviceWorker = await getExtensionServiceWorker(testCtx.browserContext)
|
|
32
|
-
await serviceWorker.evaluate(async () => {
|
|
33
|
-
await globalThis.disconnectEverything()
|
|
34
|
-
})
|
|
35
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
36
|
-
}, 600000)
|
|
37
|
-
|
|
38
|
-
afterAll(async () => {
|
|
39
|
-
await cleanupTestContext(testCtx)
|
|
40
|
-
testCtx = null
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const getBrowserContext = () => {
|
|
44
|
-
if (!testCtx?.browserContext) throw new Error('Browser not initialized')
|
|
45
|
-
return testCtx.browserContext
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
it('should use Debugger class to set breakpoints and inspect variables', async () => {
|
|
49
|
-
const browserContext = getBrowserContext()
|
|
50
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
51
|
-
|
|
52
|
-
const page = await browserContext.newPage()
|
|
53
|
-
const testUrl = 'https://example.com/?test=debugger-variables'
|
|
54
|
-
await page.goto(testUrl)
|
|
55
|
-
await page.bringToFront()
|
|
56
|
-
|
|
57
|
-
await serviceWorker.evaluate(async () => {
|
|
58
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
59
|
-
})
|
|
60
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
61
|
-
|
|
62
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
63
|
-
const cdpSession = await getCDPSessionForPage({ page })
|
|
64
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
65
|
-
|
|
66
|
-
await dbg.enable()
|
|
67
|
-
|
|
68
|
-
expect(dbg.isPaused()).toBe(false)
|
|
69
|
-
|
|
70
|
-
const pausedPromise = new Promise<void>((resolve) => {
|
|
71
|
-
cdpSession.on('Debugger.paused', () => {
|
|
72
|
-
resolve()
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
const evalPromise = cdpSession.send('Runtime.evaluate', {
|
|
77
|
-
expression: `(function testFunction() {
|
|
78
|
-
const localVar = 'hello';
|
|
79
|
-
const numberVar = 42;
|
|
80
|
-
debugger;
|
|
81
|
-
return localVar + numberVar;
|
|
82
|
-
})()`,
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
await Promise.race([
|
|
86
|
-
pausedPromise,
|
|
87
|
-
new Promise<never>((_, reject) => setTimeout(() => reject(new Error('Debugger.paused timeout')), 5000)),
|
|
88
|
-
])
|
|
89
|
-
|
|
90
|
-
expect(dbg.isPaused()).toBe(true)
|
|
91
|
-
|
|
92
|
-
const location = await dbg.getLocation()
|
|
93
|
-
expect(location.callstack[0].functionName).toBe('testFunction')
|
|
94
|
-
expect(location.sourceContext).toContain('debugger')
|
|
95
|
-
|
|
96
|
-
const vars = await dbg.inspectLocalVariables()
|
|
97
|
-
expect(vars).toMatchInlineSnapshot(`
|
|
98
|
-
{
|
|
99
|
-
"localVar": "hello",
|
|
100
|
-
"numberVar": 42,
|
|
101
|
-
}
|
|
102
|
-
`)
|
|
103
|
-
|
|
104
|
-
const evalResult = await dbg.evaluate({ expression: 'localVar + " world"' })
|
|
105
|
-
expect(evalResult.value).toBe('hello world')
|
|
106
|
-
|
|
107
|
-
await dbg.resume()
|
|
108
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
109
|
-
expect(dbg.isPaused()).toBe(false)
|
|
110
|
-
await evalPromise
|
|
111
|
-
|
|
112
|
-
await cdpSession.detach()
|
|
113
|
-
await page.close()
|
|
114
|
-
}, 60000)
|
|
115
|
-
|
|
116
|
-
it('should reuse cached CDP session and close on page close', async () => {
|
|
117
|
-
const browserContext = getBrowserContext()
|
|
118
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
119
|
-
|
|
120
|
-
const page = await browserContext.newPage()
|
|
121
|
-
const testUrl = 'https://example.com/?test=debugger-step'
|
|
122
|
-
await page.goto(testUrl)
|
|
123
|
-
await page.bringToFront()
|
|
124
|
-
|
|
125
|
-
await serviceWorker.evaluate(async () => {
|
|
126
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
127
|
-
})
|
|
128
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
129
|
-
|
|
130
|
-
const executor = new PlaywrightExecutor({
|
|
131
|
-
cdpConfig: { port: TEST_PORT },
|
|
132
|
-
logger: {
|
|
133
|
-
log: () => {},
|
|
134
|
-
error: () => {},
|
|
135
|
-
},
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
const result = await executor.execute(js`
|
|
139
|
-
const sessionA = await getCDPSession({ page })
|
|
140
|
-
const sessionB = await getCDPSession({ page })
|
|
141
|
-
await sessionA.send('Runtime.evaluate', { expression: '1 + 1', returnByValue: true })
|
|
142
|
-
const evalResult = await sessionB.send('Runtime.evaluate', { expression: '2 + 2', returnByValue: true })
|
|
143
|
-
return evalResult.result.value
|
|
144
|
-
`)
|
|
145
|
-
|
|
146
|
-
expect(result.isError).toBe(false)
|
|
147
|
-
expect(result.text).toContain('[return value] 4')
|
|
148
|
-
|
|
149
|
-
await page.close()
|
|
150
|
-
}, 60000)
|
|
151
|
-
|
|
152
|
-
it('should list scripts with Debugger class', async () => {
|
|
153
|
-
const browserContext = getBrowserContext()
|
|
154
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
155
|
-
|
|
156
|
-
// Use setContent with external script URLs so Debugger.listScripts returns them
|
|
157
|
-
const page = await browserContext.newPage()
|
|
158
|
-
await page.setContent(`
|
|
159
|
-
<html>
|
|
160
|
-
<head>
|
|
161
|
-
<script src="data:text/javascript,function hello() { return 1; }"></script>
|
|
162
|
-
<script src="data:text/javascript,function world() { return 2; }"></script>
|
|
163
|
-
</head>
|
|
164
|
-
<body><h1>Script test</h1></body>
|
|
165
|
-
</html>
|
|
166
|
-
`)
|
|
167
|
-
await page.bringToFront()
|
|
168
|
-
|
|
169
|
-
await serviceWorker.evaluate(async () => {
|
|
170
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
171
|
-
})
|
|
172
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
173
|
-
|
|
174
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
175
|
-
const cdpPage = browser
|
|
176
|
-
.contexts()[0]
|
|
177
|
-
.pages()
|
|
178
|
-
.find((p) => p.url().startsWith('about:'))
|
|
179
|
-
expect(cdpPage).toBeDefined()
|
|
180
|
-
|
|
181
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
182
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
183
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
184
|
-
|
|
185
|
-
await dbg.enable()
|
|
186
|
-
|
|
187
|
-
const scripts = await dbg.listScripts()
|
|
188
|
-
expect(scripts.length).toBeGreaterThan(0)
|
|
189
|
-
expect(scripts[0]).toHaveProperty('scriptId')
|
|
190
|
-
expect(scripts[0]).toHaveProperty('url')
|
|
191
|
-
|
|
192
|
-
await cdpSession.detach()
|
|
193
|
-
await browser.close()
|
|
194
|
-
await page.close()
|
|
195
|
-
}, 60000)
|
|
196
|
-
|
|
197
|
-
it('should manage breakpoints with Debugger class', async () => {
|
|
198
|
-
const browserContext = getBrowserContext()
|
|
199
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
200
|
-
|
|
201
|
-
const page = await browserContext.newPage()
|
|
202
|
-
await page.setContent(`
|
|
203
|
-
<html>
|
|
204
|
-
<head>
|
|
205
|
-
<script src="data:text/javascript,function testFunc() { return 42; }"></script>
|
|
206
|
-
</head>
|
|
207
|
-
<body></body>
|
|
208
|
-
</html>
|
|
209
|
-
`)
|
|
210
|
-
await page.bringToFront()
|
|
211
|
-
|
|
212
|
-
await serviceWorker.evaluate(async () => {
|
|
213
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
214
|
-
})
|
|
215
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
216
|
-
|
|
217
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
218
|
-
const cdpSession = await getCDPSessionForPage({ page })
|
|
219
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
220
|
-
|
|
221
|
-
await dbg.enable()
|
|
222
|
-
|
|
223
|
-
expect(dbg.listBreakpoints()).toHaveLength(0)
|
|
224
|
-
|
|
225
|
-
const bpId = await dbg.setBreakpoint({ file: 'https://example.com/test.js', line: 1 })
|
|
226
|
-
expect(typeof bpId).toBe('string')
|
|
227
|
-
expect(dbg.listBreakpoints()).toHaveLength(1)
|
|
228
|
-
expect(dbg.listBreakpoints()[0]).toMatchObject({
|
|
229
|
-
id: bpId,
|
|
230
|
-
file: 'https://example.com/test.js',
|
|
231
|
-
line: 1,
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
await dbg.deleteBreakpoint({ breakpointId: bpId })
|
|
235
|
-
expect(dbg.listBreakpoints()).toHaveLength(0)
|
|
236
|
-
|
|
237
|
-
await cdpSession.detach()
|
|
238
|
-
await page.close()
|
|
239
|
-
}, 60000)
|
|
240
|
-
|
|
241
|
-
it('should step through code with Debugger class', async () => {
|
|
242
|
-
const browserContext = getBrowserContext()
|
|
243
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
244
|
-
|
|
245
|
-
const page = await browserContext.newPage()
|
|
246
|
-
await page.goto('https://example.com/')
|
|
247
|
-
await page.bringToFront()
|
|
248
|
-
|
|
249
|
-
await serviceWorker.evaluate(async () => {
|
|
250
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
251
|
-
})
|
|
252
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
253
|
-
|
|
254
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
255
|
-
const cdpSession = await getCDPSessionForPage({ page })
|
|
256
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
257
|
-
|
|
258
|
-
await dbg.enable()
|
|
259
|
-
|
|
260
|
-
const pausedPromise = new Promise<void>((resolve) => {
|
|
261
|
-
cdpSession.on('Debugger.paused', () => resolve())
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
const evalPromise = cdpSession.send('Runtime.evaluate', {
|
|
265
|
-
expression: `(function outer() {
|
|
266
|
-
function inner() {
|
|
267
|
-
const x = 1;
|
|
268
|
-
debugger;
|
|
269
|
-
const y = 2;
|
|
270
|
-
return x + y;
|
|
271
|
-
}
|
|
272
|
-
const result = inner();
|
|
273
|
-
return result;
|
|
274
|
-
})()`,
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
await pausedPromise
|
|
278
|
-
expect(dbg.isPaused()).toBe(true)
|
|
279
|
-
|
|
280
|
-
const location1 = await dbg.getLocation()
|
|
281
|
-
expect(location1.callstack.length).toBeGreaterThanOrEqual(2)
|
|
282
|
-
expect(location1.callstack[0].functionName).toBe('inner')
|
|
283
|
-
expect(location1.callstack[1].functionName).toBe('outer')
|
|
284
|
-
|
|
285
|
-
const stepOverPromise = new Promise<void>((resolve) => {
|
|
286
|
-
cdpSession.on('Debugger.paused', () => resolve())
|
|
287
|
-
})
|
|
288
|
-
await dbg.stepOver()
|
|
289
|
-
await stepOverPromise
|
|
290
|
-
|
|
291
|
-
const location2 = await dbg.getLocation()
|
|
292
|
-
expect(location2.lineNumber).toBeGreaterThan(location1.lineNumber)
|
|
293
|
-
|
|
294
|
-
const stepOutPromise = new Promise<void>((resolve) => {
|
|
295
|
-
cdpSession.on('Debugger.paused', () => resolve())
|
|
296
|
-
})
|
|
297
|
-
await dbg.stepOut()
|
|
298
|
-
await stepOutPromise
|
|
299
|
-
|
|
300
|
-
const location3 = await dbg.getLocation()
|
|
301
|
-
expect(location3.callstack[0].functionName).toBe('outer')
|
|
302
|
-
|
|
303
|
-
await dbg.resume()
|
|
304
|
-
await evalPromise
|
|
305
|
-
|
|
306
|
-
await cdpSession.detach()
|
|
307
|
-
await page.close()
|
|
308
|
-
}, 60000)
|
|
309
|
-
|
|
310
|
-
it('should profile JavaScript execution using CDP Profiler', async () => {
|
|
311
|
-
const browserContext = getBrowserContext()
|
|
312
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
313
|
-
|
|
314
|
-
const page = await browserContext.newPage()
|
|
315
|
-
const testUrl = 'https://example.com/?test=debugger-profiler'
|
|
316
|
-
await page.goto(testUrl)
|
|
317
|
-
await page.bringToFront()
|
|
318
|
-
|
|
319
|
-
await serviceWorker.evaluate(async () => {
|
|
320
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
321
|
-
})
|
|
322
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
323
|
-
|
|
324
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
325
|
-
const cdpSession = await getCDPSessionForPage({ page })
|
|
326
|
-
await cdpSession.send('Profiler.enable')
|
|
327
|
-
await cdpSession.send('Profiler.start')
|
|
328
|
-
|
|
329
|
-
await cdpSession.send('Runtime.evaluate', {
|
|
330
|
-
expression: `(() => {
|
|
331
|
-
function fibonacci(n) {
|
|
332
|
-
if (n <= 1) return n
|
|
333
|
-
return fibonacci(n - 1) + fibonacci(n - 2)
|
|
334
|
-
}
|
|
335
|
-
for (let i = 0; i < 5; i++) {
|
|
336
|
-
fibonacci(20)
|
|
337
|
-
}
|
|
338
|
-
for (let i = 0; i < 1000; i++) {
|
|
339
|
-
document.querySelectorAll('*')
|
|
340
|
-
}
|
|
341
|
-
})()`,
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
const stopResult = await cdpSession.send('Profiler.stop')
|
|
345
|
-
const profile = stopResult.profile
|
|
346
|
-
|
|
347
|
-
const functionNames = profile.nodes
|
|
348
|
-
.map((n) => n.callFrame.functionName)
|
|
349
|
-
.filter((name) => name && name.length > 0)
|
|
350
|
-
.slice(0, 10)
|
|
351
|
-
|
|
352
|
-
expect(profile.nodes.length).toBeGreaterThan(0)
|
|
353
|
-
expect(profile.endTime - profile.startTime).toBeGreaterThan(0)
|
|
354
|
-
expect(functionNames.every((name) => typeof name === 'string')).toBe(true)
|
|
355
|
-
|
|
356
|
-
await cdpSession.send('Profiler.disable')
|
|
357
|
-
await cdpSession.detach()
|
|
358
|
-
await page.close()
|
|
359
|
-
}, 60000)
|
|
360
|
-
|
|
361
|
-
it('should update Target.getTargets URL after page navigation', async () => {
|
|
362
|
-
const browserContext = getBrowserContext()
|
|
363
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
364
|
-
|
|
365
|
-
await serviceWorker.evaluate(async () => {
|
|
366
|
-
await globalThis.disconnectEverything()
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
const page = await browserContext.newPage()
|
|
370
|
-
await page.goto('https://example.com/')
|
|
371
|
-
await page.bringToFront()
|
|
372
|
-
|
|
373
|
-
await serviceWorker.evaluate(async () => {
|
|
374
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
375
|
-
})
|
|
376
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
377
|
-
|
|
378
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
379
|
-
const cdpPage = browser
|
|
380
|
-
.contexts()[0]
|
|
381
|
-
.pages()
|
|
382
|
-
.find((p) => p.url().includes('example.com'))
|
|
383
|
-
expect(cdpPage).toBeDefined()
|
|
384
|
-
|
|
385
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
386
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
387
|
-
|
|
388
|
-
const initialTargets = await cdpSession.send('Target.getTargets')
|
|
389
|
-
const initialPageTarget = initialTargets.targetInfos.find((t) => t.type === 'page' && t.url.includes('example.com'))
|
|
390
|
-
expect(initialPageTarget?.url).toBe('https://example.com/')
|
|
391
|
-
|
|
392
|
-
await cdpPage!.goto('https://example.org/', { waitUntil: 'domcontentloaded' })
|
|
393
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
394
|
-
|
|
395
|
-
const afterNavTargets = await cdpSession.send('Target.getTargets')
|
|
396
|
-
const allPageTargets = afterNavTargets.targetInfos.filter((t) => t.type === 'page')
|
|
397
|
-
|
|
398
|
-
const aboutBlankTargets = allPageTargets.filter((t) => t.url === 'about:blank')
|
|
399
|
-
expect(aboutBlankTargets).toHaveLength(0)
|
|
400
|
-
|
|
401
|
-
const exampleComTargets = allPageTargets.filter((t) => t.url.includes('example.com'))
|
|
402
|
-
expect(exampleComTargets).toHaveLength(0)
|
|
403
|
-
|
|
404
|
-
const exampleOrgTargets = allPageTargets.filter((t) => t.url.includes('example.org'))
|
|
405
|
-
expect(exampleOrgTargets).toHaveLength(1)
|
|
406
|
-
|
|
407
|
-
await cdpSession.detach()
|
|
408
|
-
await browser.close()
|
|
409
|
-
await page.close()
|
|
410
|
-
}, 60000)
|
|
411
|
-
|
|
412
|
-
it('should return correct targets for multiple pages via Target.getTargets', async () => {
|
|
413
|
-
const browserContext = getBrowserContext()
|
|
414
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
415
|
-
|
|
416
|
-
await serviceWorker.evaluate(async () => {
|
|
417
|
-
await globalThis.disconnectEverything()
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
const page1 = await browserContext.newPage()
|
|
421
|
-
await page1.goto('https://example.com/')
|
|
422
|
-
await page1.bringToFront()
|
|
423
|
-
await serviceWorker.evaluate(async () => {
|
|
424
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
const page2 = await browserContext.newPage()
|
|
428
|
-
await page2.goto('https://example.org/')
|
|
429
|
-
await page2.bringToFront()
|
|
430
|
-
await serviceWorker.evaluate(async () => {
|
|
431
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
432
|
-
})
|
|
433
|
-
|
|
434
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
435
|
-
|
|
436
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
437
|
-
const cdpPage = browser
|
|
438
|
-
.contexts()[0]
|
|
439
|
-
.pages()
|
|
440
|
-
.find((p) => p.url().includes('example.com'))
|
|
441
|
-
expect(cdpPage).toBeDefined()
|
|
442
|
-
|
|
443
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
444
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
445
|
-
|
|
446
|
-
const { targetInfos } = await cdpSession.send('Target.getTargets')
|
|
447
|
-
const allPageTargets = targetInfos.filter((t) => t.type === 'page')
|
|
448
|
-
|
|
449
|
-
const aboutBlankTargets = allPageTargets.filter((t) => t.url === 'about:blank')
|
|
450
|
-
expect(aboutBlankTargets).toHaveLength(0)
|
|
451
|
-
|
|
452
|
-
const pageTargets = allPageTargets
|
|
453
|
-
.map((t) => ({ type: t.type, url: t.url }))
|
|
454
|
-
.sort((a, b) => a.url.localeCompare(b.url))
|
|
455
|
-
|
|
456
|
-
expect(pageTargets).toMatchInlineSnapshot(`
|
|
457
|
-
[
|
|
458
|
-
{
|
|
459
|
-
"type": "page",
|
|
460
|
-
"url": "https://example.com/",
|
|
461
|
-
},
|
|
462
|
-
{
|
|
463
|
-
"type": "page",
|
|
464
|
-
"url": "https://example.org/",
|
|
465
|
-
},
|
|
466
|
-
]
|
|
467
|
-
`)
|
|
468
|
-
|
|
469
|
-
await cdpSession.detach()
|
|
470
|
-
await browser.close()
|
|
471
|
-
await page1.close()
|
|
472
|
-
await page2.close()
|
|
473
|
-
}, 60000)
|
|
474
|
-
|
|
475
|
-
it('should create CDP session for page after navigation', async () => {
|
|
476
|
-
const browserContext = getBrowserContext()
|
|
477
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
478
|
-
|
|
479
|
-
const page = await browserContext.newPage()
|
|
480
|
-
await page.goto('https://example.com/')
|
|
481
|
-
await page.bringToFront()
|
|
482
|
-
|
|
483
|
-
await serviceWorker.evaluate(async () => {
|
|
484
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
485
|
-
})
|
|
486
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
487
|
-
|
|
488
|
-
await page.goto('https://example.org/', { waitUntil: 'domcontentloaded' })
|
|
489
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
490
|
-
|
|
491
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
492
|
-
const cdpPage = browser
|
|
493
|
-
.contexts()[0]
|
|
494
|
-
.pages()
|
|
495
|
-
.find((p) => p.url().includes('example.org'))
|
|
496
|
-
expect(cdpPage).toBeDefined()
|
|
497
|
-
|
|
498
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
499
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
500
|
-
|
|
501
|
-
const evalResult = await cdpSession.send('Runtime.evaluate', {
|
|
502
|
-
expression: 'document.title',
|
|
503
|
-
returnByValue: true,
|
|
504
|
-
})
|
|
505
|
-
expect(evalResult.result.value).toContain('Example Domain')
|
|
506
|
-
|
|
507
|
-
await cdpSession.detach()
|
|
508
|
-
await browser.close()
|
|
509
|
-
await page.close()
|
|
510
|
-
}, 60000)
|
|
511
|
-
|
|
512
|
-
it('should maintain CDP session functionality after page URL change', async () => {
|
|
513
|
-
const browserContext = getBrowserContext()
|
|
514
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
515
|
-
|
|
516
|
-
const page = await browserContext.newPage()
|
|
517
|
-
const initialUrl = 'https://example.com/'
|
|
518
|
-
await page.goto(initialUrl)
|
|
519
|
-
await page.bringToFront()
|
|
520
|
-
|
|
521
|
-
await serviceWorker.evaluate(async () => {
|
|
522
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
523
|
-
})
|
|
524
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
525
|
-
|
|
526
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
527
|
-
const cdpPage = browser
|
|
528
|
-
.contexts()[0]
|
|
529
|
-
.pages()
|
|
530
|
-
.find((p) => p.url().includes('example.com'))
|
|
531
|
-
expect(cdpPage).toBeDefined()
|
|
532
|
-
|
|
533
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
534
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
535
|
-
|
|
536
|
-
const initialEvalResult = await cdpSession.send('Runtime.evaluate', {
|
|
537
|
-
expression: 'document.title',
|
|
538
|
-
returnByValue: true,
|
|
539
|
-
})
|
|
540
|
-
expect(initialEvalResult.result.value).toBe('Example Domain')
|
|
541
|
-
|
|
542
|
-
const newUrl = 'https://example.org/'
|
|
543
|
-
await cdpPage!.goto(newUrl, { waitUntil: 'domcontentloaded' })
|
|
544
|
-
|
|
545
|
-
expect(cdpPage!.url()).toBe(newUrl)
|
|
546
|
-
|
|
547
|
-
const layoutMetrics = await cdpSession.send('Page.getLayoutMetrics')
|
|
548
|
-
expect(layoutMetrics.cssVisualViewport).toBeDefined()
|
|
549
|
-
expect(layoutMetrics.cssVisualViewport.clientWidth).toBeGreaterThan(0)
|
|
550
|
-
|
|
551
|
-
const afterNavEvalResult = await cdpSession.send('Runtime.evaluate', {
|
|
552
|
-
expression: 'document.title',
|
|
553
|
-
returnByValue: true,
|
|
554
|
-
})
|
|
555
|
-
expect(afterNavEvalResult.result.value).toContain('Example Domain')
|
|
556
|
-
|
|
557
|
-
const locationResult = await cdpSession.send('Runtime.evaluate', {
|
|
558
|
-
expression: 'window.location.href',
|
|
559
|
-
returnByValue: true,
|
|
560
|
-
})
|
|
561
|
-
expect(locationResult.result.value).toBe(newUrl)
|
|
562
|
-
|
|
563
|
-
await cdpSession.detach()
|
|
564
|
-
await browser.close()
|
|
565
|
-
await page.close()
|
|
566
|
-
}, 60000)
|
|
567
|
-
|
|
568
|
-
it('should pause on all exceptions with setPauseOnExceptions', async () => {
|
|
569
|
-
const browserContext = getBrowserContext()
|
|
570
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
571
|
-
|
|
572
|
-
const page = await browserContext.newPage()
|
|
573
|
-
await page.goto('https://example.com/')
|
|
574
|
-
await page.bringToFront()
|
|
575
|
-
|
|
576
|
-
await serviceWorker.evaluate(async () => {
|
|
577
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
578
|
-
})
|
|
579
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
580
|
-
|
|
581
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
582
|
-
const cdpPage = browser
|
|
583
|
-
.contexts()[0]
|
|
584
|
-
.pages()
|
|
585
|
-
.find((p) => p.url().includes('example.com'))
|
|
586
|
-
expect(cdpPage).toBeDefined()
|
|
587
|
-
|
|
588
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
589
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
590
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
591
|
-
|
|
592
|
-
await dbg.enable()
|
|
593
|
-
await dbg.setPauseOnExceptions({ state: 'all' })
|
|
594
|
-
|
|
595
|
-
const pausedPromise = new Promise<void>((resolve) => {
|
|
596
|
-
cdpSession.on('Debugger.paused', () => resolve())
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
const evalPromise = cdpSession.send('Runtime.evaluate', {
|
|
600
|
-
expression: `(function() {
|
|
601
|
-
try {
|
|
602
|
-
throw new Error('Caught test error');
|
|
603
|
-
} catch (e) {
|
|
604
|
-
// caught but should still pause with state 'all'
|
|
605
|
-
}
|
|
606
|
-
})()`,
|
|
607
|
-
})
|
|
608
|
-
|
|
609
|
-
await Promise.race([
|
|
610
|
-
pausedPromise,
|
|
611
|
-
new Promise<never>((_, reject) => setTimeout(() => reject(new Error('Debugger.paused timeout')), 5000)),
|
|
612
|
-
])
|
|
613
|
-
|
|
614
|
-
expect(dbg.isPaused()).toBe(true)
|
|
615
|
-
|
|
616
|
-
const location = await dbg.getLocation()
|
|
617
|
-
expect(location.sourceContext).toContain('throw')
|
|
618
|
-
|
|
619
|
-
await dbg.resume()
|
|
620
|
-
await evalPromise
|
|
621
|
-
|
|
622
|
-
await dbg.setPauseOnExceptions({ state: 'none' })
|
|
623
|
-
|
|
624
|
-
await cdpSession.detach()
|
|
625
|
-
await browser.close()
|
|
626
|
-
await page.close()
|
|
627
|
-
}, 60000)
|
|
628
|
-
|
|
629
|
-
it('should inspect local and global variables with inline snapshots', async () => {
|
|
630
|
-
const browserContext = getBrowserContext()
|
|
631
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
632
|
-
|
|
633
|
-
const page = await browserContext.newPage()
|
|
634
|
-
await page.setContent(`
|
|
635
|
-
<html>
|
|
636
|
-
<head>
|
|
637
|
-
<script>
|
|
638
|
-
const GLOBAL_CONFIG = 'production';
|
|
639
|
-
function runTest() {
|
|
640
|
-
const userName = 'Alice';
|
|
641
|
-
const userAge = 25;
|
|
642
|
-
const settings = { theme: 'dark', lang: 'en' };
|
|
643
|
-
const scores = [10, 20, 30];
|
|
644
|
-
debugger;
|
|
645
|
-
return userName;
|
|
646
|
-
}
|
|
647
|
-
</script>
|
|
648
|
-
</head>
|
|
649
|
-
<body>
|
|
650
|
-
<button onclick="runTest()">Run</button>
|
|
651
|
-
</body>
|
|
652
|
-
</html>
|
|
653
|
-
`)
|
|
654
|
-
await page.bringToFront()
|
|
655
|
-
|
|
656
|
-
await serviceWorker.evaluate(async () => {
|
|
657
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
658
|
-
})
|
|
659
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
660
|
-
|
|
661
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
662
|
-
let cdpPage
|
|
663
|
-
for (const p of browser.contexts()[0].pages()) {
|
|
664
|
-
const html = await p.content()
|
|
665
|
-
if (html.includes('runTest')) {
|
|
666
|
-
cdpPage = p
|
|
667
|
-
break
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
expect(cdpPage).toBeDefined()
|
|
671
|
-
|
|
672
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
673
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
674
|
-
const dbg = new Debugger({ cdp: cdpSession })
|
|
675
|
-
|
|
676
|
-
await dbg.enable()
|
|
677
|
-
|
|
678
|
-
const globalVars = await dbg.inspectGlobalVariables()
|
|
679
|
-
expect(globalVars).toMatchInlineSnapshot(`
|
|
680
|
-
[
|
|
681
|
-
"GLOBAL_CONFIG",
|
|
682
|
-
]
|
|
683
|
-
`)
|
|
684
|
-
|
|
685
|
-
const pausedPromise = new Promise<void>((resolve) => {
|
|
686
|
-
cdpSession.on('Debugger.paused', () => resolve())
|
|
687
|
-
})
|
|
688
|
-
|
|
689
|
-
// Don't await - we want it to pause at breakpoint
|
|
690
|
-
const evalPromise = cdpPage!.evaluate('runTest()').catch(() => {
|
|
691
|
-
// Ignore errors from evaluate when browser closes
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
await pausedPromise
|
|
695
|
-
expect(dbg.isPaused()).toBe(true)
|
|
696
|
-
|
|
697
|
-
const localVars = await dbg.inspectLocalVariables()
|
|
698
|
-
expect(localVars).toMatchInlineSnapshot(`
|
|
699
|
-
{
|
|
700
|
-
"GLOBAL_CONFIG": "production",
|
|
701
|
-
"scores": "[array]",
|
|
702
|
-
"settings": "[object]",
|
|
703
|
-
"userAge": 25,
|
|
704
|
-
"userName": "Alice",
|
|
705
|
-
}
|
|
706
|
-
`)
|
|
707
|
-
|
|
708
|
-
await dbg.resume()
|
|
709
|
-
// Wait for evaluate to complete after resume
|
|
710
|
-
await evalPromise
|
|
711
|
-
|
|
712
|
-
await cdpSession.detach()
|
|
713
|
-
await browser.close()
|
|
714
|
-
await page.close()
|
|
715
|
-
}, 60000)
|
|
716
|
-
|
|
717
|
-
it('should click at correct coordinates on high-DPI simulation', async () => {
|
|
718
|
-
const browserContext = getBrowserContext()
|
|
719
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
720
|
-
|
|
721
|
-
const page = await browserContext.newPage()
|
|
722
|
-
await page.goto('https://example.com/')
|
|
723
|
-
await page.bringToFront()
|
|
724
|
-
|
|
725
|
-
await serviceWorker.evaluate(async () => {
|
|
726
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
727
|
-
})
|
|
728
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
729
|
-
|
|
730
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
731
|
-
const cdpPage = browser
|
|
732
|
-
.contexts()[0]
|
|
733
|
-
.pages()
|
|
734
|
-
.find((p) => p.url().includes('example.com'))
|
|
735
|
-
expect(cdpPage).toBeDefined()
|
|
736
|
-
|
|
737
|
-
const h1Bounds = await cdpPage!.locator('h1').boundingBox()
|
|
738
|
-
expect(h1Bounds).toBeDefined()
|
|
739
|
-
console.log('H1 bounding box:', h1Bounds)
|
|
740
|
-
|
|
741
|
-
await cdpPage!.evaluate(() => {
|
|
742
|
-
;(window as any).clickedAt = null
|
|
743
|
-
document.addEventListener('click', (e) => {
|
|
744
|
-
;(window as any).clickedAt = { x: e.clientX, y: e.clientY }
|
|
745
|
-
})
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
await cdpPage!.locator('h1').click()
|
|
749
|
-
|
|
750
|
-
const clickedAt = await cdpPage!.evaluate(() => (window as any).clickedAt)
|
|
751
|
-
console.log('Clicked at:', clickedAt)
|
|
752
|
-
|
|
753
|
-
expect(clickedAt).toBeDefined()
|
|
754
|
-
expect(clickedAt.x).toBeGreaterThan(0)
|
|
755
|
-
expect(clickedAt.y).toBeGreaterThan(0)
|
|
756
|
-
|
|
757
|
-
await browser.close()
|
|
758
|
-
await page.close()
|
|
759
|
-
}, 60000)
|
|
760
|
-
|
|
761
|
-
it('should use Editor class to list, read, and edit scripts', async () => {
|
|
762
|
-
const browserContext = getBrowserContext()
|
|
763
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
764
|
-
|
|
765
|
-
const page = await browserContext.newPage()
|
|
766
|
-
await page.goto('https://example.com/')
|
|
767
|
-
await page.bringToFront()
|
|
768
|
-
|
|
769
|
-
await serviceWorker.evaluate(async () => {
|
|
770
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
771
|
-
})
|
|
772
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
773
|
-
|
|
774
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
775
|
-
const cdpPage = browser
|
|
776
|
-
.contexts()[0]
|
|
777
|
-
.pages()
|
|
778
|
-
.find((p) => p.url().includes('example.com'))
|
|
779
|
-
expect(cdpPage).toBeDefined()
|
|
780
|
-
|
|
781
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
782
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
783
|
-
const editor = new Editor({ cdp: cdpSession })
|
|
784
|
-
|
|
785
|
-
await editor.enable()
|
|
786
|
-
|
|
787
|
-
await cdpPage!.addScriptTag({
|
|
788
|
-
content: `
|
|
789
|
-
function greetUser(name) {
|
|
790
|
-
console.log('Hello, ' + name);
|
|
791
|
-
return 'Hello, ' + name;
|
|
792
|
-
}
|
|
793
|
-
`,
|
|
794
|
-
})
|
|
795
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
796
|
-
const scripts = await editor.list()
|
|
797
|
-
expect(scripts.length).toBeGreaterThan(0)
|
|
798
|
-
|
|
799
|
-
const matches = await editor.grep({ regex: /greetUser/ })
|
|
800
|
-
expect(matches.length).toBeGreaterThan(0)
|
|
801
|
-
|
|
802
|
-
const match = matches[0]
|
|
803
|
-
const { content, totalLines } = await editor.read({ url: match.url })
|
|
804
|
-
expect(content).toContain('greetUser')
|
|
805
|
-
expect(totalLines).toBeGreaterThan(0)
|
|
806
|
-
|
|
807
|
-
await editor.edit({
|
|
808
|
-
url: match.url,
|
|
809
|
-
oldString: "console.log('Hello, ' + name);",
|
|
810
|
-
newString: "console.log('Hello, ' + name); console.log('EDITOR_TEST_MARKER');",
|
|
811
|
-
})
|
|
812
|
-
|
|
813
|
-
const consoleLogs: string[] = []
|
|
814
|
-
cdpPage!.on('console', (msg) => {
|
|
815
|
-
consoleLogs.push(msg.text())
|
|
816
|
-
})
|
|
817
|
-
|
|
818
|
-
await cdpPage!.evaluate(() => {
|
|
819
|
-
;(window as any).greetUser('World')
|
|
820
|
-
})
|
|
821
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
822
|
-
|
|
823
|
-
expect(consoleLogs).toContain('Hello, World')
|
|
824
|
-
expect(consoleLogs).toContain('EDITOR_TEST_MARKER')
|
|
825
|
-
|
|
826
|
-
await cdpSession.detach()
|
|
827
|
-
await browser.close()
|
|
828
|
-
await page.close()
|
|
829
|
-
}, 60000)
|
|
830
|
-
|
|
831
|
-
it('editor can list, read, and edit CSS stylesheets', async () => {
|
|
832
|
-
const browserContext = getBrowserContext()
|
|
833
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
834
|
-
|
|
835
|
-
const page = await browserContext.newPage()
|
|
836
|
-
await page.goto('https://example.com/')
|
|
837
|
-
await page.bringToFront()
|
|
838
|
-
|
|
839
|
-
await serviceWorker.evaluate(async () => {
|
|
840
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
841
|
-
})
|
|
842
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
843
|
-
|
|
844
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
845
|
-
const cdpPage = browser
|
|
846
|
-
.contexts()[0]
|
|
847
|
-
.pages()
|
|
848
|
-
.find((p) => p.url().includes('example.com'))
|
|
849
|
-
expect(cdpPage).toBeDefined()
|
|
850
|
-
|
|
851
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
852
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
853
|
-
const editor = new Editor({ cdp: cdpSession })
|
|
854
|
-
|
|
855
|
-
await editor.enable()
|
|
856
|
-
|
|
857
|
-
await cdpPage!.addStyleTag({
|
|
858
|
-
content: `
|
|
859
|
-
.editor-test-element {
|
|
860
|
-
color: rgb(255, 0, 0);
|
|
861
|
-
background-color: rgb(0, 0, 255);
|
|
862
|
-
}
|
|
863
|
-
`,
|
|
864
|
-
})
|
|
865
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
866
|
-
const stylesheets = await editor.list({ pattern: /inline-css:/ })
|
|
867
|
-
expect(stylesheets.length).toBeGreaterThan(0)
|
|
868
|
-
|
|
869
|
-
const cssMatches = await editor.grep({ regex: /editor-test-element/, pattern: /inline-css:/ })
|
|
870
|
-
expect(cssMatches.length).toBeGreaterThan(0)
|
|
871
|
-
|
|
872
|
-
const cssMatch = cssMatches[0]
|
|
873
|
-
const { content, totalLines } = await editor.read({ url: cssMatch.url })
|
|
874
|
-
expect(content).toContain('editor-test-element')
|
|
875
|
-
expect(content).toContain('rgb(255, 0, 0)')
|
|
876
|
-
expect(totalLines).toBeGreaterThan(0)
|
|
877
|
-
|
|
878
|
-
await cdpPage!.evaluate(() => {
|
|
879
|
-
const el = document.createElement('div')
|
|
880
|
-
el.className = 'editor-test-element'
|
|
881
|
-
el.id = 'test-div'
|
|
882
|
-
el.textContent = 'Test'
|
|
883
|
-
document.body.appendChild(el)
|
|
884
|
-
})
|
|
885
|
-
|
|
886
|
-
const colorBefore = await cdpPage!.evaluate(() => {
|
|
887
|
-
const el = document.getElementById('test-div')!
|
|
888
|
-
return window.getComputedStyle(el).color
|
|
889
|
-
})
|
|
890
|
-
expect(colorBefore).toBe('rgb(255, 0, 0)')
|
|
891
|
-
|
|
892
|
-
await editor.edit({
|
|
893
|
-
url: cssMatch.url,
|
|
894
|
-
oldString: 'color: rgb(255, 0, 0);',
|
|
895
|
-
newString: 'color: rgb(0, 255, 0);',
|
|
896
|
-
})
|
|
897
|
-
|
|
898
|
-
const colorAfter = await cdpPage!.evaluate(() => {
|
|
899
|
-
const el = document.getElementById('test-div')!
|
|
900
|
-
return window.getComputedStyle(el).color
|
|
901
|
-
})
|
|
902
|
-
expect(colorAfter).toBe('rgb(0, 255, 0)')
|
|
903
|
-
|
|
904
|
-
await cdpSession.detach()
|
|
905
|
-
await browser.close()
|
|
906
|
-
await page.close()
|
|
907
|
-
}, 60000)
|
|
908
|
-
|
|
909
|
-
it('should inject bippy and find React fiber with getReactSource', async () => {
|
|
910
|
-
const browserContext = getBrowserContext()
|
|
911
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
912
|
-
|
|
913
|
-
const page = await browserContext.newPage()
|
|
914
|
-
await page.setContent(`
|
|
915
|
-
<!DOCTYPE html>
|
|
916
|
-
<html>
|
|
917
|
-
<head>
|
|
918
|
-
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
|
919
|
-
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
|
920
|
-
</head>
|
|
921
|
-
<body>
|
|
922
|
-
<div id="root"></div>
|
|
923
|
-
<script>
|
|
924
|
-
function SaveButton(props) {
|
|
925
|
-
return React.createElement('button', { id: 'react-btn' }, props.label);
|
|
926
|
-
}
|
|
927
|
-
function Panel() {
|
|
928
|
-
return React.createElement('section', null, React.createElement(SaveButton, {
|
|
929
|
-
label: 'Click me',
|
|
930
|
-
count: 3,
|
|
931
|
-
config: { variant: 'primary' },
|
|
932
|
-
onClick: () => {}
|
|
933
|
-
}));
|
|
934
|
-
}
|
|
935
|
-
function App() {
|
|
936
|
-
return React.createElement(Panel);
|
|
937
|
-
}
|
|
938
|
-
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
939
|
-
root.render(React.createElement(App));
|
|
940
|
-
</script>
|
|
941
|
-
<button id="plain-btn">Plain</button>
|
|
942
|
-
</body>
|
|
943
|
-
</html>
|
|
944
|
-
`)
|
|
945
|
-
await page.bringToFront()
|
|
946
|
-
|
|
947
|
-
await serviceWorker.evaluate(async () => {
|
|
948
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
949
|
-
})
|
|
950
|
-
await new Promise((r) => setTimeout(r, 500))
|
|
951
|
-
|
|
952
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
953
|
-
const pages = browser.contexts()[0].pages()
|
|
954
|
-
const cdpPage = pages.find((p) => p.url().startsWith('about:'))
|
|
955
|
-
expect(cdpPage).toBeDefined()
|
|
956
|
-
|
|
957
|
-
const btn = cdpPage!.locator('#react-btn')
|
|
958
|
-
const btnCount = await btn.count()
|
|
959
|
-
expect(btnCount).toBe(1)
|
|
960
|
-
|
|
961
|
-
const hasBippyBefore = await cdpPage!.evaluate(() => !!globalThis.__bippy)
|
|
962
|
-
expect(hasBippyBefore).toBe(false)
|
|
963
|
-
|
|
964
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
965
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
966
|
-
|
|
967
|
-
const { getReactSource, getReactComponentInfo } = await import('./react-source.js')
|
|
968
|
-
const source = await getReactSource({ locator: btn, cdp: cdpSession })
|
|
969
|
-
const info = await getReactComponentInfo({ locator: btn, cdp: cdpSession })
|
|
970
|
-
const plainInfo = await getReactComponentInfo({ locator: cdpPage!.locator('#plain-btn'), cdp: cdpSession })
|
|
971
|
-
|
|
972
|
-
const hasBippyAfter = await cdpPage!.evaluate(() => !!globalThis.__bippy)
|
|
973
|
-
expect(hasBippyAfter).toBe(true)
|
|
974
|
-
|
|
975
|
-
const hasFiber = await btn.evaluate((el) => {
|
|
976
|
-
const bippy = globalThis.__bippy
|
|
977
|
-
if (!bippy) return false
|
|
978
|
-
const fiber = bippy.getFiberFromHostInstance(el)
|
|
979
|
-
return !!fiber
|
|
980
|
-
})
|
|
981
|
-
expect(hasFiber).toBe(true)
|
|
982
|
-
|
|
983
|
-
const componentName = await btn.evaluate((el) => {
|
|
984
|
-
const bippy = globalThis.__bippy
|
|
985
|
-
if (!bippy) return null
|
|
986
|
-
const fiber = bippy.getFiberFromHostInstance(el)
|
|
987
|
-
let current = fiber
|
|
988
|
-
while (current) {
|
|
989
|
-
if (bippy.isCompositeFiber(current)) {
|
|
990
|
-
return bippy.getDisplayName(current.type)
|
|
991
|
-
}
|
|
992
|
-
current = current.return ?? null
|
|
993
|
-
}
|
|
994
|
-
return null
|
|
995
|
-
})
|
|
996
|
-
expect(componentName).toBe('SaveButton')
|
|
997
|
-
expect(plainInfo).toBe(null)
|
|
998
|
-
expect(info?.componentName).toBe('SaveButton')
|
|
999
|
-
expect(info?.hierarchy.map((item) => item.componentName)).toEqual(['SaveButton', 'Panel', 'App'])
|
|
1000
|
-
expect(info?.props).toEqual({
|
|
1001
|
-
label: 'Click me',
|
|
1002
|
-
count: 3,
|
|
1003
|
-
config: { variant: 'primary' },
|
|
1004
|
-
onClick: '[function]',
|
|
1005
|
-
})
|
|
1006
|
-
|
|
1007
|
-
console.log('Component name from fiber:', componentName)
|
|
1008
|
-
console.log('React component info:', info)
|
|
1009
|
-
console.log('Source location (null for UMD React, works on local dev servers with JSX transform):', source)
|
|
1010
|
-
|
|
1011
|
-
await browser.close()
|
|
1012
|
-
await page.close()
|
|
1013
|
-
}, 60000)
|
|
1014
|
-
})
|
|
1015
|
-
|
|
1016
|
-
// --- Service Worker Target Tests ---
|
|
1017
|
-
|
|
1018
|
-
describe('Service Worker Target Tests', () => {
|
|
1019
|
-
let testCtx: TestContext | null = null
|
|
1020
|
-
|
|
1021
|
-
beforeAll(async () => {
|
|
1022
|
-
testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'pw-sw-test-', toggleExtension: true })
|
|
1023
|
-
}, 600000)
|
|
1024
|
-
|
|
1025
|
-
afterAll(async () => {
|
|
1026
|
-
await cleanupTestContext(testCtx)
|
|
1027
|
-
testCtx = null
|
|
1028
|
-
})
|
|
1029
|
-
|
|
1030
|
-
const getBrowserContext = () => {
|
|
1031
|
-
if (!testCtx?.browserContext) throw new Error('Browser not initialized')
|
|
1032
|
-
return testCtx.browserContext
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
it('should not expose service worker targets to Playwright (issue #14)', async () => {
|
|
1036
|
-
const browserContext = getBrowserContext()
|
|
1037
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
1038
|
-
|
|
1039
|
-
const page = await browserContext.newPage()
|
|
1040
|
-
await page.goto('https://web.dev/', { waitUntil: 'load' })
|
|
1041
|
-
await page.bringToFront()
|
|
1042
|
-
|
|
1043
|
-
await serviceWorker.evaluate(async () => {
|
|
1044
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
1045
|
-
})
|
|
1046
|
-
await new Promise((r) => setTimeout(r, 500))
|
|
1047
|
-
|
|
1048
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
1049
|
-
const context = browser.contexts()[0]
|
|
1050
|
-
|
|
1051
|
-
const pages = context.pages()
|
|
1052
|
-
|
|
1053
|
-
for (const p of pages) {
|
|
1054
|
-
const url = p.url()
|
|
1055
|
-
console.log('Page URL:', url)
|
|
1056
|
-
expect(url).not.toMatch(/sw\.js$/i)
|
|
1057
|
-
expect(url).not.toMatch(/service.?worker/i)
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
const targetPage = pages.find((p) => p.url().includes('web.dev'))
|
|
1061
|
-
expect(targetPage).toBeDefined()
|
|
1062
|
-
|
|
1063
|
-
const title = await targetPage!.title()
|
|
1064
|
-
expect(title).toBeTruthy()
|
|
1065
|
-
|
|
1066
|
-
await safeCloseCDPBrowser(browser)
|
|
1067
|
-
await page.close()
|
|
1068
|
-
}, 60000)
|
|
1069
|
-
|
|
1070
|
-
it('should allow reading response bodies after re-enabling Network buffering', async () => {
|
|
1071
|
-
const browserContext = getBrowserContext()
|
|
1072
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
1073
|
-
|
|
1074
|
-
const page = await browserContext.newPage()
|
|
1075
|
-
await page.goto('https://example.com/')
|
|
1076
|
-
await page.bringToFront()
|
|
1077
|
-
|
|
1078
|
-
await serviceWorker.evaluate(async () => {
|
|
1079
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
1080
|
-
})
|
|
1081
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
1082
|
-
|
|
1083
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
|
1084
|
-
const cdpPage = browser
|
|
1085
|
-
.contexts()[0]
|
|
1086
|
-
.pages()
|
|
1087
|
-
.find((p) => p.url().includes('example.com'))
|
|
1088
|
-
expect(cdpPage).toBeDefined()
|
|
1089
|
-
|
|
1090
|
-
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
|
1091
|
-
const cdpSession = await getCDPSessionForPage({ page: cdpPage! })
|
|
1092
|
-
|
|
1093
|
-
await cdpSession.send('Network.disable')
|
|
1094
|
-
await cdpSession.send('Network.enable', {
|
|
1095
|
-
maxTotalBufferSize: 10000000,
|
|
1096
|
-
maxResourceBufferSize: 5000000,
|
|
1097
|
-
})
|
|
1098
|
-
|
|
1099
|
-
const [response] = await Promise.all([
|
|
1100
|
-
cdpPage!.waitForResponse((resp) => resp.url() === 'https://example.com/'),
|
|
1101
|
-
cdpPage!.goto('https://example.com/'),
|
|
1102
|
-
])
|
|
1103
|
-
|
|
1104
|
-
const body = await response.text()
|
|
1105
|
-
|
|
1106
|
-
expect(body).toBeDefined()
|
|
1107
|
-
expect(body).toContain('Example Domain')
|
|
1108
|
-
expect(body).toContain('</html>')
|
|
1109
|
-
|
|
1110
|
-
await cdpSession.detach()
|
|
1111
|
-
await browser.close()
|
|
1112
|
-
await page.close()
|
|
1113
|
-
}, 60000)
|
|
1114
|
-
|
|
1115
|
-
it('should stream SSE without waiting for response end', async () => {
|
|
1116
|
-
const browserContext = getBrowserContext()
|
|
1117
|
-
const serviceWorker = await withTimeout({
|
|
1118
|
-
promise: getExtensionServiceWorker(browserContext),
|
|
1119
|
-
timeoutMs: 5000,
|
|
1120
|
-
errorMessage: 'getExtensionServiceWorker timed out',
|
|
1121
|
-
})
|
|
1122
|
-
const sseServer = await withTimeout({
|
|
1123
|
-
promise: createSseServer(),
|
|
1124
|
-
timeoutMs: 5000,
|
|
1125
|
-
errorMessage: 'createSseServer timed out',
|
|
1126
|
-
})
|
|
1127
|
-
let page: Awaited<ReturnType<typeof browserContext.newPage>> | null = null
|
|
1128
|
-
let browser: Awaited<ReturnType<typeof chromium.connectOverCDP>> | null = null
|
|
1129
|
-
|
|
1130
|
-
try {
|
|
1131
|
-
page = await withTimeout({
|
|
1132
|
-
promise: browserContext.newPage(),
|
|
1133
|
-
timeoutMs: 5000,
|
|
1134
|
-
errorMessage: 'newPage timed out',
|
|
1135
|
-
})
|
|
1136
|
-
await withTimeout({
|
|
1137
|
-
promise: page.goto(`${sseServer.baseUrl}/`),
|
|
1138
|
-
timeoutMs: 5000,
|
|
1139
|
-
errorMessage: 'page.goto timed out',
|
|
1140
|
-
})
|
|
1141
|
-
await page.bringToFront()
|
|
1142
|
-
|
|
1143
|
-
await withTimeout({
|
|
1144
|
-
promise: serviceWorker.evaluate(async () => {
|
|
1145
|
-
await globalThis.toggleExtensionForActiveTab()
|
|
1146
|
-
}),
|
|
1147
|
-
timeoutMs: 5000,
|
|
1148
|
-
errorMessage: 'toggleExtensionForActiveTab timed out',
|
|
1149
|
-
})
|
|
1150
|
-
await new Promise((resolve) => {
|
|
1151
|
-
setTimeout(resolve, 100)
|
|
1152
|
-
})
|
|
1153
|
-
|
|
1154
|
-
browser = await withTimeout({
|
|
1155
|
-
promise: chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT })),
|
|
1156
|
-
timeoutMs: 5000,
|
|
1157
|
-
errorMessage: 'connectOverCDP timed out',
|
|
1158
|
-
})
|
|
1159
|
-
const cdpPage = browser
|
|
1160
|
-
.contexts()[0]
|
|
1161
|
-
.pages()
|
|
1162
|
-
.find((p) => {
|
|
1163
|
-
return p.url().startsWith(sseServer.baseUrl)
|
|
1164
|
-
})
|
|
1165
|
-
expect(cdpPage).toBeDefined()
|
|
1166
|
-
|
|
1167
|
-
await cdpPage!.evaluate(() => {
|
|
1168
|
-
return window.startSse()
|
|
1169
|
-
})
|
|
1170
|
-
await withTimeout({
|
|
1171
|
-
promise: cdpPage!.waitForFunction(
|
|
1172
|
-
() => {
|
|
1173
|
-
return window.__sseMessages.length > 0
|
|
1174
|
-
},
|
|
1175
|
-
{ timeout: 5000 },
|
|
1176
|
-
),
|
|
1177
|
-
timeoutMs: 7000,
|
|
1178
|
-
errorMessage: 'SSE message not received in time',
|
|
1179
|
-
})
|
|
1180
|
-
|
|
1181
|
-
const firstMessage = await cdpPage!.evaluate(() => {
|
|
1182
|
-
return window.__sseMessages[0]
|
|
1183
|
-
})
|
|
1184
|
-
expect(firstMessage).toBe('hello')
|
|
1185
|
-
|
|
1186
|
-
const sseState = sseServer.getState()
|
|
1187
|
-
expect(sseState.connected).toBe(true)
|
|
1188
|
-
expect(sseState.finished).toBe(false)
|
|
1189
|
-
expect(sseState.closed).toBe(false)
|
|
1190
|
-
expect(sseState.writeCount).toBeGreaterThan(0)
|
|
1191
|
-
|
|
1192
|
-
const readyState = await cdpPage!.evaluate(() => {
|
|
1193
|
-
if (!window.__sseSource) {
|
|
1194
|
-
return -1
|
|
1195
|
-
}
|
|
1196
|
-
return window.__sseSource.readyState
|
|
1197
|
-
})
|
|
1198
|
-
expect(readyState).toBe(1)
|
|
1199
|
-
|
|
1200
|
-
await cdpPage!.evaluate(() => {
|
|
1201
|
-
window.stopSse()
|
|
1202
|
-
})
|
|
1203
|
-
await new Promise((resolve) => {
|
|
1204
|
-
setTimeout(resolve, 100)
|
|
1205
|
-
})
|
|
1206
|
-
} finally {
|
|
1207
|
-
if (browser) {
|
|
1208
|
-
await withTimeout({
|
|
1209
|
-
promise: browser.close(),
|
|
1210
|
-
timeoutMs: 5000,
|
|
1211
|
-
errorMessage: 'browser.close timed out',
|
|
1212
|
-
})
|
|
1213
|
-
}
|
|
1214
|
-
if (page) {
|
|
1215
|
-
await withTimeout({
|
|
1216
|
-
promise: page.close(),
|
|
1217
|
-
timeoutMs: 5000,
|
|
1218
|
-
errorMessage: 'page.close timed out',
|
|
1219
|
-
})
|
|
1220
|
-
}
|
|
1221
|
-
await withTimeout({
|
|
1222
|
-
promise: sseServer.close(),
|
|
1223
|
-
timeoutMs: 5000,
|
|
1224
|
-
errorMessage: 'sseServer.close timed out',
|
|
1225
|
-
})
|
|
1226
|
-
}
|
|
1227
|
-
}, 60000)
|
|
1228
|
-
})
|
|
1229
|
-
|
|
1230
|
-
// --- Auto-enable Tests ---
|
|
1231
|
-
|
|
1232
|
-
describe('Auto-enable Tests', () => {
|
|
1233
|
-
let testCtx: TestContext | null = null
|
|
1234
|
-
let client: Awaited<ReturnType<typeof createMCPClient>>['client']
|
|
1235
|
-
let cleanup: (() => Promise<void>) | null = null
|
|
1236
|
-
|
|
1237
|
-
beforeAll(async () => {
|
|
1238
|
-
process.env.PLAYWRITER_AUTO_ENABLE = '1'
|
|
1239
|
-
testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'pw-auto-test-' })
|
|
1240
|
-
|
|
1241
|
-
const result = await createMCPClient({ port: TEST_PORT })
|
|
1242
|
-
client = result.client
|
|
1243
|
-
cleanup = result.cleanup
|
|
1244
|
-
|
|
1245
|
-
// Disconnect all tabs to start with a clean state
|
|
1246
|
-
const serviceWorker = await getExtensionServiceWorker(testCtx.browserContext)
|
|
1247
|
-
await serviceWorker.evaluate(async () => {
|
|
1248
|
-
await globalThis.disconnectEverything()
|
|
1249
|
-
})
|
|
1250
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
1251
|
-
}, 600000)
|
|
1252
|
-
|
|
1253
|
-
afterAll(async () => {
|
|
1254
|
-
delete process.env.PLAYWRITER_AUTO_ENABLE
|
|
1255
|
-
await cleanupTestContext(testCtx, cleanup)
|
|
1256
|
-
cleanup = null
|
|
1257
|
-
testCtx = null
|
|
1258
|
-
})
|
|
1259
|
-
|
|
1260
|
-
const getBrowserContext = () => {
|
|
1261
|
-
if (!testCtx?.browserContext) throw new Error('Browser not initialized')
|
|
1262
|
-
return testCtx.browserContext
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
it('should auto-create a tab when Playwright connects and no tabs exist', async () => {
|
|
1266
|
-
const browserContext = getBrowserContext()
|
|
1267
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
1268
|
-
|
|
1269
|
-
await serviceWorker.evaluate(async () => {
|
|
1270
|
-
await globalThis.disconnectEverything()
|
|
1271
|
-
})
|
|
1272
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
1273
|
-
|
|
1274
|
-
const tabCountBefore = await serviceWorker.evaluate(() => {
|
|
1275
|
-
const state = globalThis.getExtensionState()
|
|
1276
|
-
return state.tabs.size
|
|
1277
|
-
})
|
|
1278
|
-
expect(tabCountBefore).toBe(0)
|
|
1279
|
-
|
|
1280
|
-
const previousAutoEnable = process.env.PLAYWRITER_AUTO_ENABLE
|
|
1281
|
-
delete process.env.PLAYWRITER_AUTO_ENABLE
|
|
1282
|
-
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT })).finally(() => {
|
|
1283
|
-
if (previousAutoEnable === undefined) {
|
|
1284
|
-
delete process.env.PLAYWRITER_AUTO_ENABLE
|
|
1285
|
-
return
|
|
1286
|
-
}
|
|
1287
|
-
process.env.PLAYWRITER_AUTO_ENABLE = previousAutoEnable
|
|
1288
|
-
})
|
|
1289
|
-
|
|
1290
|
-
const pages = browser.contexts()[0].pages()
|
|
1291
|
-
expect(pages.length).toBeGreaterThan(0)
|
|
1292
|
-
expect(pages.length).toBe(1)
|
|
1293
|
-
|
|
1294
|
-
const autoCreatedPage = pages[0]
|
|
1295
|
-
expect(autoCreatedPage.url()).toBe('about:blank')
|
|
1296
|
-
|
|
1297
|
-
const tabCountAfter = await serviceWorker.evaluate(() => {
|
|
1298
|
-
const state = globalThis.getExtensionState()
|
|
1299
|
-
return state.tabs.size
|
|
1300
|
-
})
|
|
1301
|
-
expect(tabCountAfter).toBe(1)
|
|
1302
|
-
|
|
1303
|
-
await autoCreatedPage.setContent('<h1>Auto-created page</h1>')
|
|
1304
|
-
const title = await autoCreatedPage.locator('h1').textContent()
|
|
1305
|
-
expect(title).toBe('Auto-created page')
|
|
1306
|
-
|
|
1307
|
-
await browser.close()
|
|
1308
|
-
}, 60000)
|
|
1309
|
-
|
|
1310
|
-
it('should auto-create a page when MCP executes with no connected pages', async () => {
|
|
1311
|
-
const browserContext = getBrowserContext()
|
|
1312
|
-
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
|
1313
|
-
|
|
1314
|
-
await serviceWorker.evaluate(async () => {
|
|
1315
|
-
await globalThis.disconnectEverything()
|
|
1316
|
-
})
|
|
1317
|
-
await new Promise((r) => {
|
|
1318
|
-
setTimeout(r, 100)
|
|
1319
|
-
})
|
|
1320
|
-
|
|
1321
|
-
const tabCountBefore = await serviceWorker.evaluate(() => {
|
|
1322
|
-
const state = globalThis.getExtensionState()
|
|
1323
|
-
return state.tabs.size
|
|
1324
|
-
})
|
|
1325
|
-
expect(tabCountBefore).toBe(0)
|
|
1326
|
-
|
|
1327
|
-
const result = await client.callTool({
|
|
1328
|
-
name: 'execute',
|
|
1329
|
-
arguments: {
|
|
1330
|
-
code: js`
|
|
1331
|
-
return { pageCount: context.pages().length, url: page.url() };
|
|
1332
|
-
`,
|
|
1333
|
-
},
|
|
1334
|
-
})
|
|
1335
|
-
|
|
1336
|
-
expect((result as any).isError).toBeFalsy()
|
|
1337
|
-
const text = (result as any).content[0].text
|
|
1338
|
-
expect(text).toContain('pageCount')
|
|
1339
|
-
expect(text).toContain('about:blank')
|
|
1340
|
-
|
|
1341
|
-
const tabCountAfter = await serviceWorker.evaluate(() => {
|
|
1342
|
-
const state = globalThis.getExtensionState()
|
|
1343
|
-
return state.tabs.size
|
|
1344
|
-
})
|
|
1345
|
-
expect(tabCountAfter).toBe(1)
|
|
1346
|
-
|
|
1347
|
-
await client.callTool({
|
|
1348
|
-
name: 'execute',
|
|
1349
|
-
arguments: {
|
|
1350
|
-
code: js`
|
|
1351
|
-
await page.close();
|
|
1352
|
-
return { remaining: context.pages().length };
|
|
1353
|
-
`,
|
|
1354
|
-
},
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
|
-
await new Promise((r) => {
|
|
1358
|
-
setTimeout(r, 100)
|
|
1359
|
-
})
|
|
1360
|
-
|
|
1361
|
-
const afterCloseResult = await client.callTool({
|
|
1362
|
-
name: 'execute',
|
|
1363
|
-
arguments: {
|
|
1364
|
-
code: js`
|
|
1365
|
-
return { pageCount: context.pages().length, url: page.url() };
|
|
1366
|
-
`,
|
|
1367
|
-
},
|
|
1368
|
-
})
|
|
1369
|
-
|
|
1370
|
-
expect((afterCloseResult as any).isError).toBeFalsy()
|
|
1371
|
-
const afterCloseText = (afterCloseResult as any).content[0].text
|
|
1372
|
-
expect(afterCloseText).toContain('pageCount')
|
|
1373
|
-
expect(afterCloseText).toContain('about:blank')
|
|
1374
|
-
}, 60000)
|
|
1375
|
-
})
|