@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.cjs.js CHANGED
@@ -102,6 +102,11 @@ const THIRD_PARTY_ROUTES = {
102
102
  slack: {
103
103
  loginWithPassword: (workspace) => `https://${workspace}.slack.com/sign_in_with_password`,
104
104
  },
105
+ microsoft: {
106
+ login: "https://login.microsoftonline.com/",
107
+ myApps: "https://myapplications.microsoft.com/",
108
+ staySignedIn: "https://login.microsoftonline.com/common/SAS/ProcessAuth",
109
+ },
105
110
  zapier: {
106
111
  login: "https://zapier.com/",
107
112
  logOut: "https://zapier.com/logout",
@@ -154,6 +159,30 @@ class CustomDomainApi {
154
159
  }
155
160
  }
156
161
 
162
+ const IP_RESTRICTIONS_BASE_URL = `ip_restrictions${BASE_URL}/ip_restriction`;
163
+ class IpRestrictionsApi {
164
+ constructor(neetoPlaywrightUtilities) {
165
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
166
+ this.enable = ({ ipStart, ipEnd, addressType }) => this.neetoPlaywrightUtilities.apiRequest({
167
+ url: IP_RESTRICTIONS_BASE_URL,
168
+ method: "patch",
169
+ body: {
170
+ ip_restriction: {
171
+ is_ip_restriction_enabled: true,
172
+ allowed_ip_ranges: [
173
+ { ip_start: ipStart, ip_end: ipEnd, address_type: addressType },
174
+ ],
175
+ },
176
+ },
177
+ });
178
+ this.disable = () => this.neetoPlaywrightUtilities.apiRequest({
179
+ body: { ip_restriction: { is_ip_restriction_enabled: false } },
180
+ url: IP_RESTRICTIONS_BASE_URL,
181
+ method: "patch",
182
+ });
183
+ }
184
+ }
185
+
157
186
  class MemberApis {
158
187
  constructor(neetoPlaywrightUtilities) {
159
188
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
@@ -4627,7 +4656,7 @@ const writeDataToFile = data => {
4627
4656
  require$$0__namespace.writeFileSync(STORAGE_STATE, data, "utf8");
4628
4657
  }
4629
4658
  catch (error) {
4630
- console.log(error); // eslint-disable-line
4659
+ console.log(error);
4631
4660
  }
4632
4661
  return true;
4633
4662
  };
@@ -4640,7 +4669,7 @@ const removeCredentialFile = () => {
4640
4669
  require$$0__namespace.unlink(STORAGE_STATE, error => {
4641
4670
  if (!error)
4642
4671
  return;
4643
- console.log(error); // eslint-disable-line
4672
+ console.log(error);
4644
4673
  });
4645
4674
  };
4646
4675
  const clearCredentials = () => {
@@ -5269,6 +5298,7 @@ const IP_RESTRICTIONS_SELECTORS = {
5269
5298
  ipStartInpError: "ip-start-input-error",
5270
5299
  ipEndInpError: "ip-end-input-error",
5271
5300
  typeSelectError: "type-select-error",
5301
+ resetButton: "ip-restriction-reset-button",
5272
5302
  };
5273
5303
 
5274
5304
  const DATE_PICKER_SELECTORS = {
@@ -5295,6 +5325,15 @@ const NEETO_SEO_SELECTORS = {
5295
5325
  configureButton: "neeto-seo-configure-button",
5296
5326
  };
5297
5327
 
5328
+ const MICROSOFT_LOGIN_SELECTORS = {
5329
+ acceptButton: '[data-report-event="Signin_Submit"]',
5330
+ cancelButton: 'input[type="button"]',
5331
+ signInProfileIcon: "#mectrl_headerPicture",
5332
+ emailInput: '[type="email"]',
5333
+ placeholder: ".placeholderInnerContainer",
5334
+ dropdownMenu: "button[aria-label='NeetoForm - Stagingapp context menu']",
5335
+ };
5336
+
5298
5337
  const mimeTypeMap = {
5299
5338
  csv: "text/csv",
5300
5339
  avi: "video/x-msvideo",
@@ -5359,24 +5398,19 @@ class CustomCommands {
5359
5398
  .getAttribute("content");
5360
5399
  return this.csrfToken;
5361
5400
  };
5362
- /**
5363
- * @deprecated Use UI assertions instead.
5364
- */
5365
- this.interceptMultipleResponses = ({ responseUrl = "", responseStatus = 200, times = 1, baseUrl, customPageContext, timeout = 35000, } = {}) => {
5366
- const pageContext = customPageContext !== null && customPageContext !== void 0 ? customPageContext : this.page;
5367
- return Promise.all([...new Array(times)].map(() => pageContext.waitForResponse((response) => {
5368
- var _a, _b, _c;
5369
- if (response.request().resourceType() === "xhr" &&
5370
- response.status() === responseStatus &&
5371
- response.url().includes(responseUrl) &&
5372
- response.url().startsWith((_a = baseUrl !== null && baseUrl !== void 0 ? baseUrl : this.baseURL) !== null && _a !== void 0 ? _a : "") &&
5373
- !this.responses.includes((_b = response.headers()) === null || _b === void 0 ? void 0 : _b["x-request-id"])) {
5374
- this.responses.push((_c = response.headers()) === null || _c === void 0 ? void 0 : _c["x-request-id"]);
5375
- return true;
5376
- }
5377
- return false;
5378
- }, { timeout })));
5379
- };
5401
+ this.waitForFloatingMenu = () => test.expect(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton)).toBeVisible({ timeout: 25000 });
5402
+ this.interceptMultipleResponses = ({ responseUrl = "", responseStatus = 200, times = 1, baseUrl, customPageContext = this.page, timeout = 35000, } = {}) => Promise.all([...new Array(times)].map(() => customPageContext.waitForResponse((response) => {
5403
+ var _a, _b, _c;
5404
+ if (response.request().resourceType() === "xhr" &&
5405
+ response.status() === responseStatus &&
5406
+ response.url().includes(responseUrl) &&
5407
+ response.url().startsWith((_a = baseUrl !== null && baseUrl !== void 0 ? baseUrl : this.baseURL) !== null && _a !== void 0 ? _a : "") &&
5408
+ !this.responses.includes((_b = response.headers()) === null || _b === void 0 ? void 0 : _b["x-request-id"])) {
5409
+ this.responses.push((_c = response.headers()) === null || _c === void 0 ? void 0 : _c["x-request-id"]);
5410
+ return true;
5411
+ }
5412
+ return false;
5413
+ }, { timeout })));
5380
5414
  this.recursiveMethod = async (callback, condition, timeout, startTime, iteration) => {
5381
5415
  if (Date.now() - timeout >= startTime) {
5382
5416
  await callback();
@@ -5412,9 +5446,7 @@ class CustomCommands {
5412
5446
  /**
5413
5447
  * @deprecated Use reload & waitForPageLoad instead.
5414
5448
  */
5415
- this.reloadAndWait = async (
5416
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
5417
- requestCount, customPageContext = this.page,
5449
+ this.reloadAndWait = async (requestCount, customPageContext = this.page,
5418
5450
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5419
5451
  interceptMultipleResponsesProps = {}) => {
5420
5452
  await customPageContext.reload();
@@ -5454,24 +5486,23 @@ class CustomCommands {
5454
5486
  return await this.request[method](formattedUrl, requestOptions);
5455
5487
  };
5456
5488
  this.selectOptionFromDropdown = async ({ label = "nui", value, page = this.page, options = {}, }) => {
5457
- const selectValueContainerSelector = COMMON_SELECTORS.customSelectValueContainer(label);
5458
- const selectMenuSelector = COMMON_SELECTORS.customDropDownMenu(label);
5459
5489
  Object.assign({
5460
5490
  visibilityTimeout: 2000,
5461
5491
  textAssertionTimeout: 1000,
5462
5492
  retryTimeout: 20000,
5463
5493
  }, options);
5494
+ const menu = page.getByTestId(COMMON_SELECTORS.customDropDownMenu(label));
5495
+ const container = page.getByTestId(COMMON_SELECTORS.customSelectValueContainer(label));
5464
5496
  await test.expect(async () => {
5465
- await page.getByTestId(selectValueContainerSelector).click();
5466
- await test.expect(page.getByTestId(selectMenuSelector)).toBeVisible({
5497
+ await container.click();
5498
+ await test.expect(menu).toBeVisible({
5467
5499
  timeout: options.visibilityTimeout,
5468
5500
  });
5469
5501
  await page.keyboard.type(value);
5470
- await page
5471
- .getByTestId(selectMenuSelector)
5472
- .getByText(value, { exact: true })
5473
- .click();
5474
- await test.expect(page.getByTestId(selectValueContainerSelector)).toContainText(value, { timeout: options.textAssertionTimeout });
5502
+ await menu.getByText(value, { exact: true }).click();
5503
+ await test.expect(container).toContainText(value, {
5504
+ timeout: options.textAssertionTimeout,
5505
+ });
5475
5506
  }).toPass({ timeout: options.retryTimeout });
5476
5507
  };
5477
5508
  this.verifyFieldValue = values => {
@@ -113290,16 +113321,11 @@ const i18nFixture = {
113290
113321
  ],
113291
113322
  };
113292
113323
 
113324
+ /**
113325
+ * @deprecated
113326
+ */
113293
113327
  class AdminPanelPage {
113294
113328
  constructor(page, neetoPlaywrightUtilities) {
113295
- /**
113296
- * @deprecated This method is deprecated. Use assertCardDetails from neetoPlaywrightUtilities instead.
113297
- */
113298
- this.verifyAdminPanelCard = ({ cardLocator, title, description, }) => Promise.all([
113299
- test.expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemHeading)).toHaveText(title),
113300
- test.expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemDescription)).toHaveText(description),
113301
- test.expect(this.page.getByTestId(COMMON_SELECTORS.sidebarSubLink(title))).toHaveCSS("background-color", COLOR.transparent),
113302
- ]);
113303
113329
  this.page = page;
113304
113330
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
113305
113331
  this.t = playwrightI18nextFixture.getI18nInstance().t;
@@ -113380,26 +113406,6 @@ class ThankYouPage {
113380
113406
 
113381
113407
  class EmbedBase {
113382
113408
  constructor({ context, page, neetoPlaywrightUtilities, appName, }) {
113383
- /**
113384
- * @deprecated This method is deprecated. Use initializeEmbedPage instead.
113385
- */
113386
- this.initializeEmbedPageV2 = async ({ embedType, embedCode, customElementText = "Click here", }) => {
113387
- this.embedTestPage = await this.context.newPage();
113388
- this.embedTestPageType = embedType;
113389
- const fileContent = basicHTMLContent(this.embedTestPageType === "elementPopup"
113390
- ? `${embedCode}<a href='#' id='open-popup-button'>${customElementText}</a>`
113391
- : embedCode);
113392
- this.filePath = `tmp/${faker.faker.word.noun()}.html`;
113393
- require$$0$4.writeFileSync(this.filePath, fileContent, "utf8");
113394
- await this.embedTestPage.goto(`file://${path$1.resolve(this.filePath)}`, {
113395
- timeout: 20000,
113396
- });
113397
- await this.embedTestPage.waitForLoadState("load");
113398
- this.embeddedFrame = this.embedTestPage.frameLocator(this.embedTestPageType === "inline" || this.embedTestPageType === "iframe"
113399
- ? "iframe"
113400
- : EMBED_SELECTORS.iframe(this.appName));
113401
- return this.embedTestPage;
113402
- };
113403
113409
  this.initializeEmbedPage = async ({ embedType, embedCode, customElementText = "Click here", }) => {
113404
113410
  this.embedTestPage = await this.context.newPage();
113405
113411
  this.embedTestPageType = embedType;
@@ -113442,26 +113448,11 @@ class EmbedBase {
113442
113448
  });
113443
113449
  }).toPass({ timeout: 2 * 60 * 1000 });
113444
113450
  };
113445
- /**
113446
- * @deprecated This method is deprecated. Use copyEmbedScript instead.
113447
- */
113448
- this.copyEmbedScriptV2 = async (embedType) => {
113449
- await this.selectEmbedType(embedType);
113450
- await this.page.getByTestId(COMMON_SELECTORS.copyButton).click();
113451
- return await this.page.evaluate(() => navigator.clipboard.readText());
113452
- };
113453
113451
  this.copyEmbedScript = async (embedType) => {
113454
113452
  await this.selectEmbedType(embedType);
113455
113453
  await this.page.getByTestId(COMMON_SELECTORS.copyButton).click();
113456
113454
  return await this.page.evaluate(() => navigator.clipboard.readText());
113457
113455
  };
113458
- /**
113459
- * @deprecated This method is deprecated. Use selectEmbedType instead.
113460
- */
113461
- this.selectEmbedTypeV2 = async (embedType) => {
113462
- await this.page.locator(EMBED_SELECTORS.embedSelector(embedType)).click();
113463
- await this.neetoPlaywrightUtilities.waitForPageLoad();
113464
- };
113465
113456
  this.selectEmbedType = async (embedType) => {
113466
113457
  await this.page.locator(EMBED_SELECTORS.embedSelector(embedType)).click();
113467
113458
  await this.neetoPlaywrightUtilities.waitForPageLoad();
@@ -113633,6 +113624,20 @@ const ZAPIER_LIMIT_EXHAUSTED_MESSAGE = "Zapier free task limit is exhausted. Tes
113633
113624
  const EMOJI_LABEL = "thumbs up";
113634
113625
  const SELECT_COUNTRY = "Select country";
113635
113626
  const GOOGLE_CALENDAR_DATE_FORMAT = "YYYY/M/D";
113627
+ const MICROSOFT_LOGIN_TEXTS = {
113628
+ passwordInput: "Enter the password",
113629
+ emailInput: "Enter your email",
113630
+ enterCode: "Enter code",
113631
+ verify: "Verify",
113632
+ staySignedIn: "Stay signed in?",
113633
+ signIn: "Sign in",
113634
+ next: "Next",
113635
+ enterPassword: "Enter password",
113636
+ password: "Password",
113637
+ permissionsRequested: "Permissions requested",
113638
+ yes: "Yes",
113639
+ remove: "Remove",
113640
+ };
113636
113641
  const GOOGLE_LOGIN_TEXTS = {
113637
113642
  googleAccount: "Google Account:",
113638
113643
  connectYourGoogleAccount: "Connect your Google account",
@@ -116042,11 +116047,11 @@ class IntegrationBase {
116042
116047
  });
116043
116048
  };
116044
116049
  this.gotoIntegrationIndex = async () => {
116045
- if (neetoCist.isNotEmpty(this.integrationRouteIndex)) {
116046
- await this.page.goto(this.integrationRouteIndex, { timeout: 20000 });
116047
- await test.expect(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton)).toBeVisible({ timeout: 25000 });
116048
- await this.neetoPlaywrightUtilities.waitForPageLoad();
116049
- }
116050
+ if (ramda.isEmpty(this.integrationRouteIndex))
116051
+ return;
116052
+ await this.page.goto(this.integrationRouteIndex, { timeout: 20000 });
116053
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
116054
+ await this.neetoPlaywrightUtilities.waitForPageLoad();
116050
116055
  };
116051
116056
  this.page = page;
116052
116057
  this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
@@ -116148,14 +116153,24 @@ class GooglePage extends IntegrationBase {
116148
116153
  await this.page.waitForLoadState("load", { timeout: 25000 });
116149
116154
  await this.page.waitForURL(new RegExp(THIRD_PARTY_ROUTES.google.myAccount));
116150
116155
  };
116151
- this.enterTotpCode = (locator) => test.expect(async () => {
116152
- const totpToken = this.totp.generate({ timestamp: Date.now() + 5000 });
116153
- await this.page.getByLabel(GOOGLE_LOGIN_TEXTS.enterCode).fill(totpToken);
116154
- test.expect(this.totp.validate({ token: totpToken })).not.toBeNull();
116155
- await this.page.locator(GOOGLE_LOGIN_SELECTORS.totpNext).click();
116156
- await test.expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({ timeout: 15000 });
116157
- await test.expect(locator).toBeHidden({ timeout: 10000 });
116158
- }).toPass({ timeout: 50000 });
116156
+ this.enterTotpCode = async (locator) => {
116157
+ let previousToken = null;
116158
+ await test.expect(async () => {
116159
+ let totpToken = this.totp.generate({ timestamp: Date.now() });
116160
+ if (totpToken === previousToken) {
116161
+ const remainingTime = this.totp.remaining({ timestamp: Date.now() });
116162
+ // eslint-disable-next-line playwright/no-wait-for-timeout
116163
+ await this.page.waitForTimeout(remainingTime + 500); // Wait for the remaining time plus a small buffer (500ms) to ensure new token
116164
+ totpToken = this.totp.generate({ timestamp: Date.now() });
116165
+ }
116166
+ previousToken = totpToken;
116167
+ await this.page.getByLabel(GOOGLE_LOGIN_TEXTS.enterCode).fill(totpToken);
116168
+ test.expect(this.totp.validate({ token: totpToken })).not.toBeNull();
116169
+ await this.page.locator(GOOGLE_LOGIN_SELECTORS.totpNext).click();
116170
+ await test.expect(this.page.getByText(GOOGLE_LOGIN_TEXTS.wrongCode)).toBeHidden({ timeout: 10000 });
116171
+ await test.expect(locator).toBeHidden({ timeout: 10000 });
116172
+ }).toPass({ timeout: 2 * 60 * 1000 });
116173
+ };
116159
116174
  this.logoutFromGoogle = async () => {
116160
116175
  await this.page.goto(THIRD_PARTY_ROUTES.google.myAccount, {
116161
116176
  timeout: 20000,
@@ -116229,7 +116244,113 @@ class GooglePage extends IntegrationBase {
116229
116244
  }
116230
116245
  }
116231
116246
 
116232
- /* eslint-disable playwright/no-raw-locators */
116247
+ class MicrosoftPage extends IntegrationBase {
116248
+ constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, integration = "", }) {
116249
+ super({
116250
+ page,
116251
+ neetoPlaywrightUtilities,
116252
+ integrationRouteIndex,
116253
+ integration,
116254
+ });
116255
+ this.stagingConsentFlow = async (abortFlow = false) => {
116256
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116257
+ await test.expect(this.page.getByRole("heading", {
116258
+ name: MICROSOFT_LOGIN_TEXTS.permissionsRequested,
116259
+ })).toBeVisible({ timeout: 20000 });
116260
+ await this.page
116261
+ .locator(abortFlow
116262
+ ? MICROSOFT_LOGIN_SELECTORS.cancelButton
116263
+ : MICROSOFT_LOGIN_SELECTORS.acceptButton)
116264
+ .click();
116265
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116266
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
116267
+ };
116268
+ this.enterEmail = async () => {
116269
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116270
+ await test.expect(this.page.getByRole("heading", { name: MICROSOFT_LOGIN_TEXTS.signIn })).toBeVisible({ timeout: 20000 });
116271
+ await this.page
116272
+ .locator(MICROSOFT_LOGIN_SELECTORS.emailInput)
116273
+ .or(this.page.locator(MICROSOFT_LOGIN_SELECTORS.placeholder))
116274
+ .or(this.page.getByRole("textbox", {
116275
+ name: MICROSOFT_LOGIN_TEXTS.emailInput,
116276
+ }))
116277
+ .pressSequentially(process.env.MICROSOFT_LOGIN_EMAIL, { delay: 25 });
116278
+ };
116279
+ this.enterPassword = async () => {
116280
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116281
+ await test.expect(this.page.getByRole("heading", {
116282
+ name: MICROSOFT_LOGIN_TEXTS.enterPassword,
116283
+ })).toBeVisible({ timeout: 10000 });
116284
+ await this.page
116285
+ .getByPlaceholder(MICROSOFT_LOGIN_TEXTS.password)
116286
+ .or(this.page.locator(MICROSOFT_LOGIN_SELECTORS.placeholder))
116287
+ .or(this.page.getByRole("textbox", {
116288
+ name: MICROSOFT_LOGIN_TEXTS.passwordInput,
116289
+ }))
116290
+ .pressSequentially(process.env.MICROSOFT_LOGIN_PASSWORD, { delay: 15 });
116291
+ };
116292
+ this.loginToMicrosoft = async () => {
116293
+ if (ramda.isNil(process.env.MICROSOFT_LOGIN_EMAIL) ||
116294
+ ramda.isNil(process.env.MICROSOFT_LOGIN_PASSWORD) ||
116295
+ ramda.isNil(process.env.MICROSOFT_2FA_SECRET_KEY)) {
116296
+ throw new Error("ENV variable MICROSOFT_LOGIN_EMAIL or MICROSOFT_LOGIN_PASSWORD or MICROSOFT_2FA_SECRET_KEY is not properly configured");
116297
+ }
116298
+ await this.page.goto(THIRD_PARTY_ROUTES.microsoft.login);
116299
+ await this.enterEmail();
116300
+ await this.page
116301
+ .getByRole("button", { name: MICROSOFT_LOGIN_TEXTS.next })
116302
+ .click();
116303
+ await this.enterPassword();
116304
+ await this.page
116305
+ .getByRole("button", { name: MICROSOFT_LOGIN_TEXTS.signIn })
116306
+ .click();
116307
+ await this.enterTotpCode();
116308
+ await this.staySignedIn();
116309
+ };
116310
+ this.enterTotpCode = async () => {
116311
+ const verifyBtn = this.page.getByRole("button", {
116312
+ name: MICROSOFT_LOGIN_TEXTS.verify,
116313
+ });
116314
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116315
+ await test.expect(async () => {
116316
+ const token = this.totp.generate({ timestamp: Date.now() + 5000 });
116317
+ await this.page.getByLabel(MICROSOFT_LOGIN_TEXTS.enterCode).fill(token);
116318
+ test.expect(this.totp.validate({ token })).not.toBeNull();
116319
+ await verifyBtn.click();
116320
+ await test.expect(this.page.getByRole("alert")).toBeHidden();
116321
+ await test.expect(verifyBtn).toBeHidden();
116322
+ }).toPass({ timeout: 60 * 1000, intervals: [10000] });
116323
+ };
116324
+ this.staySignedIn = async () => {
116325
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116326
+ await this.page.waitForURL(THIRD_PARTY_ROUTES.microsoft.staySignedIn);
116327
+ await test.expect(this.page.getByRole("heading", {
116328
+ name: MICROSOFT_LOGIN_TEXTS.staySignedIn,
116329
+ })).toBeVisible({ timeout: 15000 });
116330
+ const acceptBtn = this.page.locator(MICROSOFT_LOGIN_SELECTORS.acceptButton);
116331
+ await acceptBtn.click();
116332
+ await test.expect(acceptBtn).toBeHidden({ timeout: 10000 });
116333
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116334
+ };
116335
+ this.revokePermissions = async () => {
116336
+ await this.page.goto(THIRD_PARTY_ROUTES.microsoft.myApps);
116337
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116338
+ const dropdown = this.page.locator(MICROSOFT_LOGIN_SELECTORS.dropdownMenu);
116339
+ await dropdown.click();
116340
+ await this.page
116341
+ .getByRole("menuitem", { name: MICROSOFT_LOGIN_TEXTS.remove })
116342
+ .click();
116343
+ await test.expect(dropdown).toBeHidden({ timeout: 10000 });
116344
+ await this.page.waitForLoadState("load", { timeout: 25000 });
116345
+ };
116346
+ this.mailerUtils = new MailerUtils(neetoPlaywrightUtilities);
116347
+ this.totp = initializeTotp({
116348
+ issuer: "Microsoft",
116349
+ secret: process.env.MICROSOFT_2FA_SECRET_KEY,
116350
+ });
116351
+ }
116352
+ }
116353
+
116233
116354
  class SlackPage extends IntegrationBase {
116234
116355
  constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, }) {
116235
116356
  super({
@@ -116278,6 +116399,7 @@ class SlackPage extends IntegrationBase {
116278
116399
  await this.page
116279
116400
  .getByRole("button", { name: this.t("neetoSlack.common.continue") })
116280
116401
  .click();
116402
+ await this.neetoPlaywrightUtilities.waitForPageLoad();
116281
116403
  if (customSteps) {
116282
116404
  await customSteps();
116283
116405
  }
@@ -116297,11 +116419,7 @@ class SlackPage extends IntegrationBase {
116297
116419
  await this.disconnect();
116298
116420
  await this.verifyIntegrationStatus("disconnected");
116299
116421
  };
116300
- this.updateConfigureSlackChannel = async ({ newSlackChannel = "random",
116301
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
116302
- interceptMultipleResponsesParams = {},
116303
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
116304
- refreshInterceptMultipleResponsesParams = {}, refreshChannelList = false, }) => {
116422
+ this.updateConfigureSlackChannel = async ({ newSlackChannel = "random", refreshChannelList = false, }) => {
116305
116423
  await this.page.getByTestId(INTEGRATION_SELECTORS.manageButton).click();
116306
116424
  await this.page
116307
116425
  .getByRole("button", { name: this.t("neetoSlack.common.edit") })
@@ -116367,17 +116485,16 @@ class SlackPage extends IntegrationBase {
116367
116485
  })
116368
116486
  .click();
116369
116487
  };
116370
- this.goToSlackChannel = async (slackChannel) => {
116371
- await this.slackWebappPage
116372
- .locator(SLACK_SELECTORS.virtualListItem, { hasText: slackChannel })
116373
- .click();
116374
- };
116488
+ this.goToSlackChannel = (slackChannel) => this.slackWebappPage
116489
+ .locator(SLACK_SELECTORS.virtualListItem, { hasText: slackChannel })
116490
+ .click();
116375
116491
  this.createNewSlackChannel = async ({ channelName, kind = "public", }) => {
116376
116492
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.sectionHeadingButton).click();
116377
116493
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelSectionSubmenuCreate).click();
116378
116494
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelSectionMenuCreateChannel).click();
116495
+ const spinner = this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner);
116379
116496
  await test.expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)).toBeVisible();
116380
- await test.expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner)).toBeHidden();
116497
+ await test.expect(spinner).toBeHidden();
116381
116498
  await test.expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelNameOptionsList)).toBeHidden({ timeout: 5000 });
116382
116499
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)
116383
116500
  .getByText(SLACK_WEB_TEXTS.name, { exact: true })
@@ -116386,13 +116503,14 @@ class SlackPage extends IntegrationBase {
116386
116503
  SLACK_DATA_QA_SELECTORS.skModalContent,
116387
116504
  SLACK_DATA_QA_SELECTORS.channelNameInput,
116388
116505
  ]).pressSequentially(channelName);
116389
- await test.expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.infiniteSpinner)).toBeHidden();
116390
- await test.expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton)).toBeEnabled();
116391
- await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton).click();
116506
+ const nextButton = this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton);
116507
+ await test.expect(spinner).toBeHidden();
116508
+ await test.expect(nextButton).toBeEnabled();
116509
+ await nextButton.click();
116392
116510
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)
116393
116511
  .getByRole("radio", { name: kind })
116394
116512
  .check();
116395
- await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.createChannelNextButton).click();
116513
+ await nextButton.click();
116396
116514
  await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.inviteToWorkspaceSkipButton).click();
116397
116515
  };
116398
116516
  this.deleteSlackChannel = async (channel) => {
@@ -117526,9 +117644,7 @@ class TeamMembers {
117526
117644
  }).toPass({ timeout: 40000 });
117527
117645
  await this.neetoPlaywrightUtilities.verifyToast();
117528
117646
  };
117529
- this.searchAndVerifyMemberByEmail = async ({ email,
117530
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
117531
- interceptOptions = {}, }) => {
117647
+ this.searchAndVerifyMemberByEmail = async ({ email }) => {
117532
117648
  await this.neetoPlaywrightUtilities.waitForPageLoad();
117533
117649
  await this.page.getByTestId(MEMBER_SELECTORS.searchTextField).fill(email);
117534
117650
  const emailSubstr = email.length > 20 ? email.substring(0, 20) : email;
@@ -118163,6 +118279,69 @@ class CustomDomainPage {
118163
118279
  }
118164
118280
  }
118165
118281
 
118282
+ class IPRestrictionsPage {
118283
+ constructor(page, neetoPlaywrightUtilities) {
118284
+ this.page = page;
118285
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
118286
+ this.setIPRange = async (ipRange, type, index = 0) => {
118287
+ await this.page
118288
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipStartTextField)
118289
+ // Using nth methods here as it determines which input to interact with
118290
+ // eslint-disable-next-line playwright/no-nth-methods
118291
+ .nth(index)
118292
+ .fill(ipRange[0]);
118293
+ await this.page
118294
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipEndTextField)
118295
+ // Using nth methods here as it determines which input to interact with
118296
+ // eslint-disable-next-line playwright/no-nth-methods
118297
+ .nth(index)
118298
+ .fill(ipRange[1]);
118299
+ if (!neetoCist.isPresent(type))
118300
+ return;
118301
+ await this.page
118302
+ .getByTestId(COMMON_SELECTORS.customSelectContainer("type"))
118303
+ // Using nth methods here as it determines which dropdown to interact with
118304
+ // eslint-disable-next-line playwright/no-nth-methods
118305
+ .nth(index)
118306
+ .fill(type);
118307
+ await this.page.keyboard.press("Enter");
118308
+ await test.expect(this.page
118309
+ .getByTestId(COMMON_SELECTORS.customSelectValueContainer("type"))
118310
+ // Using nth methods here as it determines which dropdown to interact with
118311
+ // eslint-disable-next-line playwright/no-nth-methods
118312
+ .nth(index)).toContainText(type);
118313
+ };
118314
+ this.saveChanges = async () => {
118315
+ await this.saveButton.click();
118316
+ await this.neetoPlaywrightUtilities.clickButtonAndAwaitLoad({
118317
+ locator: this.page.getByTestId(COMMON_SELECTORS.alertModalSubmitButton),
118318
+ });
118319
+ };
118320
+ this.disableIPRestriction = async () => {
118321
+ if (!this.page.url().includes(ROUTES.adminPanel.ipRestriction))
118322
+ return;
118323
+ const enableCheckbox = this.page.getByTestId(IP_RESTRICTIONS_SELECTORS.enableIPRestrictionChk);
118324
+ const [isChecked, isSaveDisabled, isDeleteHidden] = await Promise.all([
118325
+ enableCheckbox.isChecked(),
118326
+ this.saveButton.isDisabled(),
118327
+ this.page
118328
+ .getByTestId(IP_RESTRICTIONS_SELECTORS.ipRangeDeleteBtn)
118329
+ .isHidden(),
118330
+ ]);
118331
+ if (isChecked && (isSaveDisabled || isDeleteHidden)) {
118332
+ await enableCheckbox.click();
118333
+ if (await this.saveButton.isEnabled()) {
118334
+ await this.saveButton.click();
118335
+ await this.neetoPlaywrightUtilities.verifyToast();
118336
+ }
118337
+ }
118338
+ };
118339
+ this.t = playwrightI18nextFixture.getI18nInstance().t;
118340
+ this.ipRestrictionsApi = new IpRestrictionsApi(this.neetoPlaywrightUtilities);
118341
+ this.saveButton = this.page.getByTestId(IP_RESTRICTIONS_SELECTORS.saveChanges);
118342
+ }
118343
+ }
118344
+
118166
118345
  class RolesPage {
118167
118346
  constructor(page, neetoPlaywrightUtilities) {
118168
118347
  this.getPermissionIds = async (targetPermissions, isGranularPermission = false) => {
@@ -118226,11 +118405,6 @@ class RolesPage {
118226
118405
  this.neetoPlaywrightUtilities.verifyToast(),
118227
118406
  ]);
118228
118407
  };
118229
- this.verifyAdminPanelCard = ({ cardLocator, title, description, }) => Promise.all([
118230
- test.expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemHeading)).toHaveText(title),
118231
- test.expect(cardLocator.getByTestId(ADMIN_PANEL_SELECTORS.settingsItemDescription)).toHaveText(description),
118232
- test.expect(this.page.getByTestId(COMMON_SELECTORS.sidebarSubLink(title))).toHaveCSS("background-color", COLOR.transparent),
118233
- ]);
118234
118408
  this.deleteRoleViaUI = async (roleName) => {
118235
118409
  await this.neetoPlaywrightUtilities.waitForPageLoad();
118236
118410
  await this.page.getByTestId(ROLES_SELECTORS.searchTextField).fill(roleName);
@@ -118259,17 +118433,11 @@ class RolesPage {
118259
118433
  if (neetoCist.isNotEqualDeep(roleAccessableLinks, adminAccessableLinks)) {
118260
118434
  for (const link of adminAccessableLinks) {
118261
118435
  await this.page.goto(link);
118262
- await test.expect
118263
- .soft(this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton))
118264
- .toBeVisible({ timeout: 15000 });
118436
+ await this.neetoPlaywrightUtilities.waitForFloatingMenu();
118265
118437
  await this.neetoPlaywrightUtilities.waitForPageLoad();
118266
- await test.expect(this.page.locator(COMMON_SELECTORS.tableSpinner)).toBeHidden({ timeout: 35000 });
118267
- const unauthorizedHeading = this.page.getByRole("heading", {
118438
+ await test.expect(this.page.getByRole("heading", {
118268
118439
  name: this.t("neetoMolecules.errorPage.unauthorized"),
118269
- });
118270
- roleAccessableLinks.includes(link)
118271
- ? await test.expect(unauthorizedHeading).toBeHidden()
118272
- : await test.expect(unauthorizedHeading).toBeVisible();
118440
+ }))[roleAccessableLinks.includes(link) ? "toBeHidden" : "toBeVisible"]();
118273
118441
  }
118274
118442
  }
118275
118443
  };
@@ -123863,10 +124031,12 @@ exports.HELP_CENTER_SELECTORS = HELP_CENTER_SELECTORS;
123863
124031
  exports.HelpAndProfilePage = HelpAndProfilePage;
123864
124032
  exports.INTEGRATIONS_TEXTS = INTEGRATIONS_TEXTS;
123865
124033
  exports.INTEGRATION_SELECTORS = INTEGRATION_SELECTORS;
124034
+ exports.IPRestrictionsPage = IPRestrictionsPage;
123866
124035
  exports.IP_RESTRICTIONS_SELECTORS = IP_RESTRICTIONS_SELECTORS;
123867
124036
  exports.IS_STAGING_ENV = IS_STAGING_ENV;
123868
124037
  exports.ImageUploader = ImageUploader;
123869
124038
  exports.IntegrationBase = IntegrationBase;
124039
+ exports.IpRestrictionsApi = IpRestrictionsApi;
123870
124040
  exports.KEYBOARD_SHORTCUTS_SELECTORS = KEYBOARD_SHORTCUTS_SELECTORS;
123871
124041
  exports.LIST_MODIFIER_SELECTORS = LIST_MODIFIER_SELECTORS;
123872
124042
  exports.LIST_MODIFIER_TAGS = LIST_MODIFIER_TAGS;
@@ -123875,9 +124045,12 @@ exports.MEMBER_FORM_SELECTORS = MEMBER_FORM_SELECTORS;
123875
124045
  exports.MEMBER_SELECTORS = MEMBER_SELECTORS;
123876
124046
  exports.MEMBER_TEXTS = MEMBER_TEXTS;
123877
124047
  exports.MERGE_TAGS_SELECTORS = MERGE_TAGS_SELECTORS;
124048
+ exports.MICROSOFT_LOGIN_SELECTORS = MICROSOFT_LOGIN_SELECTORS;
124049
+ exports.MICROSOFT_LOGIN_TEXTS = MICROSOFT_LOGIN_TEXTS;
123878
124050
  exports.MailerUtils = MailerUtils;
123879
124051
  exports.Member = Member;
123880
124052
  exports.MemberApis = MemberApis;
124053
+ exports.MicrosoftPage = MicrosoftPage;
123881
124054
  exports.NEETO_AUTH_BASE_URL = NEETO_AUTH_BASE_URL;
123882
124055
  exports.NEETO_EDITOR_SELECTORS = NEETO_EDITOR_SELECTORS;
123883
124056
  exports.NEETO_FILTERS_SELECTORS = NEETO_FILTERS_SELECTORS;