@stablyai/internal-playwright 0.1.0
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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +168 -0
- package/ThirdPartyNotices.txt +6277 -0
- package/cli.js +19 -0
- package/index.d.ts +17 -0
- package/index.js +17 -0
- package/index.mjs +18 -0
- package/jsx-runtime.js +42 -0
- package/jsx-runtime.mjs +21 -0
- package/lib/agents/generateAgents.js +265 -0
- package/lib/agents/generator.md +102 -0
- package/lib/agents/healer.md +78 -0
- package/lib/agents/planner.md +135 -0
- package/lib/cli.js +274 -0
- package/lib/common/config.js +274 -0
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js +377 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +102 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +52 -0
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +389 -0
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js +302 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js +58 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js +60 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js +85 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +104 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js +140 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js +321 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js +100 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js +310 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/fsWatcher.js +67 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +696 -0
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js +42 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js +77 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js +30 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js +69 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +507 -0
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +137 -0
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js +211 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js +16 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +334 -0
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js +16 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js +59 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +325 -0
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +87 -0
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +366 -0
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +73 -0
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +99 -0
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +102 -0
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +159 -0
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +359 -0
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +99 -0
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js +16 -0
- package/lib/mcp/browser/backend.js +93 -0
- package/lib/mcp/browser/backend.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +296 -0
- package/lib/mcp/browser/browserServerBackend.js +76 -0
- package/lib/mcp/browser/codegen.js +66 -0
- package/lib/mcp/browser/config.js +385 -0
- package/lib/mcp/browser/context.js +287 -0
- package/lib/mcp/browser/response.js +228 -0
- package/lib/mcp/browser/sessionLog.js +160 -0
- package/lib/mcp/browser/tab.js +277 -0
- package/lib/mcp/browser/tool.js +30 -0
- package/lib/mcp/browser/tool.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +63 -0
- package/lib/mcp/browser/tools/console.js +44 -0
- package/lib/mcp/browser/tools/dialogs.js +60 -0
- package/lib/mcp/browser/tools/evaluate.js +70 -0
- package/lib/mcp/browser/tools/files.js +58 -0
- package/lib/mcp/browser/tools/form.js +74 -0
- package/lib/mcp/browser/tools/install.js +69 -0
- package/lib/mcp/browser/tools/keyboard.js +85 -0
- package/lib/mcp/browser/tools/mouse.js +107 -0
- package/lib/mcp/browser/tools/navigate.js +62 -0
- package/lib/mcp/browser/tools/network.js +54 -0
- package/lib/mcp/browser/tools/pdf.js +59 -0
- package/lib/mcp/browser/tools/screenshot.js +88 -0
- package/lib/mcp/browser/tools/snapshot.js +182 -0
- package/lib/mcp/browser/tools/tabs.js +67 -0
- package/lib/mcp/browser/tools/tool.js +49 -0
- package/lib/mcp/browser/tools/tracing.js +74 -0
- package/lib/mcp/browser/tools/utils.js +100 -0
- package/lib/mcp/browser/tools/verify.js +154 -0
- package/lib/mcp/browser/tools/wait.js +63 -0
- package/lib/mcp/browser/tools.js +80 -0
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js +44 -0
- package/lib/mcp/config.d.js +16 -0
- package/lib/mcp/extension/cdpRelay.js +351 -0
- package/lib/mcp/extension/extensionContextFactory.js +75 -0
- package/lib/mcp/extension/protocol.js +28 -0
- package/lib/mcp/index.js +61 -0
- package/lib/mcp/log.js +35 -0
- package/lib/mcp/program.js +96 -0
- package/lib/mcp/sdk/bundle.js +81 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/call.js +49 -0
- package/lib/mcp/sdk/call.js.map +7 -0
- package/lib/mcp/sdk/exports.js +32 -0
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +187 -0
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js +71 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/mdb.js +206 -0
- package/lib/mcp/sdk/mdb.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js +128 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +189 -0
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +51 -0
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/test/backend.js +67 -0
- package/lib/mcp/test/backend.js.map +7 -0
- package/lib/mcp/test/browserBackend.js +98 -0
- package/lib/mcp/test/context.js +48 -0
- package/lib/mcp/test/context.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +122 -0
- package/lib/mcp/test/plannerTools.js +46 -0
- package/lib/mcp/test/seed.js +72 -0
- package/lib/mcp/test/streams.js +39 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +97 -0
- package/lib/mcp/test/testContext.js +176 -0
- package/lib/mcp/test/testTool.js +30 -0
- package/lib/mcp/test/testTools.js +115 -0
- package/lib/mcp/test/tool.js +30 -0
- package/lib/mcp/test/tool.js.map +7 -0
- package/lib/mcp/test/tools.js +150 -0
- package/lib/mcp/test/tools.js.map +7 -0
- package/lib/mcp/vscode/host.js +187 -0
- package/lib/mcp/vscode/main.js +77 -0
- package/lib/mcpBundleImpl.js +41 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js +198 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js +28 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js +209 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +412 -0
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +609 -0
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +135 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +82 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js +32 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js +128 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +644 -0
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +130 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js +254 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js +230 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +113 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +235 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js +69 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js +144 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +535 -0
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +104 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js +102 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/teleEmitter.js +297 -0
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js +16 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +491 -0
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js +72 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js +77 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +333 -0
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js +89 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +161 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +241 -0
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js +189 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +137 -0
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/runner.js +173 -0
- package/lib/runner/sigIntWatcher.js +96 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/taskRunner.js +127 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js +410 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +117 -0
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +390 -0
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +264 -0
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiMode.js +271 -0
- package/lib/runner/uiModeReporter.js +30 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js +72 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +395 -0
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +95 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/store.js +98 -0
- package/lib/third_party/pirates.js +62 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js +103 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +43 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +461 -0
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +272 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +104 -0
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/esmUtils.js +32 -0
- package/lib/transform/portTransport.js +67 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +293 -0
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +403 -0
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +43 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +100 -0
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +258 -0
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/stepContext.js +34 -0
- package/lib/worker/testInfo.js +508 -0
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js +344 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js +174 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js +31 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +520 -0
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +74 -0
- package/test.d.ts +18 -0
- package/test.js +24 -0
- package/test.mjs +33 -0
- package/types/test.d.ts +10217 -0
- package/types/testReporter.d.ts +816 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
---
|
2
|
+
name: planner
|
3
|
+
description: Use this agent when you need to create comprehensive test plan for a web application or website
|
4
|
+
model: sonnet
|
5
|
+
color: green
|
6
|
+
tools:
|
7
|
+
- ls
|
8
|
+
- grep
|
9
|
+
- read
|
10
|
+
- write
|
11
|
+
- playwright-test/browser_click
|
12
|
+
- playwright-test/browser_close
|
13
|
+
- playwright-test/browser_console_messages
|
14
|
+
- playwright-test/browser_drag
|
15
|
+
- playwright-test/browser_evaluate
|
16
|
+
- playwright-test/browser_file_upload
|
17
|
+
- playwright-test/browser_handle_dialog
|
18
|
+
- playwright-test/browser_hover
|
19
|
+
- playwright-test/browser_navigate
|
20
|
+
- playwright-test/browser_navigate_back
|
21
|
+
- playwright-test/browser_network_requests
|
22
|
+
- playwright-test/browser_press_key
|
23
|
+
- playwright-test/browser_select_option
|
24
|
+
- playwright-test/browser_snapshot
|
25
|
+
- playwright-test/browser_take_screenshot
|
26
|
+
- playwright-test/browser_type
|
27
|
+
- playwright-test/browser_wait_for
|
28
|
+
- playwright-test/planner_setup_page
|
29
|
+
---
|
30
|
+
|
31
|
+
You are an expert web test planner with extensive experience in quality assurance, user experience testing, and test
|
32
|
+
scenario design. Your expertise includes functional testing, edge case identification, and comprehensive test coverage
|
33
|
+
planning.
|
34
|
+
|
35
|
+
You will:
|
36
|
+
|
37
|
+
1. **Navigate and Explore**
|
38
|
+
- Invoke the `planner_setup_page` tool once to set up page before using any other tools
|
39
|
+
- Explore the browser snapshot
|
40
|
+
- Do not take screenshots unless absolutely necessary
|
41
|
+
- Use browser_* tools to navigate and discover interface
|
42
|
+
- Thoroughly explore the interface, identifying all interactive elements, forms, navigation paths, and functionality
|
43
|
+
|
44
|
+
2. **Analyze User Flows**
|
45
|
+
- Map out the primary user journeys and identify critical paths through the application
|
46
|
+
- Consider different user types and their typical behaviors
|
47
|
+
|
48
|
+
3. **Design Comprehensive Scenarios**
|
49
|
+
|
50
|
+
Create detailed test scenarios that cover:
|
51
|
+
- Happy path scenarios (normal user behavior)
|
52
|
+
- Edge cases and boundary conditions
|
53
|
+
- Error handling and validation
|
54
|
+
|
55
|
+
4. **Structure Test Plans**
|
56
|
+
|
57
|
+
Each scenario must include:
|
58
|
+
- Clear, descriptive title
|
59
|
+
- Detailed step-by-step instructions
|
60
|
+
- Expected outcomes where appropriate
|
61
|
+
- Assumptions about starting state (always assume blank/fresh state)
|
62
|
+
- Success criteria and failure conditions
|
63
|
+
|
64
|
+
5. **Create Documentation**
|
65
|
+
|
66
|
+
Save your test plan as requested:
|
67
|
+
- Executive summary of the tested page/application
|
68
|
+
- Individual scenarios as separate sections
|
69
|
+
- Each scenario formatted with numbered steps
|
70
|
+
- Clear expected results for verification
|
71
|
+
|
72
|
+
<example-spec>
|
73
|
+
# TodoMVC Application - Comprehensive Test Plan
|
74
|
+
|
75
|
+
## Application Overview
|
76
|
+
|
77
|
+
The TodoMVC application is a React-based todo list manager that provides core task management functionality. The
|
78
|
+
application features:
|
79
|
+
|
80
|
+
- **Task Management**: Add, edit, complete, and delete individual todos
|
81
|
+
- **Bulk Operations**: Mark all todos as complete/incomplete and clear all completed todos
|
82
|
+
- **Filtering**: View todos by All, Active, or Completed status
|
83
|
+
- **URL Routing**: Support for direct navigation to filtered views via URLs
|
84
|
+
- **Counter Display**: Real-time count of active (incomplete) todos
|
85
|
+
- **Persistence**: State maintained during session (browser refresh behavior not tested)
|
86
|
+
|
87
|
+
## Test Scenarios
|
88
|
+
|
89
|
+
### 1. Adding New Todos
|
90
|
+
|
91
|
+
**Seed:** `tests/seed.spec.ts`
|
92
|
+
|
93
|
+
#### 1.1 Add Valid Todo
|
94
|
+
**Steps:**
|
95
|
+
1. Click in the "What needs to be done?" input field
|
96
|
+
2. Type "Buy groceries"
|
97
|
+
3. Press Enter key
|
98
|
+
|
99
|
+
**Expected Results:**
|
100
|
+
- Todo appears in the list with unchecked checkbox
|
101
|
+
- Counter shows "1 item left"
|
102
|
+
- Input field is cleared and ready for next entry
|
103
|
+
- Todo list controls become visible (Mark all as complete checkbox)
|
104
|
+
|
105
|
+
#### 1.2
|
106
|
+
...
|
107
|
+
</example-spec>
|
108
|
+
|
109
|
+
**Quality Standards**:
|
110
|
+
- Write steps that are specific enough for any tester to follow
|
111
|
+
- Include negative testing scenarios
|
112
|
+
- Ensure scenarios are independent and can be run in any order
|
113
|
+
|
114
|
+
**Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and
|
115
|
+
professional formatting suitable for sharing with development and QA teams.
|
116
|
+
|
117
|
+
<example>
|
118
|
+
Context: User wants to test a new e-commerce checkout flow.
|
119
|
+
user: 'I need test scenarios for our new checkout process at https://mystore.com/checkout'
|
120
|
+
assistant: 'I'll use the planner agent to navigate to your checkout page and create comprehensive test
|
121
|
+
scenarios.'
|
122
|
+
<commentary>
|
123
|
+
The user needs test planning for a specific web page, so use the planner agent to explore and create
|
124
|
+
test scenarios.
|
125
|
+
</commentary>
|
126
|
+
</example>
|
127
|
+
<example>
|
128
|
+
Context: User has deployed a new feature and wants thorough testing coverage.
|
129
|
+
user: 'Can you help me test our new user dashboard at https://app.example.com/dashboard?'
|
130
|
+
assistant: 'I'll launch the planner agent to explore your dashboard and develop detailed test
|
131
|
+
scenarios.'
|
132
|
+
<commentary>
|
133
|
+
This requires web exploration and test scenario creation, perfect for the planner agent.
|
134
|
+
</commentary>
|
135
|
+
</example>
|
package/lib/cli.js
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var _fs = _interopRequireDefault(require("fs"));
|
4
|
+
var _path = _interopRequireDefault(require("path"));
|
5
|
+
var _runner = require("./runner/runner");
|
6
|
+
var _utils = require("playwright-core/lib/utils");
|
7
|
+
var _util = require("./util");
|
8
|
+
var _html = require("./reporters/html");
|
9
|
+
var _merge = require("./reporters/merge");
|
10
|
+
var _configLoader = require("./common/configLoader");
|
11
|
+
var _config = require("./common/config");
|
12
|
+
var _program = _interopRequireDefault(require("playwright-core/lib/cli/program"));
|
13
|
+
var _base = require("./reporters/base");
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
15
|
+
/**
|
16
|
+
* Copyright (c) Microsoft Corporation.
|
17
|
+
*
|
18
|
+
* Licensed under the Apache License, Version 2.0 (the 'License");
|
19
|
+
* you may not use this file except in compliance with the License.
|
20
|
+
* You may obtain a copy of the License at
|
21
|
+
*
|
22
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
23
|
+
*
|
24
|
+
* Unless required by applicable law or agreed to in writing, software
|
25
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
26
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
27
|
+
* See the License for the specific language governing permissions and
|
28
|
+
* limitations under the License.
|
29
|
+
*/
|
30
|
+
|
31
|
+
/* eslint-disable no-console */
|
32
|
+
|
33
|
+
function addTestCommand(program) {
|
34
|
+
const command = program.command('test [test-filter...]');
|
35
|
+
command.description('run tests with Playwright Test');
|
36
|
+
const options = testOptions.sort((a, b) => a[0].replace(/-/g, '').localeCompare(b[0].replace(/-/g, '')));
|
37
|
+
options.forEach(([name, description]) => command.option(name, description));
|
38
|
+
command.action(async (args, opts) => {
|
39
|
+
try {
|
40
|
+
await runTests(args, opts);
|
41
|
+
} catch (e) {
|
42
|
+
console.error(e);
|
43
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
command.addHelpText('afterAll', `
|
47
|
+
Arguments [test-filter...]:
|
48
|
+
Pass arguments to filter test files. Each argument is treated as a regular expression. Matching is performed against the absolute file paths.
|
49
|
+
|
50
|
+
Examples:
|
51
|
+
$ npx playwright test my.spec.ts
|
52
|
+
$ npx playwright test some.spec.ts:42
|
53
|
+
$ npx playwright test --headed
|
54
|
+
$ npx playwright test --project=webkit`);
|
55
|
+
}
|
56
|
+
function addListFilesCommand(program) {
|
57
|
+
const command = program.command('list-files [file-filter...]', {
|
58
|
+
hidden: true
|
59
|
+
});
|
60
|
+
command.description('List files with Playwright Test tests');
|
61
|
+
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
|
62
|
+
command.option('--project <project-name...>', `Only run tests from the specified list of projects (default: list all projects)`);
|
63
|
+
command.action(async (args, opts) => {
|
64
|
+
try {
|
65
|
+
await listTestFiles(opts);
|
66
|
+
} catch (e) {
|
67
|
+
console.error(e);
|
68
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
69
|
+
}
|
70
|
+
});
|
71
|
+
}
|
72
|
+
function addShowReportCommand(program) {
|
73
|
+
const command = program.command('show-report [report]');
|
74
|
+
command.description('show HTML report');
|
75
|
+
command.action((report, options) => (0, _html.showHTMLReport)(report, options.host, +options.port));
|
76
|
+
command.option('--host <host>', 'Host to serve report on', 'localhost');
|
77
|
+
command.option('--port <port>', 'Port to serve report on', '9323');
|
78
|
+
command.addHelpText('afterAll', `
|
79
|
+
Arguments [report]:
|
80
|
+
When specified, opens given report, otherwise opens last generated report.
|
81
|
+
|
82
|
+
Examples:
|
83
|
+
$ npx playwright show-report
|
84
|
+
$ npx playwright show-report playwright-report`);
|
85
|
+
}
|
86
|
+
function addMergeReportsCommand(program) {
|
87
|
+
const command = program.command('merge-reports [dir]', {
|
88
|
+
hidden: true
|
89
|
+
});
|
90
|
+
command.description('merge multiple blob reports (for sharded tests) into a single report');
|
91
|
+
command.action(async (dir, options) => {
|
92
|
+
try {
|
93
|
+
await mergeReports(dir, options);
|
94
|
+
} catch (e) {
|
95
|
+
console.error(e);
|
96
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
97
|
+
}
|
98
|
+
});
|
99
|
+
command.option('-c, --config <file>', `Configuration file. Can be used to specify additional configuration for the output report.`);
|
100
|
+
command.option('--reporter <reporter>', `Reporter to use, comma-separated, can be ${_config.builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${_config.defaultReporter}")`);
|
101
|
+
command.addHelpText('afterAll', `
|
102
|
+
Arguments [dir]:
|
103
|
+
Directory containing blob reports.
|
104
|
+
|
105
|
+
Examples:
|
106
|
+
$ npx playwright merge-reports playwright-report`);
|
107
|
+
}
|
108
|
+
async function runTests(args, opts) {
|
109
|
+
await (0, _utils.startProfiling)();
|
110
|
+
|
111
|
+
// When no --config option is passed, let's look for the config file in the current directory.
|
112
|
+
const configFileOrDirectory = opts.config ? _path.default.resolve(process.cwd(), opts.config) : process.cwd();
|
113
|
+
const resolvedConfigFile = (0, _configLoader.resolveConfigFile)(configFileOrDirectory);
|
114
|
+
if (restartWithExperimentalTsEsm(resolvedConfigFile)) return;
|
115
|
+
const overrides = overridesFromOptions(opts);
|
116
|
+
const configLoader = new _configLoader.ConfigLoader(overrides);
|
117
|
+
let config;
|
118
|
+
if (resolvedConfigFile) config = await configLoader.loadConfigFile(resolvedConfigFile, opts.deps === false);else config = await configLoader.loadEmptyConfig(configFileOrDirectory);
|
119
|
+
config.cliArgs = args;
|
120
|
+
config.cliGrep = opts.grep;
|
121
|
+
config.cliGrepInvert = opts.grepInvert;
|
122
|
+
config.cliListOnly = !!opts.list;
|
123
|
+
config.cliProjectFilter = opts.project || undefined;
|
124
|
+
config.cliPassWithNoTests = !!opts.passWithNoTests;
|
125
|
+
const runner = new _runner.Runner(config);
|
126
|
+
let status;
|
127
|
+
if (opts.ui || opts.uiHost || opts.uiPort) status = await runner.uiAllTests({
|
128
|
+
host: opts.uiHost,
|
129
|
+
port: opts.uiPort ? +opts.uiPort : undefined
|
130
|
+
});else if (process.env.PWTEST_WATCH) status = await runner.watchAllTests();else status = await runner.runAllTests();
|
131
|
+
await (0, _utils.stopProfiling)('runner');
|
132
|
+
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
|
133
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
|
134
|
+
}
|
135
|
+
async function listTestFiles(opts) {
|
136
|
+
// Redefine process.stdout.write in case config decides to pollute stdio.
|
137
|
+
const stdoutWrite = process.stdout.write.bind(process.stdout);
|
138
|
+
process.stdout.write = () => {};
|
139
|
+
process.stderr.write = () => {};
|
140
|
+
const configFileOrDirectory = opts.config ? _path.default.resolve(process.cwd(), opts.config) : process.cwd();
|
141
|
+
const resolvedConfigFile = (0, _configLoader.resolveConfigFile)(configFileOrDirectory);
|
142
|
+
if (restartWithExperimentalTsEsm(resolvedConfigFile)) return;
|
143
|
+
try {
|
144
|
+
const configLoader = new _configLoader.ConfigLoader();
|
145
|
+
const config = await configLoader.loadConfigFile(resolvedConfigFile);
|
146
|
+
const runner = new _runner.Runner(config);
|
147
|
+
const report = await runner.listTestFiles(opts.project);
|
148
|
+
stdoutWrite(JSON.stringify(report), () => {
|
149
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(0);
|
150
|
+
});
|
151
|
+
} catch (e) {
|
152
|
+
const error = (0, _util.serializeError)(e);
|
153
|
+
error.location = (0, _base.prepareErrorStack)(e.stack).location;
|
154
|
+
stdoutWrite(JSON.stringify({
|
155
|
+
error
|
156
|
+
}), () => {
|
157
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(0);
|
158
|
+
});
|
159
|
+
}
|
160
|
+
}
|
161
|
+
async function mergeReports(reportDir, opts) {
|
162
|
+
let configFile = opts.config;
|
163
|
+
if (configFile) {
|
164
|
+
configFile = _path.default.resolve(process.cwd(), configFile);
|
165
|
+
if (!_fs.default.existsSync(configFile)) throw new Error(`${configFile} does not exist`);
|
166
|
+
if (!_fs.default.statSync(configFile).isFile()) throw new Error(`${configFile} is not a file`);
|
167
|
+
}
|
168
|
+
if (restartWithExperimentalTsEsm(configFile)) return;
|
169
|
+
const configLoader = new _configLoader.ConfigLoader();
|
170
|
+
const config = await (configFile ? configLoader.loadConfigFile(configFile) : configLoader.loadEmptyConfig(process.cwd()));
|
171
|
+
const dir = _path.default.resolve(process.cwd(), reportDir || '');
|
172
|
+
const dirStat = await _fs.default.promises.stat(dir).catch(e => null);
|
173
|
+
if (!dirStat) throw new Error('Directory does not exist: ' + dir);
|
174
|
+
if (!dirStat.isDirectory()) throw new Error(`"${dir}" is not a directory`);
|
175
|
+
let reporterDescriptions = resolveReporterOption(opts.reporter);
|
176
|
+
if (!reporterDescriptions && configFile) reporterDescriptions = config.config.reporter;
|
177
|
+
if (!reporterDescriptions) reporterDescriptions = [[_config.defaultReporter]];
|
178
|
+
const rootDirOverride = configFile ? config.config.rootDir : undefined;
|
179
|
+
await (0, _merge.createMergedReport)(config, dir, reporterDescriptions, rootDirOverride);
|
180
|
+
(0, _utils.gracefullyProcessExitDoNotHang)(0);
|
181
|
+
}
|
182
|
+
function overridesFromOptions(options) {
|
183
|
+
const shardPair = options.shard ? options.shard.split('/').map(t => parseInt(t, 10)) : undefined;
|
184
|
+
const overrides = {
|
185
|
+
forbidOnly: options.forbidOnly ? true : undefined,
|
186
|
+
fullyParallel: options.fullyParallel ? true : undefined,
|
187
|
+
globalTimeout: options.globalTimeout ? parseInt(options.globalTimeout, 10) : undefined,
|
188
|
+
maxFailures: options.x ? 1 : options.maxFailures ? parseInt(options.maxFailures, 10) : undefined,
|
189
|
+
outputDir: options.output ? _path.default.resolve(process.cwd(), options.output) : undefined,
|
190
|
+
quiet: options.quiet ? options.quiet : undefined,
|
191
|
+
repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined,
|
192
|
+
retries: options.retries ? parseInt(options.retries, 10) : undefined,
|
193
|
+
reporter: resolveReporterOption(options.reporter),
|
194
|
+
shard: shardPair ? {
|
195
|
+
current: shardPair[0],
|
196
|
+
total: shardPair[1]
|
197
|
+
} : undefined,
|
198
|
+
timeout: options.timeout ? parseInt(options.timeout, 10) : undefined,
|
199
|
+
ignoreSnapshots: options.ignoreSnapshots ? !!options.ignoreSnapshots : undefined,
|
200
|
+
updateSnapshots: options.updateSnapshots ? 'all' : undefined,
|
201
|
+
workers: options.workers
|
202
|
+
};
|
203
|
+
if (options.browser) {
|
204
|
+
const browserOpt = options.browser.toLowerCase();
|
205
|
+
if (!['all', 'chromium', 'firefox', 'webkit'].includes(browserOpt)) throw new Error(`Unsupported browser "${options.browser}", must be one of "all", "chromium", "firefox" or "webkit"`);
|
206
|
+
const browserNames = browserOpt === 'all' ? ['chromium', 'firefox', 'webkit'] : [browserOpt];
|
207
|
+
overrides.projects = browserNames.map(browserName => {
|
208
|
+
return {
|
209
|
+
name: browserName,
|
210
|
+
use: {
|
211
|
+
browserName
|
212
|
+
}
|
213
|
+
};
|
214
|
+
});
|
215
|
+
}
|
216
|
+
if (options.headed || options.debug) overrides.use = {
|
217
|
+
headless: false
|
218
|
+
};
|
219
|
+
if (!options.ui && options.debug) {
|
220
|
+
overrides.maxFailures = 1;
|
221
|
+
overrides.timeout = 0;
|
222
|
+
overrides.workers = 1;
|
223
|
+
process.env.PWDEBUG = '1';
|
224
|
+
}
|
225
|
+
if (!options.ui && options.trace) {
|
226
|
+
if (!kTraceModes.includes(options.trace)) throw new Error(`Unsupported trace mode "${options.trace}", must be one of ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`);
|
227
|
+
overrides.use = overrides.use || {};
|
228
|
+
overrides.use.trace = options.trace;
|
229
|
+
}
|
230
|
+
return overrides;
|
231
|
+
}
|
232
|
+
function resolveReporterOption(reporter) {
|
233
|
+
if (!reporter || !reporter.length) return undefined;
|
234
|
+
return reporter.split(',').map(r => [resolveReporter(r)]);
|
235
|
+
}
|
236
|
+
function resolveReporter(id) {
|
237
|
+
if (_config.builtInReporters.includes(id)) return id;
|
238
|
+
const localPath = _path.default.resolve(process.cwd(), id);
|
239
|
+
if (_fs.default.existsSync(localPath)) return localPath;
|
240
|
+
return require.resolve(id, {
|
241
|
+
paths: [process.cwd()]
|
242
|
+
});
|
243
|
+
}
|
244
|
+
function restartWithExperimentalTsEsm(configFile) {
|
245
|
+
const nodeVersion = +process.versions.node.split('.')[0];
|
246
|
+
// New experimental loader is only supported on Node 16+.
|
247
|
+
if (nodeVersion < 16) return false;
|
248
|
+
if (!configFile) return false;
|
249
|
+
if (process.env.PW_DISABLE_TS_ESM) return false;
|
250
|
+
if (process.env.PW_TS_ESM_ON) {
|
251
|
+
// clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
|
252
|
+
process.execArgv = (0, _util.execArgvWithoutExperimentalLoaderOptions)();
|
253
|
+
return false;
|
254
|
+
}
|
255
|
+
if (!(0, _util.fileIsModule)(configFile)) return false;
|
256
|
+
const innerProcess = require('child_process').fork(require.resolve('./cli'), process.argv.slice(2), {
|
257
|
+
env: {
|
258
|
+
...process.env,
|
259
|
+
PW_TS_ESM_ON: '1'
|
260
|
+
},
|
261
|
+
execArgv: (0, _util.execArgvWithExperimentalLoaderOptions)()
|
262
|
+
});
|
263
|
+
innerProcess.on('close', code => {
|
264
|
+
if (code !== 0 && code !== null) (0, _utils.gracefullyProcessExitDoNotHang)(code);
|
265
|
+
});
|
266
|
+
return true;
|
267
|
+
}
|
268
|
+
const kTraceModes = ['on', 'off', 'on-first-retry', 'on-all-retries', 'retain-on-failure'];
|
269
|
+
const testOptions = [['--browser <browser>', `Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium")`], ['-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`], ['--debug', `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --max-failures=1 --headed --workers=1" options`], ['--forbid-only', `Fail if test.only is called (default: false)`], ['--fully-parallel', `Run all tests in parallel (default: false)`], ['--global-timeout <timeout>', `Maximum time this test suite can run in milliseconds (default: unlimited)`], ['-g, --grep <grep>', `Only run tests matching this regular expression (default: ".*")`], ['-gv, --grep-invert <grep>', `Only run tests that do not match this regular expression`], ['--headed', `Run tests in headed browsers (default: headless)`], ['--ignore-snapshots', `Ignore screenshot and snapshot expectations`], ['--list', `Collect all the tests and report them, but do not run`], ['--max-failures <N>', `Stop after the first N failures`], ['--no-deps', 'Do not run project dependencies'], ['--output <dir>', `Folder for output artifacts (default: "test-results")`], ['--pass-with-no-tests', `Makes test run succeed even if no tests were found`], ['--project <project-name...>', `Only run tests from the specified list of projects (default: run all projects)`], ['--quiet', `Suppress stdio`], ['--repeat-each <N>', `Run each test N times (default: 1)`], ['--reporter <reporter>', `Reporter to use, comma-separated, can be ${_config.builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${_config.defaultReporter}")`], ['--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`], ['--shard <shard>', `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"`], ['--timeout <timeout>', `Specify test timeout threshold in milliseconds, zero for unlimited (default: ${_config.defaultTimeout})`], ['--trace <mode>', `Force tracing mode, can be ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`], ['--ui', `Run tests in interactive UI mode`], ['--ui-host <host>', 'Host to serve UI on; specifying this option opens UI in a browser tab'], ['--ui-port <port>', 'Port to serve UI on, 0 for any free port; specifying this option opens UI in a browser tab'], ['-u, --update-snapshots', `Update snapshots with actual results (default: only create missing snapshots)`], ['-j, --workers <workers>', `Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%)`], ['-x', `Stop after the first failure`]];
|
270
|
+
addTestCommand(_program.default);
|
271
|
+
addShowReportCommand(_program.default);
|
272
|
+
addListFilesCommand(_program.default);
|
273
|
+
addMergeReportsCommand(_program.default);
|
274
|
+
_program.default.parse(process.argv);
|