@empiricalrun/playwright-utils 0.10.0 → 0.13.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/CHANGELOG.md +27 -0
- package/README.md +58 -1
- package/dist/captcha/index.d.ts +7 -0
- package/dist/captcha/index.d.ts.map +1 -0
- package/dist/captcha/index.js +28 -0
- package/dist/{captcha.d.ts → captcha/vision.d.ts} +1 -1
- package/dist/captcha/vision.d.ts.map +1 -0
- package/dist/email.d.ts +8 -1
- package/dist/email.d.ts.map +1 -1
- package/dist/email.js +34 -17
- package/dist/reporter/custom.d.ts +5 -1
- package/dist/reporter/custom.d.ts.map +1 -1
- package/dist/reporter/custom.js +93 -35
- package/package.json +4 -2
- package/dist/captcha.d.ts.map +0 -1
- /package/dist/{captcha.js → captcha/vision.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @empiricalrun/playwright-utils
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- cff4d1c: feat: add third party captcha solver
|
|
8
|
+
|
|
9
|
+
## 0.12.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 3c94c63: feat: EmailClient support for email otp logins
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- ab045ff: fix: set dynamic maxQueueSize and clearer error logs
|
|
18
|
+
|
|
19
|
+
## 0.11.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- ae142a5: feat: queue uploads in reporter
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [ae142a5]
|
|
28
|
+
- @empiricalrun/r2-uploader@0.1.3
|
|
29
|
+
|
|
3
30
|
## 0.10.0
|
|
4
31
|
|
|
5
32
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
1
|
# playwright-utils
|
|
2
2
|
|
|
3
|
-
Playwright utils for test code repos of our customers
|
|
3
|
+
Playwright utils for test code repos of our customers
|
|
4
|
+
|
|
5
|
+
## Utilities
|
|
6
|
+
|
|
7
|
+
- Default config for Playwright projects
|
|
8
|
+
- Custom reporter
|
|
9
|
+
- Highlight user actions
|
|
10
|
+
- Custom fixture to wrap around that
|
|
11
|
+
- Vision capabilities
|
|
12
|
+
- `locator.query` API
|
|
13
|
+
- Captcha
|
|
14
|
+
- Email automation
|
|
15
|
+
|
|
16
|
+
## Email automation
|
|
17
|
+
|
|
18
|
+
### Example usage
|
|
19
|
+
|
|
20
|
+
#### Dynamic email
|
|
21
|
+
|
|
22
|
+
This dynamically generates a random email address that can
|
|
23
|
+
be used for the test (e.g. invite a new user).
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { EmailClient } from "@empiricalrun/playwright-utils";
|
|
27
|
+
|
|
28
|
+
const client = new EmailClient();
|
|
29
|
+
const address = client.getAddress();
|
|
30
|
+
|
|
31
|
+
// Input the `address` in the application
|
|
32
|
+
// that sends the email.
|
|
33
|
+
|
|
34
|
+
// Get email received on the `address`
|
|
35
|
+
const email = await client.waitForEmail();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Static email
|
|
39
|
+
|
|
40
|
+
This uses a known (static) email that can be used to login
|
|
41
|
+
into an application.
|
|
42
|
+
|
|
43
|
+
This needs an email id (e.g. `test-login-user`). The email id
|
|
44
|
+
is appended with the domain (managed internally) to get the full
|
|
45
|
+
email address.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { EmailClient } from "@empiricalrun/playwright-utils";
|
|
49
|
+
|
|
50
|
+
const emailId = `test-login-user`;
|
|
51
|
+
|
|
52
|
+
const client = new EmailClient({ emailId });
|
|
53
|
+
const address = client.getAddress(); // Returns full address with domain
|
|
54
|
+
|
|
55
|
+
// Get email received on the `address`
|
|
56
|
+
const email = await client.waitForEmail();
|
|
57
|
+
|
|
58
|
+
// Get login OTP
|
|
59
|
+
const loginCode = email.codes[0];
|
|
60
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/captcha/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAKxC,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,UAAU,GAAG,YAAY,CAAC;CACrC,CAAC;AAMF,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAAiC,iBAe3C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.solveRecaptcha = void 0;
|
|
7
|
+
const puppeteer_extra_plugin_recaptcha_1 = __importDefault(require("puppeteer-extra-plugin-recaptcha"));
|
|
8
|
+
const vision_1 = require("./vision");
|
|
9
|
+
const defaultOpts = {
|
|
10
|
+
provider: "2captcha",
|
|
11
|
+
};
|
|
12
|
+
async function solveRecaptcha(page, options = defaultOpts) {
|
|
13
|
+
const { provider } = options;
|
|
14
|
+
if (provider === "2captcha") {
|
|
15
|
+
const rcPlugin = (0, puppeteer_extra_plugin_recaptcha_1.default)({
|
|
16
|
+
provider: {
|
|
17
|
+
id: "2captcha",
|
|
18
|
+
token: process.env.TWOCAPTCHA_API_KEY,
|
|
19
|
+
},
|
|
20
|
+
visualFeedback: true,
|
|
21
|
+
});
|
|
22
|
+
await rcPlugin.solveRecaptchas(page);
|
|
23
|
+
}
|
|
24
|
+
else if (provider === "llm-vision") {
|
|
25
|
+
return (0, vision_1.solveRecaptcha)(page);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.solveRecaptcha = solveRecaptcha;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vision.d.ts","sourceRoot":"","sources":["../../src/captcha/vision.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAyExD,wBAAsB,cAAc,CAAC,IAAI,EAAE,IAAI,iBAiB9C"}
|
package/dist/email.d.ts
CHANGED
|
@@ -8,11 +8,18 @@ export type Email = {
|
|
|
8
8
|
text?: string;
|
|
9
9
|
html?: string;
|
|
10
10
|
links: Link[];
|
|
11
|
+
codes: string[];
|
|
12
|
+
};
|
|
13
|
+
type EmailClientOptions = {
|
|
14
|
+
timeout?: number;
|
|
15
|
+
emailId?: string;
|
|
11
16
|
};
|
|
12
17
|
export declare class EmailClient {
|
|
13
18
|
address: string;
|
|
14
19
|
client: MailosaurClient;
|
|
15
|
-
|
|
20
|
+
timeout: number;
|
|
21
|
+
serverId: string;
|
|
22
|
+
constructor(opts?: EmailClientOptions);
|
|
16
23
|
getAddress(): string;
|
|
17
24
|
waitForEmail(): Promise<Email | undefined>;
|
|
18
25
|
}
|
package/dist/email.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,WAAW,CAAC;AAGxC,KAAK,IAAI,GAAG;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,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;AAIF,KAAK,kBAAkB,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,qBAAa,WAAW;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,SAAc;gBAEV,IAAI,GAAE,kBAAuB;IAWzC,UAAU;IAIJ,YAAY,IAAI,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;CAkCjD"}
|
package/dist/email.js
CHANGED
|
@@ -5,36 +5,53 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.EmailClient = void 0;
|
|
7
7
|
const mailosaur_1 = __importDefault(require("mailosaur"));
|
|
8
|
-
const
|
|
8
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
9
9
|
class EmailClient {
|
|
10
10
|
address;
|
|
11
11
|
client;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.join("");
|
|
16
|
-
this.address = `${randomString}@${serverId}.mailosaur.net`;
|
|
12
|
+
timeout;
|
|
13
|
+
serverId = "pnyrwq5o";
|
|
14
|
+
constructor(opts = {}) {
|
|
17
15
|
this.client = new mailosaur_1.default("NAEZtp2DVibTCzCxdYkZzhG4hrxSlBrV");
|
|
16
|
+
const { timeout = DEFAULT_TIMEOUT, emailId: knownEmailId } = opts;
|
|
17
|
+
this.timeout = timeout;
|
|
18
|
+
const emailId = knownEmailId ||
|
|
19
|
+
[...Array(7)].map(() => Math.random().toString(36)[2]).join("");
|
|
20
|
+
const emailDomain = `${this.serverId}.mailosaur.net`;
|
|
21
|
+
this.address = `${emailId}@${emailDomain}`;
|
|
18
22
|
}
|
|
19
23
|
getAddress() {
|
|
20
24
|
return this.address;
|
|
21
25
|
}
|
|
22
26
|
async waitForEmail() {
|
|
23
27
|
try {
|
|
24
|
-
const email = await this.client.messages.get(serverId, {
|
|
28
|
+
const email = await this.client.messages.get(this.serverId, {
|
|
25
29
|
sentTo: this.address,
|
|
26
|
-
}, { timeout:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
30
|
+
}, { timeout: this.timeout });
|
|
31
|
+
const codesAsString = (email.html?.codes || []).map((code) => code.value);
|
|
32
|
+
return {
|
|
33
|
+
subject: email.subject,
|
|
34
|
+
text: email.text?.body,
|
|
35
|
+
html: email.html?.body,
|
|
36
|
+
links: email.html?.links || [],
|
|
37
|
+
codes: codesAsString,
|
|
38
|
+
};
|
|
35
39
|
}
|
|
36
40
|
catch (error) {
|
|
37
|
-
|
|
41
|
+
if (error.errorType) {
|
|
42
|
+
const mailosaurError = error;
|
|
43
|
+
if (mailosaurError.errorType === "authentication_error") {
|
|
44
|
+
throw new Error("Email provider error: Authentication error");
|
|
45
|
+
}
|
|
46
|
+
else if (mailosaurError.errorType === "search_timeout") {
|
|
47
|
+
throw new Error(`Email not received within ${this.timeout}ms`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.error(`Mailosaur error: ${mailosaurError.httpResponseBody}`);
|
|
51
|
+
throw new Error(`Unknown error: ${mailosaurError.errorType}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
38
55
|
}
|
|
39
56
|
}
|
|
40
57
|
}
|
|
@@ -40,7 +40,11 @@ declare class HtmlReporter implements ReporterV2 {
|
|
|
40
40
|
private _port;
|
|
41
41
|
private _host;
|
|
42
42
|
private _testCount;
|
|
43
|
-
private
|
|
43
|
+
private uploadExecutionQueue;
|
|
44
|
+
private uploadWaitingQueue;
|
|
45
|
+
private uploadMaxQueueSize;
|
|
46
|
+
private processQueue;
|
|
47
|
+
private waitForAllTasksToFinish;
|
|
44
48
|
private _buildResult;
|
|
45
49
|
private _topLevelErrors;
|
|
46
50
|
constructor(options: HtmlReporterOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAEV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAgBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiC/C,QAAA,MAAM,iBAAiB,UAAoC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,cAAM,YAAa,YAAW,UAAU;IACtC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,kBAAkB,CAEpB;IAEN,OAAO,CAAC,YAAY;YA8BN,uBAAuB;IAQrC,OAAO,CAAC,YAAY,CAEN;IACd,OAAO,CAAC,eAAe,CAAmB;gBAE9B,OAAO,EAAE,mBAAmB;IAIxC,aAAa;IAIb,QAAQ;IAER,QAAQ;IAER,WAAW;IAEX,SAAS;IAET,OAAO,IAAI,IAAI;IAIf,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAQvC,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;IA4DxD,WAAW,CAAC,MAAM,EAAE,UAAU;IAI9B,OAAO,CAAC,KAAK,EAAE,KAAK;IAYpB,eAAe,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B;IAsBD,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IASxD,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU;IA6FxB,MAAM;CA8Bb;AAkCD,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,MAAoB,EAC1B,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAqBhB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBhE;AAqiBD,eAAe,YAAY,CAAC"}
|
package/dist/reporter/custom.js
CHANGED
|
@@ -47,7 +47,44 @@ class HtmlReporter {
|
|
|
47
47
|
_port;
|
|
48
48
|
_host;
|
|
49
49
|
_testCount = 1;
|
|
50
|
-
|
|
50
|
+
uploadExecutionQueue = [];
|
|
51
|
+
uploadWaitingQueue = [];
|
|
52
|
+
uploadMaxQueueSize = process.env.UPLOAD_MAX_QUEUE_SIZE
|
|
53
|
+
? parseInt(process.env.UPLOAD_MAX_QUEUE_SIZE)
|
|
54
|
+
: 2;
|
|
55
|
+
processQueue() {
|
|
56
|
+
try {
|
|
57
|
+
while (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize &&
|
|
58
|
+
this.uploadWaitingQueue.length > 0) {
|
|
59
|
+
const task = this.uploadWaitingQueue.shift();
|
|
60
|
+
if (task) {
|
|
61
|
+
const promise = task()
|
|
62
|
+
.catch(() => {
|
|
63
|
+
// this.retryTask(task); // Retries handled within task itself
|
|
64
|
+
// console.log("Upload failed", e); // error is already logged in the upload function
|
|
65
|
+
})
|
|
66
|
+
.finally(() => {
|
|
67
|
+
// console.log("Finished upload execution from waiting queue"); // we already log in the upload function on successful upload
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
69
|
+
this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
|
|
70
|
+
this.processQueue();
|
|
71
|
+
});
|
|
72
|
+
console.log("Executing task from queue");
|
|
73
|
+
this.uploadExecutionQueue.push(promise);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error("Error while processing queue", e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async waitForAllTasksToFinish() {
|
|
82
|
+
return Promise.allSettled(this.uploadExecutionQueue).then(async () => {
|
|
83
|
+
if (this.uploadExecutionQueue.length > 0) {
|
|
84
|
+
await this.waitForAllTasksToFinish();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
51
88
|
_buildResult;
|
|
52
89
|
_topLevelErrors = [];
|
|
53
90
|
constructor(options) {
|
|
@@ -69,8 +106,6 @@ class HtmlReporter {
|
|
|
69
106
|
this._testCount += 1;
|
|
70
107
|
}
|
|
71
108
|
onTestEnd(test, result) {
|
|
72
|
-
// upload folder to R2
|
|
73
|
-
// iterate over attachments
|
|
74
109
|
try {
|
|
75
110
|
result.attachments.forEach(async (attachment) => {
|
|
76
111
|
if (!attachment.path)
|
|
@@ -83,8 +118,7 @@ class HtmlReporter {
|
|
|
83
118
|
return;
|
|
84
119
|
}
|
|
85
120
|
try {
|
|
86
|
-
const
|
|
87
|
-
// upload the exact file individually
|
|
121
|
+
const uploadTask = async () => (0, r2_uploader_1.uploadDirectory)({
|
|
88
122
|
fileList: [attachment.path],
|
|
89
123
|
sourceDir: this._outputFolder + "/data/" + folderName,
|
|
90
124
|
destinationDir: process.env.PROJECT_NAME +
|
|
@@ -94,9 +128,29 @@ class HtmlReporter {
|
|
|
94
128
|
folderName,
|
|
95
129
|
uploadBucket: "test-report",
|
|
96
130
|
});
|
|
97
|
-
this.
|
|
131
|
+
if (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize) {
|
|
132
|
+
const promise = uploadTask()
|
|
133
|
+
.catch((e) => {
|
|
134
|
+
console.error("Upload failed for", attachment.path, e);
|
|
135
|
+
// this.retryTask(uploadTask); // Retry logic
|
|
136
|
+
})
|
|
137
|
+
.finally(() => {
|
|
138
|
+
// we already log in the upload function on successful upload
|
|
139
|
+
// console.log("Finished upload execution for ", attachment.path);
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
141
|
+
this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
|
|
142
|
+
this.processQueue(); // Keep processing queue
|
|
143
|
+
});
|
|
144
|
+
console.log("Executing upload task for ", attachment.path);
|
|
145
|
+
this.uploadExecutionQueue.push(promise);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log("Queuing upload task ", attachment.path);
|
|
149
|
+
this.uploadWaitingQueue.push(uploadTask);
|
|
150
|
+
}
|
|
98
151
|
}
|
|
99
152
|
catch (e) {
|
|
153
|
+
console.log("Error while uploading attachment", e);
|
|
100
154
|
// tests shouldn't stop no matter whatever error we get
|
|
101
155
|
}
|
|
102
156
|
});
|
|
@@ -160,35 +214,39 @@ class HtmlReporter {
|
|
|
160
214
|
second: "2-digit",
|
|
161
215
|
}).format(startTime));
|
|
162
216
|
try {
|
|
163
|
-
await Promise.allSettled([
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
217
|
+
// await Promise.allSettled([
|
|
218
|
+
const uploadTraceTask = async () => (0, r2_uploader_1.uploadDirectory)({
|
|
219
|
+
sourceDir: this._outputFolder + "/trace",
|
|
220
|
+
destinationDir: process.env.PROJECT_NAME +
|
|
221
|
+
"/" +
|
|
222
|
+
process.env.TEST_RUN_GITHUB_ACTION_ID +
|
|
223
|
+
"/trace",
|
|
224
|
+
uploadBucket: "test-report",
|
|
225
|
+
});
|
|
226
|
+
// upload index.html
|
|
227
|
+
const uploadIndexTask = async () => (0, r2_uploader_1.uploadDirectory)({
|
|
228
|
+
sourceDir: this._outputFolder,
|
|
229
|
+
fileList: [path_1.default.join(this._outputFolder, "index.html")],
|
|
230
|
+
destinationDir: process.env.PROJECT_NAME +
|
|
231
|
+
"/" +
|
|
232
|
+
process.env.TEST_RUN_GITHUB_ACTION_ID,
|
|
233
|
+
uploadBucket: "test-report",
|
|
234
|
+
});
|
|
235
|
+
// upload summary.json
|
|
236
|
+
const uploadSummaryTask = async () => (0, r2_uploader_1.uploadDirectory)({
|
|
237
|
+
sourceDir: this._outputFolder,
|
|
238
|
+
fileList: [path_1.default.join(this._outputFolder, "summary.json")],
|
|
239
|
+
destinationDir: process.env.PROJECT_NAME +
|
|
240
|
+
"/" +
|
|
241
|
+
process.env.TEST_RUN_GITHUB_ACTION_ID,
|
|
242
|
+
uploadBucket: "test-report",
|
|
243
|
+
});
|
|
244
|
+
this.uploadWaitingQueue.push(uploadTraceTask);
|
|
245
|
+
this.uploadWaitingQueue.push(uploadIndexTask);
|
|
246
|
+
this.uploadWaitingQueue.push(uploadSummaryTask);
|
|
247
|
+
console.log("Waiting for all uploads to finish");
|
|
248
|
+
await this.waitForAllTasksToFinish();
|
|
249
|
+
console.log("All uploads finished");
|
|
192
250
|
const endTime = new Date().getTime();
|
|
193
251
|
console.log("Finished final report upload at: ", new Intl.DateTimeFormat("en-US", {
|
|
194
252
|
hour: "2-digit",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/playwright-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -36,8 +36,10 @@
|
|
|
36
36
|
"md5": "^2.3.0",
|
|
37
37
|
"mime": "3.0.0",
|
|
38
38
|
"playwright-core": "^1.46.1",
|
|
39
|
+
"playwright-extra": "^4.3.6",
|
|
40
|
+
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
|
|
39
41
|
"@empiricalrun/llm": "^0.9.1",
|
|
40
|
-
"@empiricalrun/r2-uploader": "^0.1.
|
|
42
|
+
"@empiricalrun/r2-uploader": "^0.1.3"
|
|
41
43
|
},
|
|
42
44
|
"scripts": {
|
|
43
45
|
"dev": "tsc --build --watch",
|
package/dist/captcha.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"captcha.d.ts","sourceRoot":"","sources":["../src/captcha.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAyExD,wBAAsB,cAAc,CAAC,IAAI,EAAE,IAAI,iBAiB9C"}
|
|
File without changes
|