@bigbinary/neeto-playwright-commons 4.2.3 → 4.3.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.
Files changed (3) hide show
  1. package/index.d.ts +135 -2
  2. package/index.js +435 -107
  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;
@@ -898,6 +973,7 @@ interface RailsEmail {
898
973
  htmlBody?: string;
899
974
  textBody?: string;
900
975
  receivedAt: string;
976
+ messageId?: string;
901
977
  attachments?: RailsEmailAttachment[];
902
978
  }
903
979
  interface BaseRailsEmailSearchParams {
@@ -1249,6 +1325,7 @@ interface FormattedList$1 {
1249
1325
  subject: string;
1250
1326
  attachments: Attachment$1[];
1251
1327
  blobId: string;
1328
+ messageId?: string;
1252
1329
  }
1253
1330
  interface AttachmentDetails$1 {
1254
1331
  filename: string | null;
@@ -1263,7 +1340,7 @@ declare class RailsEmailUtils {
1263
1340
  private convertRailsEmailToFormattedList;
1264
1341
  clearEmails: () => Promise<unknown>;
1265
1342
  clearStaleEmails: () => Promise<unknown>;
1266
- getLatestEmail: (searchParams: RailsEmailSearchParams) => Promise<void>;
1343
+ getLatestEmail: (searchParams: RailsEmailSearchParams) => Promise<RailsEmail | null>;
1267
1344
  listEmails: (searchParams?: RailsEmailSearchParams) => Promise<RailsEmail[]>;
1268
1345
  /**
1269
1346
  *
@@ -1403,6 +1480,10 @@ declare class RailsEmailUtils {
1403
1480
  receivedAfter,
1404
1481
  expectedEmailCount
1405
1482
  }?: Partial<FindMessageFilterOptions$1> | undefined, shouldThrowErrorOnTimeout?: boolean) => Promise<FormattedList$1 | Record<string, never>>;
1483
+ getLatestMessageId: (subject: string, {
1484
+ timeout,
1485
+ receivedAfter
1486
+ }?: Partial<FindMessageFilterOptions$1> | undefined) => Promise<string | undefined>;
1406
1487
  /**
1407
1488
  *
1408
1489
  * A helper method that is used to find the first code value from the matching email body. This method has been built to match the Neeto OTP emails.
@@ -1524,6 +1605,7 @@ declare class FastmailApi {
1524
1605
  headers: FastmailHeaders;
1525
1606
  accountId: string | undefined;
1526
1607
  constructor(neetoPlaywrightUtilities: CustomCommands);
1608
+ private assertApiKey;
1527
1609
  /**
1528
1610
  *
1529
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.
@@ -1615,14 +1697,17 @@ interface FormattedList {
1615
1697
  subject: string;
1616
1698
  attachments: Attachment[];
1617
1699
  blobId: string;
1700
+ messageId?: string;
1618
1701
  }
1619
1702
  declare class MailerUtils {
1620
1703
  private neetoPlaywrightUtilities;
1621
1704
  accountId: string | undefined;
1622
1705
  fastmailApi: FastmailApi;
1706
+ mailpitApi: MailpitApi;
1623
1707
  railsEmailUtils: RailsEmailUtils;
1624
1708
  constructor(neetoPlaywrightUtilities: CustomCommands);
1625
1709
  private queryEmail;
1710
+ private buildMessageBodies;
1626
1711
  private getEmails;
1627
1712
  /**
1628
1713
  *
@@ -1800,6 +1885,10 @@ declare class MailerUtils {
1800
1885
  *
1801
1886
  */
1802
1887
  generateRandomEmail: () => string;
1888
+ getLatestMessageId: (subject: string, {
1889
+ timeout,
1890
+ receivedAfter
1891
+ }?: Partial<FindMessageFilterOptions> | undefined) => Promise<string | undefined>;
1803
1892
  /**
1804
1893
  *
1805
1894
  * This method is used to return an attachment from the first email matching the search criteria. It supports filtering attachments by name, by MIME content-type, or both. If no matching attachment is found, an error is thrown.
@@ -1883,6 +1972,45 @@ declare class MailerUtils {
1883
1972
  receivedAfter,
1884
1973
  expectedEmailCount
1885
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>;
1886
2014
  }
1887
2015
  /**
1888
2016
  *
@@ -4067,6 +4195,11 @@ declare const CUSTOM_DOMAIN_SUFFIX = "aceinvoice.com";
4067
4195
  * @endexample
4068
4196
  */
4069
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;
4070
4203
  declare const SINGULAR: {
4071
4204
  count: number;
4072
4205
  };
@@ -9344,5 +9477,5 @@ interface Overrides {
9344
9477
  * @endexample
9345
9478
  */
9346
9479
  declare const definePlaywrightConfig: (overrides: Overrides) => PlaywrightTestConfig<{}, {}>;
9347
- 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 };
9348
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;
@@ -351,6 +507,7 @@ class RailsEmailApiClient {
351
507
  htmlBody: raw.html_body,
352
508
  textBody: raw.text_body,
353
509
  receivedAt: raw.received_at,
510
+ ...(raw.message_id && { messageId: raw.message_id }),
354
511
  attachments: raw.attachments?.map(({ filename, mime_type, data }) => ({
355
512
  name: filename,
356
513
  type: mime_type,
@@ -477,87 +634,6 @@ class TagsApi {
477
634
  });
478
635
  }
479
636
 
480
- const ENVIRONMENT = {
481
- development: "development",
482
- staging: "staging",
483
- review: "review",
484
- };
485
- const EXAMPLE_URL = "https://example.com";
486
- const IS_STAGING_ENV = process.env.TEST_ENV === ENVIRONMENT.staging;
487
- const IS_DEV_ENV = process.env.TEST_ENV === ENVIRONMENT.development;
488
- const IS_CI = isPresent(process.env.NEETO_CI_JOB_ID);
489
- const DEFAULT_WEBHOOKS_RESPONSE_TEXT = JSON.stringify({ success: true });
490
- const STORAGE_STATE = "./e2e/auth/user.json";
491
- const GLOBAL_TRANSLATIONS_PATTERN = "../node_modules/@bigbinary/**/translations/en.json";
492
- const PROJECT_TRANSLATIONS_PATH = "../app/javascript/src/translations/en.json";
493
- const CREDENTIALS = {
494
- firstName: "Oliver",
495
- lastName: "Smith",
496
- name: "Oliver Smith",
497
- email: "oliver@example.com",
498
- password: "welcome",
499
- subdomainName: "spinkart",
500
- };
501
- const OTP_EMAIL_PATTERN = "Your login code is";
502
- const SLACK_DEFAULT_CHANNEL = "general";
503
- const CUSTOM_DOMAIN_SUFFIX = "aceinvoice.com";
504
- const ZAPIER_TEST_EMAIL = (product) => `neeto-${product}-zapier-test@${process.env.FASTMAIL_DOMAIN_NAME}`;
505
- // constants for translation
506
- const SINGULAR = { count: 1 };
507
- const PLURAL = { count: 2 };
508
- const COLOR = {
509
- transparent: "rgba(0, 0, 0, 0)",
510
- softBlue: "rgb(230, 244, 255)",
511
- };
512
- const DATE_TEXTS = { now: "Now", nextYear: "next-year" };
513
- const EMPTY_STORAGE_STATE = {
514
- storageState: { cookies: [], origins: [] },
515
- };
516
- const CURRENT_TIME_RANGES = {
517
- last24Hours: "Last 24 hours",
518
- thisWeek: "This week",
519
- thisMonth: "This month",
520
- thisYear: "This year",
521
- thisQuarter: "This quarter",
522
- last30Days: "Last 30 days",
523
- last7Days: "Last 7 days",
524
- };
525
- const PAST_TIME_RANGES = {
526
- lastWeek: "Last week",
527
- lastMonth: "Last month",
528
- lastYear: "Last year",
529
- lastQuarter: "Last quarter",
530
- };
531
- const TIME_RANGES = {
532
- ...PAST_TIME_RANGES,
533
- ...CURRENT_TIME_RANGES,
534
- customDuration: "Custom duration",
535
- };
536
- const DATE_RANGES = {
537
- ...PAST_TIME_RANGES,
538
- ...CURRENT_TIME_RANGES,
539
- after: "After",
540
- before: "Before",
541
- customDateRange: "Custom date range",
542
- };
543
- const CERTIFICATE_LIMIT_EXCEEDED_REGEXP = `too many certificates \\(\\d+\\) already issued for "${CUSTOM_DOMAIN_SUFFIX}"`;
544
- const CERTIFICATE_LIMIT_EXCEEDED_MESSAGE = "Certificate limit exceeded for custom domain";
545
- const EXPORT_FILE_TYPES = {
546
- pdf: "pdf",
547
- excel: "excel",
548
- csv: "csv",
549
- };
550
- const CALENDAR_LABELS = {
551
- month: "month panel",
552
- year: "year panel",
553
- };
554
- const DATE_FORMATS = {
555
- month: "MMM",
556
- year: "YYYY",
557
- date: "DD/MM/YYYY",
558
- calendarDate: "YYYY-MM-DD",
559
- };
560
-
561
637
  const THANK_YOU_URL = "/neeto_thank_you/thank_you_configurations";
562
638
  class ThankYouApi {
563
639
  neetoPlaywrightUtilities;
@@ -69536,16 +69612,19 @@ class FastmailApi {
69536
69612
  accountId;
69537
69613
  constructor(neetoPlaywrightUtilities) {
69538
69614
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
69539
- if (!IS_DEV_ENV && !process.env.NEETO_AUTOMATION_FASTMAIL_API_KEY)
69540
- 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.");
69541
69615
  this.headers = {
69542
69616
  "Content-Type": "application/json",
69543
69617
  Authorization: `Bearer ${process.env.NEETO_AUTOMATION_FASTMAIL_API_KEY}`,
69544
69618
  };
69545
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
+ };
69546
69624
  authorizeAndSetAccountId = async () => {
69547
69625
  if (IS_DEV_ENV)
69548
69626
  return;
69627
+ this.assertApiKey();
69549
69628
  const response = await this.neetoPlaywrightUtilities.apiRequest({
69550
69629
  method: "get",
69551
69630
  url: "https://api.fastmail.com/.well-known/jmap",
@@ -69555,6 +69634,7 @@ class FastmailApi {
69555
69634
  this.accountId = accountId;
69556
69635
  };
69557
69636
  apiRequest = async (method, body) => {
69637
+ this.assertApiKey();
69558
69638
  const response = await this.neetoPlaywrightUtilities.apiRequest({
69559
69639
  method: "post",
69560
69640
  url: "https://api.fastmail.com/jmap/api/",
@@ -69653,6 +69733,7 @@ class RailsEmailUtils {
69653
69733
  type: att.type,
69654
69734
  })) || [],
69655
69735
  blobId: "",
69736
+ ...(railsEmail.messageId && { messageId: railsEmail.messageId }),
69656
69737
  };
69657
69738
  };
69658
69739
  clearEmails = () => this.railsEmailClient.clearEmails();
@@ -69662,7 +69743,7 @@ class RailsEmailUtils {
69662
69743
  };
69663
69744
  getLatestEmail = async (searchParams) => {
69664
69745
  await this.clearStaleEmails();
69665
- await this.railsEmailClient.getLatestEmail(searchParams);
69746
+ return this.railsEmailClient.getLatestEmail(searchParams);
69666
69747
  };
69667
69748
  listEmails = (searchParams) => this.railsEmailClient.listEmails(searchParams);
69668
69749
  listMessages = async (messageSearchCriteria = {}, { receivedAfter = new Date(new Date().valueOf() - 60 * 60 * 1000), } = {}) => {
@@ -69702,6 +69783,12 @@ class RailsEmailUtils {
69702
69783
  }
69703
69784
  return email;
69704
69785
  };
69786
+ getLatestMessageId = async (subject, { timeout = 10_000, receivedAfter = new Date(new Date().valueOf() - 60 * 1000), } = {}) => {
69787
+ const email = await this.findMessage({ subject }, { timeout, receivedAfter }, false);
69788
+ if (!("messageId" in email) || !email.messageId)
69789
+ return undefined;
69790
+ return email.messageId.replace(/^<|>$/g, "");
69791
+ };
69705
69792
  findOtpFromEmail = async ({ email, subjectSubstring = OTP_EMAIL_PATTERN, timeout = 10_000, receivedAfter = new Date(), expectedEmailCount = 1, }) => {
69706
69793
  const otp = await this.neetoPlaywrightUtilities.executeRecursively({
69707
69794
  callback: async () => {
@@ -69772,14 +69859,23 @@ class RailsEmailUtils {
69772
69859
  }
69773
69860
 
69774
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}.`);
69775
69869
  class MailerUtils {
69776
69870
  neetoPlaywrightUtilities;
69777
69871
  accountId;
69778
69872
  fastmailApi;
69873
+ mailpitApi;
69779
69874
  railsEmailUtils;
69780
69875
  constructor(neetoPlaywrightUtilities) {
69781
69876
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
69782
69877
  this.fastmailApi = new FastmailApi(neetoPlaywrightUtilities);
69878
+ this.mailpitApi = new MailpitApi(neetoPlaywrightUtilities);
69783
69879
  this.railsEmailUtils = new RailsEmailUtils(neetoPlaywrightUtilities);
69784
69880
  }
69785
69881
  queryEmail = async (messageSearchCriteria, { receivedAfter = dateTimeOneHourAgo(), page = 1, itemsPerPage = 50, }) => {
@@ -69805,9 +69901,29 @@ class MailerUtils {
69805
69901
  }
69806
69902
  return { ids, total };
69807
69903
  };
69808
- getEmails = async (ids) => {
69904
+ buildMessageBodies = (emailBody, { stripInjectedLinks = false } = {}) => {
69809
69905
  const LINK_REGEX = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])/g;
69810
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) => {
69811
69927
  const messageDetailsBody = {
69812
69928
  ids,
69813
69929
  bodyProperties: ["type", "name"],
@@ -69815,24 +69931,11 @@ class MailerUtils {
69815
69931
  };
69816
69932
  const { methodResponses: [[, { list }]], } = await this.fastmailApi.apiRequest("Email/get", messageDetailsBody);
69817
69933
  const formattedList = list.map((listItem) => {
69818
- const { id, from, to, bodyValues, cc, bcc, replyTo, receivedAt, subject, attachments, blobId, } = listItem;
69934
+ const { id, from, to, bodyValues, cc, bcc, replyTo, receivedAt, subject, messageId, attachments, blobId, } = listItem;
69819
69935
  const emailBody = Object.values(pluck("value", bodyValues)).join(" ");
69820
- const emailBodyWithStrippedHead = emailBody.split("</head>").at(-1);
69821
- const links = emailBodyWithStrippedHead.match(LINK_REGEX);
69822
- const codes = emailBodyWithStrippedHead.match(CODE_REGEX);
69823
- // Remove first and last links as Fastmail adds dot image links
69824
- const filteredLinks = links && links.length > 2 ? links.slice(1, -1) : links;
69825
- const contentRecognitions = {
69826
- links: filteredLinks,
69827
- codes: codes && [...codes],
69828
- };
69829
- const html = { body: emailBody, ...contentRecognitions };
69830
- const wrappedHtml = /<html[\s>]/i.test(emailBody)
69831
- ? emailBody.replace(/\sxmlns="[^"]+"/g, "")
69832
- : basicHTMLContent(emailBody);
69833
- const root = distExports.parse(wrappedHtml, { comment: false });
69834
- const textBody = root.querySelector("body")?.text.trim() || "";
69835
- const text = { body: textBody, ...contentRecognitions };
69936
+ const { html, text } = this.buildMessageBodies(emailBody, {
69937
+ stripInjectedLinks: true,
69938
+ });
69836
69939
  return {
69837
69940
  html,
69838
69941
  text,
@@ -69846,6 +69949,7 @@ class MailerUtils {
69846
69949
  subject,
69847
69950
  attachments,
69848
69951
  blobId,
69952
+ ...(messageId?.[0] && { messageId: messageId[0] }),
69849
69953
  };
69850
69954
  });
69851
69955
  return formattedList;
@@ -69866,10 +69970,10 @@ class MailerUtils {
69866
69970
  return ids;
69867
69971
  },
69868
69972
  condition: async () => {
69869
- const { total } = await this.queryEmail(messageSearchCriteria, {
69973
+ const { ids } = await this.queryEmail(messageSearchCriteria, {
69870
69974
  receivedAfter,
69871
69975
  });
69872
- return total >= expectedEmailCount;
69976
+ return ids.length >= expectedEmailCount;
69873
69977
  },
69874
69978
  timeout,
69875
69979
  }));
@@ -69926,6 +70030,46 @@ class MailerUtils {
69926
70030
  return codes?.[0];
69927
70031
  };
69928
70032
  generateRandomEmail = () => faker.internet.email({ provider: process.env.FASTMAIL_DOMAIN_NAME });
70033
+ getLatestMessageId = async (subject, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), } = {}) => {
70034
+ if (IS_DEV_ENV) {
70035
+ return this.railsEmailUtils.getLatestMessageId(subject, {
70036
+ timeout: timeout / 3,
70037
+ receivedAfter,
70038
+ });
70039
+ }
70040
+ if (!this.accountId) {
70041
+ await this.fastmailApi.authorizeAndSetAccountId();
70042
+ }
70043
+ const messageId = (await this.neetoPlaywrightUtilities.executeRecursively({
70044
+ callback: async () => {
70045
+ const { methodResponses: [[, { ids }]], } = await this.fastmailApi.apiRequest("Email/query", {
70046
+ filter: { subject, after: receivedAfter.toISOString() },
70047
+ sort: [{ property: "receivedAt", isAscending: false }],
70048
+ limit: 1,
70049
+ });
70050
+ const emailId = ids?.[0];
70051
+ if (!emailId)
70052
+ return null;
70053
+ const { methodResponses: [[, { list }]], } = await this.fastmailApi.apiRequest("Email/get", {
70054
+ ids: [emailId],
70055
+ properties: ["messageId"],
70056
+ });
70057
+ const rawMessageId = list?.[0]?.messageId?.[0];
70058
+ if (!rawMessageId)
70059
+ return null;
70060
+ return rawMessageId.replace(/^<|>$/g, "");
70061
+ },
70062
+ condition: async () => {
70063
+ const { methodResponses: [[, { ids }]], } = await this.fastmailApi.apiRequest("Email/query", {
70064
+ filter: { subject, after: receivedAfter.toISOString() },
70065
+ limit: 1,
70066
+ });
70067
+ return ids.length >= 1;
70068
+ },
70069
+ timeout,
70070
+ }));
70071
+ return messageId || undefined;
70072
+ };
69929
70073
  getEmailAttachment = async ({ name, type }, messageSearchCriteria = {}, { timeout = 10_000, receivedAfter = dateTimeOneHourAgo(), expectedEmailCount = 1, } = {}, shouldThrowErrorOnTimeout = true) => {
69930
70074
  if (IS_DEV_ENV)
69931
70075
  return this.railsEmailUtils.getEmailAttachment({ name, type }, messageSearchCriteria, { receivedAfter, expectedEmailCount, timeout: timeout / 3 }, shouldThrowErrorOnTimeout);
@@ -69947,6 +70091,189 @@ class MailerUtils {
69947
70091
  return matchesName && matchesType;
69948
70092
  });
69949
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
+ };
69950
70277
  }
69951
70278
 
69952
70279
  var HeaderTypes;
@@ -116619,7 +116946,8 @@ const commands = {
116619
116946
  },
116620
116947
  mailerUtils: async ({ neetoPlaywrightUtilities }, use) => {
116621
116948
  const mailerUtils = new MailerUtils(neetoPlaywrightUtilities);
116622
- await mailerUtils.fastmailApi.authorizeAndSetAccountId();
116949
+ if (!IS_MAILPIT_ENABLED)
116950
+ await mailerUtils.fastmailApi.authorizeAndSetAccountId();
116623
116951
  await use(mailerUtils);
116624
116952
  IS_DEV_ENV && (await mailerUtils.railsEmailUtils.clearStaleEmails());
116625
116953
  },
@@ -126177,4 +126505,4 @@ const definePlaywrightConfig = (overrides) => {
126177
126505
  });
126178
126506
  };
126179
126507
 
126180
- 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.3",
3
+ "version": "4.3.0",
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",