@empiricalrun/playwright-utils 0.60.0 → 0.60.2

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.
@@ -1,4 +1,5 @@
1
1
  import type { ApiWorkerClient } from "./api-worker-client";
2
+ import type { WaitForEmailOptions } from "./email";
2
3
  type Link = {
3
4
  text?: string;
4
5
  href?: string;
@@ -19,15 +20,9 @@ export declare class InboxClient {
19
20
  private timeout;
20
21
  constructor(opts: InboxClientOptions);
21
22
  private isInboxMessageList;
22
- waitForEmail(address: string, filter?: {
23
- from?: string;
24
- subject?: string;
25
- body?: string;
26
- }): Promise<InboxEmail>;
23
+ waitForEmail(address: string, options?: WaitForEmailOptions): Promise<InboxEmail>;
27
24
  private pollForMessage;
28
25
  private parseMessage;
29
- private extractLinks;
30
- private extractCodes;
31
26
  }
32
27
  export {};
33
28
  //# sourceMappingURL=inbox-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inbox-client.d.ts","sourceRoot":"","sources":["../src/inbox-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,KAAK,IAAI,GAAG;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAcF,KAAK,kBAAkB,GAAG;IACxB,SAAS,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,IAAI,EAAE,kBAAkB,EAGnC;IAED,OAAO,CAAC,kBAAkB;IAWpB,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,UAAU,CAAC,CAOrB;YAEa,cAAc;IAyD5B,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;CAgBrB"}
1
+ {"version":3,"file":"inbox-client.d.ts","sourceRoot":"","sources":["../src/inbox-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,KAAK,IAAI,GAAG;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAiBF,KAAK,kBAAkB,GAAG;IACxB,SAAS,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,IAAI,EAAE,kBAAkB,EAGnC;IAED,OAAO,CAAC,kBAAkB;IAWpB,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAOrB;YAEa,cAAc;IAyD5B,OAAO,CAAC,YAAY;CASrB"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InboxClient = void 0;
4
4
  const DEFAULT_POLL_DELAY = 1000;
5
+ const DEFAULT_RECEIVED_AFTER_LOOKBACK = 5_000;
5
6
  class InboxClient {
6
7
  apiClient;
7
8
  timeout;
@@ -15,11 +16,10 @@ class InboxClient {
15
16
  "data" in value &&
16
17
  Array.isArray(value.data));
17
18
  }
18
- async waitForEmail(address, filter) {
19
- const now = new Date();
20
- const bufferPeriod = 5_000;
21
- const receivedAfter = new Date(now.getTime() - bufferPeriod);
22
- const message = await this.pollForMessage(address, receivedAfter, filter);
19
+ async waitForEmail(address, options) {
20
+ const receivedAfter = options?.receivedAfter ??
21
+ new Date(Date.now() - DEFAULT_RECEIVED_AFTER_LOOKBACK);
22
+ const message = await this.pollForMessage(address, receivedAfter, options);
23
23
  return this.parseMessage(message);
24
24
  }
25
25
  async pollForMessage(address, receivedAfter, filter) {
@@ -67,51 +67,13 @@ class InboxClient {
67
67
  }
68
68
  }
69
69
  parseMessage(message) {
70
- const links = this.extractLinks(message.html_body, message.text_body);
71
- const codes = this.extractCodes(message.html_body, message.text_body);
72
70
  return {
73
71
  subject: message.subject || undefined,
74
72
  text: message.text_body || undefined,
75
73
  html: message.html_body || undefined,
76
- links,
77
- codes,
74
+ links: message.links,
75
+ codes: message.codes,
78
76
  };
79
77
  }
80
- extractLinks(html, text) {
81
- const links = [];
82
- if (html) {
83
- const hrefRegex = /<a[^>]+href="([^"]*)"[^>]*>(.*?)<\/a>/gi;
84
- let match;
85
- while ((match = hrefRegex.exec(html)) !== null) {
86
- links.push({ href: match[1], text: match[2]?.replace(/<[^>]*>/g, "") });
87
- }
88
- }
89
- if (text) {
90
- const urlRegex = /https?:\/\/[^\s<>"')\]]+/g;
91
- let match;
92
- while ((match = urlRegex.exec(text)) !== null) {
93
- if (!links.some((l) => l.href === match[0])) {
94
- links.push({ href: match[0] });
95
- }
96
- }
97
- }
98
- return links;
99
- }
100
- extractCodes(html, text) {
101
- const codes = [];
102
- const codeRegex = /\b(\d{4,8})\b/g;
103
- for (const content of [text, html]) {
104
- if (!content) {
105
- continue;
106
- }
107
- let match;
108
- while ((match = codeRegex.exec(content)) !== null) {
109
- if (!codes.includes(match[1])) {
110
- codes.push(match[1]);
111
- }
112
- }
113
- }
114
- return codes;
115
- }
116
78
  }
117
79
  exports.InboxClient = InboxClient;
@@ -1,4 +1,5 @@
1
1
  import type { ApiWorkerClient } from "./api-worker-client";
2
+ import type { WaitForEmailOptions } from "./email";
2
3
  type Link = {
3
4
  text?: string;
4
5
  href?: string;
@@ -21,11 +22,7 @@ export declare class MailosaurClient {
21
22
  private timeout;
22
23
  constructor(opts: MailosaurClientOptions);
23
24
  private makeRequest;
24
- waitForEmail(address: string, filter?: {
25
- from?: string;
26
- subject?: string;
27
- body?: string;
28
- }): Promise<MailosaurEmail>;
25
+ waitForEmail(address: string, options?: WaitForEmailOptions): Promise<MailosaurEmail>;
29
26
  private searchWithPolling;
30
27
  private getMessageById;
31
28
  private parseEmailResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"mailosaur-client.d.ts","sourceRoot":"","sources":["../src/mailosaur-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,KAAK,IAAI,GAAG;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAiCF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,IAAI,EAAE,sBAAsB,EAIvC;YAEa,WAAW;IAwBnB,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC,cAAc,CAAC,CAmBzB;YAEa,iBAAiB;YA2EjB,cAAc;IA+B5B,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,KAAK;CAGd"}
1
+ {"version":3,"file":"mailosaur-client.d.ts","sourceRoot":"","sources":["../src/mailosaur-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,KAAK,IAAI,GAAG;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAkCF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,IAAI,EAAE,sBAAsB,EAIvC;YAEa,WAAW;IAwBnB,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAmBzB;YAEa,iBAAiB;YA2EjB,cAAc;IA+B5B,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,KAAK;CAGd"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MailosaurClient = void 0;
4
4
  const DEFAULT_POLL_DELAY = 1000;
5
+ const DEFAULT_RECEIVED_AFTER_LOOKBACK = 5_000;
5
6
  class MailosaurClient {
6
7
  apiClient;
7
8
  serverId;
@@ -23,15 +24,14 @@ class MailosaurClient {
23
24
  status: 200,
24
25
  };
25
26
  }
26
- async waitForEmail(address, filter) {
27
- const now = new Date();
28
- const bufferPeriod = 5_000;
29
- const receivedAfter = new Date(now.getTime() - bufferPeriod);
27
+ async waitForEmail(address, options) {
28
+ const receivedAfter = options?.receivedAfter ??
29
+ new Date(Date.now() - DEFAULT_RECEIVED_AFTER_LOOKBACK);
30
30
  const searchCriteria = {
31
31
  sentTo: address,
32
- ...(filter?.from && { sentFrom: filter.from }),
33
- ...(filter?.subject && { subject: filter.subject }),
34
- ...(filter?.body && { body: filter.body }),
32
+ ...(options?.from && { sentFrom: options.from }),
33
+ ...(options?.subject && { subject: options.subject }),
34
+ ...(options?.body && { body: options.body }),
35
35
  };
36
36
  const messageId = await this.searchWithPolling(searchCriteria, receivedAfter, address);
37
37
  const message = await this.getMessageById(messageId);
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/reporter/util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAQhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AA0BnC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqB7D;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,UAQhC;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CA6CD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ;IAqBlD,MAAM;IACN,WAAW;EAEd;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GACnC,GAAG,CAIL;AAED,wBAAsB,gCAAgC,CACpD,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,iBAoFjB;AAED;;;;;;;;;;GAUG;AACH;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAe,GAC9B,iBAAiB,CAgBnB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,6CA+BlB"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/reporter/util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAQhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AA0BnC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqB7D;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,UAQhC;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CA6CD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ;IAqBlD,MAAM;IACN,WAAW;EAEd;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GACnC,GAAG,CAIL;AAED,wBAAsB,gCAAgC,CACpD,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,iBAoFjB;AAED;;;;;;;;;;GAUG;AACH;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAe,GAC9B,iBAAiB,CAgBnB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,6CA+BlB"}
@@ -15,11 +15,11 @@ exports.checkFileExistsAsync = checkFileExistsAsync;
15
15
  exports.updateSummaryJsonAttachmentPaths = updateSummaryJsonAttachmentPaths;
16
16
  const zip_1 = require("@empiricalrun/r2-uploader/zip");
17
17
  const reporter_1 = require("@empiricalrun/reporter");
18
- const async_retry_1 = __importDefault(require("async-retry"));
19
18
  const crypto_1 = __importDefault(require("crypto"));
20
19
  const fs_1 = __importDefault(require("fs"));
21
20
  const mime_1 = __importDefault(require("mime"));
22
21
  const path_1 = __importDefault(require("path"));
22
+ const api_worker_client_1 = require("../api-worker-client");
23
23
  const logger_1 = require("../logger");
24
24
  // Mirrors https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/tools/cli-client/program.ts#L440
25
25
  function calculateSha1(buffer) {
@@ -125,40 +125,25 @@ function suitesAndProjectForTest(test) {
125
125
  };
126
126
  }
127
127
  async function sendTestCaseUpdateToDashboard(params) {
128
- const DOMAIN = process.env.DASHBOARD_DOMAIN || "https://api.empirical.run";
129
128
  try {
130
129
  const requestBody = {
131
130
  name: "test_case_run_end",
132
131
  data: {
133
132
  ...params,
133
+ result: {
134
+ ...params.result,
135
+ startTime: params.result.startTime instanceof Date
136
+ ? params.result.startTime.toISOString()
137
+ : params.result.startTime,
138
+ },
134
139
  },
135
140
  };
136
- if (!DOMAIN) {
137
- console.warn("No dashboard domain found. Skipping send message to dashboard.");
138
- return;
139
- }
140
141
  if (!process.env.EMPIRICALRUN_API_KEY) {
141
142
  console.log("No API token found. Skipping send message to dashboard.");
142
143
  return;
143
144
  }
144
- await (0, async_retry_1.default)(async () => {
145
- const response = await fetch(`${DOMAIN}/api/test-runs/events`, {
146
- method: "PUT",
147
- headers: {
148
- "Content-Type": "application/json",
149
- Authorization: `Bearer ${process.env.EMPIRICALRUN_API_KEY}`,
150
- },
151
- body: JSON.stringify(requestBody),
152
- });
153
- if (!response.ok) {
154
- throw new Error(`Failed to publish test case diagnois: ${response.status}`);
155
- }
156
- }, {
157
- retries: 3,
158
- minTimeout: 1000,
159
- maxTimeout: 60_000,
160
- factor: 3,
161
- });
145
+ const client = new api_worker_client_1.ApiWorkerClient();
146
+ await client.putTestCaseRunEndEvent(requestBody);
162
147
  logger_1.logger.debug("Successfully sent test case update to dashboard");
163
148
  }
164
149
  catch (e) {
@@ -94,7 +94,7 @@ class OverlayDismissAgent {
94
94
  // and we need app to be able to use page.pause for agent actions.
95
95
  // Currently, page.pause does not cleanup properly, causing it to work
96
96
  // only once in a particular test run.
97
- // Ran into this here: https://dash.empirical.run/quizizz-tests/sessions/2825
97
+ // Ran into this here: https://empirical.run/quizizz-tests/sessions/2825
98
98
  prefersElementFromPointCodegen: true,
99
99
  // Overlay dismissal doesn't need page navigation — the overlay is
100
100
  // already on the current page. Including page_goto causes the model
package/docs/email.md CHANGED
@@ -76,3 +76,22 @@ const email = await client.waitForEmail({
76
76
  body: "verification code",
77
77
  });
78
78
  ```
79
+
80
+ ### Searching from a specific time
81
+
82
+ By default, `waitForEmail` includes emails received up to five seconds before
83
+ it is called. Pass `receivedAfter` to control the start of the search window.
84
+ Capturing the time immediately before the action that sends the email avoids
85
+ matching older messages without missing an email that arrives before polling
86
+ begins.
87
+
88
+ ```ts
89
+ const receivedAfter = new Date();
90
+
91
+ await page.getByRole("button", { name: "Send code" }).click();
92
+
93
+ const email = await client.waitForEmail({
94
+ receivedAfter,
95
+ subject: "Your login code",
96
+ });
97
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.60.0",
3
+ "version": "0.60.2",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -26,7 +26,8 @@
26
26
  },
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/empirical-run/empirical.git"
29
+ "url": "git+https://github.com/empirical-run/test-generator.git",
30
+ "directory": "packages/playwright-utils"
30
31
  },
31
32
  "author": "Empirical Team <hey@empirical.run>",
32
33
  "devDependencies": {
@@ -41,7 +42,7 @@
41
42
  "openapi-typescript": "7.6.1",
42
43
  "playwright-core": "1.62.1",
43
44
  "serve-handler": "^6.1.6",
44
- "@empiricalrun/shared-types": "0.17.0"
45
+ "@empiricalrun/shared-types": "0.19.0"
45
46
  },
46
47
  "dependencies": {
47
48
  "@babel/code-frame": "^7.24.7",