@bigbinary/neeto-playwright-commons 2.2.0 → 2.2.1
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/index.cjs.js +115 -84
- package/index.cjs.js.map +1 -1
- package/index.d.ts +27 -16
- package/index.js +114 -84
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.cjs.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var child_process = require('child_process');
|
|
4
3
|
var neetoCist = require('@bigbinary/neeto-cist');
|
|
5
4
|
var faker = require('@faker-js/faker');
|
|
6
5
|
var fs$4 = require('fs');
|
|
@@ -10,6 +9,7 @@ var test = require('@playwright/test');
|
|
|
10
9
|
var playwrightI18nextFixture = require('playwright-i18next-fixture');
|
|
11
10
|
var require$$0$3 = require('util');
|
|
12
11
|
var ramda = require('ramda');
|
|
12
|
+
var child_process = require('child_process');
|
|
13
13
|
var dayjs = require('dayjs');
|
|
14
14
|
var require$$0$7 = require('stream');
|
|
15
15
|
var require$$0$6 = require('node:buffer');
|
|
@@ -247,86 +247,63 @@ class MemberApis {
|
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
class
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
250
|
+
class RailsEmailApiClient {
|
|
251
|
+
port = process.env.RAILS_SERVER_PORT;
|
|
252
|
+
subdomain = process.env.SUBDOMAIN ?? "spinkart";
|
|
253
|
+
baseUrl = `http://${this.subdomain}.lvh.me:${this.port}`;
|
|
254
|
+
emailsEndpoint = `${this.baseUrl}/api/v1/testing/emails`;
|
|
255
|
+
constructor() { }
|
|
256
|
+
convertRawEmail = (raw) => ({
|
|
257
|
+
from: raw.from,
|
|
258
|
+
to: raw.to,
|
|
259
|
+
cc: raw.cc,
|
|
260
|
+
bcc: raw.bcc,
|
|
261
|
+
replyTo: raw.reply_to,
|
|
262
|
+
subject: raw.subject,
|
|
263
|
+
htmlBody: raw.html_body,
|
|
264
|
+
textBody: raw.text_body,
|
|
265
|
+
receivedAt: raw.received_at,
|
|
266
|
+
attachments: raw.attachments?.map(({ filename, mime_type, data }) => ({
|
|
267
|
+
name: filename,
|
|
268
|
+
type: mime_type,
|
|
269
|
+
content: data,
|
|
269
270
|
})),
|
|
270
271
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
stdout += data.toString();
|
|
280
|
-
});
|
|
281
|
-
childProcess.stderr?.on("data", data => {
|
|
282
|
-
stderr += data.toString();
|
|
283
|
-
});
|
|
284
|
-
const exitCode = await new Promise((resolve, reject) => {
|
|
285
|
-
childProcess.on("error", reject);
|
|
286
|
-
childProcess.on("close", resolve);
|
|
287
|
-
});
|
|
288
|
-
if (exitCode !== 0) {
|
|
289
|
-
throw new Error(`Rake task ${taskName} failed: ${stderr || stdout || `Exit code ${exitCode}`}`);
|
|
290
|
-
}
|
|
291
|
-
return this.extractJsonFromOutput(stdout);
|
|
292
|
-
};
|
|
293
|
-
extractJsonFromOutput = (output) => {
|
|
294
|
-
const delimiterMatch = output.match(/<-- Captured Emails Start-->([\s\S]*?)<-- Captured Emails End-->/);
|
|
295
|
-
return delimiterMatch ? delimiterMatch[1].trim() : output.trim();
|
|
272
|
+
buildQueryString = (params) => {
|
|
273
|
+
if (!params)
|
|
274
|
+
return "";
|
|
275
|
+
const filtered = Object.fromEntries(Object.entries(neetoCist.keysToSnakeCase(params))
|
|
276
|
+
.filter(([, v]) => v != null && v !== "")
|
|
277
|
+
.map(([k, v]) => [k, String(v)]));
|
|
278
|
+
const query = new URLSearchParams(filtered).toString();
|
|
279
|
+
return query ? `?${query}` : "";
|
|
296
280
|
};
|
|
297
|
-
|
|
281
|
+
fetchJson = async (url, options) => {
|
|
298
282
|
try {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const rawEmails = JSON.parse(output);
|
|
304
|
-
return rawEmails.map(this.convertRawEmail);
|
|
283
|
+
const res = await fetch(url, options);
|
|
284
|
+
if (!res.ok)
|
|
285
|
+
return null;
|
|
286
|
+
return (await res.json());
|
|
305
287
|
}
|
|
306
|
-
catch (
|
|
307
|
-
console.error("
|
|
308
|
-
return
|
|
288
|
+
catch (err) {
|
|
289
|
+
console.error("API error:", err);
|
|
290
|
+
return null;
|
|
309
291
|
}
|
|
310
292
|
};
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
293
|
+
listEmails = async (searchParams) => {
|
|
294
|
+
const query = this.buildQueryString(searchParams);
|
|
295
|
+
const data = await this.fetchJson(`${this.emailsEndpoint}${query}`);
|
|
296
|
+
return data?.map(this.convertRawEmail) ?? [];
|
|
297
|
+
};
|
|
314
298
|
getLatestEmail = async (searchParams) => {
|
|
315
299
|
const emails = await this.listEmails(searchParams);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
? current
|
|
320
|
-
: latest);
|
|
321
|
-
};
|
|
322
|
-
clearEmails = async () => {
|
|
323
|
-
try {
|
|
324
|
-
await this.executeRakeTask("playwright:clear_captured_emails");
|
|
325
|
-
}
|
|
326
|
-
catch (error) {
|
|
327
|
-
console.error("Failed to clear emails:", error);
|
|
328
|
-
}
|
|
300
|
+
return emails.reduce((latest, curr) => !latest || new Date(curr.receivedAt) > new Date(latest.receivedAt)
|
|
301
|
+
? curr
|
|
302
|
+
: latest, null);
|
|
329
303
|
};
|
|
304
|
+
clearEmails = () => this.fetchJson(this.emailsEndpoint, {
|
|
305
|
+
method: "DELETE",
|
|
306
|
+
});
|
|
330
307
|
}
|
|
331
308
|
|
|
332
309
|
class RoleApis {
|
|
@@ -60309,10 +60286,10 @@ const hexToRGB = (hex) => {
|
|
|
60309
60286
|
|
|
60310
60287
|
class RailsEmailUtils {
|
|
60311
60288
|
neetoPlaywrightUtilities;
|
|
60312
|
-
|
|
60289
|
+
railsEmailClient;
|
|
60313
60290
|
constructor(neetoPlaywrightUtilities) {
|
|
60314
60291
|
this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
|
|
60315
|
-
this.
|
|
60292
|
+
this.railsEmailClient = new RailsEmailApiClient();
|
|
60316
60293
|
}
|
|
60317
60294
|
convertRailsEmailToFormattedList = (railsEmail) => {
|
|
60318
60295
|
if (!railsEmail)
|
|
@@ -60363,11 +60340,11 @@ class RailsEmailUtils {
|
|
|
60363
60340
|
blobId: "",
|
|
60364
60341
|
};
|
|
60365
60342
|
};
|
|
60366
|
-
clearEmails = () => this.
|
|
60367
|
-
getLatestEmail = (searchParams) => this.
|
|
60368
|
-
listEmails = (searchParams) => this.
|
|
60343
|
+
clearEmails = () => this.railsEmailClient.clearEmails();
|
|
60344
|
+
getLatestEmail = (searchParams) => this.railsEmailClient.getLatestEmail(searchParams);
|
|
60345
|
+
listEmails = (searchParams) => this.railsEmailClient.listEmails(searchParams);
|
|
60369
60346
|
listMessages = async (messageSearchCriteria = {}, { receivedAfter = new Date(new Date().valueOf() - 60 * 60 * 1000), } = {}) => {
|
|
60370
|
-
const emails = await this.
|
|
60347
|
+
const emails = await this.railsEmailClient.listEmails({
|
|
60371
60348
|
...messageSearchCriteria,
|
|
60372
60349
|
receivedAfter: receivedAfter.toISOString(),
|
|
60373
60350
|
});
|
|
@@ -60378,7 +60355,7 @@ class RailsEmailUtils {
|
|
|
60378
60355
|
findMessage = async (messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = new Date(new Date().valueOf() - 60 * 60 * 1000), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
|
|
60379
60356
|
const email = (await this.neetoPlaywrightUtilities.executeRecursively({
|
|
60380
60357
|
callback: async () => {
|
|
60381
|
-
const railsEmail = await this.
|
|
60358
|
+
const railsEmail = await this.railsEmailClient.getLatestEmail({
|
|
60382
60359
|
...messageSearchCriteria,
|
|
60383
60360
|
receivedAfter: receivedAfter.toISOString(),
|
|
60384
60361
|
});
|
|
@@ -60387,7 +60364,7 @@ class RailsEmailUtils {
|
|
|
60387
60364
|
return this.convertRailsEmailToFormattedList(railsEmail);
|
|
60388
60365
|
},
|
|
60389
60366
|
condition: async () => {
|
|
60390
|
-
const emails = await this.
|
|
60367
|
+
const emails = await this.railsEmailClient.listEmails({
|
|
60391
60368
|
...messageSearchCriteria,
|
|
60392
60369
|
receivedAfter: receivedAfter.toISOString(),
|
|
60393
60370
|
});
|
|
@@ -60406,7 +60383,7 @@ class RailsEmailUtils {
|
|
|
60406
60383
|
findOtpFromEmail = async ({ email, subjectSubstring = OTP_EMAIL_PATTERN, timeout = 10_000, receivedAfter = new Date(), expectedEmailCount = 1, }) => {
|
|
60407
60384
|
const otp = await this.neetoPlaywrightUtilities.executeRecursively({
|
|
60408
60385
|
callback: async () => {
|
|
60409
|
-
const railsEmail = await this.
|
|
60386
|
+
const railsEmail = await this.railsEmailClient.getLatestEmail({
|
|
60410
60387
|
to: email,
|
|
60411
60388
|
subject: subjectSubstring,
|
|
60412
60389
|
receivedAfter: receivedAfter.toISOString(),
|
|
@@ -60419,7 +60396,7 @@ class RailsEmailUtils {
|
|
|
60419
60396
|
return formattedEmail.html.codes?.[0] || formattedEmail.text.codes?.[0];
|
|
60420
60397
|
},
|
|
60421
60398
|
condition: async () => {
|
|
60422
|
-
const emails = await this.
|
|
60399
|
+
const emails = await this.railsEmailClient.listEmails({
|
|
60423
60400
|
to: email,
|
|
60424
60401
|
subject: subjectSubstring,
|
|
60425
60402
|
receivedAfter: receivedAfter.toISOString(),
|
|
@@ -60433,7 +60410,7 @@ class RailsEmailUtils {
|
|
|
60433
60410
|
getEmailAttachment = async (attachmentName, messageSearchCriteria = {}, { receivedAfter = new Date(new Date().valueOf() - 60 * 60 * 1000), expectedEmailCount = 1, timeout = 10_000, } = {}, shouldThrowErrorOnTimeout = true) => {
|
|
60434
60411
|
const attachmentDetails = (await this.neetoPlaywrightUtilities.executeRecursively({
|
|
60435
60412
|
callback: async () => {
|
|
60436
|
-
const railsEmail = await this.
|
|
60413
|
+
const railsEmail = await this.railsEmailClient.getLatestEmail({
|
|
60437
60414
|
...messageSearchCriteria,
|
|
60438
60415
|
receivedAfter: receivedAfter.toISOString(),
|
|
60439
60416
|
});
|
|
@@ -60450,7 +60427,7 @@ class RailsEmailUtils {
|
|
|
60450
60427
|
};
|
|
60451
60428
|
},
|
|
60452
60429
|
condition: async () => {
|
|
60453
|
-
const emails = await this.
|
|
60430
|
+
const emails = await this.railsEmailClient.listEmails({
|
|
60454
60431
|
...messageSearchCriteria,
|
|
60455
60432
|
receivedAfter: receivedAfter.toISOString(),
|
|
60456
60433
|
});
|
|
@@ -107252,7 +107229,35 @@ class ColorPickerUtils {
|
|
|
107252
107229
|
};
|
|
107253
107230
|
}
|
|
107254
107231
|
|
|
107232
|
+
const STATIC_ASSET_PATTERN = /\.(js|css|woff2?|ttf|eot|png|svg|ico|gif|webp)(\?.*)?$/;
|
|
107233
|
+
const assetCache = new Map();
|
|
107255
107234
|
const commands = {
|
|
107235
|
+
context: async ({ context }, use) => {
|
|
107236
|
+
if (IS_DEV_ENV) {
|
|
107237
|
+
await context.route(STATIC_ASSET_PATTERN, async (route) => {
|
|
107238
|
+
const url = route.request().url();
|
|
107239
|
+
const hit = assetCache.get(url);
|
|
107240
|
+
if (hit)
|
|
107241
|
+
return route.fulfill(hit);
|
|
107242
|
+
try {
|
|
107243
|
+
const response = await route.fetch();
|
|
107244
|
+
const body = await response.body();
|
|
107245
|
+
const entry = {
|
|
107246
|
+
body,
|
|
107247
|
+
status: response.status(),
|
|
107248
|
+
headers: response.headers(),
|
|
107249
|
+
};
|
|
107250
|
+
if (response.ok())
|
|
107251
|
+
assetCache.set(url, entry);
|
|
107252
|
+
return route.fulfill(entry);
|
|
107253
|
+
}
|
|
107254
|
+
catch {
|
|
107255
|
+
return route.continue();
|
|
107256
|
+
}
|
|
107257
|
+
});
|
|
107258
|
+
}
|
|
107259
|
+
await use(context);
|
|
107260
|
+
},
|
|
107256
107261
|
neetoPlaywrightUtilities: async ({ page, request, baseURL }, use) => {
|
|
107257
107262
|
const commands = new CustomCommands(page, request, baseURL);
|
|
107258
107263
|
await use(commands);
|
|
@@ -124970,6 +124975,31 @@ const generatePhoneNumberDetails = () => {
|
|
|
124970
124975
|
return { flag: country.flag, name: country.name, code: country.code, number };
|
|
124971
124976
|
};
|
|
124972
124977
|
|
|
124978
|
+
const DEFAULT_WARMUP_URLS = ["/login"];
|
|
124979
|
+
async function warmup({ urls = DEFAULT_WARMUP_URLS, timeout = 60_000, } = {}) {
|
|
124980
|
+
if (!IS_DEV_ENV)
|
|
124981
|
+
return;
|
|
124982
|
+
const { RAILS_SERVER_PORT, SUBDOMAIN = "spinkart" } = process.env;
|
|
124983
|
+
if (!RAILS_SERVER_PORT) {
|
|
124984
|
+
throw new Error("RAILS_SERVER_PORT is not defined in environment variables.");
|
|
124985
|
+
}
|
|
124986
|
+
const baseURL = `http://${SUBDOMAIN}.lvh.me:${RAILS_SERVER_PORT}`;
|
|
124987
|
+
const browser = await test.chromium.launch();
|
|
124988
|
+
const page = await browser.newPage();
|
|
124989
|
+
try {
|
|
124990
|
+
for (const url of urls) {
|
|
124991
|
+
const fullUrl = url.startsWith("http") ? url : `${baseURL}${url}`;
|
|
124992
|
+
await page.goto(fullUrl, {
|
|
124993
|
+
waitUntil: "networkidle", // eslint-disable-line playwright/no-networkidle
|
|
124994
|
+
timeout,
|
|
124995
|
+
});
|
|
124996
|
+
}
|
|
124997
|
+
}
|
|
124998
|
+
finally {
|
|
124999
|
+
await browser.close();
|
|
125000
|
+
}
|
|
125001
|
+
}
|
|
125002
|
+
|
|
124973
125003
|
const CONFIG = {
|
|
124974
125004
|
DIR: "/tmp/neeto-auth-web",
|
|
124975
125005
|
LOG: "/tmp/neeto-auth-server.log",
|
|
@@ -125985,7 +126015,7 @@ exports.PROJECT_NAMES = PROJECT_NAMES;
|
|
|
125985
126015
|
exports.PROJECT_TRANSLATIONS_PATH = PROJECT_TRANSLATIONS_PATH;
|
|
125986
126016
|
exports.ROLES_SELECTORS = ROLES_SELECTORS;
|
|
125987
126017
|
exports.ROUTES = ROUTES;
|
|
125988
|
-
exports.
|
|
126018
|
+
exports.RailsEmailApiClient = RailsEmailApiClient;
|
|
125989
126019
|
exports.RailsEmailUtils = RailsEmailUtils;
|
|
125990
126020
|
exports.RoleApis = RoleApis;
|
|
125991
126021
|
exports.RolesPage = RolesPage;
|
|
@@ -126087,5 +126117,6 @@ exports.stealthTest = stealth;
|
|
|
126087
126117
|
exports.tableUtils = tableUtils;
|
|
126088
126118
|
exports.toCamelCase = toCamelCase;
|
|
126089
126119
|
exports.updateCredentials = updateCredentials;
|
|
126120
|
+
exports.warmup = warmup;
|
|
126090
126121
|
exports.writeDataToFile = writeDataToFile;
|
|
126091
126122
|
//# sourceMappingURL=index.cjs.js.map
|