@bigbinary/neeto-playwright-commons 1.8.42 → 1.8.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -88,6 +88,7 @@ const CREDENTIALS = {
88
88
  };
89
89
  const OTP_EMAIL_PATTERN = "is your login code";
90
90
  const SLACK_DEFAULT_CHANNEL = "general";
91
+ const ZAPIER_TEST_EMAIL = (product) => `neeto-${product}-zapier-test@${process.env.INTEGRATION_MAILOSAUR_SERVER_ID}.mailosaur.net`;
91
92
 
92
93
  /* eslint-disable playwright/no-skipped-test */
93
94
  const execCommand = (command) => child_process.execSync(command)
@@ -12589,12 +12590,22 @@ const API_ROUTES = {
12589
12590
  index: "/team_members/teams",
12590
12591
  show: (id) => `/team_members/teams/${id}`,
12591
12592
  },
12593
+ integrations: {
12594
+ zapier: {
12595
+ api_keys: "/neeto_integrations/zapier/api_keys",
12596
+ },
12597
+ },
12592
12598
  };
12593
12599
  const THIRD_PARTY_ROUTES = {
12594
12600
  webhooks: { site: "https://webhook.site/" },
12595
12601
  slack: {
12596
12602
  loginWithPassword: (workspace) => `https://${workspace}.slack.com/sign_in_with_password`,
12597
12603
  },
12604
+ zapier: {
12605
+ login: "https://zapier.com/app/login",
12606
+ logOut: "https://zapier.com/logout",
12607
+ zapEditor: (zapId) => `https://zapier.com/editor/${zapId}`,
12608
+ },
12598
12609
  };
12599
12610
 
12600
12611
  const CHAT_WIDGET_TEXTS = {
@@ -12617,6 +12628,34 @@ const SLACK_WEB_TEXTS = {
12617
12628
  permanentlyDeleteTheChannel: "Yes, permanently delete the channel",
12618
12629
  deleteChannel: "Delete channel",
12619
12630
  };
12631
+ const ZAPIER_WEB_TEXTS = {
12632
+ account: "Account",
12633
+ email: "Email",
12634
+ continue: "Continue",
12635
+ statusLabel: "Status",
12636
+ password: "Password",
12637
+ editExistingDraft: "Edit existing draft",
12638
+ signInTo: "Sign in to *",
12639
+ yesContinueTo: "Yes, Continue to *",
12640
+ testTrigger: "Test trigger",
12641
+ editStep: "Edit step",
12642
+ continueWithSelectedRecord: "Continue with selected record",
12643
+ publish: "Publish",
12644
+ delete: "Delete",
12645
+ loading: "Loading",
12646
+ subdomain: "Subdomain",
12647
+ apiKey: "API key",
12648
+ publishingZapHeading: "Preparing Zap to go live",
12649
+ connectionListMenu: "Connection List Item Menu",
12650
+ usageRegExp: "Usage resets in *",
12651
+ trialEndsRegExp: "Trial ends on",
12652
+ testCurrentlyInQueue: "Test currently in queue",
12653
+ welcomeText: (zapierLoginEmail) => `Welcome back ${zapierLoginEmail}`,
12654
+ };
12655
+ const TOASTR_MESSAGES = {
12656
+ zapierApiKeyGenerated: "Zapier API key is generated successfully!",
12657
+ };
12658
+ const ZAPIER_LIMIT_EXHAUSTED_MESSAGE = "Zapier free task limit is exhausted. Test will be aborted";
12620
12659
 
12621
12660
  const HELP_CENTER_SELECTORS = {
12622
12661
  helpButton: "help-button",
@@ -13229,6 +13268,228 @@ class WebhooksPage {
13229
13268
  }
13230
13269
  }
13231
13270
 
13271
+ const ZAPIER_SELECTORS = {
13272
+ zapTriggerStep: (zapId) => `[data-testid='step-node-${zapId}']`,
13273
+ zapAccountSubstep: "[data-testid='substep-Account']",
13274
+ zapOpenSubstepContainer: "[data-testid='open-sub-step-container']",
13275
+ modal: "[data-testid='Modal']",
13276
+ fmPrettytext: ".fm-prettytext",
13277
+ spinner: "[data-testid='spinner']",
13278
+ skeletonBlock: "[data-testid='SkeletonBlock']",
13279
+ accountsLoader: "[data-testid='accounts-loader']",
13280
+ floatingBox: "[data-testid='floating-box']",
13281
+ connection: "[data-testid='Connection']",
13282
+ deleteConnectionModal: "[data-testid='DeleteAuthModal-root']",
13283
+ deleteConnectionDropdownButton: "[data-testid='connection-list-item-dropdown-item-Delete']",
13284
+ usageAmounts: "css=[class$=UsageBar__amounts]",
13285
+ universalSidebar: "[data-testid='universalSidebar']",
13286
+ sidebarFooter: "css=[class$=InAppSidebarFooter__footerWrapper]",
13287
+ contextualSideBar: "[data-testid='contextual-sidebar']",
13288
+ };
13289
+
13290
+ class ZapierPage extends IntegrationBase {
13291
+ constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, }) {
13292
+ super({
13293
+ page,
13294
+ integration: "zapier",
13295
+ neetoPlaywrightUtilities,
13296
+ integrationRouteIndex,
13297
+ });
13298
+ this.loginToZapier = async (zapierWebPage) => {
13299
+ this.zapierWebPage = zapierWebPage;
13300
+ this.continueButton = this.zapierWebPage.getByRole("button", {
13301
+ name: ZAPIER_WEB_TEXTS.continue,
13302
+ exact: true,
13303
+ });
13304
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.login);
13305
+ await this.zapierWebPage
13306
+ .getByLabel(ZAPIER_WEB_TEXTS.email)
13307
+ .pressSequentially(process.env.ZAPIER_LOGIN_EMAIL, { delay: 100 });
13308
+ await this.continueButton.click();
13309
+ await test$1.expect(this.zapierWebPage.getByText(ZAPIER_WEB_TEXTS.welcomeText(process.env.ZAPIER_LOGIN_EMAIL))).toBeVisible();
13310
+ await this.zapierWebPage
13311
+ .getByLabel(ZAPIER_WEB_TEXTS.password)
13312
+ .pressSequentially(process.env.ZAPIER_LOGIN_PASSWORD, { delay: 100 });
13313
+ await this.continueButton.click();
13314
+ };
13315
+ this.logoutFromZapier = async () => {
13316
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.logOut, {
13317
+ waitUntil: "commit",
13318
+ });
13319
+ await this.zapierWebPage.close();
13320
+ };
13321
+ this.reconnectAccountAndPublish = async (zapierApiKey) => {
13322
+ var _a;
13323
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.zapEditor(process.env.ZAP_ID));
13324
+ await this.zapierWebPage
13325
+ .locator(ZAPIER_SELECTORS.zapTriggerStep(process.env.ZAP_ID))
13326
+ .getByLabel(ZAPIER_WEB_TEXTS.editStep)
13327
+ .click();
13328
+ if (await this.zapierWebPage.locator(ZAPIER_SELECTORS.modal).isVisible()) {
13329
+ await this.zapierWebPage
13330
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.editExistingDraft })
13331
+ .click();
13332
+ }
13333
+ await this.zapierWebPage
13334
+ .getByRole("link", { name: ZAPIER_WEB_TEXTS.account })
13335
+ .or(this.zapierWebPage.locator(ZAPIER_SELECTORS.zapAccountSubstep))
13336
+ .click();
13337
+ const signInPagePromise = this.zapierWebPage.waitForEvent("popup");
13338
+ await this.zapierWebPage
13339
+ .getByLabel(RegExp(ZAPIER_WEB_TEXTS.signInTo))
13340
+ .click();
13341
+ const signInPage = await signInPagePromise;
13342
+ await signInPage.waitForLoadState();
13343
+ await test$1.expect(signInPage.getByRole("heading", { name: ZAPIER_WEB_TEXTS.loading })).toBeHidden({ timeout: 10000 });
13344
+ // The zapier connect page have two custom fm-prettytext boxes
13345
+ // (not an input/textarea) without aria-label or data-cy
13346
+ const subdomainBox = signInPage
13347
+ .locator(ZAPIER_SELECTORS.fmPrettytext)
13348
+ // eslint-disable-next-line playwright/no-nth-methods
13349
+ .nth(0);
13350
+ // eslint-disable-next-line playwright/no-nth-methods
13351
+ const apiKeyBox = signInPage.locator(ZAPIER_SELECTORS.fmPrettytext).nth(1);
13352
+ await subdomainBox.click();
13353
+ await subdomainBox.pressSequentially((_a = getGlobalUserState()) === null || _a === void 0 ? void 0 : _a.subdomainName, {
13354
+ delay: 100,
13355
+ });
13356
+ await apiKeyBox.click();
13357
+ await apiKeyBox.pressSequentially(zapierApiKey, { delay: 100 });
13358
+ await signInPage
13359
+ .getByRole("button", {
13360
+ name: RegExp(ZAPIER_WEB_TEXTS.yesContinueTo),
13361
+ })
13362
+ .click();
13363
+ await this.continueButton.click({ timeout: 30000 });
13364
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.spinner)).toBeHidden({ timeout: 10000 });
13365
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.skeletonBlock)).toHaveCount(0, { timeout: 10000 });
13366
+ const testTriggerButton = this.zapierWebPage.getByRole("button", {
13367
+ name: ZAPIER_WEB_TEXTS.testTrigger,
13368
+ });
13369
+ await test$1.expect(testTriggerButton).toBeVisible();
13370
+ await testTriggerButton.click();
13371
+ await test$1.expect(this.zapierWebPage.getByText(ZAPIER_WEB_TEXTS.testCurrentlyInQueue)).toBeHidden({ timeout: 20000 });
13372
+ await test$1.expect(this.zapierWebPage.getByLabel(ZAPIER_WEB_TEXTS.statusLabel, {
13373
+ exact: true,
13374
+ })).toBeVisible({ timeout: 10000 });
13375
+ await this.zapierWebPage
13376
+ .getByRole("button", {
13377
+ name: ZAPIER_WEB_TEXTS.continueWithSelectedRecord,
13378
+ })
13379
+ .click({ timeout: 20000 });
13380
+ await this.continueButton.click();
13381
+ await this.continueButton.click();
13382
+ await this.zapierWebPage
13383
+ .locator(ZAPIER_SELECTORS.contextualSideBar)
13384
+ .getByLabel(ZAPIER_WEB_TEXTS.publish)
13385
+ .or(this.zapierWebPage
13386
+ .locator(ZAPIER_SELECTORS.zapOpenSubstepContainer)
13387
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.publish }))
13388
+ .click();
13389
+ await this.zapierWebPage
13390
+ .locator(ZAPIER_SELECTORS.modal)
13391
+ .getByLabel(ZAPIER_WEB_TEXTS.publish)
13392
+ .or(this.zapierWebPage
13393
+ .locator(ZAPIER_SELECTORS.modal)
13394
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.publish, exact: true }))
13395
+ .click();
13396
+ await this.zapierWebPage
13397
+ .getByLabel(ZAPIER_WEB_TEXTS.publishingZapHeading)
13398
+ .waitFor();
13399
+ await test$1.expect(this.zapierWebPage.getByLabel(ZAPIER_WEB_TEXTS.publishingZapHeading)).toBeHidden({ timeout: 15000 });
13400
+ };
13401
+ this.deleteAllConnections = async (zapierAppLink) => {
13402
+ await this.zapierWebPage.goto(zapierAppLink);
13403
+ await this.zapierWebPage.waitForLoadState();
13404
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.accountsLoader)).toBeHidden();
13405
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.skeletonBlock)).toHaveCount(0);
13406
+ const connectionLocator = this.zapierWebPage.locator(ZAPIER_SELECTORS.connection);
13407
+ const connections = await connectionLocator.all();
13408
+ const deleteButton = this.zapierWebPage
13409
+ .locator(ZAPIER_SELECTORS.floatingBox)
13410
+ .locator(ZAPIER_SELECTORS.deleteConnectionDropdownButton);
13411
+ for (const connection of connections) {
13412
+ await test$1.expect(async () => {
13413
+ await connection
13414
+ .getByLabel(ZAPIER_WEB_TEXTS.connectionListMenu)
13415
+ .click();
13416
+ await deleteButton.click();
13417
+ await this.zapierWebPage
13418
+ .locator(ZAPIER_SELECTORS.deleteConnectionModal)
13419
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.delete })
13420
+ .click();
13421
+ }).toPass({ timeout: 20000 });
13422
+ }
13423
+ // eslint-disable-next-line playwright/no-standalone-expect
13424
+ await test$1.expect(connectionLocator).toHaveCount(0, {
13425
+ timeout: 10000,
13426
+ });
13427
+ };
13428
+ this.verifyZapIsTriggered = ({ productName, submittedEmail, zapTriggeredAfter, }) => this.mailosaur.messages.get(process.env.INTEGRATION_MAILOSAUR_SERVER_ID, { sentTo: ZAPIER_TEST_EMAIL(productName), body: submittedEmail }, { timeout: 2 * 60000, receivedAfter: zapTriggeredAfter });
13429
+ this.skipIfTaskLimitIsExhausted = async () => {
13430
+ var _a;
13431
+ // Zapier provides 100 free task limit for free account; skip test if it's exhausted
13432
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.universalSidebar)).toBeVisible({ timeout: 15000 });
13433
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.sidebarFooter)).toBeVisible({ timeout: 10000 });
13434
+ if (await this.zapierWebPage
13435
+ .getByText(RegExp(ZAPIER_WEB_TEXTS.trialEndsRegExp))
13436
+ .isVisible()) {
13437
+ return;
13438
+ }
13439
+ await test$1.expect(this.zapierWebPage.getByText(RegExp(ZAPIER_WEB_TEXTS.usageRegExp))).toBeVisible({ timeout: 30000 });
13440
+ const freeTaskLimit = (_a = (await this.zapierWebPage
13441
+ .locator(ZAPIER_SELECTORS.usageAmounts)
13442
+ // There are two usageAmount span elements
13443
+ // and there is no better approach than to use first()
13444
+ // eslint-disable-next-line playwright/no-nth-methods
13445
+ .first()
13446
+ .textContent())) !== null && _a !== void 0 ? _a : "";
13447
+ const [taskRunCount, taskLimitForMonth] = freeTaskLimit
13448
+ .split("/")
13449
+ .map(str => parseInt(str));
13450
+ // eslint-disable-next-line playwright/no-skipped-test
13451
+ test__default["default"].skip(taskRunCount >= taskLimitForMonth, ZAPIER_LIMIT_EXHAUSTED_MESSAGE);
13452
+ };
13453
+ this.connectAndVerify = async ({ apiKeyLabel }) => {
13454
+ await this.connect();
13455
+ await this.page.getByTestId(COMMON_SELECTORS.inputField).fill(apiKeyLabel);
13456
+ await this.page
13457
+ .getByRole("button", {
13458
+ name: this.t("neetoIntegrations.zapier.generateApiKey"),
13459
+ })
13460
+ .click();
13461
+ await this.neetoPlaywrightUtilities.verifySuccessToast({
13462
+ message: TOASTR_MESSAGES.zapierApiKeyGenerated,
13463
+ });
13464
+ await this.page
13465
+ .getByRole("button", {
13466
+ name: this.t("neetoIntegrations.zapier.copyApiKey"),
13467
+ })
13468
+ .click();
13469
+ const apiKey = await this.page.evaluate(() => navigator.clipboard.readText());
13470
+ await this.verifyIntegrationStatus();
13471
+ return apiKey;
13472
+ };
13473
+ this.disconnectAndVerify = async () => {
13474
+ await this.disconnect({
13475
+ times: 1,
13476
+ responseUrl: API_ROUTES.integrations.zapier.api_keys,
13477
+ });
13478
+ await this.verifyIntegrationStatus("disconnected");
13479
+ };
13480
+ if (ramda.isNil(process.env.INTEGRATION_MAILOSAUR_API_KEY) ||
13481
+ ramda.isNil(process.env.INTEGRATION_MAILOSAUR_SERVER_ID)) {
13482
+ throw new Error("ENV variable INTEGRATION_MAILOSAUR_API_KEY or INTEGRATION_MAILOSAUR_SERVER_ID is not properly configured");
13483
+ }
13484
+ if (ramda.isNil(process.env.ZAPIER_LOGIN_PASSWORD) ||
13485
+ ramda.isNil(process.env.ZAPIER_LOGIN_EMAIL) ||
13486
+ ramda.isNil(process.env.ZAP_ID)) {
13487
+ throw new Error("ENV variable ZAPIER_LOGIN_PASSWORD or ZAPIER_LOGIN_EMAIL or ZAP_ID is not properly configured");
13488
+ }
13489
+ this.mailosaur = new MailosaurClient__default["default"](process.env.INTEGRATION_MAILOSAUR_API_KEY);
13490
+ }
13491
+ }
13492
+
13232
13493
  const SIGNUP_SELECTORS = {
13233
13494
  emailTextField: "signup-email-text-field",
13234
13495
  firstNameTextField: "signup-profile-first-name-text-field",
@@ -13605,6 +13866,7 @@ const loginWithoutSSO = async ({ page, neetoPlaywrightUtilities, loginPath = "/"
13605
13866
  };
13606
13867
  const login = async ({ page, neetoPlaywrightUtilities, loginPath, }) => !IS_STAGING_ENV &&
13607
13868
  (await loginWithoutSSO({ page, neetoPlaywrightUtilities, loginPath }));
13869
+ const generateRandomBypassEmail = () => `cpt${process.env.OTP_BYPASS_KEY}+${faker.faker.number.int()}@bigbinary.com`;
13608
13870
 
13609
13871
  const addMemberViaRequest = ({ email, role = MEMBER_TEXTS.agent, appName, neetoPlaywrightUtilities, }) => neetoPlaywrightUtilities.apiRequest({
13610
13872
  method: "post",
@@ -147217,8 +147479,14 @@ exports.SidebarSection = SidebarSection;
147217
147479
  exports.SlackPage = SlackPage;
147218
147480
  exports.TAGS_SELECTORS = TAGS_SELECTORS;
147219
147481
  exports.THIRD_PARTY_ROUTES = THIRD_PARTY_ROUTES;
147482
+ exports.TOASTR_MESSAGES = TOASTR_MESSAGES;
147220
147483
  exports.USER_AGENTS = USER_AGENTS;
147221
147484
  exports.WebhooksPage = WebhooksPage;
147485
+ exports.ZAPIER_LIMIT_EXHAUSTED_MESSAGE = ZAPIER_LIMIT_EXHAUSTED_MESSAGE;
147486
+ exports.ZAPIER_SELECTORS = ZAPIER_SELECTORS;
147487
+ exports.ZAPIER_TEST_EMAIL = ZAPIER_TEST_EMAIL;
147488
+ exports.ZAPIER_WEB_TEXTS = ZAPIER_WEB_TEXTS;
147489
+ exports.ZapierPage = ZapierPage;
147222
147490
  exports.basicHTMLContent = basicHTMLContent;
147223
147491
  exports.clearCredentials = clearCredentials;
147224
147492
  exports.commands = commands;
@@ -147227,6 +147495,7 @@ exports.decodeQRCodeFromFile = decodeQRCodeFromFile;
147227
147495
  exports.definePlaywrightConfig = definePlaywrightConfig;
147228
147496
  exports.executeWithThrottledResources = executeWithThrottledResources;
147229
147497
  exports.extractSubdomainFromError = extractSubdomainFromError;
147498
+ exports.generateRandomBypassEmail = generateRandomBypassEmail;
147230
147499
  exports.generateStagingData = generateStagingData;
147231
147500
  exports.getByDataQA = getByDataQA;
147232
147501
  exports.getGlobalUserState = getGlobalUserState;