@@ -301,72 +301,87 @@ const tracker = new UICoverageTracker({ app: 'my-ui-app' });
301
301
302
302
### Advanced Example
303
303
304
- This example demonstrates how to use ` ui-coverage-scenario-tool-js ` with execution context to automatically track UI
305
- coverage scenarios in Playwright — without manually passing the tracker through every layer of your app.
304
+ This example demonstrates how to use ` ui-coverage-scenario-tool-js ` with a manual context based on ` WeakMap ` — ideal
305
+ when you prefer to avoid Node.js-specific features like ` AsyncLocalStorage ` , or want to keep the tracker tied directly
306
+ to the Page object.
306
307
307
- #### Step 1: Initialize the tracker
308
+ #### Step 1: Initialize the tracker storage
308
309
309
- Create a single instance of ` UICoverageTracker ` that will be shared across all tests.
310
+ Instead of a global singleton tracker or implicit context, we use a ` WeakMap ` to associate a ` UICoverageTracker ` with
311
+ each Playwright ` Page ` instance.
310
312
311
313
` ./coverage.ts `
312
314
313
315
``` typescript
314
316
import { UICoverageTracker } from ' ui-coverage-scenario-tool-js' ;
317
+ import type { Page } from ' @playwright/test' ;
315
318
316
- export const tracker = new UICoverageTracker ({ app: ' ui-course' });
319
+ // Map from Playwright Page to its UI coverage tracker
320
+ export const trackerByPage = new WeakMap <Page , UICoverageTracker >();
317
321
```
318
322
319
- #### Step 2: Extend Playwright’s test with scenario setup and teardown
323
+ #### Step 2: Extend Playwright’s test with setup and teardown
320
324
321
- Create a custom test wrapper where :
325
+ Wrap Playwright’s test to :
322
326
323
- - the scenario is started before each test (with a name and a link to an external TMS),
324
- - and ended after the test is complete.
327
+ - create and register a new tracker for each test,
328
+ - start a scenario before the test begins,
329
+ - and end it after the test completes.
325
330
326
331
` ./tests/base.ts `
327
332
328
333
``` typescript
329
334
import { test as base } from ' @playwright/test' ;
330
- import { coverageContext } from ' ui- coverage-scenario-tool-js ' ;
331
- import { tracker } from ' ../ coverage' ;
335
+ import { trackerByPage } from ' ../ coverage' ;
336
+ import { UICoverageTracker } from ' ui- coverage-scenario-tool-js ' ;
332
337
333
338
export const test = base .extend <{}>({
334
339
async page({ page }, use , testInfo ) {
335
- coverageContext .run (tracker , () => {
336
- tracker .startScenario ({
337
- url: ` https://company.tms.com/testcases/${testInfo .testId } ` , // link to external test case
338
- name: testInfo .title
339
- });
340
+ // Create a new tracker for this test
341
+ const tracker = new UICoverageTracker ({ app: ' ui-course' });
342
+
343
+ // Start the scenario with test name and external link
344
+ tracker .startScenario ({
345
+ name: testInfo .title ,
346
+ url: ` https://company.tms.com/testcases/${testInfo .testId } ` // link to external test case
340
347
});
341
348
349
+ // Associate the tracker with this page instance
350
+ trackerByPage .set (page , tracker );
351
+
352
+ // Run the test
342
353
await use (page );
343
354
344
- await coverageContext .get ()?.endScenario ();
355
+ // Finalize scenario and clean up
356
+ await tracker .endScenario ();
357
+ trackerByPage .delete (page ); // important: cleanup to avoid leaks
345
358
}
346
359
});
347
360
```
348
361
349
- _ This uses ` AsyncLocalStorage ` internally to propagate the tracker across async calls — you don’t need to pass it
350
- manually._
351
-
352
362
#### Step 3: Track interactions inside PageObjects
353
363
354
- Inside your PageObject or UI component, simply call ` coverageContext.get() ` to record interactions:
364
+ Inside your PageObjects (or components), retrieve the tracker via ` trackerByPage ` using the current ` Page ` , and use it
365
+ to track user interactions.
355
366
356
367
` ./pages/login-page.ts `
357
368
358
369
``` typescript
359
370
import { Page } from ' @playwright/test' ;
360
- import { ActionType , coverageContext , SelectorType } from ' ui-coverage-scenario-tool-js' ;
371
+ import { ActionType , SelectorType } from ' ui-coverage-scenario-tool-js' ;
372
+ import { trackerByPage } from ' ../coverage' ;
361
373
362
374
export class LoginPage {
363
375
constructor (private page : Page ) {
364
376
}
365
377
366
378
async clickLoginButton() {
379
+ // Perform actual UI interaction
367
380
await this .page .click (' #login' );
368
381
369
- await coverageContext .get ()?.trackCoverage ({
382
+ // Track the interaction with the coverage tool
383
+ const tracker = trackerByPage .get (this .page );
384
+ tracker ?.trackCoverage ({
370
385
selector: ' #login' ,
371
386
actionType: ActionType .Click ,
372
387
selectorType: SelectorType .CSS
@@ -375,9 +390,9 @@ export class LoginPage {
375
390
}
376
391
```
377
392
378
- #### Step 4: Writing tests
393
+ #### Step 4: Write clean tests
379
394
380
- Now your test stays clean and focused — and coverage tracking happens behind the scenes.
395
+ Now your tests remain clean and focused — and coverage tracking happens behind the scenes via ` WeakMap ` .
381
396
382
397
` ./tests/important-feature.spec.ts `
383
398
@@ -391,12 +406,13 @@ test('Should login via the login button', async ({ page }) => {
391
406
});
392
407
```
393
408
394
- #### Why this matters
409
+ #### Why this approach works
395
410
396
- - Context-aware tracking — no need to manually pass the tracker around.
397
- - Scenario binding — each interaction is tied to the test that triggered it.
398
- - TMS integration — easily associate scenarios with external test cases or tickets.
399
- - Parallel-safe — works reliably even with concurrent test execution.
411
+ - ** Context-aware tracking** — without relying on Node.js internals.
412
+ - ** Explicit association** — tracker is tied directly to the Playwright ` Page ` .
413
+ - ** Scenario binding** — each test has its own isolated tracker and scenario.
414
+ - ** Parallel-safe** — works reliably even with concurrent test execution.
415
+ - ** Browser-compatible** — works in environments that lack AsyncLocalStorage.
400
416
401
417
### Coverage Report Generation
402
418
0 commit comments