playwright-zed-language-server 0.0.0-stage → 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 +21 -0
- package/README.md +24 -2
- package/bin/playwright-zed-language-server.js +4 -0
- package/dist/commands.js +99 -0
- package/dist/commands.js.map +1 -0
- package/dist/discovery.js +96 -0
- package/dist/discovery.js.map +1 -0
- package/dist/reporting.js +95 -0
- package/dist/reporting.js.map +1 -0
- package/dist/runner.js +156 -0
- package/dist/runner.js.map +1 -0
- package/dist/server.js +424 -0
- package/dist/server.js.map +1 -0
- package/dist/spawn.js +140 -0
- package/dist/spawn.js.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/version.js +29 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace.js +135 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +48 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Radek Bednarik
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# playwright-zed-language-server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Language server behind the [Playwright for Zed](https://github.com/radekBednarik/playwright-zed)
|
|
4
|
+
extension. The Zed extension installs this package from npm at runtime; you do not need to
|
|
5
|
+
install it yourself.
|
|
6
|
+
|
|
7
|
+
It detects Playwright workspaces, discovers tests through `playwright test --list`, and runs
|
|
8
|
+
tests with the `@playwright/test` package installed in your project, reporting results back to
|
|
9
|
+
the editor over the Language Server Protocol.
|
|
10
|
+
|
|
11
|
+
Usage: `playwright-zed-language-server --stdio`.
|
|
12
|
+
|
|
13
|
+
This is an independent community project, not affiliated with, endorsed by, or maintained by
|
|
14
|
+
Microsoft or the Playwright team. "Playwright" is a trademark of Microsoft Corporation. The
|
|
15
|
+
package contains no Playwright code and does not bundle Playwright.
|
|
16
|
+
|
|
17
|
+
**Work in progress.** This is the first slice of the extension (detection, run at cursor,
|
|
18
|
+
run file, re-run last). Expect breaking changes between minor versions; the extension pins the
|
|
19
|
+
exact server version it was built against.
|
|
20
|
+
|
|
21
|
+
**Built with AI assistance.** The server, like the rest of the extension, is developed with
|
|
22
|
+
AI assistance throughout, using GitHub Spec Kit driven by Claude Code with the Claude models
|
|
23
|
+
Fable and Opus, with maintainer review and recorded verification for every feature.
|
|
24
|
+
|
|
25
|
+
License: MIT.
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ALL_COMMANDS = exports.COMMAND_RERUN_LAST = exports.COMMAND_RUN_FILE = exports.COMMAND_RUN_AT_CURSOR = void 0;
|
|
37
|
+
exports.resolveTestLocation = resolveTestLocation;
|
|
38
|
+
exports.buildRunArgs = buildRunArgs;
|
|
39
|
+
exports.countSelectedTests = countSelectedTests;
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
exports.COMMAND_RUN_AT_CURSOR = 'playwright.runAtCursor';
|
|
42
|
+
exports.COMMAND_RUN_FILE = 'playwright.runFile';
|
|
43
|
+
exports.COMMAND_RERUN_LAST = 'playwright.rerunLast';
|
|
44
|
+
exports.ALL_COMMANDS = [exports.COMMAND_RUN_AT_CURSOR, exports.COMMAND_RUN_FILE, exports.COMMAND_RERUN_LAST];
|
|
45
|
+
/**
|
|
46
|
+
* Resolves what the cursor points at (data-model "TestLocation").
|
|
47
|
+
*
|
|
48
|
+
* 1. A test's span starts at its title line and ends on the line before the next test or
|
|
49
|
+
* describe title line in the same file; the last test's span extends to end of file.
|
|
50
|
+
* Cursor inside a span, or on the title line, means kind `test`.
|
|
51
|
+
* 2. Else, cursor exactly on a describe title line means kind `describe`.
|
|
52
|
+
* 3. Else kind `file`.
|
|
53
|
+
*
|
|
54
|
+
* `cursorLine` is 1-based.
|
|
55
|
+
*/
|
|
56
|
+
function resolveTestLocation(tests, file, cursorLine) {
|
|
57
|
+
const inFile = tests.filter((t) => t.file === file);
|
|
58
|
+
const testLines = Array.from(new Set(inFile.map((t) => t.line))).sort((a, b) => a - b);
|
|
59
|
+
const describeLines = new Set(inFile.flatMap((t) => t.describeLines));
|
|
60
|
+
let enclosingTestLine = null;
|
|
61
|
+
for (const line of testLines) {
|
|
62
|
+
if (line <= cursorLine)
|
|
63
|
+
enclosingTestLine = line;
|
|
64
|
+
else
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (enclosingTestLine !== null) {
|
|
68
|
+
// A describe title strictly between the test line and the cursor ends the test's span.
|
|
69
|
+
let boundaryCrossed = false;
|
|
70
|
+
for (const d of describeLines) {
|
|
71
|
+
if (d > enclosingTestLine && d <= cursorLine) {
|
|
72
|
+
boundaryCrossed = true;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!boundaryCrossed)
|
|
77
|
+
return { kind: 'test', file, line: enclosingTestLine };
|
|
78
|
+
}
|
|
79
|
+
if (describeLines.has(cursorLine))
|
|
80
|
+
return { kind: 'describe', file, line: cursorLine };
|
|
81
|
+
return { kind: 'file', file, line: null };
|
|
82
|
+
}
|
|
83
|
+
/** CLI arguments for a run, per contracts/playwright-cli.md. */
|
|
84
|
+
function buildRunArgs(location, config) {
|
|
85
|
+
let target = path.relative(config.configDir, location.file);
|
|
86
|
+
if (location.kind !== 'file' && location.line !== null)
|
|
87
|
+
target = `${target}:${location.line}`;
|
|
88
|
+
return ['test', target, '-c', config.configPath, '--reporter=list,json'];
|
|
89
|
+
}
|
|
90
|
+
/** Number of discovered tests a location selects, used for progress messages. */
|
|
91
|
+
function countSelectedTests(tests, location) {
|
|
92
|
+
const inFile = tests.filter((t) => t.file === location.file);
|
|
93
|
+
if (location.kind === 'file')
|
|
94
|
+
return inFile.length;
|
|
95
|
+
if (location.kind === 'test')
|
|
96
|
+
return inFile.filter((t) => t.line === location.line).length;
|
|
97
|
+
return inFile.filter((t) => t.describeLines.includes(location.line)).length;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseListReport = parseListReport;
|
|
37
|
+
exports.runList = runList;
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const spawn_1 = require("./spawn");
|
|
40
|
+
/** Flattens Playwright's `--list --reporter=json` output into discovered tests. */
|
|
41
|
+
function parseListReport(json) {
|
|
42
|
+
const report = (json ?? {});
|
|
43
|
+
const rootDir = report.config?.rootDir ?? '';
|
|
44
|
+
const testDirs = Array.from(new Set((report.config?.projects ?? []).map((p) => p.testDir).filter((d) => !!d)));
|
|
45
|
+
const tests = [];
|
|
46
|
+
const walk = (suite, describeTitles, describeLines) => {
|
|
47
|
+
const isDescribe = suite.line > 0;
|
|
48
|
+
const titles = isDescribe ? [...describeTitles, suite.title] : describeTitles;
|
|
49
|
+
const lines = isDescribe ? [...describeLines, suite.line] : describeLines;
|
|
50
|
+
for (const spec of suite.specs ?? []) {
|
|
51
|
+
tests.push({
|
|
52
|
+
file: path.resolve(rootDir, spec.file),
|
|
53
|
+
line: spec.line,
|
|
54
|
+
column: spec.column,
|
|
55
|
+
title: spec.title,
|
|
56
|
+
titlePath: [...titles, spec.title],
|
|
57
|
+
describeLines: lines,
|
|
58
|
+
projects: (spec.tests ?? []).map((t) => t.projectName ?? '').filter((n) => n !== ''),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
for (const child of suite.suites ?? [])
|
|
62
|
+
walk(child, titles, lines);
|
|
63
|
+
};
|
|
64
|
+
for (const suite of report.suites ?? [])
|
|
65
|
+
walk(suite, [], []);
|
|
66
|
+
tests.sort((a, b) => (a.file === b.file ? a.line - b.line || a.column - b.column : a.file.localeCompare(b.file)));
|
|
67
|
+
return { rootDir, testDirs, tests };
|
|
68
|
+
}
|
|
69
|
+
let listCounter = 0;
|
|
70
|
+
/** Runs discovery for one config and stores the result on it. Returns the CLI error text, if any. */
|
|
71
|
+
async function runList(config, spawnFn = spawn_1.runPlaywright) {
|
|
72
|
+
config.discoveryState = 'running';
|
|
73
|
+
config.discoveryError = undefined;
|
|
74
|
+
const id = String(++listCounter);
|
|
75
|
+
const handle = spawnFn({
|
|
76
|
+
cli: config.playwrightCli,
|
|
77
|
+
args: ['test', '--list', '--reporter=json', '-c', config.configPath],
|
|
78
|
+
cwd: config.configDir,
|
|
79
|
+
env: { CI: '1' },
|
|
80
|
+
reportFile: (0, spawn_1.reportFilePath)('list', id),
|
|
81
|
+
});
|
|
82
|
+
const outcome = await handle.promise;
|
|
83
|
+
if (outcome.spawnError || outcome.report === null) {
|
|
84
|
+
const detail = outcome.spawnError ?? (outcome.stderr.trim() || outcome.stdout.trim() || `exit code ${outcome.code}`);
|
|
85
|
+
config.discoveryState = 'error';
|
|
86
|
+
config.discoveryError = `${outcome.command}\n${detail}`;
|
|
87
|
+
return config.discoveryError;
|
|
88
|
+
}
|
|
89
|
+
const parsed = parseListReport(outcome.report);
|
|
90
|
+
config.rootDir = parsed.rootDir;
|
|
91
|
+
config.testDirs = parsed.testDirs;
|
|
92
|
+
config.tests = parsed.tests;
|
|
93
|
+
config.discoveryState = 'idle';
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Reporter = exports.DIAGNOSTIC_SOURCE = void 0;
|
|
4
|
+
const node_1 = require("vscode-languageserver/node");
|
|
5
|
+
const node_url_1 = require("node:url");
|
|
6
|
+
exports.DIAGNOSTIC_SOURCE = 'playwright';
|
|
7
|
+
/** Thin wrappers over the LSP channels Zed renders (progress, messages, diagnostics, log). */
|
|
8
|
+
class Reporter {
|
|
9
|
+
connection;
|
|
10
|
+
constructor(connection) {
|
|
11
|
+
this.connection = connection;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Starts a `$/progress` sequence whose token is the run request id, as the contract states.
|
|
15
|
+
* Returns false when the client refuses to create the token; progress is then skipped.
|
|
16
|
+
*/
|
|
17
|
+
async progressBegin(token, testCount, file) {
|
|
18
|
+
try {
|
|
19
|
+
await this.connection.sendRequest(node_1.WorkDoneProgressCreateRequest.type, { token });
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
void this.connection.sendProgress(node_1.WorkDoneProgress.type, token, {
|
|
25
|
+
kind: 'begin',
|
|
26
|
+
title: 'Playwright',
|
|
27
|
+
message: `Running ${testCount} test(s) in ${file}`,
|
|
28
|
+
});
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
progressEnd(token, active, summary) {
|
|
32
|
+
if (!active)
|
|
33
|
+
return;
|
|
34
|
+
void this.connection.sendProgress(node_1.WorkDoneProgress.type, token, { kind: 'report', message: summary });
|
|
35
|
+
void this.connection.sendProgress(node_1.WorkDoneProgress.type, token, { kind: 'end', message: summary });
|
|
36
|
+
}
|
|
37
|
+
/** Sends the `window/showMessage` notification (the library helpers would send a request). */
|
|
38
|
+
showMessage(type, message) {
|
|
39
|
+
void this.connection.sendNotification(node_1.ShowMessageNotification.type, { type, message });
|
|
40
|
+
}
|
|
41
|
+
showInfo(message) {
|
|
42
|
+
this.showMessage(node_1.MessageType.Info, message);
|
|
43
|
+
}
|
|
44
|
+
showWarning(message) {
|
|
45
|
+
this.showMessage(node_1.MessageType.Warning, message);
|
|
46
|
+
}
|
|
47
|
+
showError(message) {
|
|
48
|
+
this.showMessage(node_1.MessageType.Error, message);
|
|
49
|
+
}
|
|
50
|
+
/** Publishes one Error diagnostic per failure, grouped by file. */
|
|
51
|
+
publishFailures(failures) {
|
|
52
|
+
const byFile = new Map();
|
|
53
|
+
for (const failure of failures) {
|
|
54
|
+
const line = Math.max(0, failure.line - 1);
|
|
55
|
+
const character = Math.max(0, failure.column - 1);
|
|
56
|
+
const diagnostic = {
|
|
57
|
+
range: { start: { line, character }, end: { line, character: character + 1 } },
|
|
58
|
+
severity: node_1.DiagnosticSeverity.Error,
|
|
59
|
+
source: exports.DIAGNOSTIC_SOURCE,
|
|
60
|
+
message: `${failure.title}: ${failure.message}`,
|
|
61
|
+
};
|
|
62
|
+
const list = byFile.get(failure.file) ?? [];
|
|
63
|
+
list.push(diagnostic);
|
|
64
|
+
byFile.set(failure.file, list);
|
|
65
|
+
}
|
|
66
|
+
for (const [file, diagnostics] of byFile) {
|
|
67
|
+
void this.connection.sendDiagnostics({ uri: (0, node_url_1.pathToFileURL)(file).toString(), diagnostics });
|
|
68
|
+
}
|
|
69
|
+
return Array.from(byFile.keys());
|
|
70
|
+
}
|
|
71
|
+
clearDiagnostics(files) {
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
void this.connection.sendDiagnostics({ uri: (0, node_url_1.pathToFileURL)(file).toString(), diagnostics: [] });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
clearDiagnosticsForUri(uri) {
|
|
77
|
+
void this.connection.sendDiagnostics({ uri, diagnostics: [] });
|
|
78
|
+
}
|
|
79
|
+
log(line) {
|
|
80
|
+
this.connection.console.log(line);
|
|
81
|
+
}
|
|
82
|
+
info(line) {
|
|
83
|
+
this.connection.console.info(line);
|
|
84
|
+
}
|
|
85
|
+
async refreshCodeLenses() {
|
|
86
|
+
try {
|
|
87
|
+
await this.connection.sendRequest(node_1.CodeLensRefreshRequest.type);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// client without refresh support
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.Reporter = Reporter;
|
|
95
|
+
//# sourceMappingURL=reporting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporting.js","sourceRoot":"","sources":["../src/reporting.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RunManager = void 0;
|
|
37
|
+
exports.stripAnsi = stripAnsi;
|
|
38
|
+
exports.parseRunReport = parseRunReport;
|
|
39
|
+
exports.mapExitCode = mapExitCode;
|
|
40
|
+
exports.summarize = summarize;
|
|
41
|
+
exports.emptyCounts = emptyCounts;
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const spawn_1 = require("./spawn");
|
|
44
|
+
const commands_1 = require("./commands");
|
|
45
|
+
const ANSI = /\u001b\[[0-9;]*[A-Za-z]/g;
|
|
46
|
+
function stripAnsi(text) {
|
|
47
|
+
return text.replace(ANSI, '');
|
|
48
|
+
}
|
|
49
|
+
/** Extracts counts and failures from a `--reporter=json` run report. */
|
|
50
|
+
function parseRunReport(json) {
|
|
51
|
+
const report = (json ?? {});
|
|
52
|
+
const rootDir = report.config?.rootDir ?? '';
|
|
53
|
+
const counts = {
|
|
54
|
+
expected: report.stats?.expected ?? 0,
|
|
55
|
+
unexpected: report.stats?.unexpected ?? 0,
|
|
56
|
+
skipped: report.stats?.skipped ?? 0,
|
|
57
|
+
flaky: report.stats?.flaky ?? 0,
|
|
58
|
+
};
|
|
59
|
+
const failures = [];
|
|
60
|
+
const walk = (suite) => {
|
|
61
|
+
for (const spec of suite.specs ?? []) {
|
|
62
|
+
if (spec.ok !== false)
|
|
63
|
+
continue;
|
|
64
|
+
const result = (spec.tests ?? [])
|
|
65
|
+
.flatMap((t) => t.results ?? [])
|
|
66
|
+
.find((r) => r.error) ?? (spec.tests ?? []).flatMap((t) => t.results ?? []).at(-1);
|
|
67
|
+
const rawMessage = result?.error?.message ?? 'Test failed without an error message';
|
|
68
|
+
const fullMessage = stripAnsi(rawMessage).trim();
|
|
69
|
+
const loc = result?.error?.location;
|
|
70
|
+
failures.push({
|
|
71
|
+
file: loc?.file ?? path.resolve(rootDir, spec.file),
|
|
72
|
+
line: loc?.line ?? spec.line,
|
|
73
|
+
column: loc?.column ?? spec.column,
|
|
74
|
+
title: spec.title,
|
|
75
|
+
message: fullMessage.split('\n')[0] ?? fullMessage,
|
|
76
|
+
fullMessage,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
for (const child of suite.suites ?? [])
|
|
80
|
+
walk(child);
|
|
81
|
+
};
|
|
82
|
+
for (const suite of report.suites ?? [])
|
|
83
|
+
walk(suite);
|
|
84
|
+
const durationMs = typeof report.stats?.duration === 'number' ? report.stats.duration : null;
|
|
85
|
+
return { counts, failures, durationMs };
|
|
86
|
+
}
|
|
87
|
+
/** 0 passed, 1 with a report failed, anything else is a run error. */
|
|
88
|
+
function mapExitCode(code, hasReport) {
|
|
89
|
+
if (code === 0)
|
|
90
|
+
return 'passed';
|
|
91
|
+
if (code === 1 && hasReport)
|
|
92
|
+
return 'failed';
|
|
93
|
+
return 'error';
|
|
94
|
+
}
|
|
95
|
+
/** `3 passed, 0 failed, 1 skipped (1.2s)`; the duration is Playwright's own measurement. */
|
|
96
|
+
function summarize(counts, durationMs = null) {
|
|
97
|
+
const base = `${counts.expected} passed, ${counts.unexpected} failed, ${counts.skipped} skipped`;
|
|
98
|
+
return durationMs === null ? base : `${base} (${(durationMs / 1000).toFixed(1)}s)`;
|
|
99
|
+
}
|
|
100
|
+
function emptyCounts() {
|
|
101
|
+
return { expected: 0, unexpected: 0, skipped: 0, flaky: 0 };
|
|
102
|
+
}
|
|
103
|
+
/** One running Playwright process per workspace; a new request cancels the running one. */
|
|
104
|
+
class RunManager {
|
|
105
|
+
spawnFn;
|
|
106
|
+
active = null;
|
|
107
|
+
counter = 0;
|
|
108
|
+
constructor(spawnFn = spawn_1.runPlaywright) {
|
|
109
|
+
this.spawnFn = spawnFn;
|
|
110
|
+
}
|
|
111
|
+
nextId() {
|
|
112
|
+
return String(++this.counter);
|
|
113
|
+
}
|
|
114
|
+
get running() {
|
|
115
|
+
return this.active?.request ?? null;
|
|
116
|
+
}
|
|
117
|
+
/** Cancels the active run, if any, and returns its request. */
|
|
118
|
+
cancelActive() {
|
|
119
|
+
if (!this.active)
|
|
120
|
+
return null;
|
|
121
|
+
const { request, handle } = this.active;
|
|
122
|
+
handle.cancel();
|
|
123
|
+
return request;
|
|
124
|
+
}
|
|
125
|
+
async start(request) {
|
|
126
|
+
this.cancelActive();
|
|
127
|
+
const config = request.config;
|
|
128
|
+
const handle = this.spawnFn({
|
|
129
|
+
cli: config.playwrightCli,
|
|
130
|
+
args: (0, commands_1.buildRunArgs)(request.location, config),
|
|
131
|
+
cwd: config.configDir,
|
|
132
|
+
env: { FORCE_COLOR: '0' },
|
|
133
|
+
reportFile: (0, spawn_1.reportFilePath)('run', request.id),
|
|
134
|
+
});
|
|
135
|
+
const entry = { request, handle };
|
|
136
|
+
this.active = entry;
|
|
137
|
+
const outcome = await handle.promise;
|
|
138
|
+
if (this.active === entry)
|
|
139
|
+
this.active = null;
|
|
140
|
+
const rawOutput = `${outcome.stdout}${outcome.stderr ? `\n${outcome.stderr}` : ''}`;
|
|
141
|
+
const base = { request, rawOutput, command: outcome.command, failures: [], counts: emptyCounts(), durationMs: null };
|
|
142
|
+
if (outcome.cancelled)
|
|
143
|
+
return { ...base, status: 'cancelled' };
|
|
144
|
+
if (outcome.spawnError)
|
|
145
|
+
return { ...base, status: 'error', errorMessage: outcome.spawnError };
|
|
146
|
+
const status = mapExitCode(outcome.code, outcome.report !== null);
|
|
147
|
+
if (status === 'error') {
|
|
148
|
+
const detail = outcome.stderr.trim() || outcome.stdout.trim() || `exit code ${outcome.code}`;
|
|
149
|
+
return { ...base, status, errorMessage: stripAnsi(detail) };
|
|
150
|
+
}
|
|
151
|
+
const parsed = parseRunReport(outcome.report);
|
|
152
|
+
return { ...base, status, counts: parsed.counts, failures: parsed.failures, durationMs: parsed.durationMs };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.RunManager = RunManager;
|
|
156
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|