@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 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://www.testdino.com/docs)** | **[Get Your Token](https://www.testdino.com/docs/getting-started)**
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 --save-dev @testdino/playwright
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.50.0
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://www.testdino.com/docs/getting-started).
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://www.testdino.com/docs)
303
- - [Getting Started](https://www.testdino.com/docs/getting-started)
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 the CLI from the built distribution (CommonJS)
9
- import('../dist/cli/index.js').catch((error) => {
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
  });
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { readFileSync, existsSync, statSync, writeFileSync, unlinkSync } from 'fs';
4
- import { dirname, join } from 'path';
5
- import { fileURLToPath } from 'url';
6
- import jiti from 'jiti';
7
- import { randomUUID } from 'crypto';
8
- import { tmpdir } from 'os';
9
- import chalk from 'chalk';
10
- import { execa } from 'execa';
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 = join(this.cwd, filename);
195
- if (existsSync(configPath)) {
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 = jiti(dirname(configPath), {
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 : fileURLToPath(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 (typeof t.statements === "number") config.thresholds.statements = t.statements;
340
- if (typeof t.branches === "number") config.thresholds.branches = t.branches;
341
- if (typeof t.functions === "number") config.thresholds.functions = t.functions;
342
- if (typeof t.lines === "number") config.thresholds.lines = t.lines;
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 (existsSync(tempPath)) {
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-${randomUUID()}.json`;
701
- return join(tmpdir(), filename);
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$1 = fileURLToPath(import.meta.url);
872
- var __dirname$1 = dirname(__filename$1);
889
+ var __filename = fileURLToPath3(import.meta.url);
890
+ var __dirname = dirname3(__filename);
873
891
  function getVersion() {
874
892
  try {
875
- const packagePath = join(__dirname$1, "../../package.json");
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