@bigbinary/neeto-playwright-commons 1.23.9 → 1.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -6,7 +6,7 @@ import test, { expect, test as test$1, chromium as chromium$1, defineConfig, dev
6
6
  import { getI18nInstance, initI18n } from 'playwright-i18next-fixture';
7
7
  import require$$0$4 from 'util';
8
8
  import { curry, not, isEmpty, pluck, mergeDeepLeft, isNil, isNotNil, mergeAll } from 'ramda';
9
- import { hyphenate, isPresent, isNotPresent, isNotEmpty, humanize, keysToSnakeCase, dynamicArray, truncate, findBy, isNotEqualDeep, randomPick } from '@bigbinary/neeto-cist';
9
+ import { hyphenate, isPresent, isNotPresent, humanize, keysToSnakeCase, dynamicArray, truncate, isNotEmpty, findBy, isNotEqualDeep, randomPick } from '@bigbinary/neeto-cist';
10
10
  import { execSync } from 'child_process';
11
11
  import { faker } from '@faker-js/faker';
12
12
  import dayjs from 'dayjs';
@@ -81,6 +81,11 @@ const THIRD_PARTY_ROUTES = {
81
81
  slack: {
82
82
  loginWithPassword: (workspace) => `https://${workspace}.slack.com/sign_in_with_password`,
83
83
  },
84
+ microsoft: {
85
+ login: "https://login.microsoftonline.com/",
86
+ myApps: "https://myapplications.microsoft.com/",
87
+ staySignedIn: "https://login.microsoftonline.com/common/SAS/ProcessAuth",
88
+ },
84
89
  zapier: {
85
90
  login: "https://zapier.com/",
86
91
  logOut: "https://zapier.com/logout",
@@ -133,6 +138,30 @@ class CustomDomainApi {
133
138
  }
134
139
  }
135
140
 
141
+ const IP_RESTRICTIONS_BASE_URL = `ip_restrictions${BASE_URL}/ip_restriction`;
142
+ class IpRestrictionsApi {
143
+ constructor(neetoPlaywrightUtilities) {
144
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
145
+ this.enable = ({ ipStart, ipEnd, addressType }) => this.neetoPlaywrightUtilities.apiRequest({
146
+ url: IP_RESTRICTIONS_BASE_URL,
147
+ method: "patch",
148
+ body: {
149
+ ip_restriction: {
150
+ is_ip_restriction_enabled: true,
151
+ allowed_ip_ranges: [
152
+ { ip_start: ipStart, ip_end: ipEnd, address_type: addressType },
153
+ ],
154
+ },
155
+ },
156
+ });
157
+ this.disable = () => this.neetoPlaywrightUtilities.apiRequest({
158
+ body: { ip_restriction: { is_ip_restriction_enabled: false } },
159
+ url: IP_RESTRICTIONS_BASE_URL,
160
+ method: "patch",
161
+ });
162
+ }
163
+ }
164
+
136
165
  class MemberApis {
137
166
  constructor(neetoPlaywrightUtilities) {
138
167
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
@@ -4606,7 +4635,7 @@ const writeDataToFile = data => {
4606
4635
  require$$0$3.writeFileSync(STORAGE_STATE, data, "utf8");
4607
4636
  }
4608
4637
  catch (error) {
4609
- console.log(error); // eslint-disable-line
4638
+ console.log(error);
4610
4639
  }
4611
4640
  return true;
4612
4641
  };
@@ -4619,7 +4648,7 @@ const removeCredentialFile = () => {
4619
4648
  require$$0$3.unlink(STORAGE_STATE, error => {
4620
4649
  if (!error)
4621
4650
  return;
4622
- console.log(error); // eslint-disable-line
4651
+ console.log(error);
4623
4652
  });
4624
4653
  };
4625
4654
  const clearCredentials = () => {
@@ -5248,6 +5277,7 @@ const IP_RESTRICTIONS_SELECTORS = {
5248
5277
  ipStartInpError: "ip-start-input-error",
5249
5278
  ipEndInpError: "ip-end-input-error",
5250
5279
  typeSelectError: "type-select-error",
5280
+ resetButton: "ip-restriction-reset-button",
5251
5281
  };
5252
5282
 
5253
5283
  const DATE_PICKER_SELECTORS = {
@@ -5274,6 +5304,15 @@ const NEETO_SEO_SELECTORS = {
5274
5304
  configureButton: "neeto-seo-configure-button",
5275
5305
  };
5276
5306
 
5307
+ const MICROSOFT_LOGIN_SELECTORS = {
5308
+ acceptButton: '[data-report-event="Signin_Submit"]',
5309
+ cancelButton: 'input[type="button"]',
5310
+ signInProfileIcon: "#mectrl_headerPicture",
5311
+ emailInput: '[type="email"]',
5312
+ placeholder: ".placeholderInnerContainer",
5313
+ dropdownMenu: "button[aria-label='NeetoForm - Stagingapp context menu']",
5314
+ };
5315
+
5277
5316
  const mimeTypeMap = {
5278
5317
  csv: "text/csv",
5279
5318
  avi: "video/x-msvideo",
@@ -5338,24 +5377,19 @@ class CustomCommands {
5338
5377
  .getAttribute("content");
5339
5378
  return this.csrfToken;
5340
5379
  };
5341
- /**
5342
- * @deprecated Use UI assertions instead.
5343
- */
5344
- this.interceptMultipleResponses = ({ responseUrl = "", responseStatus = 200, times = 1, baseUrl, customPageContext, timeout = 35000, } = {}) => {
5345
- const pageContext = customPageContext !== null && customPageContext !== void 0 ? customPageContext : this.page;
5346
- return Promise.all([...new Array(times)].map(() => pageContext.waitForResponse((response) => {
5347
- var _a, _b, _c;
5348
- if (response.request().resourceType() === "xhr" &&
5349
- response.status() === responseStatus &&
5350
- response.url().includes(responseUrl) &&
5351
- response.url().startsWith((_a = baseUrl !== null && baseUrl !== void 0 ? baseUrl : this.baseURL) !== null && _a !== void 0 ? _a : "") &&
5352
- !this.responses.includes((_b = response.headers()) === null || _b === void 0 ? void 0 : _b["x-request-id"])) {
5353
- this.responses.push((_c = response.headers()) === null || _c === void 0 ? void 0 : _c["x-request-id"]);
5354
- return true;
5355
- }
5356
- return false;
5357
- }, { timeout })));
5358
- };
5380
+ this.waitForFloatingMenu = () => expect(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton)).toBeVisible({ timeout: 25000 });
5381
+ this.interceptMultipleResponses = ({ responseUrl = "", responseStatus = 200, times = 1, baseUrl, customPageContext = this.page, timeout = 35000, } = {}) => Promise.all([...new Array(times)].map(() => customPageContext.waitForResponse((response) => {
5382
+ var _a, _b, _c;
5383
+ if (response.request().resourceType() === "xhr" &&
5384
+ response.status() === responseStatus &&
5385
+ response.url().includes(responseUrl) &&
5386
+ response.url().startsWith((_a = baseUrl !== null && baseUrl !== void 0 ? baseUrl : this.baseURL) !== null && _a !== void 0 ? _a : "") &&
5387
+ !this.responses.includes((_b = response.headers()) === null || _b === void 0 ? void 0 : _b["x-request-id"])) {
5388
+ this.responses.push((_c = response.headers()) === null || _c === void 0 ? void 0 : _c["x-request-id"]);
5389
+ return true;
5390
+ }
5391
+ return false;
5392
+ }, { timeout })));
5359
5393
  this.recursiveMethod = async (callback, condition, timeout, startTime, iteration) => {
5360
5394
  if (Date.now() - timeout >= startTime) {
5361
5395
  await callback();
@@ -5391,9 +5425,7 @@ class CustomCommands {
5391
5425
  /**
5392
5426
  * @deprecated Use reload & waitForPageLoad instead.
5393
5427
  */
5394
- this.reloadAndWait = async (
5395
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
5396
- requestCount, customPageContext = this.page,
5428
+ this.reloadAndWait = async (requestCount, customPageContext = this.page,
5397
5429
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5398
5430
  interceptMultipleResponsesProps = {}) => {
5399
5431
  await customPageContext.reload();
@@ -5433,24 +5465,23 @@ class CustomCommands {
5433
5465
  return await this.request[method](formattedUrl, requestOptions);
5434
5466
  };
5435
5467
  this.selectOptionFromDropdown = async ({ label = "nui", value, page = this.page, options = {}, }) => {
5436
- const selectValueContainerSelector = COMMON_SELECTORS.customSelectValueContainer(label);
5437
- const selectMenuSelector = COMMON_SELECTORS.customDropDownMenu(label);
5438
5468
  Object.assign({
5439
5469
  visibilityTimeout: 2000,
5440
5470
  textAssertionTimeout: 1000,
5441
5471
  retryTimeout: 20000,
5442
5472
  }, options);
5473
+ const menu = page.getByTestId(COMMON_SELECTORS.customDropDownMenu(label));
5474
+ const container = page.getByTestId(COMMON_SELECTORS.customSelectValueContainer(label));
5443
5475
  await expect(async () => {
5444
- await page.getByTestId(selectValueContainerSelector).click();
5445
- await expect(page.getByTestId(selectMenuSelector)).toBeVisible({
5476
+ await container.click();
5477
+ await expect(menu).toBeVisible({
5446
5478
  timeout: options.visibilityTimeout,
5447
5479
  });
5448
5480
  await page.keyboard.type(value);
5449
- await page
5450
- .getByTestId(selectMenuSelector)
5451
- .getByText(value, { exact: true })
5452
- .click();
5453
- await expect(page.getByTestId(selectValueContainerSelector)).toContainText(value, { timeout: options.textAssertionTimeout });
5481
+ await menu.getByText(value, { exact: true }).click();
5482
+ await expect(container).toContainText(value, {
5483
+ timeout: options.textAssertionTimeout,
5484
+ });
5454
5485
  }).toPass({ timeout: options.retryTimeout });
5455
5486
  };
5456
5487
  this.verifyFieldValue = values => {
@@ -113269,16 +113300,11 @@ const i18nFixture = {
113269
113300
  ],
113270
113301
  };
113271
113302
 
113303
+ /**
113304
+ * @deprecated
113305
+ */
113272
113306
  class AdminPanelPage {
113273
113307
  constructor(page, neetoPlaywrightUtilities) {
113274
- /**
113275
- * @deprecated This method is deprecated. Use assertCardDetails from neetoPlaywrightUtilities instead.
113276
- */
113277
- this.verifyAdminPanelCard = ({ cardLocator, title, description, }) => Promise.all([
113278
- expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemHeading)).toHaveText(title),
113279
- expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemDescription)).toHaveText(description),
113280
- expect(this.page.getByTestId(COMMON_SELECTORS.sidebarSubLink(title))).toHaveCSS("background-color", COLOR.transparent),
113281
- ]);
113282
113308
  this.page = page;
113283
113309
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
113284
113310
  this.t = getI18nInstance().t;
@@ -113359,26 +113385,6 @@ class ThankYouPage {
113359
113385
 
113360
113386
  class EmbedBase {
113361
113387
  constructor({ context, page, neetoPlaywrightUtilities, appName, }) {
113362
- /**
113363
- * @deprecated This method is deprecated. Use initializeEmbedPage instead.
113364
- */
113365
- this.initializeEmbedPageV2 = async ({ embedType, embedCode, customElementText = "Click here", }) => {
113366
- this.embedTestPage = await this.context.newPage();
113367
- this.embedTestPageType = embedType;
113368
- const fileContent = basicHTMLContent(this.embedTestPageType === "elementPopup"
113369
- ? `${embedCode}<a href='#' id='open-popup-button'>${customElementText}</a>`
113370
- : embedCode);
113371
- this.filePath = `tmp/${faker.word.noun()}.html`;
113372
- writeFileSync(this.filePath, fileContent, "utf8");
113373
- await this.embedTestPage.goto(`file://${path__default.resolve(this.filePath)}`, {
113374
- timeout: 20000,
113375
- });
113376
- await this.embedTestPage.waitForLoadState("load");
113377
- this.embeddedFrame = this.embedTestPage.frameLocator(this.embedTestPageType === "inline" || this.embedTestPageType === "iframe"
113378
- ? "iframe"
113379
- : EMBED_SELECTORS.iframe(this.appName));
113380
- return this.embedTestPage;
113381
- };
113382
113388
  this.initializeEmbedPage = async ({ embedType, embedCode, customElementText = "Click here", }) => {
113383
113389
  this.embedTestPage = await this.context.newPage();
113384
113390
  this.embedTestPageType = embedType;
@@ -113421,26 +113427,11 @@ class EmbedBase {
113421
113427
  });
113422
113428
  }).toPass({ timeout: 2 * 60 * 1000 });
113423
113429
  };
113424
- /**
113425
- * @deprecated This method is deprecated. Use copyEmbedScript instead.
113426
- */
113427
- this.copyEmbedScriptV2 = async (embedType) => {
113428
- await this.selectEmbedType(embedType);
113429
- await this.page.getByTestId(COMMON_SELECTORS.copyButton).click();
113430
- return await this.page.evaluate(() => navigator.clipboard.readText());
113431
- };
113432
113430
  this.copyEmbedScript = async (embedType) => {
113433
113431
  await this.selectEmbedType(embedType);
113434
113432
  await this.page.getByTestId(COMMON_SELECTORS.copyButton).click();
113435
113433
  return await this.page.evaluate(() => navigator.clipboard.readText());
113436
113434
  };
113437
- /**
113438
- * @deprecated This method is deprecated. Use selectEmbedType instead.
113439
- */
113440
- this.selectEmbedTypeV2 = async (embedType) => {
113441
- await this.page.locator(EMBED_SELECTORS.embedSelector(embedType)).click();
113442
- await this.neetoPlaywrightUtilities.waitForPageLoad();
113443
- };
113444
113435
  this.selectEmbedType = async (embedType) => {
113445
113436
  await this.page.locator(EMBED_SELECTORS.embedSelector(embedType)).click();
113446
113437
  await this.neetoPlaywrightUtilities.waitForPageLoad();
@@ -113612,6 +113603,20 @@ const ZAPIER_LIMIT_EXHAUSTED_MESSAGE = "Zapier free task limit is exhausted. Tes
113612
113603
  const EMOJI_LABEL = "thumbs up";
113613
113604
  const SELECT_COUNTRY = "Select country";
113614
113605
  const GOOGLE_CALENDAR_DATE_FORMAT = "YYYY/M/D";
113606
+ const MICROSOFT_LOGIN_TEXTS = {
113607
+ passwordInput: "Enter the password",
113608
+ emailInput: "Enter your email",
113609
+ enterCode: "Enter code",
113610
+ verify: "Verify",
113611
+ staySignedIn: "Stay signed in?",
113612
+ signIn: "Sign in",
113613
+ next: "Next",
113614
+ enterPassword: "Enter password",
113615
+ password: "Password",
113616
+ permissionsRequested: "Permissions requested",
113617
+ yes: "Yes",
113618
+ remove: "Remove",
113619
+ };
113615
113620
  const GOOGLE_LOGIN_TEXTS = {
113616
113621
  googleAccount: "Google Account:",
113617
113622
  connectYourGoogleAccount: "Connect your Google account",
@@ -116021,11 +116026,11 @@ class IntegrationBase {
116021
116026
  });
116022
116027
  };
116023
116028
  this.gotoIntegrationIndex = async () => {
116024
- if (isNotEmpty(this.integrationRouteIndex)) {
116025
- await this.page.goto(this.integrationRouteIndex, { timeout: 20000 });
116026
- await expect(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton)).toBeVisible({ timeout: 25000 });
116027
- await this.neetoPlaywrightUtilities.waitForPageLoad();
116028
- }
116029
+ if (isEmpty(this.integrationRouteIndex))
116030
+ return;
116031
+ await this.page.goto(this.integrationRouteIndex, { timeout: 20000 });
116032
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
116033
+ await this.neetoPlaywrightUtilities.waitForPageLoad();
116029
116034
  };
116030
116035
  this.page = page;
116031
116036
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
@@ -116127,14 +116132,24 @@ class GooglePage extends IntegrationBase {
116127
116132
  await this.page.waitForLoadState("load", { timeout: 25000 });
116128
116133
  await this.page.waitForURL(new RegExp(THIRD_PARTY_ROUTES.google.myAccount));
116129
116134
  };
116130
- this.enterTotpCode = (locator) => expect(async () => {
116131
- const totpToken = this.totp.generate({ timestamp: Date.now() + 5000 });
116132
- await this.page.getByLabel(GOOGLE_LOGIN_TEXTS.enterCode).fill(totpToken);
116133
- expect(this.totp.validate({ token: totpToken })).not.toBeNull();
116134
- await this.page.locator(GOOGLE_LOGIN_SELECTORS.totpNext).click();
116135
- await expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({ timeout: 15000 });
116136
- await expect(locator).toBeHidden({ timeout: 10000 });
116137
- }).toPass({ timeout: 50000 });
116135
+ this.enterTotpCode = async (locator) => {
116136
+ let previousToken = null;
116137
+ await expect(async () => {
116138
+ let totpToken = this.totp.generate({ timestamp: Date.now() });
116139
+ if (totpToken === previousToken) {
116140
+ const remainingTime = this.totp.remaining({ timestamp: Date.now() });
116141
+ // eslint-disable-next-line playwright/no-wait-for-timeout
116142
+ await this.page.waitForTimeout(remainingTime + 500); // Wait for the remaining time plus a small buffer (500ms) to ensure new token
116143
+ totpToken = this.totp.generate({ timestamp: Date.now() });
116144
+ }
116145
+ previousToken = totpToken;
116146
+ await this.page.getByLabel(GOOGLE_LOGIN_TEXTS.enterCode).fill(totpToken);
116147
+ expect(this.totp.validate({ token: totpToken })).not.toBeNull();
116148
+ await this.page.locator(GOOGLE_LOGIN_SELECTORS.totpNext).click();
116149
+ await expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({ timeout: 10000 });
116150
+ await expect(locator).toBeHidden({ timeout: 10000 });
116151
+ }).toPass({ timeout: 2 * 60 * 1000 });
116152
+ };
116138
116153
  this.logoutFromGoogle = async () => {
116139
116154
  await this.page.goto(THIRD_PARTY_ROUTES.google.myAccount, {
116140
116155
  timeout: 20000,
@@ -116208,7 +116223,113 @@ class GooglePage extends IntegrationBase {
116208
116223
  }
116209
116224
  }
116210
116225
 
116211
- /* eslint-disable playwright/no-raw-locators */
116226
+ class MicrosoftPage extends IntegrationBase {
116227
+ constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, integration = "", }) {
116228
+ super({
116229
+ page,
116230
+ neetoPlaywrightUtilities,
116231
+ integrationRouteIndex,
116232
+ integration,
116233
+ });
116234
+ this.stagingConsentFlow = async (abortFlow = false) => {
116235
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116236
+ await expect(this.page.getByRole("heading", {
116237
+ name: MICROSOFT_LOGIN_TEXTS.permissionsRequested,
116238
+ })).toBeVisible({ timeout: 20000 });
116239
+ await this.page
116240
+ .locator(abortFlow
116241
+ ? MICROSOFT_LOGIN_SELECTORS.cancelButton
116242
+ : MICROSOFT_LOGIN_SELECTORS.acceptButton)
116243
+ .click();
116244
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116245
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
116246
+ };
116247
+ this.enterEmail = async () => {
116248
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116249
+ await expect(this.page.getByRole("heading", { name: MICROSOFT_LOGIN_TEXTS.signIn })).toBeVisible({ timeout: 20000 });
116250
+ await this.page
116251
+ .locator(MICROSOFT_LOGIN_SELECTORS.emailInput)
116252
+ .or(this.page.locator(MICROSOFT_LOGIN_SELECTORS.placeholder))
116253
+ .or(this.page.getByRole("textbox", {
116254
+ name: MICROSOFT_LOGIN_TEXTS.emailInput,
116255
+ }))
116256
+ .pressSequentially(process.env.MICROSOFT_LOGIN_EMAIL, { delay: 25 });
116257
+ };
116258
+ this.enterPassword = async () => {
116259
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116260
+ await expect(this.page.getByRole("heading", {
116261
+ name: MICROSOFT_LOGIN_TEXTS.enterPassword,
116262
+ })).toBeVisible({ timeout: 10000 });
116263
+ await this.page
116264
+ .getByPlaceholder(MICROSOFT_LOGIN_TEXTS.password)
116265
+ .or(this.page.locator(MICROSOFT_LOGIN_SELECTORS.placeholder))
116266
+ .or(this.page.getByRole("textbox", {
116267
+ name: MICROSOFT_LOGIN_TEXTS.passwordInput,
116268
+ }))
116269
+ .pressSequentially(process.env.MICROSOFT_LOGIN_PASSWORD, { delay: 15 });
116270
+ };
116271
+ this.loginToMicrosoft = async () => {
116272
+ if (isNil(process.env.MICROSOFT_LOGIN_EMAIL) ||
116273
+ isNil(process.env.MICROSOFT_LOGIN_PASSWORD) ||
116274
+ isNil(process.env.MICROSOFT_2FA_SECRET_KEY)) {
116275
+ throw new Error("ENV variable MICROSOFT_LOGIN_EMAIL or MICROSOFT_LOGIN_PASSWORD or MICROSOFT_2FA_SECRET_KEY is not properly configured");
116276
+ }
116277
+ await this.page.goto(THIRD_PARTY_ROUTES.microsoft.login);
116278
+ await this.enterEmail();
116279
+ await this.page
116280
+ .getByRole("button", { name: MICROSOFT_LOGIN_TEXTS.next })
116281
+ .click();
116282
+ await this.enterPassword();
116283
+ await this.page
116284
+ .getByRole("button", { name: MICROSOFT_LOGIN_TEXTS.signIn })
116285
+ .click();
116286
+ await this.enterTotpCode();
116287
+ await this.staySignedIn();
116288
+ };
116289
+ this.enterTotpCode = async () => {
116290
+ const verifyBtn = this.page.getByRole("button", {
116291
+ name: MICROSOFT_LOGIN_TEXTS.verify,
116292
+ });
116293
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116294
+ await expect(async () => {
116295
+ const token = this.totp.generate({ timestamp: Date.now() + 5000 });
116296
+ await this.page.getByLabel(MICROSOFT_LOGIN_TEXTS.enterCode).fill(token);
116297
+ expect(this.totp.validate({ token })).not.toBeNull();
116298
+ await verifyBtn.click();
116299
+ await expect(this.page.getByRole("alert")).toBeHidden();
116300
+ await expect(verifyBtn).toBeHidden();
116301
+ }).toPass({ timeout: 60 * 1000, intervals: [10000] });
116302
+ };
116303
+ this.staySignedIn = async () => {
116304
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116305
+ await this.page.waitForURL(THIRD_PARTY_ROUTES.microsoft.staySignedIn);
116306
+ await expect(this.page.getByRole("heading", {
116307
+ name: MICROSOFT_LOGIN_TEXTS.staySignedIn,
116308
+ })).toBeVisible({ timeout: 15000 });
116309
+ const acceptBtn = this.page.locator(MICROSOFT_LOGIN_SELECTORS.acceptButton);
116310
+ await acceptBtn.click();
116311
+ await expect(acceptBtn).toBeHidden({ timeout: 10000 });
116312
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116313
+ };
116314
+ this.revokePermissions = async () => {
116315
+ await this.page.goto(THIRD_PARTY_ROUTES.microsoft.myApps);
116316
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116317
+ const dropdown = this.page.locator(MICROSOFT_LOGIN_SELECTORS.dropdownMenu);
116318
+ await dropdown.click();
116319
+ await this.page
116320
+ .getByRole("menuitem", { name: MICROSOFT_LOGIN_TEXTS.remove })
116321
+ .click();
116322
+ await expect(dropdown).toBeHidden({ timeout: 10000 });
116323
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116324
+ };
116325
+ this.mailerUtils = new MailerUtils(neetoPlaywrightUtilities);
116326
+ this.totp = initializeTotp({
116327
+ issuer: "Microsoft",
116328
+ secret: process.env.MICROSOFT_2FA_SECRET_KEY,
116329
+ });
116330
+ }
116331
+ }
116332
+
116212
116333
  class SlackPage extends IntegrationBase {
116213
116334
  constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, }) {
116214
116335
  super({
@@ -116257,6 +116378,7 @@ class SlackPage extends IntegrationBase {
116257
116378
  await this.page
116258
116379
  .getByRole("button", { name: this.t("neetoSlack.common.continue") })
116259
116380
  .click();
116381
+ await this.neetoPlaywrightUtilities.waitForPageLoad();
116260
116382
  if (customSteps) {
116261
116383
  await customSteps();
116262
116384
  }
@@ -116276,11 +116398,7 @@ class SlackPage extends IntegrationBase {
116276
116398
  await this.disconnect();
116277
116399
  await this.verifyIntegrationStatus("disconnected");
116278
116400
  };
116279
- this.updateConfigureSlackChannel = async ({ newSlackChannel = "random",
116280
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
116281
- interceptMultipleResponsesParams = {},
116282
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
116283
- refreshInterceptMultipleResponsesParams = {}, refreshChannelList = false, }) => {
116401
+ this.updateConfigureSlackChannel = async ({ newSlackChannel = "random", refreshChannelList = false, }) => {
116284
116402
  await this.page.getByTestId(INTEGRATION_SELECTORS.manageButton).click();
116285
116403
  await this.page
116286
116404
  .getByRole("button", { name: this.t("neetoSlack.common.edit") })
@@ -116346,17 +116464,16 @@ class SlackPage extends IntegrationBase {
116346
116464
  })
116347
116465
  .click();
116348
116466
  };
116349
- this.goToSlackChannel = async (slackChannel) => {
116350
- await this.slackWebappPage
116351
- .locator(SLACK_SELECTORS.virtualListItem, { hasText: slackChannel })
116352
- .click();
116353
- };
116467
+ this.goToSlackChannel = (slackChannel) => this.slackWebappPage
116468
+ .locator(SLACK_SELECTORS.virtualListItem, { hasText: slackChannel })
116469
+ .click();
116354
116470
  this.createNewSlackChannel = async ({ channelName, kind = "public", }) => {
116355
116471
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.sectionHeadingButton).click();
116356
116472
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelSectionSubmenuCreate).click();
116357
116473
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelSectionMenuCreateChannel).click();
116474
+ const spinner = this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner);
116358
116475
  await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)).toBeVisible();
116359
- await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner)).toBeHidden();
116476
+ await expect(spinner).toBeHidden();
116360
116477
  await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelNameOptionsList)).toBeHidden({ timeout: 5000 });
116361
116478
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)
116362
116479
  .getByText(SLACK_WEB_TEXTS.name, { exact: true })
@@ -116365,13 +116482,14 @@ class SlackPage extends IntegrationBase {
116365
116482
  SLACK_DATA_QA_SELECTORS.skModalContent,
116366
116483
  SLACK_DATA_QA_SELECTORS.channelNameInput,
116367
116484
  ]).pressSequentially(channelName);
116368
- await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner)).toBeHidden();
116369
- await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton)).toBeEnabled();
116370
- await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton).click();
116485
+ const nextButton = this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton);
116486
+ await expect(spinner).toBeHidden();
116487
+ await expect(nextButton).toBeEnabled();
116488
+ await nextButton.click();
116371
116489
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)
116372
116490
  .getByRole("radio", { name: kind })
116373
116491
  .check();
116374
- await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton).click();
116492
+ await nextButton.click();
116375
116493
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.inviteToWorkspaceSkipButton).click();
116376
116494
  };
116377
116495
  this.deleteSlackChannel = async (channel) => {
@@ -117505,9 +117623,7 @@ class TeamMembers {
117505
117623
  }).toPass({ timeout: 40000 });
117506
117624
  await this.neetoPlaywrightUtilities.verifyToast();
117507
117625
  };
117508
- this.searchAndVerifyMemberByEmail = async ({ email,
117509
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
117510
- interceptOptions = {}, }) => {
117626
+ this.searchAndVerifyMemberByEmail = async ({ email }) => {
117511
117627
  await this.neetoPlaywrightUtilities.waitForPageLoad();
117512
117628
  await this.page.getByTestId(MEMBER_SELECTORS.searchTextField).fill(email);
117513
117629
  const emailSubstr = email.length > 20 ? email.substring(0, 20) : email;
@@ -118142,6 +118258,69 @@ class CustomDomainPage {
118142
118258
  }
118143
118259
  }
118144
118260
 
118261
+ class IPRestrictionsPage {
118262
+ constructor(page, neetoPlaywrightUtilities) {
118263
+ this.page = page;
118264
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
118265
+ this.setIPRange = async (ipRange, type, index = 0) => {
118266
+ await this.page
118267
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipStartTextField)
118268
+ // Using nth methods here as it determines which input to interact with
118269
+ // eslint-disable-next-line playwright/no-nth-methods
118270
+ .nth(index)
118271
+ .fill(ipRange[0]);
118272
+ await this.page
118273
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipEndTextField)
118274
+ // Using nth methods here as it determines which input to interact with
118275
+ // eslint-disable-next-line playwright/no-nth-methods
118276
+ .nth(index)
118277
+ .fill(ipRange[1]);
118278
+ if (!isPresent(type))
118279
+ return;
118280
+ await this.page
118281
+ .getByTestId(COMMON_SELECTORS.customSelectContainer("type"))
118282
+ // Using nth methods here as it determines which dropdown to interact with
118283
+ // eslint-disable-next-line playwright/no-nth-methods
118284
+ .nth(index)
118285
+ .fill(type);
118286
+ await this.page.keyboard.press("Enter");
118287
+ await expect(this.page
118288
+ .getByTestId(COMMON_SELECTORS.customSelectValueContainer("type"))
118289
+ // Using nth methods here as it determines which dropdown to interact with
118290
+ // eslint-disable-next-line playwright/no-nth-methods
118291
+ .nth(index)).toContainText(type);
118292
+ };
118293
+ this.saveChanges = async () => {
118294
+ await this.saveButton.click();
118295
+ await this.neetoPlaywrightUtilities.clickButtonAndAwaitLoad({
118296
+ locator: this.page.getByTestId(COMMON_SELECTORS.alertModalSubmitButton),
118297
+ });
118298
+ };
118299
+ this.disableIPRestriction = async () => {
118300
+ if (!this.page.url().includes(ROUTES.adminPanel.ipRestriction))
118301
+ return;
118302
+ const enableCheckbox = this.page.getByTestId(IP_RESTRICTIONS_SELECTORS.enableIPRestrictionChk);
118303
+ const [isChecked, isSaveDisabled, isDeleteHidden] = await Promise.all([
118304
+ enableCheckbox.isChecked(),
118305
+ this.saveButton.isDisabled(),
118306
+ this.page
118307
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipRangeDeleteBtn)
118308
+ .isHidden(),
118309
+ ]);
118310
+ if (isChecked && (isSaveDisabled || isDeleteHidden)) {
118311
+ await enableCheckbox.click();
118312
+ if (await this.saveButton.isEnabled()) {
118313
+ await this.saveButton.click();
118314
+ await this.neetoPlaywrightUtilities.verifyToast();
118315
+ }
118316
+ }
118317
+ };
118318
+ this.t = getI18nInstance().t;
118319
+ this.ipRestrictionsApi = new IpRestrictionsApi(this.neetoPlaywrightUtilities);
118320
+ this.saveButton = this.page.getByTestId(IP_RESTRICTIONS_SELECTORS.saveChanges);
118321
+ }
118322
+ }
118323
+
118145
118324
  class RolesPage {
118146
118325
  constructor(page, neetoPlaywrightUtilities) {
118147
118326
  this.getPermissionIds = async (targetPermissions, isGranularPermission = false) => {
@@ -118205,11 +118384,6 @@ class RolesPage {
118205
118384
  this.neetoPlaywrightUtilities.verifyToast(),
118206
118385
  ]);
118207
118386
  };
118208
- this.verifyAdminPanelCard = ({ cardLocator, title, description, }) => Promise.all([
118209
- expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemHeading)).toHaveText(title),
118210
- expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemDescription)).toHaveText(description),
118211
- expect(this.page.getByTestId(COMMON_SELECTORS.sidebarSubLink(title))).toHaveCSS("background-color", COLOR.transparent),
118212
- ]);
118213
118387
  this.deleteRoleViaUI = async (roleName) => {
118214
118388
  await this.neetoPlaywrightUtilities.waitForPageLoad();
118215
118389
  await this.page.getByTestId(ROLES_SELECTORS.searchTextField).fill(roleName);
@@ -118238,17 +118412,11 @@ class RolesPage {
118238
118412
  if (isNotEqualDeep(roleAccessableLinks, adminAccessableLinks)) {
118239
118413
  for (const link of adminAccessableLinks) {
118240
118414
  await this.page.goto(link);
118241
- await expect
118242
- .soft(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton))
118243
- .toBeVisible({ timeout: 15000 });
118415
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
118244
118416
  await this.neetoPlaywrightUtilities.waitForPageLoad();
118245
- await expect(this.page.locator(COMMON_SELECTORS.tableSpinner)).toBeHidden({ timeout: 35000 });
118246
- const unauthorizedHeading = this.page.getByRole("heading", {
118417
+ await expect(this.page.getByRole("heading", {
118247
118418
  name: this.t("neetoMolecules.errorPage.unauthorized"),
118248
- });
118249
- roleAccessableLinks.includes(link)
118250
- ? await expect(unauthorizedHeading).toBeHidden()
118251
- : await expect(unauthorizedHeading).toBeVisible();
118419
+ }))[roleAccessableLinks.includes(link) ? "toBeHidden" : "toBeVisible"]();
118252
118420
  }
118253
118421
  }
118254
118422
  };
@@ -123794,5 +123962,5 @@ const definePlaywrightConfig = (overrides) => {
123794
123962
  });
123795
123963
  };
123796
123964
 
123797
- export { ADMIN_PANEL_SELECTORS, API_KEYS_SELECTORS, API_ROUTES, AUDIT_LOGS_TEXTS, AdminPanelPage, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, 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, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXPANDED_FONT_SIZE, EditorPage, EmbedBase, FILE_FORMATS, FONT_SIZE_SELECTORS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IP_RESTRICTIONS_SELECTORS, IS_STAGING_ENV, ImageUploader, IntegrationBase, KEYBOARD_SHORTCUTS_SELECTORS, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MailerUtils, Member, MemberApis, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RoleApis, RolesPage, SELECT_COUNTRY, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SidebarSection, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouPage, USER_AGENTS, WEBHOOK_SELECTORS, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getListCount, globalShortcuts, grantClipboardPermissions, headerUtils, hexToRGB, hexToRGBA, hyphenize, i18nFixture, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, joinHyphenCase, joinString, login, loginWithoutSSO, networkConditions, networkThrottlingUsingCDP, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, writeDataToFile };
123965
+ export { ADMIN_PANEL_SELECTORS, API_KEYS_SELECTORS, API_ROUTES, AUDIT_LOGS_TEXTS, AdminPanelPage, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, 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, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXPANDED_FONT_SIZE, EditorPage, EmbedBase, FILE_FORMATS, FONT_SIZE_SELECTORS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, 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, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RoleApis, RolesPage, SELECT_COUNTRY, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SidebarSection, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouPage, USER_AGENTS, WEBHOOK_SELECTORS, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getListCount, globalShortcuts, grantClipboardPermissions, headerUtils, hexToRGB, hexToRGBA, hyphenize, i18nFixture, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, joinHyphenCase, joinString, login, loginWithoutSSO, networkConditions, networkThrottlingUsingCDP, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, writeDataToFile };
123798
123966
  //# sourceMappingURL=index.js.map