@testdino/playwright 1.0.8 → 1.0.10
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/README.md +81 -6
- package/bin/tdpw.js +2 -2
- package/dist/cli/index.mjs +51 -34
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -10
- package/dist/index.d.ts +2 -10
- package/dist/index.js +229 -149
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +131 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -935
- package/dist/cli/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Real-time streaming reporter and CLI for Playwright that captures comprehensive test execution data and streams it to [TestDino](https://www.testdino.com) for advanced analytics and insights.
|
|
7
7
|
|
|
8
|
-
**[Website](https://www.testdino.com)** | **[Documentation](https://
|
|
8
|
+
**[Website](https://www.testdino.com)** | **[Documentation](https://docs.testdino.com/)** | **[Get Your Token](https://docs.testdino.com/getting-started)**
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
@@ -20,13 +20,13 @@ Real-time streaming reporter and CLI for Playwright that captures comprehensive
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
npm install
|
|
23
|
+
npm install @testdino/playwright
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
**Requirements:**
|
|
27
27
|
|
|
28
28
|
- Node.js >= 18.0.0
|
|
29
|
-
- @playwright/test >= 1.
|
|
29
|
+
- @playwright/test >= 1.52.0
|
|
30
30
|
|
|
31
31
|
## Quick Start
|
|
32
32
|
|
|
@@ -127,6 +127,7 @@ npx playwright test
|
|
|
127
127
|
| `debug` | `--debug` | `TESTDINO_DEBUG` | Enable debug logging |
|
|
128
128
|
| `ciRunId` | `--ci-run-id` | - | Group sharded test runs |
|
|
129
129
|
| `artifacts` | `--no-artifacts` | - | Upload artifacts (screenshots, videos, traces). Enabled by default; use `--no-artifacts` to disable |
|
|
130
|
+
| `coverage` | `--coverage` | - | Enable code coverage collection (see [Code Coverage](#code-coverage)) |
|
|
130
131
|
|
|
131
132
|
### Configuration File
|
|
132
133
|
|
|
@@ -137,6 +138,16 @@ Create `testdino.config.ts` (or `.js`) in your project root for persistent setti
|
|
|
137
138
|
export default {
|
|
138
139
|
token: process.env.TESTDINO_TOKEN,
|
|
139
140
|
debug: false,
|
|
141
|
+
artifacts: true,
|
|
142
|
+
coverage: {
|
|
143
|
+
enabled: true,
|
|
144
|
+
include: ['src/**'],
|
|
145
|
+
exclude: ['**/node_modules/**'],
|
|
146
|
+
thresholds: {
|
|
147
|
+
lines: 80,
|
|
148
|
+
branches: 60,
|
|
149
|
+
},
|
|
150
|
+
},
|
|
140
151
|
};
|
|
141
152
|
```
|
|
142
153
|
|
|
@@ -233,6 +244,70 @@ TestDino automatically collects environment metadata at the start of each test r
|
|
|
233
244
|
|
|
234
245
|
Metadata collection is non-blocking. Tests continue even if some metadata is unavailable.
|
|
235
246
|
|
|
247
|
+
## Code Coverage
|
|
248
|
+
|
|
249
|
+
TestDino can collect Istanbul-based code coverage from your application during test execution.
|
|
250
|
+
|
|
251
|
+
### Setup
|
|
252
|
+
|
|
253
|
+
**1. Instrument your application** with Istanbul (e.g., via `babel-plugin-istanbul` or `nyc`). Your app must expose `window.__coverage__` in the browser.
|
|
254
|
+
|
|
255
|
+
**2. Use the TestDino test fixture** in your test files:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Use TestDino's test and expect instead of Playwright's
|
|
259
|
+
import { test, expect } from '@testdino/playwright';
|
|
260
|
+
|
|
261
|
+
test('my test', async ({ page }) => {
|
|
262
|
+
await page.goto('/');
|
|
263
|
+
// Coverage is collected automatically after each test
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**3. Enable coverage** via CLI flag, config file, or Playwright reporter options:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# CLI flag
|
|
271
|
+
npx tdpw test --coverage
|
|
272
|
+
|
|
273
|
+
# Or configure in testdino.config.ts (see Configuration File section)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Coverage Options
|
|
277
|
+
|
|
278
|
+
| Option | Type | Description |
|
|
279
|
+
| ------------ | ---------- | ------------------------------------------------------------- |
|
|
280
|
+
| `enabled` | `boolean` | Enable coverage collection (HTML report output: `./coverage`) |
|
|
281
|
+
| `include` | `string[]` | Glob patterns to include files |
|
|
282
|
+
| `exclude` | `string[]` | Glob patterns to exclude files |
|
|
283
|
+
| `thresholds` | `object` | Fail the run if coverage is below thresholds |
|
|
284
|
+
|
|
285
|
+
**Include/exclude example:**
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
coverage: {
|
|
289
|
+
enabled: true,
|
|
290
|
+
include: ['src/**'],
|
|
291
|
+
exclude: ['**/node_modules/**', '**/*.test.ts'],
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Thresholds example:**
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
coverage: {
|
|
299
|
+
enabled: true,
|
|
300
|
+
thresholds: {
|
|
301
|
+
lines: 80,
|
|
302
|
+
branches: 60,
|
|
303
|
+
functions: 80,
|
|
304
|
+
statements: 80,
|
|
305
|
+
},
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Coverage works with sharded test execution — TestDino automatically merges coverage data across shards on the server.
|
|
310
|
+
|
|
236
311
|
## Troubleshooting
|
|
237
312
|
|
|
238
313
|
### Token Error
|
|
@@ -283,7 +358,7 @@ npx tdpw test --debug
|
|
|
283
358
|
## FAQ
|
|
284
359
|
|
|
285
360
|
**Q: How do I get a token?**
|
|
286
|
-
Sign up at [testdino.com](https://www.testdino.com) and follow the [Getting Started Guide](https://
|
|
361
|
+
Sign up at [testdino.com](https://www.testdino.com) and follow the [Getting Started Guide](https://docs.testdino.com/getting-started).
|
|
287
362
|
|
|
288
363
|
**Q: Can I use TestDino with other Playwright reporters?**
|
|
289
364
|
Yes. TestDino works alongside HTML, JUnit, or any other reporter.
|
|
@@ -299,8 +374,8 @@ Yes. Configure TestDino in `playwright.config.ts` for VSCode integration.
|
|
|
299
374
|
|
|
300
375
|
## Support
|
|
301
376
|
|
|
302
|
-
- [Documentation](https://
|
|
303
|
-
- [Getting Started](https://
|
|
377
|
+
- [Documentation](https://docs.testdino.com/)
|
|
378
|
+
- [Getting Started](https://docs.testdino.com/getting-started)
|
|
304
379
|
- [Email Support](mailto:support@testdino.com)
|
|
305
380
|
|
|
306
381
|
---
|
package/bin/tdpw.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Imports and runs the CLI from the built dist directory
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
// Import
|
|
9
|
-
import('../dist/cli/index.
|
|
8
|
+
// Import CLI from built ESM (.mjs) for proper module resolution (e.g., chalk dependency)
|
|
9
|
+
import('../dist/cli/index.mjs').catch((error) => {
|
|
10
10
|
console.error('Failed to load CLI:', error.message);
|
|
11
11
|
process.exit(1);
|
|
12
12
|
});
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
2
|
+
|
|
3
|
+
// src/cli/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
7
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8
|
+
|
|
9
|
+
// src/cli/config-loader.ts
|
|
10
|
+
import { existsSync, statSync } from "fs";
|
|
11
|
+
import { join, dirname } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import jiti from "jiti";
|
|
11
14
|
|
|
12
15
|
// src/cli/errors.ts
|
|
13
16
|
var TestDinoError = class extends Error {
|
|
@@ -160,8 +163,17 @@ var ConfigLoader = class {
|
|
|
160
163
|
return config ?? {};
|
|
161
164
|
}
|
|
162
165
|
};
|
|
166
|
+
|
|
167
|
+
// src/cli/config-detector.ts
|
|
168
|
+
import { existsSync as existsSync2 } from "fs";
|
|
169
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
170
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
171
|
+
import jiti2 from "jiti";
|
|
163
172
|
var PLAYWRIGHT_CONFIG_FILENAMES = ["playwright.config.ts", "playwright.config.js"];
|
|
164
173
|
var TESTDINO_REPORTER_NAMES = ["@testdino/playwright", "testdino-playwright", "TestdinoReporter"];
|
|
174
|
+
function isValidThreshold(value) {
|
|
175
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 100;
|
|
176
|
+
}
|
|
165
177
|
var ConfigDetector = class {
|
|
166
178
|
cwd;
|
|
167
179
|
constructor(cwd = process.cwd()) {
|
|
@@ -191,8 +203,8 @@ var ConfigDetector = class {
|
|
|
191
203
|
*/
|
|
192
204
|
findPlaywrightConfig() {
|
|
193
205
|
for (const filename of PLAYWRIGHT_CONFIG_FILENAMES) {
|
|
194
|
-
const configPath =
|
|
195
|
-
if (
|
|
206
|
+
const configPath = join2(this.cwd, filename);
|
|
207
|
+
if (existsSync2(configPath)) {
|
|
196
208
|
return configPath;
|
|
197
209
|
}
|
|
198
210
|
}
|
|
@@ -202,7 +214,7 @@ var ConfigDetector = class {
|
|
|
202
214
|
* Load and parse Playwright config using jiti
|
|
203
215
|
*/
|
|
204
216
|
loadPlaywrightConfig(configPath) {
|
|
205
|
-
const jitiLoader =
|
|
217
|
+
const jitiLoader = jiti2(dirname2(configPath), {
|
|
206
218
|
interopDefault: true,
|
|
207
219
|
cache: false,
|
|
208
220
|
extensions: [".ts", ".js"]
|
|
@@ -213,7 +225,7 @@ var ConfigDetector = class {
|
|
|
213
225
|
if (!resolved) {
|
|
214
226
|
throw new Error(`Could not resolve Playwright config: ${configPath}`);
|
|
215
227
|
}
|
|
216
|
-
const resolvedPath = typeof resolved === "string" ? resolved :
|
|
228
|
+
const resolvedPath = typeof resolved === "string" ? resolved : fileURLToPath2(resolved);
|
|
217
229
|
loaded = jitiLoader(resolvedPath);
|
|
218
230
|
} catch (error) {
|
|
219
231
|
throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -318,15 +330,6 @@ var ConfigDetector = class {
|
|
|
318
330
|
const config = {
|
|
319
331
|
enabled: typeof raw.enabled === "boolean" ? raw.enabled : false
|
|
320
332
|
};
|
|
321
|
-
if (Array.isArray(raw.projects)) {
|
|
322
|
-
config.projects = raw.projects.filter((p) => typeof p === "string");
|
|
323
|
-
}
|
|
324
|
-
if (typeof raw.localReport === "boolean") {
|
|
325
|
-
config.localReport = raw.localReport;
|
|
326
|
-
}
|
|
327
|
-
if (typeof raw.localReportDir === "string") {
|
|
328
|
-
config.localReportDir = raw.localReportDir;
|
|
329
|
-
}
|
|
330
333
|
if (Array.isArray(raw.include)) {
|
|
331
334
|
config.include = raw.include.filter((p) => typeof p === "string");
|
|
332
335
|
}
|
|
@@ -336,14 +339,17 @@ var ConfigDetector = class {
|
|
|
336
339
|
if (typeof raw.thresholds === "object" && raw.thresholds !== null) {
|
|
337
340
|
const t = raw.thresholds;
|
|
338
341
|
config.thresholds = {};
|
|
339
|
-
if (
|
|
340
|
-
if (
|
|
341
|
-
if (
|
|
342
|
-
if (
|
|
342
|
+
if (isValidThreshold(t.statements)) config.thresholds.statements = t.statements;
|
|
343
|
+
if (isValidThreshold(t.branches)) config.thresholds.branches = t.branches;
|
|
344
|
+
if (isValidThreshold(t.functions)) config.thresholds.functions = t.functions;
|
|
345
|
+
if (isValidThreshold(t.lines)) config.thresholds.lines = t.lines;
|
|
343
346
|
}
|
|
344
347
|
return config;
|
|
345
348
|
}
|
|
346
349
|
};
|
|
350
|
+
|
|
351
|
+
// src/cli/config-merger.ts
|
|
352
|
+
import { randomUUID } from "crypto";
|
|
347
353
|
var ConfigMerger = class _ConfigMerger {
|
|
348
354
|
static DEFAULT_SERVER_URL = "https://api.testdino.com";
|
|
349
355
|
/**
|
|
@@ -504,6 +510,15 @@ var ArgFilter = class {
|
|
|
504
510
|
}
|
|
505
511
|
};
|
|
506
512
|
|
|
513
|
+
// src/cli/temp-config.ts
|
|
514
|
+
import { writeFileSync, unlinkSync, existsSync as existsSync3 } from "fs";
|
|
515
|
+
import { join as join3 } from "path";
|
|
516
|
+
import { tmpdir } from "os";
|
|
517
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
518
|
+
|
|
519
|
+
// src/cli/logger.ts
|
|
520
|
+
import chalk from "chalk";
|
|
521
|
+
|
|
507
522
|
// src/utils/index.ts
|
|
508
523
|
function isDebugEnabled() {
|
|
509
524
|
return process.env.TESTDINO_DEBUG === "true" || process.env.TESTDINO_DEBUG === "1" || process.env.DEBUG === "true";
|
|
@@ -608,7 +623,7 @@ ${title}`));
|
|
|
608
623
|
);
|
|
609
624
|
}
|
|
610
625
|
};
|
|
611
|
-
new Logger(isDebugEnabled());
|
|
626
|
+
var logger = new Logger(isDebugEnabled());
|
|
612
627
|
|
|
613
628
|
// src/cli/temp-config.ts
|
|
614
629
|
var TempConfigManager = class {
|
|
@@ -655,7 +670,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
655
670
|
*/
|
|
656
671
|
cleanup(tempPath) {
|
|
657
672
|
try {
|
|
658
|
-
if (
|
|
673
|
+
if (existsSync3(tempPath)) {
|
|
659
674
|
unlinkSync(tempPath);
|
|
660
675
|
}
|
|
661
676
|
this.tempFiles.delete(tempPath);
|
|
@@ -697,8 +712,8 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
697
712
|
* Generate unique temp file path
|
|
698
713
|
*/
|
|
699
714
|
generateTempPath() {
|
|
700
|
-
const filename = `testdino-config-${
|
|
701
|
-
return
|
|
715
|
+
const filename = `testdino-config-${randomUUID2()}.json`;
|
|
716
|
+
return join3(tmpdir(), filename);
|
|
702
717
|
}
|
|
703
718
|
/**
|
|
704
719
|
* Register cleanup handlers for process exit and signals
|
|
@@ -740,6 +755,9 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
740
755
|
return Array.from(this.tempFiles);
|
|
741
756
|
}
|
|
742
757
|
};
|
|
758
|
+
|
|
759
|
+
// src/cli/playwright-spawner.ts
|
|
760
|
+
import { execa } from "execa";
|
|
743
761
|
var PlaywrightSpawner = class {
|
|
744
762
|
logger;
|
|
745
763
|
constructor(logger3) {
|
|
@@ -868,11 +886,11 @@ var TestCommand = class {
|
|
|
868
886
|
};
|
|
869
887
|
|
|
870
888
|
// src/cli/index.ts
|
|
871
|
-
var __filename
|
|
872
|
-
var __dirname
|
|
889
|
+
var __filename = fileURLToPath3(import.meta.url);
|
|
890
|
+
var __dirname = dirname3(__filename);
|
|
873
891
|
function getVersion() {
|
|
874
892
|
try {
|
|
875
|
-
const packagePath =
|
|
893
|
+
const packagePath = join4(__dirname, "../../package.json");
|
|
876
894
|
const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
877
895
|
return packageJson.version;
|
|
878
896
|
} catch {
|
|
@@ -923,5 +941,4 @@ main().catch((error) => {
|
|
|
923
941
|
logger2.error("Unexpected error", error instanceof Error ? error : void 0);
|
|
924
942
|
process.exit(1);
|
|
925
943
|
});
|
|
926
|
-
//# sourceMappingURL=index.mjs.map
|
|
927
944
|
//# sourceMappingURL=index.mjs.map
|