@bigbinary/neeto-playwright-commons 4.2.4 → 4.3.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.
Files changed (3) hide show
  1. package/index.d.ts +123 -1
  2. package/index.js +382 -103
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -870,6 +870,81 @@ declare class IpRestrictionsApi {
870
870
  }: AllowedIpRange) => Promise<playwright_core.APIResponse | undefined>;
871
871
  disable: () => Promise<playwright_core.APIResponse | undefined>;
872
872
  }
873
+ interface MailpitAddress {
874
+ Name: string;
875
+ Address: string;
876
+ }
877
+ interface MailpitPart {
878
+ PartID: string;
879
+ FileName: string;
880
+ ContentType: string;
881
+ ContentID: string;
882
+ Size: number;
883
+ }
884
+ interface MailpitMessageSummary {
885
+ ID: string;
886
+ MessageID: string;
887
+ From: MailpitAddress | null;
888
+ To: MailpitAddress[] | null;
889
+ Cc: MailpitAddress[] | null;
890
+ Bcc: MailpitAddress[] | null;
891
+ ReplyTo: MailpitAddress[] | null;
892
+ Subject: string;
893
+ Created: string;
894
+ Size: number;
895
+ Attachments: number;
896
+ Snippet: string;
897
+ }
898
+ interface MailpitMessage {
899
+ ID: string;
900
+ MessageID: string;
901
+ From: MailpitAddress | null;
902
+ To: MailpitAddress[] | null;
903
+ Cc: MailpitAddress[] | null;
904
+ Bcc: MailpitAddress[] | null;
905
+ ReplyTo: MailpitAddress[] | null;
906
+ Subject: string;
907
+ Date: string;
908
+ Text: string;
909
+ HTML: string;
910
+ Size: number;
911
+ Attachments: MailpitPart[] | null;
912
+ Inline: MailpitPart[] | null;
913
+ }
914
+ interface MailpitSearchParams {
915
+ query?: string;
916
+ start?: number;
917
+ limit?: number;
918
+ tz?: string;
919
+ }
920
+ interface MailpitSearchResult {
921
+ messages: MailpitMessageSummary[];
922
+ messagesCount: number;
923
+ }
924
+ declare class MailpitApi {
925
+ private neetoPlaywrightUtilities;
926
+ readonly baseUrl: string;
927
+ private readonly headers;
928
+ constructor(neetoPlaywrightUtilities: CustomCommands);
929
+ /**
930
+ *
931
+ * Used to authorize the Fastmail API and get the account details. There is usually no need to call this method since this is invoked when the fixture is setup and will save the credentials for all the future callback of mailerUtils methods.
932
+ *
933
+ * This method doesn't accept any arguments and doesn't return anything.
934
+ *
935
+ */
936
+ authorizeAndSetAccountId: () => Promise<void>;
937
+ private warnOnUnexpectedResponse;
938
+ search: ({
939
+ query,
940
+ start,
941
+ limit,
942
+ tz
943
+ }: MailpitSearchParams) => Promise<MailpitSearchResult>;
944
+ getMessage: (id: string) => Promise<MailpitMessage | null>;
945
+ fetchRawMessage: (id: string) => Promise<Buffer<ArrayBufferLike> | null>;
946
+ deleteMessages: (ids: string[]) => Promise<void>;
947
+ }
873
948
  declare class MemberApis {
874
949
  private neetoPlaywrightUtilities;
875
950
  private readonly teamMembersBaseUrl;
@@ -1530,6 +1605,7 @@ declare class FastmailApi {
1530
1605
  headers: FastmailHeaders;
1531
1606
  accountId: string | undefined;
1532
1607
  constructor(neetoPlaywrightUtilities: CustomCommands);
1608
+ private assertApiKey;
1533
1609
  /**
1534
1610
  *
1535
1611
  * Used to authorize the Fastmail API and get the account details. There is usually no need to call this method since this is invoked when the fixture is setup and will save the credentials for all the future callback of mailerUtils methods.
@@ -1627,9 +1703,11 @@ declare class MailerUtils {
1627
1703
  private neetoPlaywrightUtilities;
1628
1704
  accountId: string | undefined;
1629
1705
  fastmailApi: FastmailApi;
1706
+ mailpitApi: MailpitApi;
1630
1707
  railsEmailUtils: RailsEmailUtils;
1631
1708
  constructor(neetoPlaywrightUtilities: CustomCommands);
1632
1709
  private queryEmail;
1710
+ private buildMessageBodies;
1633
1711
  private getEmails;
1634
1712
  /**
1635
1713
  *
@@ -1894,6 +1972,45 @@ declare class MailerUtils {
1894
1972
  receivedAfter,
1895
1973
  expectedEmailCount
1896
1974
  }?: Partial<FindMessageFilterOptions> | undefined, shouldThrowErrorOnTimeout?: boolean) => Promise<AttachmentDetails | undefined>;
1975
+ private toIdentifiers;
1976
+ private toMailpitAttachments;
1977
+ private toFormattedList;
1978
+ private matchesSummaryCriteria;
1979
+ private warnOnNonMailpitRecipient;
1980
+ private queryMailpitEmails;
1981
+ private getEmailsV2;
1982
+ private pollForMailpitSummaries;
1983
+ listMessagesV2: (messageSearchCriteria?: Partial<MessageSearchCriteria> | undefined, listMessagesFilterCriteria?: Partial<ListMessagesFilterCriteria> | undefined) => Promise<FormattedList[]>;
1984
+ getEmailIdsV2: (messageSearchCriteria?: Partial<MessageSearchCriteria>, {
1985
+ timeout,
1986
+ receivedAfter,
1987
+ expectedEmailCount
1988
+ }?: Partial<FindMessageFilterOptions> | undefined, shouldThrowErrorOnTimeout?: boolean) => Promise<string[]>;
1989
+ findMessageV2: (messageSearchCriteria?: Partial<MessageSearchCriteria>, {
1990
+ timeout,
1991
+ receivedAfter,
1992
+ expectedEmailCount
1993
+ }?: Partial<FindMessageFilterOptions> | undefined, shouldThrowErrorOnTimeout?: boolean) => Promise<FormattedList | Record<string, never>>;
1994
+ findOtpFromEmailV2: ({
1995
+ email,
1996
+ subjectSubstring,
1997
+ timeout,
1998
+ receivedAfter,
1999
+ expectedEmailCount
2000
+ }: FindOtpFromEmailParams) => Promise<string | undefined>;
2001
+ generateRandomEmailV2: () => string;
2002
+ getLatestMessageIdV2: (subject: string, {
2003
+ timeout,
2004
+ receivedAfter
2005
+ }?: Partial<FindMessageFilterOptions> | undefined) => Promise<string | undefined>;
2006
+ getEmailAttachmentV2: ({
2007
+ name,
2008
+ type
2009
+ }: AttachmentFilter, messageSearchCriteria?: Partial<MessageSearchCriteria>, {
2010
+ timeout,
2011
+ receivedAfter,
2012
+ expectedEmailCount
2013
+ }?: Partial<FindMessageFilterOptions> | undefined, shouldThrowErrorOnTimeout?: boolean) => Promise<AttachmentDetails | undefined>;
1897
2014
  }
1898
2015
  /**
1899
2016
  *
@@ -4078,6 +4195,11 @@ declare const CUSTOM_DOMAIN_SUFFIX = "aceinvoice.com";
4078
4195
  * @endexample
4079
4196
  */
4080
4197
  declare const ZAPIER_TEST_EMAIL: (product: string) => string;
4198
+ declare const MAILPIT_BASE_URL = "https://mailpit.neetodeployapp.com";
4199
+ declare const MAILPIT_DOMAIN_NAME = "mail.aceinvoice.com";
4200
+ declare const IS_MAILPIT_ENABLED: boolean;
4201
+ declare const mailpitDomainName: () => string;
4202
+ declare const ZAPIER_TEST_EMAIL_V2: (product: string) => string;
4081
4203
  declare const SINGULAR: {
4082
4204
  count: number;
4083
4205
  };
@@ -9355,5 +9477,5 @@ interface Overrides {
9355
9477
  * @endexample
9356
9478
  */
9357
9479
  declare const definePlaywrightConfig: (overrides: Overrides) => PlaywrightTestConfig<{}, {}>;
9358
- export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, _default as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
9480
+ export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_MAILPIT_ENABLED, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MAILPIT_BASE_URL, MAILPIT_DOMAIN_NAME, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, MailpitApi, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_TEST_EMAIL_V2, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, mailpitDomainName, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, _default as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
9359
9481
  export type { BaseThemeStyle, BaseThemeStyleType, ColumnMenuAction, CountryProps, CustomFixture, EmailDeliveryConnectParams, EmailDeliveryProvider, EmailDeliveryVerifiedEmail, EmailDeliveryVerifyEmailParams, EmailDeliveryVerifyEmailResponse, EmailMatchCriteria, IntroPageThemeStyle, IntroPageThemeStyleType, OAuthEmailDeliveryProvider, ProjectName, ThemeCategory, ValueOf };
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { keysToSnakeCase, isPresent, hyphenate, isNotPresent, noop as noop$2, humanize, findBy, dynamicArray, truncate, isNotEmpty, isNotEqualDeep, randomPick } from '@bigbinary/neeto-cist';
1
+ import { isPresent, keysToSnakeCase, hyphenate, isNotPresent, noop as noop$2, humanize, findBy, dynamicArray, truncate, isNotEmpty, isNotEqualDeep, randomPick } from '@bigbinary/neeto-cist';
2
2
  import { faker } from '@faker-js/faker';
3
3
  import * as fs from 'fs';
4
4
  import fs__default, { readFileSync, promises, existsSync, writeFileSync, unlinkSync, mkdirSync, rmSync, createWriteStream } from 'fs';
@@ -299,6 +299,162 @@ class IpRestrictionsApi {
299
299
  });
300
300
  }
301
301
 
302
+ const ENVIRONMENT = {
303
+ development: "development",
304
+ staging: "staging",
305
+ review: "review",
306
+ };
307
+ const EXAMPLE_URL = "https://example.com";
308
+ const IS_STAGING_ENV = process.env.TEST_ENV === ENVIRONMENT.staging;
309
+ const IS_DEV_ENV = process.env.TEST_ENV === ENVIRONMENT.development;
310
+ const IS_CI = isPresent(process.env.NEETO_CI_JOB_ID);
311
+ const DEFAULT_WEBHOOKS_RESPONSE_TEXT = JSON.stringify({ success: true });
312
+ const STORAGE_STATE = "./e2e/auth/user.json";
313
+ const GLOBAL_TRANSLATIONS_PATTERN = "../node_modules/@bigbinary/**/translations/en.json";
314
+ const PROJECT_TRANSLATIONS_PATH = "../app/javascript/src/translations/en.json";
315
+ const CREDENTIALS = {
316
+ firstName: "Oliver",
317
+ lastName: "Smith",
318
+ name: "Oliver Smith",
319
+ email: "oliver@example.com",
320
+ password: "welcome",
321
+ subdomainName: "spinkart",
322
+ };
323
+ const OTP_EMAIL_PATTERN = "Your login code is";
324
+ const SLACK_DEFAULT_CHANNEL = "general";
325
+ const CUSTOM_DOMAIN_SUFFIX = "aceinvoice.com";
326
+ const ZAPIER_TEST_EMAIL = (product) => `neeto-${product}-zapier-test@${process.env.FASTMAIL_DOMAIN_NAME}`;
327
+ const MAILPIT_BASE_URL = "https://mailpit.neetodeployapp.com";
328
+ const MAILPIT_DOMAIN_NAME = "mail.aceinvoice.com";
329
+ const IS_MAILPIT_ENABLED = isPresent(process.env.MAILPIT_DOMAIN_NAME);
330
+ const mailpitDomainName = () => process.env.MAILPIT_DOMAIN_NAME || MAILPIT_DOMAIN_NAME;
331
+ const ZAPIER_TEST_EMAIL_V2 = (product) => `neeto-${product}-zapier-test@${mailpitDomainName()}`;
332
+ // constants for translation
333
+ const SINGULAR = { count: 1 };
334
+ const PLURAL = { count: 2 };
335
+ const COLOR = {
336
+ transparent: "rgba(0, 0, 0, 0)",
337
+ softBlue: "rgb(230, 244, 255)",
338
+ };
339
+ const DATE_TEXTS = { now: "Now", nextYear: "next-year" };
340
+ const EMPTY_STORAGE_STATE = {
341
+ storageState: { cookies: [], origins: [] },
342
+ };
343
+ const CURRENT_TIME_RANGES = {
344
+ last24Hours: "Last 24 hours",
345
+ thisWeek: "This week",
346
+ thisMonth: "This month",
347
+ thisYear: "This year",
348
+ thisQuarter: "This quarter",
349
+ last30Days: "Last 30 days",
350
+ last7Days: "Last 7 days",
351
+ };
352
+ const PAST_TIME_RANGES = {
353
+ lastWeek: "Last week",
354
+ lastMonth: "Last month",
355
+ lastYear: "Last year",
356
+ lastQuarter: "Last quarter",
357
+ };
358
+ const TIME_RANGES = {
359
+ ...PAST_TIME_RANGES,
360
+ ...CURRENT_TIME_RANGES,
361
+ customDuration: "Custom duration",
362
+ };
363
+ const DATE_RANGES = {
364
+ ...PAST_TIME_RANGES,
365
+ ...CURRENT_TIME_RANGES,
366
+ after: "After",
367
+ before: "Before",
368
+ customDateRange: "Custom date range",
369
+ };
370
+ const CERTIFICATE_LIMIT_EXCEEDED_REGEXP = `too many certificates \\(\\d+\\) already issued for "${CUSTOM_DOMAIN_SUFFIX}"`;
371
+ const CERTIFICATE_LIMIT_EXCEEDED_MESSAGE = "Certificate limit exceeded for custom domain";
372
+ const EXPORT_FILE_TYPES = {
373
+ pdf: "pdf",
374
+ excel: "excel",
375
+ csv: "csv",
376
+ };
377
+ const CALENDAR_LABELS = {
378
+ month: "month panel",
379
+ year: "year panel",
380
+ };
381
+ const DATE_FORMATS = {
382
+ month: "MMM",
383
+ year: "YYYY",
384
+ date: "DD/MM/YYYY",
385
+ calendarDate: "YYYY-MM-DD",
386
+ };
387
+
388
+ const EMPTY_SEARCH_RESULT = {
389
+ messages: [],
390
+ messagesCount: 0,
391
+ };
392
+ class MailpitApi {
393
+ neetoPlaywrightUtilities;
394
+ baseUrl;
395
+ headers;
396
+ constructor(neetoPlaywrightUtilities) {
397
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
398
+ this.baseUrl = (process.env.MAILPIT_BASE_URL || MAILPIT_BASE_URL).replace(/\/+$/, "");
399
+ const { MAILPIT_USERNAME, MAILPIT_PASSWORD } = process.env;
400
+ this.headers =
401
+ MAILPIT_USERNAME && MAILPIT_PASSWORD
402
+ ? {
403
+ Authorization: `Basic ${Buffer.from(`${MAILPIT_USERNAME}:${MAILPIT_PASSWORD}`).toString("base64")}`,
404
+ }
405
+ : {};
406
+ }
407
+ authorizeAndSetAccountId = async () => { };
408
+ warnOnUnexpectedResponse = (endpoint, response) => {
409
+ if (response.ok() || response.status() === 404)
410
+ return;
411
+ if (response.status() === 401) {
412
+ console.warn(`Mailpit rejected the credentials for ${endpoint}. Set MAILPIT_USERNAME and MAILPIT_PASSWORD to the basic auth credentials of ${this.baseUrl}, otherwise every email lookup will time out.`);
413
+ return;
414
+ }
415
+ console.warn(`Mailpit responded with ${response.status()} for ${endpoint}. Treating it as no result, so an email lookup may time out even though the email exists.`);
416
+ };
417
+ search = async ({ query, start = 0, limit = 50, tz = "UTC", }) => {
418
+ const isSearch = Boolean(query);
419
+ const endpoint = `/api/v1/${isSearch ? "search" : "messages"}`;
420
+ const response = await this.neetoPlaywrightUtilities.request.get(`${this.baseUrl}${endpoint}`, {
421
+ params: isSearch
422
+ ? { query: query, start, limit, tz }
423
+ : { start, limit },
424
+ headers: this.headers,
425
+ failOnStatusCode: false,
426
+ timeout: 15_000,
427
+ });
428
+ this.warnOnUnexpectedResponse(endpoint, response);
429
+ if (!response.ok())
430
+ return EMPTY_SEARCH_RESULT;
431
+ const { messages, messages_count: messagesCount } = await response.json();
432
+ return { messages: messages ?? [], messagesCount: messagesCount ?? 0 };
433
+ };
434
+ getMessage = async (id) => {
435
+ const endpoint = `/api/v1/message/${id}`;
436
+ const response = await this.neetoPlaywrightUtilities.request.get(`${this.baseUrl}${endpoint}`, { headers: this.headers, failOnStatusCode: false, timeout: 15_000 });
437
+ this.warnOnUnexpectedResponse(endpoint, response);
438
+ return response.ok() ? await response.json() : null;
439
+ };
440
+ fetchRawMessage = async (id) => {
441
+ const endpoint = `/api/v1/message/${id}/raw`;
442
+ const response = await this.neetoPlaywrightUtilities.request.get(`${this.baseUrl}${endpoint}`, { headers: this.headers, failOnStatusCode: false, timeout: 15_000 });
443
+ this.warnOnUnexpectedResponse(endpoint, response);
444
+ return response.ok() ? await response.body() : null;
445
+ };
446
+ deleteMessages = async (ids) => {
447
+ if (!ids?.length)
448
+ throw new Error("MailpitApi.deleteMessages requires a non-empty list of message IDs. Mailpit deletes every stored message when the list is empty, and the inbox is shared across neeto products.");
449
+ await this.neetoPlaywrightUtilities.request.delete(`${this.baseUrl}/api/v1/messages`, {
450
+ data: { IDs: ids },
451
+ headers: this.headers,
452
+ failOnStatusCode: false,
453
+ timeout: 15_000,
454
+ });
455
+ };
456
+ }
457
+
302
458
  class MemberApis {
303
459
  neetoPlaywrightUtilities;
304
460
  teamMembersBaseUrl;
@@ -478,87 +634,6 @@ class TagsApi {
478
634
  });
479
635
  }
480
636
 
481
- const ENVIRONMENT = {
482
- development: "development",
483
- staging: "staging",
484
- review: "review",
485
- };
486
- const EXAMPLE_URL = "https://example.com";
487
- const IS_STAGING_ENV = process.env.TEST_ENV === ENVIRONMENT.staging;
488
- const IS_DEV_ENV = process.env.TEST_ENV === ENVIRONMENT.development;
489
- const IS_CI = isPresent(process.env.NEETO_CI_JOB_ID);
490
- const DEFAULT_WEBHOOKS_RESPONSE_TEXT = JSON.stringify({ success: true });
491
- const STORAGE_STATE = "./e2e/auth/user.json";
492
- const GLOBAL_TRANSLATIONS_PATTERN = "../node_modules/@bigbinary/**/translations/en.json";
493
- const PROJECT_TRANSLATIONS_PATH = "../app/javascript/src/translations/en.json";
494
- const CREDENTIALS = {
495
- firstName: "Oliver",
496
- lastName: "Smith",
497
- name: "Oliver Smith",
498
- email: "oliver@example.com",
499
- password: "welcome",
500
- subdomainName: "spinkart",
501
- };
502
- const OTP_EMAIL_PATTERN = "Your login code is";
503
- const SLACK_DEFAULT_CHANNEL = "general";
504
- const CUSTOM_DOMAIN_SUFFIX = "aceinvoice.com";
505
- const ZAPIER_TEST_EMAIL = (product) => `neeto-${product}-zapier-test@${process.env.FASTMAIL_DOMAIN_NAME}`;
506
- // constants for translation
507
- const SINGULAR = { count: 1 };
508
- const PLURAL = { count: 2 };
509
- const COLOR = {
510
- transparent: "rgba(0, 0, 0, 0)",
511
- softBlue: "rgb(230, 244, 255)",
512
- };
513
- const DATE_TEXTS = { now: "Now", nextYear: "next-year" };
514
- const EMPTY_STORAGE_STATE = {
515
- storageState: { cookies: [], origins: [] },
516
- };
517
- const CURRENT_TIME_RANGES = {
518
- last24Hours: "Last 24 hours",
519
- thisWeek: "This week",
520
- thisMonth: "This month",
521
- thisYear: "This year",
522
- thisQuarter: "This quarter",
523
- last30Days: "Last 30 days",
524
- last7Days: "Last 7 days",
525
- };
526
- const PAST_TIME_RANGES = {
527
- lastWeek: "Last week",
528
- lastMonth: "Last month",
529
- lastYear: "Last year",
530
- lastQuarter: "Last quarter",
531
- };
532
- const TIME_RANGES = {
533
- ...PAST_TIME_RANGES,
534
- ...CURRENT_TIME_RANGES,
535
- customDuration: "Custom duration",
536
- };
537
- const DATE_RANGES = {
538
- ...PAST_TIME_RANGES,
539
- ...CURRENT_TIME_RANGES,
540
- after: "After",
541
- before: "Before",
542
- customDateRange: "Custom date range",
543
- };
544
- const CERTIFICATE_LIMIT_EXCEEDED_REGEXP = `too many certificates \\(\\d+\\) already issued for "${CUSTOM_DOMAIN_SUFFIX}"`;
545
- const CERTIFICATE_LIMIT_EXCEEDED_MESSAGE = "Certificate limit exceeded for custom domain";
546
- const EXPORT_FILE_TYPES = {
547
- pdf: "pdf",
548
- excel: "excel",
549
- csv: "csv",
550
- };
551
- const CALENDAR_LABELS = {
552
- month: "month panel",
553
- year: "year panel",
554
- };
555
- const DATE_FORMATS = {
556
- month: "MMM",
557
- year: "YYYY",
558
- date: "DD/MM/YYYY",
559
- calendarDate: "YYYY-MM-DD",
560
- };
561
-
562
637
  const THANK_YOU_URL = "/neeto_thank_you/thank_you_configurations";
563
638
  class ThankYouApi {
564
639
  neetoPlaywrightUtilities;
@@ -69537,16 +69612,19 @@ class FastmailApi {
69537
69612
  accountId;
69538
69613
  constructor(neetoPlaywrightUtilities) {
69539
69614
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
69540
- if (!IS_DEV_ENV && !process.env.NEETO_AUTOMATION_FASTMAIL_API_KEY)
69541
- throw new Error("Please set the environment variable NEETO_AUTOMATION_FASTMAIL_API_KEYS. Credentials can be found in the Automation Credentials vault in the BigBinary 1Password account.");
69542
69615
  this.headers = {
69543
69616
  "Content-Type": "application/json",
69544
69617
  Authorization: `Bearer ${process.env.NEETO_AUTOMATION_FASTMAIL_API_KEY}`,
69545
69618
  };
69546
69619
  }
69620
+ assertApiKey = () => {
69621
+ if (!process.env.NEETO_AUTOMATION_FASTMAIL_API_KEY)
69622
+ throw new Error("Please set the environment variable NEETO_AUTOMATION_FASTMAIL_API_KEY. Credentials can be found in the Automation Credentials vault in the BigBinary 1Password account.");
69623
+ };
69547
69624
  authorizeAndSetAccountId = async () => {
69548
69625
  if (IS_DEV_ENV)
69549
69626
  return;
69627
+ this.assertApiKey();
69550
69628
  const response = await this.neetoPlaywrightUtilities.apiRequest({
69551
69629
  method: "get",
69552
69630
  url: "https://api.fastmail.com/.well-known/jmap",
@@ -69556,6 +69634,7 @@ class FastmailApi {
69556
69634
  this.accountId = accountId;
69557
69635
  };
69558
69636
  apiRequest = async (method, body) => {
69637
+ this.assertApiKey();
69559
69638
  const response = await this.neetoPlaywrightUtilities.apiRequest({
69560
69639
  method: "post",
69561
69640
  url: "https://api.fastmail.com/jmap/api/",
@@ -69780,14 +69859,23 @@ class RailsEmailUtils {
69780
69859
  }
69781
69860
 
69782
69861
  const dateTimeOneHourAgo = () => new Date(new Date().valueOf() - 60 * 60 * 1000);
69862
+ const MAILPIT_SEARCH_DATE_MARGIN = 24 * 60 * 60 * 1000;
69863
+ const toMailpitSearchDate = (date) => new Date(date.valueOf() - MAILPIT_SEARCH_DATE_MARGIN)
69864
+ .toISOString()
69865
+ .slice(0, 10)
69866
+ .replace(/-/g, "/");
69867
+ const toMailpitSearchTerm = (value) => `"${value.replace(/"/g, "")}"`;
69868
+ const mailpitTimeoutError = (messageSearchCriteria, receivedAfter, expectedEmailCount) => new Error(`Timed out waiting for matching message. Searched Mailpit for ${JSON.stringify(messageSearchCriteria)} received after ${receivedAfter.toISOString()}, expecting at least ${expectedEmailCount}.`);
69783
69869
  class MailerUtils {
69784
69870
  neetoPlaywrightUtilities;
69785
69871
  accountId;
69786
69872
  fastmailApi;
69873
+ mailpitApi;
69787
69874
  railsEmailUtils;
69788
69875
  constructor(neetoPlaywrightUtilities) {
69789
69876
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
69790
69877
  this.fastmailApi = new FastmailApi(neetoPlaywrightUtilities);
69878
+ this.mailpitApi = new MailpitApi(neetoPlaywrightUtilities);
69791
69879
  this.railsEmailUtils = new RailsEmailUtils(neetoPlaywrightUtilities);
69792
69880
  }
69793
69881
  queryEmail = async (messageSearchCriteria, { receivedAfter = dateTimeOneHourAgo(), page = 1, itemsPerPage = 50, }) => {
@@ -69813,9 +69901,29 @@ class MailerUtils {
69813
69901
  }
69814
69902
  return { ids, total };
69815
69903
  };
69816
- getEmails = async (ids) => {
69904
+ buildMessageBodies = (emailBody, { stripInjectedLinks = false } = {}) => {
69817
69905
  const LINK_REGEX = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])/g;
69818
69906
  const CODE_REGEX = /(?<![#/])\b\d{4,}\b/g;
69907
+ const emailBodyWithStrippedHead = emailBody.split("</head>").at(-1);
69908
+ const links = emailBodyWithStrippedHead.match(LINK_REGEX);
69909
+ const codes = emailBodyWithStrippedHead.match(CODE_REGEX);
69910
+ const filteredLinks = stripInjectedLinks && links && links.length > 2
69911
+ ? links.slice(1, -1)
69912
+ : links;
69913
+ const contentRecognitions = {
69914
+ links: filteredLinks,
69915
+ codes: codes && [...codes],
69916
+ };
69917
+ const html = { body: emailBody, ...contentRecognitions };
69918
+ const wrappedHtml = /<html[\s>]/i.test(emailBody)
69919
+ ? emailBody.replace(/\sxmlns="[^"]+"/g, "")
69920
+ : basicHTMLContent(emailBody);
69921
+ const root = distExports.parse(wrappedHtml, { comment: false });
69922
+ const textBody = root.querySelector("body")?.text.trim() || "";
69923
+ const text = { body: textBody, ...contentRecognitions };
69924
+ return { html, text };
69925
+ };
69926
+ getEmails = async (ids) => {
69819
69927
  const messageDetailsBody = {
69820
69928
  ids,
69821
69929
  bodyProperties: ["type", "name"],
@@ -69825,22 +69933,9 @@ class MailerUtils {
69825
69933
  const formattedList = list.map((listItem) => {
69826
69934
  const { id, from, to, bodyValues, cc, bcc, replyTo, receivedAt, subject, messageId, attachments, blobId, } = listItem;
69827
69935
  const emailBody = Object.values(pluck("value", bodyValues)).join(" ");
69828
- const emailBodyWithStrippedHead = emailBody.split("</head>").at(-1);
69829
- const links = emailBodyWithStrippedHead.match(LINK_REGEX);
69830
- const codes = emailBodyWithStrippedHead.match(CODE_REGEX);
69831
- // Remove first and last links as Fastmail adds dot image links
69832
- const filteredLinks = links && links.length > 2 ? links.slice(1, -1) : links;
69833
- const contentRecognitions = {
69834
- links: filteredLinks,
69835
- codes: codes && [...codes],
69836
- };
69837
- const html = { body: emailBody, ...contentRecognitions };
69838
- const wrappedHtml = /<html[\s>]/i.test(emailBody)
69839
- ? emailBody.replace(/\sxmlns="[^"]+"/g, "")
69840
- : basicHTMLContent(emailBody);
69841
- const root = distExports.parse(wrappedHtml, { comment: false });
69842
- const textBody = root.querySelector("body")?.text.trim() || "";
69843
- const text = { body: textBody, ...contentRecognitions };
69936
+ const { html, text } = this.buildMessageBodies(emailBody, {
69937
+ stripInjectedLinks: true,
69938
+ });
69844
69939
  return {
69845
69940
  html,
69846
69941
  text,
@@ -69996,6 +70091,189 @@ class MailerUtils {
69996
70091
  return matchesName && matchesType;
69997
70092
  });
69998
70093
  };
70094
+ toIdentifiers = (addresses) => {
70095
+ if (!addresses)
70096
+ return [];
70097
+ return (Array.isArray(addresses) ? addresses : [addresses]).map(({ Name, Address }) => ({ name: Name || "", email: Address || "" }));
70098
+ };
70099
+ toMailpitAttachments = (message) => [
70100
+ ...(message?.Attachments || []),
70101
+ ...(message?.Inline || []).filter(({ ContentID }) => !ContentID),
70102
+ ];
70103
+ toFormattedList = (summary, message) => {
70104
+ const { html, text } = this.buildMessageBodies(message.HTML || "", {
70105
+ stripInjectedLinks: true,
70106
+ });
70107
+ const attachments = this.toMailpitAttachments(message).map(({ FileName, ContentType }) => ({
70108
+ name: FileName || null,
70109
+ type: ContentType,
70110
+ }));
70111
+ const messageId = (message.MessageID || summary.MessageID || "").replace(/^<|>$/g, "");
70112
+ return {
70113
+ html,
70114
+ text,
70115
+ id: summary.ID,
70116
+ from: this.toIdentifiers(message.From || summary.From),
70117
+ to: this.toIdentifiers(message.To || summary.To),
70118
+ cc: this.toIdentifiers(message.Cc || summary.Cc),
70119
+ bcc: this.toIdentifiers(message.Bcc || summary.Bcc),
70120
+ replyTo: this.toIdentifiers(message.ReplyTo || summary.ReplyTo),
70121
+ received: new Date(summary.Created),
70122
+ subject: message.Subject ?? summary.Subject,
70123
+ attachments,
70124
+ blobId: "",
70125
+ ...(messageId && { messageId }),
70126
+ };
70127
+ };
70128
+ matchesSummaryCriteria = (summary, { to, from, subject }) => {
70129
+ if (to &&
70130
+ !this.toIdentifiers(summary.To).some(recipient => recipient.email.toLowerCase() === to.toLowerCase()))
70131
+ return false;
70132
+ if (from &&
70133
+ !this.toIdentifiers(summary.From).some(sender => sender.email.toLowerCase() === from.toLowerCase()))
70134
+ return false;
70135
+ if (subject &&
70136
+ !(summary.Subject || "").toLowerCase().includes(subject.toLowerCase()))
70137
+ return false;
70138
+ return true;
70139
+ };
70140
+ warnOnNonMailpitRecipient = ({ to, }) => {
70141
+ const domain = mailpitDomainName().toLowerCase();
70142
+ if (to && !to.toLowerCase().endsWith(`@${domain}`))
70143
+ console.warn(`MailerUtils V2 reads from Mailpit, but "${to}" is not on the Mailpit domain "${domain}". Unless mail for that address is relayed to Mailpit, this lookup will poll until it times out. Generate recipients with generateRandomEmailV2().`);
70144
+ };
70145
+ queryMailpitEmails = async (messageSearchCriteria, { receivedAfter = dateTimeOneHourAgo(), page = 1, itemsPerPage = 50, }) => {
70146
+ if (itemsPerPage > 100 || itemsPerPage < 1)
70147
+ throw new Error("itemsPerPage should be in the range of 1-100");
70148
+ const { to, from } = messageSearchCriteria;
70149
+ const query = [
70150
+ ...(to ? [`to:${toMailpitSearchTerm(to)}`] : []),
70151
+ ...(from ? [`from:${toMailpitSearchTerm(from)}`] : []),
70152
+ `after:${toMailpitSearchDate(receivedAfter)}`,
70153
+ ].join(" ");
70154
+ const { messages } = await this.mailpitApi.search({
70155
+ query,
70156
+ start: (page - 1) * itemsPerPage,
70157
+ limit: itemsPerPage,
70158
+ });
70159
+ return messages.filter(summary => new Date(summary.Created).valueOf() >= receivedAfter.valueOf() &&
70160
+ this.matchesSummaryCriteria(summary, messageSearchCriteria));
70161
+ };
70162
+ getEmailsV2 = async (summaries) => {
70163
+ const emails = await Promise.all(summaries.map(async (summary) => {
70164
+ const message = await this.mailpitApi.getMessage(summary.ID);
70165
+ return message && this.toFormattedList(summary, message);
70166
+ }));
70167
+ return emails.filter(Boolean);
70168
+ };
70169
+ pollForMailpitSummaries = async (messageSearchCriteria, { timeout, receivedAfter, expectedEmailCount, }) => {
70170
+ const requiresBodyMatch = Boolean(messageSearchCriteria.body);
70171
+ let matchingSummaries = [];
70172
+ const summaries = await this.neetoPlaywrightUtilities.executeRecursively({
70173
+ callback: async () => matchingSummaries,
70174
+ condition: async () => {
70175
+ const candidates = await this.queryMailpitEmails(messageSearchCriteria, { receivedAfter });
70176
+ if (requiresBodyMatch) {
70177
+ const emails = await this.getEmailsV2(candidates);
70178
+ const matchedIds = new Set(emails
70179
+ .filter(email => this.matchesCriteria(email, messageSearchCriteria))
70180
+ .map(({ id }) => id));
70181
+ matchingSummaries = candidates.filter(({ ID }) => matchedIds.has(ID));
70182
+ }
70183
+ else {
70184
+ matchingSummaries = candidates;
70185
+ }
70186
+ return matchingSummaries.length >= expectedEmailCount;
70187
+ },
70188
+ timeout,
70189
+ });
70190
+ return summaries === false ? null : summaries;
70191
+ };
70192
+ listMessagesV2 = async (messageSearchCriteria = {}, listMessagesFilterCriteria = {}) => {
70193
+ if (IS_DEV_ENV) {
70194
+ return this.railsEmailUtils.listMessages(messageSearchCriteria, listMessagesFilterCriteria);
70195
+ }
70196
+ this.warnOnNonMailpitRecipient(messageSearchCriteria);
70197
+ const summaries = await this.queryMailpitEmails(messageSearchCriteria, listMessagesFilterCriteria);
70198
+ const emails = await this.getEmailsV2(summaries);
70199
+ return emails.filter(email => this.matchesCriteria(email, messageSearchCriteria));
70200
+ };
70201
+ getEmailIdsV2 = async (messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
70202
+ if (IS_DEV_ENV) {
70203
+ const emails = await this.railsEmailUtils.listMessages(messageSearchCriteria, { receivedAfter });
70204
+ return emails.map(({ id }) => id);
70205
+ }
70206
+ this.warnOnNonMailpitRecipient(messageSearchCriteria);
70207
+ const summaries = await this.pollForMailpitSummaries(messageSearchCriteria, { timeout, receivedAfter, expectedEmailCount });
70208
+ if (!summaries) {
70209
+ if (shouldThrowErrorOnTimeout)
70210
+ throw mailpitTimeoutError(messageSearchCriteria, receivedAfter, expectedEmailCount);
70211
+ return [];
70212
+ }
70213
+ return summaries.map(({ ID }) => ID);
70214
+ };
70215
+ findMessageV2 = async (messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
70216
+ if (IS_DEV_ENV) {
70217
+ return this.railsEmailUtils.findMessage(messageSearchCriteria, { receivedAfter, expectedEmailCount, timeout: timeout / 3 }, shouldThrowErrorOnTimeout);
70218
+ }
70219
+ this.warnOnNonMailpitRecipient(messageSearchCriteria);
70220
+ const summaries = await this.pollForMailpitSummaries(messageSearchCriteria, { timeout, receivedAfter, expectedEmailCount });
70221
+ if (!summaries) {
70222
+ if (shouldThrowErrorOnTimeout)
70223
+ throw mailpitTimeoutError(messageSearchCriteria, receivedAfter, expectedEmailCount);
70224
+ return {};
70225
+ }
70226
+ const emails = await this.getEmailsV2(summaries);
70227
+ const filteredEmails = emails.filter(email => this.matchesCriteria(email, messageSearchCriteria));
70228
+ return filteredEmails[0] || {};
70229
+ };
70230
+ findOtpFromEmailV2 = async ({ email, subjectSubstring = OTP_EMAIL_PATTERN, timeout = 2 * 60 * 1000, receivedAfter = new Date(Date.now() - 3000), expectedEmailCount = 1, }) => {
70231
+ if (IS_DEV_ENV) {
70232
+ return this.railsEmailUtils.findOtpFromEmail({
70233
+ email,
70234
+ subjectSubstring,
70235
+ receivedAfter,
70236
+ expectedEmailCount,
70237
+ timeout: timeout / 3,
70238
+ });
70239
+ }
70240
+ const message = await this.findMessageV2({ to: email, subject: subjectSubstring }, { timeout, receivedAfter, expectedEmailCount });
70241
+ return message.html?.codes?.[0];
70242
+ };
70243
+ generateRandomEmailV2 = () => {
70244
+ const domain = mailpitDomainName();
70245
+ const [localPart] = faker.internet.email({ provider: domain }).split("@");
70246
+ return `${localPart}.${faker.string.alphanumeric(8).toLowerCase()}@${domain}`;
70247
+ };
70248
+ getLatestMessageIdV2 = async (subject, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), } = {}) => {
70249
+ if (IS_DEV_ENV) {
70250
+ return this.railsEmailUtils.getLatestMessageId(subject, {
70251
+ timeout: timeout / 3,
70252
+ receivedAfter,
70253
+ });
70254
+ }
70255
+ const summaries = await this.pollForMailpitSummaries({ subject }, { timeout, receivedAfter, expectedEmailCount: 1 });
70256
+ const messageId = summaries?.[0]?.MessageID;
70257
+ return messageId ? messageId.replace(/^<|>$/g, "") : undefined;
70258
+ };
70259
+ getEmailAttachmentV2 = async ({ name, type }, messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
70260
+ if (IS_DEV_ENV)
70261
+ return this.railsEmailUtils.getEmailAttachment({ name, type }, messageSearchCriteria, { receivedAfter, expectedEmailCount, timeout: timeout / 3 }, shouldThrowErrorOnTimeout);
70262
+ const { id } = await this.findMessageV2(messageSearchCriteria, { expectedEmailCount, receivedAfter, timeout }, shouldThrowErrorOnTimeout);
70263
+ const rawMessage = id ? await this.mailpitApi.fetchRawMessage(id) : null;
70264
+ if (!rawMessage)
70265
+ throw new Error("No such attachment exists");
70266
+ const parsedEmail = await mailparserExports.simpleParser(rawMessage);
70267
+ const attachments = parsedEmail.attachments;
70268
+ const attachment = attachments.find(att => {
70269
+ const matchesName = name ? att.filename?.includes(name) : true;
70270
+ const matchesType = type ? att.contentType?.startsWith(type) : true;
70271
+ return matchesName && matchesType;
70272
+ });
70273
+ if (!attachment)
70274
+ throw new Error("No such attachment exists");
70275
+ return attachment;
70276
+ };
69999
70277
  }
70000
70278
 
70001
70279
  var HeaderTypes;
@@ -116668,7 +116946,8 @@ const commands = {
116668
116946
  },
116669
116947
  mailerUtils: async ({ neetoPlaywrightUtilities }, use) => {
116670
116948
  const mailerUtils = new MailerUtils(neetoPlaywrightUtilities);
116671
- await mailerUtils.fastmailApi.authorizeAndSetAccountId();
116949
+ if (!IS_MAILPIT_ENABLED)
116950
+ await mailerUtils.fastmailApi.authorizeAndSetAccountId();
116672
116951
  await use(mailerUtils);
116673
116952
  IS_DEV_ENV && (await mailerUtils.railsEmailUtils.clearStaleEmails());
116674
116953
  },
@@ -126226,4 +126505,4 @@ const definePlaywrightConfig = (overrides) => {
126226
126505
  });
126227
126506
  };
126228
126507
 
126229
- export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
126508
+ export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_MAILPIT_ENABLED, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MAILPIT_BASE_URL, MAILPIT_DOMAIN_NAME, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, MailpitApi, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_TEST_EMAIL_V2, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, mailpitDomainName, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbinary/neeto-playwright-commons",
3
- "version": "4.2.4",
3
+ "version": "4.3.1",
4
4
  "description": "A package encapsulating common playwright code across neeto projects.",
5
5
  "repository": "git@github.com:bigbinary/neeto-playwright-commons.git",
6
6
  "license": "apache-2.0",