@bigbinary/neeto-playwright-commons 1.27.1 → 1.28.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.
package/index.d.ts CHANGED
@@ -963,6 +963,7 @@ declare class SlackApi {
963
963
  fetchMessages: (channelId: string, unixTimestamp: number) => Promise<playwright_core.APIResponse | undefined>;
964
964
  createChannel: (channelName: string) => Promise<playwright_core.APIResponse | undefined>;
965
965
  addUser: (channelId: string, userId: string) => Promise<playwright_core.APIResponse | undefined>;
966
+ mockChannelDeleted: (channelId: string) => Promise<playwright_core.APIResponse | undefined>;
966
967
  }
967
968
  declare class WebhookSiteApi {
968
969
  private readonly request;
@@ -2688,6 +2689,9 @@ interface CreateNewSlackChannelParams {
2688
2689
  declare class SlackPage extends IntegrationBase {
2689
2690
  slackWebappPage: Page;
2690
2691
  slackWebappPageDataQa: (dataQa: string | [string, string]) => Locator;
2692
+ allowButton: Locator;
2693
+ callbackUrl: string;
2694
+ currentWorkspace: string;
2691
2695
  constructor({
2692
2696
  page,
2693
2697
  neetoPlaywrightUtilities,
@@ -2705,15 +2709,40 @@ declare class SlackPage extends IntegrationBase {
2705
2709
  * @endexample
2706
2710
  */
2707
2711
  setupCloseHandlers: (slackWebappPage?: Page) => Promise<void>;
2712
+ private initializeSlackPermissionPage;
2708
2713
  /**
2709
2714
  *
2710
- * Connects to slack integration and verifies the connection. It takes the following parameters:
2715
+ * Navigates the page to the captured Slack OAuth callback URL. Uses HTTP in place of HTTPS for local/dev. Call captureCallbackUrl before starting the OAuth flow so the callback URL is set. Used when running test against
2711
2716
  *
2712
- * redirectUrl: URL to redirect after connecting.
2717
+ * dev env.
2718
+ *
2719
+ * @example
2720
+ *
2721
+ * await slackPage.navigateToCallbackUrl();
2722
+ * @endexample
2723
+ */
2724
+ navigateToCallbackUrl: () => Promise<void>;
2725
+ /**
2726
+ *
2727
+ * Registers a request listener that captures the Slack OAuth callback URL when a request to /neeto_slack/api/v2/slack/callbacks is made. The URL is stored for use by navigateToCallbackUrl. Call this before starting the OAuth flow (e.g. before clicking the Slack "Allow" button in dev).
2728
+ *
2729
+ * @example
2730
+ *
2731
+ * slackPage.captureCallbackUrl();
2732
+ * @endexample
2733
+ */
2734
+ captureCallbackUrl: () => Page;
2735
+ private connectAndVerifyInDev;
2736
+ private connectAndVerifyInStaging;
2737
+ /**
2738
+ *
2739
+ * Completes the Slack OAuth flow and verifies the integration is connected. In dev, captures the callback URL and navigates to it; in staging, relies on redirect. Then configures the given channel and runs optional custom steps.
2740
+ *
2741
+ * redirectUrl: URL or pattern to wait for after OAuth redirect.
2713
2742
  *
2714
2743
  * customSteps (optional): Custom steps to perform after connection.
2715
2744
  *
2716
- * channelToConfigure (optional): Channel to configure.
2745
+ * channelToConfigure (optional): Slack channel to select in the configure step. Defaults to SLACK_DEFAULT_CHANNEL.
2717
2746
  *
2718
2747
  * @example
2719
2748
  *
@@ -2725,6 +2754,7 @@ declare class SlackPage extends IntegrationBase {
2725
2754
  * @endexample
2726
2755
  */
2727
2756
  connectAndVerifyIntegration: (redirectUrl: RedirectUrl, customSteps?: AsyncNoArgsFunction, channelToConfigure?: string) => Promise<void>;
2757
+ private completeSlackChannelSetup;
2728
2758
  /**
2729
2759
  *
2730
2760
  * Disconnects from Slack integration and verifies disconnection.
package/index.js CHANGED
@@ -521,6 +521,14 @@ class SlackApi {
521
521
  this.fetchMessages = (channelId, unixTimestamp) => this.apiRequest("history", { channel: channelId, oldest: unixTimestamp });
522
522
  this.createChannel = (channelName) => this.apiRequest("create", { name: channelName });
523
523
  this.addUser = (channelId, userId) => this.apiRequest("invite", { channel: channelId, users: userId });
524
+ this.mockChannelDeleted = (channelId) => this.neetoPlaywrightUtilities.apiRequest({
525
+ url: "/neeto_slack/api/v1/testing/webhooks",
526
+ method: "post",
527
+ data: keysToSnakeCase({
528
+ eventType: "channel_deleted",
529
+ notificationChannelId: channelId,
530
+ }),
531
+ });
524
532
  if (!process.env.SLACK_BOT_TOKEN) {
525
533
  throw new Error("SLACK_BOT_TOKEN is not set");
526
534
  }
@@ -116887,11 +116895,17 @@ class GooglePage extends IntegrationBase {
116887
116895
  totpToken = this.totp.generate({ timestamp: Date.now() });
116888
116896
  }
116889
116897
  previousToken = totpToken;
116898
+ if (await codeInput.isHidden())
116899
+ return;
116890
116900
  await codeInput.fill(totpToken);
116891
116901
  expect(this.totp.validate({ token: totpToken })).not.toBeNull();
116892
116902
  await this.page.locator(GOOGLE_LOGIN_SELECTORS.totpNext).click();
116893
- await expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({ timeout: 10000 });
116894
- await expect(codeInput).toBeHidden({ timeout: 15000 });
116903
+ await Promise.all([
116904
+ expect(codeInput).toBeHidden({ timeout: 20000 }),
116905
+ expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({
116906
+ timeout: 20000,
116907
+ }),
116908
+ ]);
116895
116909
  }).toPass({ timeout: 2 * 60 * 1000 });
116896
116910
  };
116897
116911
  this.logoutFromGoogle = async () => {
@@ -117088,32 +117102,58 @@ class SlackPage extends IntegrationBase {
117088
117102
  await slackWebappPage.addLocatorHandler(slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.messagePaneBannerCloseIcon), locator => locator.click(), { times: 1 });
117089
117103
  await slackWebappPage.addLocatorHandler(slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.permissionBannerCloseIcon), locator => locator.click(), { noWaitAfter: true, times: 2 });
117090
117104
  };
117091
- this.connectAndVerifyIntegration = async (redirectUrl, customSteps, channelToConfigure = SLACK_DEFAULT_CHANNEL) => {
117105
+ this.initializeSlackPermissionPage = async () => {
117092
117106
  await this.connect();
117093
- const loginButton = this.page.getByRole("button", {
117094
- name: this.t("neetoSlack.slack.connect.loginButton"),
117095
- });
117096
- const installButton = this.page.locator(SLACK_SELECTORS.installButton);
117097
- const allowButton = this.page.getByRole("button", {
117098
- name: SLACK_WEB_TEXTS.allow,
117099
- });
117100
- const button = installButton.or(allowButton);
117101
- if (await loginButton.isVisible()) {
117102
- await loginButton.click({ delay: 5000 });
117103
- await this.page.waitForURL(RegExp("(.*)slack.com/.*"));
117104
- }
117105
117107
  await this.page.waitForLoadState("domcontentloaded", { timeout: 25000 });
117106
- await expect(button).toBeVisible({ timeout: 25000 });
117107
- await expect(button).toBeEnabled({ timeout: 25000 });
117108
- const currentWorkspace = (await this.page
117108
+ await expect(this.allowButton).toBeVisible({ timeout: 25000 });
117109
+ await expect(this.allowButton).toBeEnabled({ timeout: 25000 });
117110
+ return await this.page
117109
117111
  .locator(SLACK_SELECTORS.teamPicketButtonContent)
117110
- .textContent()) || "";
117111
- await button.click({ timeout: 25000 });
117112
- await this.page.waitForURL(redirectUrl);
117112
+ .textContent();
117113
+ };
117114
+ this.navigateToCallbackUrl = async () => {
117115
+ await this.page.goto(this.callbackUrl.replace(/^https:/, "http:"));
117116
+ await this.neetoPlaywrightUtilities.waitForPageLoad();
117117
+ };
117118
+ this.captureCallbackUrl = () => this.page.on("request", (request) => {
117119
+ const url = request.url();
117120
+ if (url.includes("/neeto_slack/api/v2/slack/callbacks") &&
117121
+ url.startsWith("https:")) {
117122
+ this.callbackUrl = url;
117123
+ }
117124
+ });
117125
+ this.connectAndVerifyInDev = async (redirectUrl, channelToConfigure, customSteps) => {
117126
+ this.currentWorkspace = (await this.initializeSlackPermissionPage()) || "";
117127
+ this.captureCallbackUrl();
117128
+ await this.allowButton.click({ timeout: 25000 });
117129
+ await expect(this.allowButton).toBeHidden({ timeout: 25000 });
117130
+ await this.page.waitForLoadState("domcontentloaded", { timeout: 20000 });
117131
+ await this.navigateToCallbackUrl();
117132
+ await this.page.waitForURL(redirectUrl, {
117133
+ timeout: 15000,
117134
+ });
117135
+ await this.completeSlackChannelSetup(channelToConfigure, customSteps);
117136
+ };
117137
+ this.connectAndVerifyInStaging = async (redirectUrl, channelToConfigure, customSteps) => {
117138
+ this.currentWorkspace = (await this.initializeSlackPermissionPage()) || "";
117139
+ await this.allowButton.click({ timeout: 25000 });
117140
+ await expect(this.allowButton).toBeHidden({ timeout: 25000 });
117141
+ await this.page.waitForLoadState("domcontentloaded", { timeout: 20000 });
117142
+ await this.page.waitForURL(redirectUrl, {
117143
+ timeout: 15000,
117144
+ });
117145
+ await this.completeSlackChannelSetup(channelToConfigure, customSteps);
117146
+ };
117147
+ this.connectAndVerifyIntegration = async (redirectUrl, customSteps, channelToConfigure = SLACK_DEFAULT_CHANNEL) => {
117148
+ IS_DEV_ENV
117149
+ ? await this.connectAndVerifyInDev(redirectUrl, channelToConfigure, customSteps)
117150
+ : await this.connectAndVerifyInStaging(redirectUrl, channelToConfigure, customSteps);
117151
+ };
117152
+ this.completeSlackChannelSetup = async (channelToConfigure, customSteps) => {
117113
117153
  await this.neetoPlaywrightUtilities.waitForPageLoad();
117114
117154
  await expect(this.page.getByRole("heading", {
117115
117155
  name: this.t("neetoSlack.slack.configure.title", {
117116
- teamName: currentWorkspace,
117156
+ teamName: this.currentWorkspace,
117117
117157
  }),
117118
117158
  })).toBeVisible({ timeout: 10000 });
117119
117159
  await this.neetoPlaywrightUtilities.selectOptionFromDropdown({
@@ -117122,14 +117162,17 @@ class SlackPage extends IntegrationBase {
117122
117162
  await this.page
117123
117163
  .getByRole("button", { name: this.t("neetoSlack.common.continue") })
117124
117164
  .click();
117125
- await this.neetoPlaywrightUtilities.waitForPageLoad();
117165
+ await Promise.all([
117166
+ this.neetoPlaywrightUtilities.waitForPageLoad(),
117167
+ this.neetoPlaywrightUtilities.verifyToast(),
117168
+ ]);
117126
117169
  if (customSteps) {
117127
117170
  await customSteps();
117128
117171
  }
117129
117172
  else {
117130
117173
  await expect(this.page.getByRole("heading", {
117131
117174
  name: this.t("neetoSlack.slack.finish.title", {
117132
- teamName: currentWorkspace,
117175
+ teamName: this.currentWorkspace,
117133
117176
  }),
117134
117177
  })).toBeVisible();
117135
117178
  await this.page
@@ -117256,6 +117299,9 @@ class SlackPage extends IntegrationBase {
117256
117299
  .click();
117257
117300
  await expect(channelItem).toBeHidden();
117258
117301
  };
117302
+ this.allowButton = this.page.getByRole("button", {
117303
+ name: SLACK_WEB_TEXTS.allow,
117304
+ });
117259
117305
  }
117260
117306
  }
117261
117307
 
@@ -119388,7 +119434,9 @@ class CustomDomainPage {
119388
119434
  ]);
119389
119435
  await this.neetoPlaywrightUtilities.waitForPageLoad();
119390
119436
  await validateButton.click();
119391
- await expect(this.page.getByTestId(COMMON_SELECTORS.calloutElement)).toBeVisible({ timeout: 15000 });
119437
+ await expect
119438
+ .soft(this.page.getByTestId(COMMON_SELECTORS.calloutElement))
119439
+ .toBeVisible({ timeout: 15000 });
119392
119440
  let isCertificateLimitExceeded = false;
119393
119441
  await expect(async () => {
119394
119442
  isCertificateLimitExceeded = await this.isCertificateLimitExceeded();