@bigbinary/neeto-playwright-commons 1.8.43 → 1.8.45

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",
@@ -12841,10 +12880,12 @@ class HelpAndProfilePage {
12841
12880
  await test$1.expect(profileSidebarHeader).toBeHidden();
12842
12881
  });
12843
12882
  await test$1.test.step("Step 3: Open Help center and verify", this.openHelpCenterV2);
12844
- await test$1.test.step("Step 4: Open My organization link and verify", async () => this.openAuthLinkAndVerify({
12845
- linkSelector: PROFILE_SECTION_SELECTORS.profileOrganizationSettingsButton,
12846
- redirectLink: ROUTES.authSettings,
12847
- }));
12883
+ await test$1.test.step("Step 4: Open My organization link and verify", async () => {
12884
+ await this.page
12885
+ .getByTestId(PROFILE_SECTION_SELECTORS.profileOrganizationSettingsButton)
12886
+ .click();
12887
+ await test$1.expect(this.page).toHaveURL(new RegExp(ROUTES.authSettings));
12888
+ });
12848
12889
  };
12849
12890
  this.verifyLogoutV2 = async () => {
12850
12891
  if (shouldSkipSetupAndTeardown())
@@ -13229,6 +13270,228 @@ class WebhooksPage {
13229
13270
  }
13230
13271
  }
13231
13272
 
13273
+ const ZAPIER_SELECTORS = {
13274
+ zapTriggerStep: (zapId) => `[data-testid='step-node-${zapId}']`,
13275
+ zapAccountSubstep: "[data-testid='substep-Account']",
13276
+ zapOpenSubstepContainer: "[data-testid='open-sub-step-container']",
13277
+ modal: "[data-testid='Modal']",
13278
+ fmPrettytext: ".fm-prettytext",
13279
+ spinner: "[data-testid='spinner']",
13280
+ skeletonBlock: "[data-testid='SkeletonBlock']",
13281
+ accountsLoader: "[data-testid='accounts-loader']",
13282
+ floatingBox: "[data-testid='floating-box']",
13283
+ connection: "[data-testid='Connection']",
13284
+ deleteConnectionModal: "[data-testid='DeleteAuthModal-root']",
13285
+ deleteConnectionDropdownButton: "[data-testid='connection-list-item-dropdown-item-Delete']",
13286
+ usageAmounts: "css=[class$=UsageBar__amounts]",
13287
+ universalSidebar: "[data-testid='universalSidebar']",
13288
+ sidebarFooter: "css=[class$=InAppSidebarFooter__footerWrapper]",
13289
+ contextualSideBar: "[data-testid='contextual-sidebar']",
13290
+ };
13291
+
13292
+ class ZapierPage extends IntegrationBase {
13293
+ constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, }) {
13294
+ super({
13295
+ page,
13296
+ integration: "zapier",
13297
+ neetoPlaywrightUtilities,
13298
+ integrationRouteIndex,
13299
+ });
13300
+ this.loginToZapier = async (zapierWebPage) => {
13301
+ this.zapierWebPage = zapierWebPage;
13302
+ this.continueButton = this.zapierWebPage.getByRole("button", {
13303
+ name: ZAPIER_WEB_TEXTS.continue,
13304
+ exact: true,
13305
+ });
13306
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.login);
13307
+ await this.zapierWebPage
13308
+ .getByLabel(ZAPIER_WEB_TEXTS.email)
13309
+ .pressSequentially(process.env.ZAPIER_LOGIN_EMAIL, { delay: 100 });
13310
+ await this.continueButton.click();
13311
+ await test$1.expect(this.zapierWebPage.getByText(ZAPIER_WEB_TEXTS.welcomeText(process.env.ZAPIER_LOGIN_EMAIL))).toBeVisible();
13312
+ await this.zapierWebPage
13313
+ .getByLabel(ZAPIER_WEB_TEXTS.password)
13314
+ .pressSequentially(process.env.ZAPIER_LOGIN_PASSWORD, { delay: 100 });
13315
+ await this.continueButton.click();
13316
+ };
13317
+ this.logoutFromZapier = async () => {
13318
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.logOut, {
13319
+ waitUntil: "commit",
13320
+ });
13321
+ await this.zapierWebPage.close();
13322
+ };
13323
+ this.reconnectAccountAndPublish = async (zapierApiKey) => {
13324
+ var _a;
13325
+ await this.zapierWebPage.goto(THIRD_PARTY_ROUTES.zapier.zapEditor(process.env.ZAP_ID));
13326
+ await this.zapierWebPage
13327
+ .locator(ZAPIER_SELECTORS.zapTriggerStep(process.env.ZAP_ID))
13328
+ .getByLabel(ZAPIER_WEB_TEXTS.editStep)
13329
+ .click();
13330
+ if (await this.zapierWebPage.locator(ZAPIER_SELECTORS.modal).isVisible()) {
13331
+ await this.zapierWebPage
13332
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.editExistingDraft })
13333
+ .click();
13334
+ }
13335
+ await this.zapierWebPage
13336
+ .getByRole("link", { name: ZAPIER_WEB_TEXTS.account })
13337
+ .or(this.zapierWebPage.locator(ZAPIER_SELECTORS.zapAccountSubstep))
13338
+ .click();
13339
+ const signInPagePromise = this.zapierWebPage.waitForEvent("popup");
13340
+ await this.zapierWebPage
13341
+ .getByLabel(RegExp(ZAPIER_WEB_TEXTS.signInTo))
13342
+ .click();
13343
+ const signInPage = await signInPagePromise;
13344
+ await signInPage.waitForLoadState();
13345
+ await test$1.expect(signInPage.getByRole("heading", { name: ZAPIER_WEB_TEXTS.loading })).toBeHidden({ timeout: 10000 });
13346
+ // The zapier connect page have two custom fm-prettytext boxes
13347
+ // (not an input/textarea) without aria-label or data-cy
13348
+ const subdomainBox = signInPage
13349
+ .locator(ZAPIER_SELECTORS.fmPrettytext)
13350
+ // eslint-disable-next-line playwright/no-nth-methods
13351
+ .nth(0);
13352
+ // eslint-disable-next-line playwright/no-nth-methods
13353
+ const apiKeyBox = signInPage.locator(ZAPIER_SELECTORS.fmPrettytext).nth(1);
13354
+ await subdomainBox.click();
13355
+ await subdomainBox.pressSequentially((_a = getGlobalUserState()) === null || _a === void 0 ? void 0 : _a.subdomainName, {
13356
+ delay: 100,
13357
+ });
13358
+ await apiKeyBox.click();
13359
+ await apiKeyBox.pressSequentially(zapierApiKey, { delay: 100 });
13360
+ await signInPage
13361
+ .getByRole("button", {
13362
+ name: RegExp(ZAPIER_WEB_TEXTS.yesContinueTo),
13363
+ })
13364
+ .click();
13365
+ await this.continueButton.click({ timeout: 30000 });
13366
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.spinner)).toBeHidden({ timeout: 10000 });
13367
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.skeletonBlock)).toHaveCount(0, { timeout: 10000 });
13368
+ const testTriggerButton = this.zapierWebPage.getByRole("button", {
13369
+ name: ZAPIER_WEB_TEXTS.testTrigger,
13370
+ });
13371
+ await test$1.expect(testTriggerButton).toBeVisible();
13372
+ await testTriggerButton.click();
13373
+ await test$1.expect(this.zapierWebPage.getByText(ZAPIER_WEB_TEXTS.testCurrentlyInQueue)).toBeHidden({ timeout: 20000 });
13374
+ await test$1.expect(this.zapierWebPage.getByLabel(ZAPIER_WEB_TEXTS.statusLabel, {
13375
+ exact: true,
13376
+ })).toBeVisible({ timeout: 10000 });
13377
+ await this.zapierWebPage
13378
+ .getByRole("button", {
13379
+ name: ZAPIER_WEB_TEXTS.continueWithSelectedRecord,
13380
+ })
13381
+ .click({ timeout: 20000 });
13382
+ await this.continueButton.click();
13383
+ await this.continueButton.click();
13384
+ await this.zapierWebPage
13385
+ .locator(ZAPIER_SELECTORS.contextualSideBar)
13386
+ .getByLabel(ZAPIER_WEB_TEXTS.publish)
13387
+ .or(this.zapierWebPage
13388
+ .locator(ZAPIER_SELECTORS.zapOpenSubstepContainer)
13389
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.publish }))
13390
+ .click();
13391
+ await this.zapierWebPage
13392
+ .locator(ZAPIER_SELECTORS.modal)
13393
+ .getByLabel(ZAPIER_WEB_TEXTS.publish)
13394
+ .or(this.zapierWebPage
13395
+ .locator(ZAPIER_SELECTORS.modal)
13396
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.publish, exact: true }))
13397
+ .click();
13398
+ await this.zapierWebPage
13399
+ .getByLabel(ZAPIER_WEB_TEXTS.publishingZapHeading)
13400
+ .waitFor();
13401
+ await test$1.expect(this.zapierWebPage.getByLabel(ZAPIER_WEB_TEXTS.publishingZapHeading)).toBeHidden({ timeout: 15000 });
13402
+ };
13403
+ this.deleteAllConnections = async (zapierAppLink) => {
13404
+ await this.zapierWebPage.goto(zapierAppLink);
13405
+ await this.zapierWebPage.waitForLoadState();
13406
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.accountsLoader)).toBeHidden();
13407
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.skeletonBlock)).toHaveCount(0);
13408
+ const connectionLocator = this.zapierWebPage.locator(ZAPIER_SELECTORS.connection);
13409
+ const connections = await connectionLocator.all();
13410
+ const deleteButton = this.zapierWebPage
13411
+ .locator(ZAPIER_SELECTORS.floatingBox)
13412
+ .locator(ZAPIER_SELECTORS.deleteConnectionDropdownButton);
13413
+ for (const connection of connections) {
13414
+ await test$1.expect(async () => {
13415
+ await connection
13416
+ .getByLabel(ZAPIER_WEB_TEXTS.connectionListMenu)
13417
+ .click();
13418
+ await deleteButton.click();
13419
+ await this.zapierWebPage
13420
+ .locator(ZAPIER_SELECTORS.deleteConnectionModal)
13421
+ .getByRole("button", { name: ZAPIER_WEB_TEXTS.delete })
13422
+ .click();
13423
+ }).toPass({ timeout: 20000 });
13424
+ }
13425
+ // eslint-disable-next-line playwright/no-standalone-expect
13426
+ await test$1.expect(connectionLocator).toHaveCount(0, {
13427
+ timeout: 10000,
13428
+ });
13429
+ };
13430
+ 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 });
13431
+ this.skipIfTaskLimitIsExhausted = async () => {
13432
+ var _a;
13433
+ // Zapier provides 100 free task limit for free account; skip test if it's exhausted
13434
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.universalSidebar)).toBeVisible({ timeout: 15000 });
13435
+ await test$1.expect(this.zapierWebPage.locator(ZAPIER_SELECTORS.sidebarFooter)).toBeVisible({ timeout: 10000 });
13436
+ if (await this.zapierWebPage
13437
+ .getByText(RegExp(ZAPIER_WEB_TEXTS.trialEndsRegExp))
13438
+ .isVisible()) {
13439
+ return;
13440
+ }
13441
+ await test$1.expect(this.zapierWebPage.getByText(RegExp(ZAPIER_WEB_TEXTS.usageRegExp))).toBeVisible({ timeout: 30000 });
13442
+ const freeTaskLimit = (_a = (await this.zapierWebPage
13443
+ .locator(ZAPIER_SELECTORS.usageAmounts)
13444
+ // There are two usageAmount span elements
13445
+ // and there is no better approach than to use first()
13446
+ // eslint-disable-next-line playwright/no-nth-methods
13447
+ .first()
13448
+ .textContent())) !== null && _a !== void 0 ? _a : "";
13449
+ const [taskRunCount, taskLimitForMonth] = freeTaskLimit
13450
+ .split("/")
13451
+ .map(str => parseInt(str));
13452
+ // eslint-disable-next-line playwright/no-skipped-test
13453
+ test__default["default"].skip(taskRunCount >= taskLimitForMonth, ZAPIER_LIMIT_EXHAUSTED_MESSAGE);
13454
+ };
13455
+ this.connectAndVerify = async ({ apiKeyLabel }) => {
13456
+ await this.connect();
13457
+ await this.page.getByTestId(COMMON_SELECTORS.inputField).fill(apiKeyLabel);
13458
+ await this.page
13459
+ .getByRole("button", {
13460
+ name: this.t("neetoIntegrations.zapier.generateApiKey"),
13461
+ })
13462
+ .click();
13463
+ await this.neetoPlaywrightUtilities.verifySuccessToast({
13464
+ message: TOASTR_MESSAGES.zapierApiKeyGenerated,
13465
+ });
13466
+ await this.page
13467
+ .getByRole("button", {
13468
+ name: this.t("neetoIntegrations.zapier.copyApiKey"),
13469
+ })
13470
+ .click();
13471
+ const apiKey = await this.page.evaluate(() => navigator.clipboard.readText());
13472
+ await this.verifyIntegrationStatus();
13473
+ return apiKey;
13474
+ };
13475
+ this.disconnectAndVerify = async () => {
13476
+ await this.disconnect({
13477
+ times: 1,
13478
+ responseUrl: API_ROUTES.integrations.zapier.api_keys,
13479
+ });
13480
+ await this.verifyIntegrationStatus("disconnected");
13481
+ };
13482
+ if (ramda.isNil(process.env.INTEGRATION_MAILOSAUR_API_KEY) ||
13483
+ ramda.isNil(process.env.INTEGRATION_MAILOSAUR_SERVER_ID)) {
13484
+ throw new Error("ENV variable INTEGRATION_MAILOSAUR_API_KEY or INTEGRATION_MAILOSAUR_SERVER_ID is not properly configured");
13485
+ }
13486
+ if (ramda.isNil(process.env.ZAPIER_LOGIN_PASSWORD) ||
13487
+ ramda.isNil(process.env.ZAPIER_LOGIN_EMAIL) ||
13488
+ ramda.isNil(process.env.ZAP_ID)) {
13489
+ throw new Error("ENV variable ZAPIER_LOGIN_PASSWORD or ZAPIER_LOGIN_EMAIL or ZAP_ID is not properly configured");
13490
+ }
13491
+ this.mailosaur = new MailosaurClient__default["default"](process.env.INTEGRATION_MAILOSAUR_API_KEY);
13492
+ }
13493
+ }
13494
+
13232
13495
  const SIGNUP_SELECTORS = {
13233
13496
  emailTextField: "signup-email-text-field",
13234
13497
  firstNameTextField: "signup-profile-first-name-text-field",
@@ -147218,8 +147481,14 @@ exports.SidebarSection = SidebarSection;
147218
147481
  exports.SlackPage = SlackPage;
147219
147482
  exports.TAGS_SELECTORS = TAGS_SELECTORS;
147220
147483
  exports.THIRD_PARTY_ROUTES = THIRD_PARTY_ROUTES;
147484
+ exports.TOASTR_MESSAGES = TOASTR_MESSAGES;
147221
147485
  exports.USER_AGENTS = USER_AGENTS;
147222
147486
  exports.WebhooksPage = WebhooksPage;
147487
+ exports.ZAPIER_LIMIT_EXHAUSTED_MESSAGE = ZAPIER_LIMIT_EXHAUSTED_MESSAGE;
147488
+ exports.ZAPIER_SELECTORS = ZAPIER_SELECTORS;
147489
+ exports.ZAPIER_TEST_EMAIL = ZAPIER_TEST_EMAIL;
147490
+ exports.ZAPIER_WEB_TEXTS = ZAPIER_WEB_TEXTS;
147491
+ exports.ZapierPage = ZapierPage;
147223
147492
  exports.basicHTMLContent = basicHTMLContent;
147224
147493
  exports.clearCredentials = clearCredentials;
147225
147494
  exports.commands = commands;