@bigbinary/neeto-playwright-commons 1.26.36 → 1.27.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
@@ -5025,7 +5025,6 @@ const generateStagingData = (product = "invoice") => {
5025
5025
  };
5026
5026
  };
5027
5027
 
5028
- /* eslint-disable playwright/no-skipped-test */
5029
5028
  const execCommand = (command) => execSync(command)
5030
5029
  .toString("utf-8")
5031
5030
  .replace(/[\n\r\s]+$/, "");
@@ -5190,7 +5189,7 @@ const globalShortcuts = (t) => [
5190
5189
  },
5191
5190
  {
5192
5191
  description: t("neetoMolecules.keyboardShortcuts.global.openProductSwitcher"),
5193
- sequence: "ctrl+e",
5192
+ sequence: "ctrl+u",
5194
5193
  },
5195
5194
  ];
5196
5195
  const generatePhoneNumber = () => `${"+91"} 9${faker.string.numeric(4)} ${faker.string.numeric(5)}`;
@@ -5356,8 +5355,9 @@ const NEETO_FILTERS_SELECTORS = {
5356
5355
  };
5357
5356
 
5358
5357
  const HELP_CENTER_SELECTORS = {
5358
+ helpMenuBtn: "help-menu-button",
5359
5359
  helpButton: "help-button",
5360
- documentationButton: "help-link-help-center-button",
5360
+ documentationButton: "help-link-help-articles-button",
5361
5361
  keyboardShortcutButton: "help-link-keyboard-shortcut-button",
5362
5362
  chatButton: "help-link-live-chat-button",
5363
5363
  whatsNewButton: "help-link-engage-button",
@@ -29075,9 +29075,10 @@ function requireAddressparser () {
29075
29075
  * Converts tokens for a single address into an address object
29076
29076
  *
29077
29077
  * @param {Array} tokens Tokens object
29078
+ * @param {Number} depth Current recursion depth for nested group protection
29078
29079
  * @return {Object} Address object
29079
29080
  */
29080
- function _handleAddress(tokens) {
29081
+ function _handleAddress(tokens, depth) {
29081
29082
  let isGroup = false;
29082
29083
  let state = 'text';
29083
29084
  let address;
@@ -29158,7 +29159,7 @@ function requireAddressparser () {
29158
29159
  // Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
29159
29160
  let groupMembers = [];
29160
29161
  if (data.group.length) {
29161
- let parsedGroup = addressparser(data.group.join(','));
29162
+ let parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
29162
29163
  // Flatten: if any member is itself a group, extract its members into the sequence
29163
29164
  parsedGroup.forEach(member => {
29164
29165
  if (member.group) {
@@ -29368,6 +29369,13 @@ function requireAddressparser () {
29368
29369
  }
29369
29370
  }
29370
29371
 
29372
+ /**
29373
+ * Maximum recursion depth for parsing nested groups.
29374
+ * RFC 5322 doesn't allow nested groups, so this is a safeguard against
29375
+ * malicious input that could cause stack overflow.
29376
+ */
29377
+ const MAX_NESTED_GROUP_DEPTH = 50;
29378
+
29371
29379
  /**
29372
29380
  * Parses structured e-mail addresses from an address field
29373
29381
  *
@@ -29380,10 +29388,18 @@ function requireAddressparser () {
29380
29388
  * [{name: 'Name', address: 'address@domain'}]
29381
29389
  *
29382
29390
  * @param {String} str Address field
29391
+ * @param {Object} options Optional options object
29392
+ * @param {Number} options._depth Internal recursion depth counter (do not set manually)
29383
29393
  * @return {Array} An array of address objects
29384
29394
  */
29385
29395
  function addressparser(str, options) {
29386
29396
  options = options || {};
29397
+ let depth = options._depth || 0;
29398
+
29399
+ // Prevent stack overflow from deeply nested groups (DoS protection)
29400
+ if (depth > MAX_NESTED_GROUP_DEPTH) {
29401
+ return [];
29402
+ }
29387
29403
 
29388
29404
  let tokenizer = new Tokenizer(str);
29389
29405
  let tokens = tokenizer.tokenize();
@@ -29408,7 +29424,7 @@ function requireAddressparser () {
29408
29424
  }
29409
29425
 
29410
29426
  addresses.forEach(address => {
29411
- address = _handleAddress(address);
29427
+ address = _handleAddress(address, depth);
29412
29428
  if (address.length) {
29413
29429
  parsedAddresses = parsedAddresses.concat(address);
29414
29430
  }
@@ -40920,6 +40936,8 @@ function requireStreams () {
40920
40936
  return streams;
40921
40937
  }
40922
40938
 
40939
+ lib$a.exports;
40940
+
40923
40941
  var hasRequiredLib$a;
40924
40942
 
40925
40943
  function requireLib$a () {
@@ -40931,22 +40949,21 @@ function requireLib$a () {
40931
40949
 
40932
40950
  var bomHandling = requireBomHandling();
40933
40951
  var mergeModules = requireMergeExports();
40934
- var iconv = module.exports;
40935
40952
 
40936
40953
  // All codecs and aliases are kept here, keyed by encoding name/alias.
40937
40954
  // They are lazy loaded in `iconv.getCodec` from `encodings/index.js`.
40938
40955
  // Cannot initialize with { __proto__: null } because Boolean({ __proto__: null }) === true
40939
- iconv.encodings = null;
40956
+ module.exports.encodings = null;
40940
40957
 
40941
40958
  // Characters emitted in case of error.
40942
- iconv.defaultCharUnicode = "�";
40943
- iconv.defaultCharSingleByte = "?";
40959
+ module.exports.defaultCharUnicode = "�";
40960
+ module.exports.defaultCharSingleByte = "?";
40944
40961
 
40945
40962
  // Public API.
40946
- iconv.encode = function encode (str, encoding, options) {
40963
+ module.exports.encode = function encode (str, encoding, options) {
40947
40964
  str = "" + (str || ""); // Ensure string.
40948
40965
 
40949
- var encoder = iconv.getEncoder(encoding, options);
40966
+ var encoder = module.exports.getEncoder(encoding, options);
40950
40967
 
40951
40968
  var res = encoder.write(str);
40952
40969
  var trail = encoder.end();
@@ -40954,17 +40971,17 @@ function requireLib$a () {
40954
40971
  return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res
40955
40972
  };
40956
40973
 
40957
- iconv.decode = function decode (buf, encoding, options) {
40974
+ module.exports.decode = function decode (buf, encoding, options) {
40958
40975
  if (typeof buf === "string") {
40959
- if (!iconv.skipDecodeWarning) {
40976
+ if (!module.exports.skipDecodeWarning) {
40960
40977
  console.error("Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding");
40961
- iconv.skipDecodeWarning = true;
40978
+ module.exports.skipDecodeWarning = true;
40962
40979
  }
40963
40980
 
40964
40981
  buf = Buffer.from("" + (buf || ""), "binary"); // Ensure buffer.
40965
40982
  }
40966
40983
 
40967
- var decoder = iconv.getDecoder(encoding, options);
40984
+ var decoder = module.exports.getDecoder(encoding, options);
40968
40985
 
40969
40986
  var res = decoder.write(buf);
40970
40987
  var trail = decoder.end();
@@ -40972,9 +40989,9 @@ function requireLib$a () {
40972
40989
  return trail ? (res + trail) : res
40973
40990
  };
40974
40991
 
40975
- iconv.encodingExists = function encodingExists (enc) {
40992
+ module.exports.encodingExists = function encodingExists (enc) {
40976
40993
  try {
40977
- iconv.getCodec(enc);
40994
+ module.exports.getCodec(enc);
40978
40995
  return true
40979
40996
  } catch (e) {
40980
40997
  return false
@@ -40982,31 +40999,31 @@ function requireLib$a () {
40982
40999
  };
40983
41000
 
40984
41001
  // Legacy aliases to convert functions
40985
- iconv.toEncoding = iconv.encode;
40986
- iconv.fromEncoding = iconv.decode;
41002
+ module.exports.toEncoding = module.exports.encode;
41003
+ module.exports.fromEncoding = module.exports.decode;
40987
41004
 
40988
41005
  // Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache.
40989
- iconv._codecDataCache = { __proto__: null };
41006
+ module.exports._codecDataCache = { __proto__: null };
40990
41007
 
40991
- iconv.getCodec = function getCodec (encoding) {
40992
- if (!iconv.encodings) {
41008
+ module.exports.getCodec = function getCodec (encoding) {
41009
+ if (!module.exports.encodings) {
40993
41010
  var raw = requireEncodings();
40994
41011
  // TODO: In future versions when old nodejs support is removed can use object.assign
40995
- iconv.encodings = { __proto__: null }; // Initialize as empty object.
40996
- mergeModules(iconv.encodings, raw);
41012
+ module.exports.encodings = { __proto__: null }; // Initialize as empty object.
41013
+ mergeModules(module.exports.encodings, raw);
40997
41014
  }
40998
41015
 
40999
41016
  // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
41000
- var enc = iconv._canonicalizeEncoding(encoding);
41017
+ var enc = module.exports._canonicalizeEncoding(encoding);
41001
41018
 
41002
41019
  // Traverse iconv.encodings to find actual codec.
41003
41020
  var codecOptions = {};
41004
41021
  while (true) {
41005
- var codec = iconv._codecDataCache[enc];
41022
+ var codec = module.exports._codecDataCache[enc];
41006
41023
 
41007
41024
  if (codec) { return codec }
41008
41025
 
41009
- var codecDef = iconv.encodings[enc];
41026
+ var codecDef = module.exports.encodings[enc];
41010
41027
 
41011
41028
  switch (typeof codecDef) {
41012
41029
  case "string": // Direct alias to other encoding.
@@ -41027,9 +41044,9 @@ function requireLib$a () {
41027
41044
  // The codec function must load all tables and return object with .encoder and .decoder methods.
41028
41045
  // It'll be called only once (for each different options object).
41029
41046
  //
41030
- codec = new codecDef(codecOptions, iconv);
41047
+ codec = new codecDef(codecOptions, module.exports);
41031
41048
 
41032
- iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.
41049
+ module.exports._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.
41033
41050
  return codec
41034
41051
 
41035
41052
  default:
@@ -41038,13 +41055,13 @@ function requireLib$a () {
41038
41055
  }
41039
41056
  };
41040
41057
 
41041
- iconv._canonicalizeEncoding = function (encoding) {
41058
+ module.exports._canonicalizeEncoding = function (encoding) {
41042
41059
  // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
41043
41060
  return ("" + encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "")
41044
41061
  };
41045
41062
 
41046
- iconv.getEncoder = function getEncoder (encoding, options) {
41047
- var codec = iconv.getCodec(encoding);
41063
+ module.exports.getEncoder = function getEncoder (encoding, options) {
41064
+ var codec = module.exports.getCodec(encoding);
41048
41065
  var encoder = new codec.encoder(options, codec);
41049
41066
 
41050
41067
  if (codec.bomAware && options && options.addBOM) { encoder = new bomHandling.PrependBOM(encoder, options); }
@@ -41052,8 +41069,8 @@ function requireLib$a () {
41052
41069
  return encoder
41053
41070
  };
41054
41071
 
41055
- iconv.getDecoder = function getDecoder (encoding, options) {
41056
- var codec = iconv.getCodec(encoding);
41072
+ module.exports.getDecoder = function getDecoder (encoding, options) {
41073
+ var codec = module.exports.getCodec(encoding);
41057
41074
  var decoder = new codec.decoder(options, codec);
41058
41075
 
41059
41076
  if (codec.bomAware && !(options && options.stripBOM === false)) { decoder = new bomHandling.StripBOM(decoder, options); }
@@ -41066,26 +41083,26 @@ function requireLib$a () {
41066
41083
  // up to 100Kb to the output bundle. To avoid unnecessary code bloat, we don't enable Streaming API in browser by default.
41067
41084
  // If you would like to enable it explicitly, please add the following code to your app:
41068
41085
  // > iconv.enableStreamingAPI(require('stream'));
41069
- iconv.enableStreamingAPI = function enableStreamingAPI (streamModule) {
41070
- if (iconv.supportsStreams) { return }
41086
+ module.exports.enableStreamingAPI = function enableStreamingAPI (streamModule) {
41087
+ if (module.exports.supportsStreams) { return }
41071
41088
 
41072
41089
  // Dependency-inject stream module to create IconvLite stream classes.
41073
41090
  var streams = requireStreams()(streamModule);
41074
41091
 
41075
41092
  // Not public API yet, but expose the stream classes.
41076
- iconv.IconvLiteEncoderStream = streams.IconvLiteEncoderStream;
41077
- iconv.IconvLiteDecoderStream = streams.IconvLiteDecoderStream;
41093
+ module.exports.IconvLiteEncoderStream = streams.IconvLiteEncoderStream;
41094
+ module.exports.IconvLiteDecoderStream = streams.IconvLiteDecoderStream;
41078
41095
 
41079
41096
  // Streaming API.
41080
- iconv.encodeStream = function encodeStream (encoding, options) {
41081
- return new iconv.IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options)
41097
+ module.exports.encodeStream = function encodeStream (encoding, options) {
41098
+ return new module.exports.IconvLiteEncoderStream(module.exports.getEncoder(encoding, options), options)
41082
41099
  };
41083
41100
 
41084
- iconv.decodeStream = function decodeStream (encoding, options) {
41085
- return new iconv.IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options)
41101
+ module.exports.decodeStream = function decodeStream (encoding, options) {
41102
+ return new module.exports.IconvLiteDecoderStream(module.exports.getDecoder(encoding, options), options)
41086
41103
  };
41087
41104
 
41088
- iconv.supportsStreams = true;
41105
+ module.exports.supportsStreams = true;
41089
41106
  };
41090
41107
 
41091
41108
  // Enable Streaming API automatically if 'stream' module is available and non-empty (the majority of environments).
@@ -41095,10 +41112,10 @@ function requireLib$a () {
41095
41112
  } catch (e) {}
41096
41113
 
41097
41114
  if (streamModule && streamModule.Transform) {
41098
- iconv.enableStreamingAPI(streamModule);
41115
+ module.exports.enableStreamingAPI(streamModule);
41099
41116
  } else {
41100
41117
  // In rare cases where 'stream' module is not available by default, throw a helpful exception.
41101
- iconv.encodeStream = iconv.decodeStream = function () {
41118
+ module.exports.encodeStream = module.exports.decodeStream = function () {
41102
41119
  throw new Error("iconv-lite Streaming API is not enabled. Use iconv.enableStreamingAPI(require('stream')); to enable it.")
41103
41120
  };
41104
41121
  }
@@ -51175,7 +51192,6 @@ var require$$11 = [
51175
51192
  "drive",
51176
51193
  "dtv",
51177
51194
  "dubai",
51178
- "dunlop",
51179
51195
  "dupont",
51180
51196
  "durban",
51181
51197
  "dvag",
@@ -53407,7 +53423,11 @@ function requireMailParser () {
53407
53423
  result.push(textPart);
53408
53424
  }
53409
53425
 
53410
- result.push(`<a href="${link.url}">${link.text}</a>`);
53426
+ // Escape quotes in URL to prevent XSS
53427
+ let safeUrl = link.url.replace(/"/g, '&quot;');
53428
+ // Escape HTML entities in link text
53429
+ let safeText = he.encode(link.text, { useNamedReferences: true });
53430
+ result.push(`<a href="${safeUrl}">${safeText}</a>`);
53411
53431
 
53412
53432
  last = link.lastIndex;
53413
53433
  });
@@ -114375,29 +114395,21 @@ const THEMES_TEXTS = {
114375
114395
 
114376
114396
  class HelpAndProfilePage {
114377
114397
  constructor({ page, neetoPlaywrightUtilities, chatApiBaseURL, kbDocsBaseURL, changelogBaseURL, }) {
114378
- this.hoverOnBody = () => this.page.locator("body").hover({ timeout: 10000 });
114379
114398
  this.openHelpCenter = async () => {
114399
+ const floatingActionMenuBtn = this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton);
114380
114400
  await expect(async () => {
114381
- await this.hoverOnBody();
114382
- const floatingActionMenuButton = this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton);
114383
- await floatingActionMenuButton.scrollIntoViewIfNeeded();
114384
- await floatingActionMenuButton.hover();
114385
- await expect(this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton)).toBeVisible();
114401
+ await floatingActionMenuBtn.scrollIntoViewIfNeeded();
114402
+ await floatingActionMenuBtn.hover();
114403
+ await expect(this.page.getByTestId(HELP_CENTER_SELECTORS.whatsNewButton)).toBeVisible();
114386
114404
  }).toPass({ timeout: 60000 });
114387
114405
  };
114388
- this.openLiveChatAndVerify = async (widgetVisibilityTimeout = 10000) => {
114389
- await expect(async () => {
114390
- await this.openHelpCenter();
114391
- await this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton).click();
114392
- await expect(this.neetoChatWidget).toBeVisible({
114393
- timeout: widgetVisibilityTimeout,
114394
- });
114395
- await expect(this.neetoChatSpinner).toBeHidden({ timeout: 20 * 1000 });
114396
- await expect(this.neetoChatWidget).toBeVisible({
114397
- timeout: widgetVisibilityTimeout,
114398
- });
114399
- }).toPass({ timeout: 35000 + widgetVisibilityTimeout * 2 });
114400
- };
114406
+ this.openLiveChatAndVerify = () => expect(async () => {
114407
+ await this.openHelpCenter();
114408
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114409
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton).click();
114410
+ await expect(this.neetoChatSpinner).toBeHidden({ timeout: 20000 });
114411
+ await expect(this.neetoChatWidget).toBeVisible({ timeout: 10000 });
114412
+ }).toPass({ timeout: 60000 });
114401
114413
  /**
114402
114414
  * @deprecated This method is deprecated. Use openAndVerifyChatWidget instead.
114403
114415
  */
@@ -114417,7 +114429,7 @@ class HelpAndProfilePage {
114417
114429
  this.openAndVerifyChatWidget = async () => {
114418
114430
  await this.page.reload();
114419
114431
  await this.neetoPlaywrightUtilities.waitForPageLoad();
114420
- await test$1.step("1: Open live chat and verify iframe", () => this.openLiveChatAndVerify());
114432
+ await test$1.step("1: Open live chat", this.openLiveChatAndVerify);
114421
114433
  await test$1.step("2: Close and reopen live chat frame", async () => {
114422
114434
  await this.page.getByTestId(CHAT_WIDGET_SELECTORS.closeChat).click();
114423
114435
  await expect(this.neetoChatWidget).toBeHidden({ timeout: 35000 });
@@ -114446,6 +114458,7 @@ class HelpAndProfilePage {
114446
114458
  this.openAndVerifyHelpArticles = async () => {
114447
114459
  await test$1.step("1: Open Help Center links", this.openHelpCenter);
114448
114460
  await test$1.step("2: Open and verify help articles link", async () => {
114461
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114449
114462
  const helpArticlesPromise = this.page.waitForEvent("popup");
114450
114463
  await this.page
114451
114464
  .getByTestId(HELP_CENTER_SELECTORS.documentationButton)
@@ -114486,7 +114499,7 @@ class HelpAndProfilePage {
114486
114499
  });
114487
114500
  };
114488
114501
  this.openAndVerifyChangelog = async () => {
114489
- await test$1.step("1: Open Help Center links and changelog", this.openChangelogPane);
114502
+ await test$1.step("1: Open changelog", this.openChangelogPane);
114490
114503
  await test$1.step("2: Close and reopen changelog pane", async () => {
114491
114504
  await this.page
114492
114505
  .getByTestId(CHANGELOG_WIDGET_SELECTORS.closeButton)
@@ -114503,8 +114516,10 @@ class HelpAndProfilePage {
114503
114516
  await this.neetoPlaywrightUtilities.waitForPageLoad({
114504
114517
  customPageContext: changelogPage,
114505
114518
  });
114506
- await expect(changelogPage.getByRole("button", { name: ENGAGE_TEXTS.subscribe })).toBeVisible({ timeout: 10000 });
114507
- await expect(changelogPage).toHaveURL(this.changelogBaseURL);
114519
+ await Promise.all([
114520
+ expect(changelogPage).toHaveURL(this.changelogBaseURL),
114521
+ expect(changelogPage.getByRole("button", { name: ENGAGE_TEXTS.subscribe })).toBeVisible({ timeout: 10000 }),
114522
+ ]);
114508
114523
  await changelogPage.close();
114509
114524
  });
114510
114525
  };
@@ -114623,21 +114638,21 @@ class HelpAndProfilePage {
114623
114638
  await expect(this.page.getByTestId(COMMON_SELECTORS.appSwitcherWrapper)).toBeVisible();
114624
114639
  }).toPass({ timeout: 45000 }));
114625
114640
  await test$1.step("2: Verify search functionality", async () => {
114626
- const playdashAppLink = this.page.getByTestId(COMMON_SELECTORS.appLink(productName));
114627
- const replayAppLink = this.page.getByTestId(COMMON_SELECTORS.appLink("Replay"));
114641
+ const playdash = this.page.getByTestId(COMMON_SELECTORS.appLink(productName));
114642
+ const replay = this.page.getByTestId(COMMON_SELECTORS.appLink("Replay"));
114628
114643
  const searchInput = this.page.getByTestId(COMMON_SELECTORS.productSwitcherSearchInput);
114629
114644
  await searchInput.fill(faker.word.words(3));
114630
114645
  //TODO: Use data-testid label when this https://github.com/bigbinary/neeto-molecules/issues/2114 is resolved
114631
114646
  await expect(this.page.getByText(this.t("neetoMolecules.productSwitcher.noApps"))).toBeVisible();
114632
114647
  await searchInput.fill(searchQueryPartial);
114633
114648
  await Promise.all([
114634
- expect(playdashAppLink).toBeVisible(),
114635
- expect(replayAppLink).toBeVisible(),
114649
+ expect(playdash).toBeVisible(),
114650
+ expect(replay).toBeVisible(),
114636
114651
  ]);
114637
114652
  await searchInput.fill(searchQueryFull);
114638
114653
  await Promise.all([
114639
- expect(playdashAppLink).toBeVisible(),
114640
- expect(replayAppLink).toBeHidden(),
114654
+ expect(playdash).toBeVisible(),
114655
+ expect(replay).toBeHidden(),
114641
114656
  ]);
114642
114657
  });
114643
114658
  };
@@ -114664,7 +114679,7 @@ class HelpAndProfilePage {
114664
114679
  this.verifyLogout = async () => {
114665
114680
  if (shouldSkipSetupAndTeardown())
114666
114681
  return;
114667
- await test$1.step("1: Open Help center and verify", this.openHelpCenter);
114682
+ await test$1.step("1: Open Help center", this.openHelpCenter);
114668
114683
  await test$1.step("2: Click logout and verify", async () => {
114669
114684
  await this.page
114670
114685
  .getByTestId(PROFILE_SECTION_SELECTORS.logoutButton)
@@ -114746,6 +114761,7 @@ class HelpAndProfilePage {
114746
114761
  this.openAndVerifyStatus = async (appName) => {
114747
114762
  await test$1.step("1: Open Help Center links", this.openHelpCenter);
114748
114763
  await test$1.step("2: Open and verify status page", async () => {
114764
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114749
114765
  const statusPagePromise = this.page.waitForEvent("popup");
114750
114766
  await this.page.getByTestId(HELP_CENTER_SELECTORS.statusButton).click();
114751
114767
  const statusPage = await statusPagePromise;
@@ -114759,6 +114775,7 @@ class HelpAndProfilePage {
114759
114775
  this.openAndVerifyCommunity = async () => {
114760
114776
  await test$1.step("1: Open Help Center links", this.openHelpCenter);
114761
114777
  await test$1.step("2: Open and verify community", async () => {
114778
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114762
114779
  const communityPagePromise = this.page.waitForEvent("popup");
114763
114780
  await this.page
114764
114781
  .getByTestId(HELP_CENTER_SELECTORS.communityButton)
@@ -119207,36 +119224,45 @@ class OrganizationPage {
119207
119224
  }
119208
119225
  }
119209
119226
 
119227
+ dayjs.extend(customParseFormat);
119210
119228
  class ApiKeysPage {
119211
119229
  constructor(page, neetoPlaywrightUtilities) {
119230
+ this.page = page;
119231
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
119232
+ this.enableExpiryDate = async (expiryDate) => {
119233
+ const userProps = await getGlobalUserProps(this.page);
119234
+ const normalizedDate = dayjs(expiryDate, DATE_FORMATS.date);
119235
+ const formattedExpiryDate = normalizedDate.format(userProps === null || userProps === void 0 ? void 0 : userProps.dateFormat);
119236
+ const expiryDateInput = this.page
119237
+ .getByTestId(COMMON_SELECTORS.paneBody)
119238
+ .getByTestId(ADMIN_PANEL_SELECTORS.expiryDateInput);
119239
+ const nextYearBtn = this.page.getByLabel(DATE_TEXTS.nextYear, {
119240
+ exact: true,
119241
+ });
119242
+ await this.page
119243
+ .getByTestId(COMMON_SELECTORS.checkboxInput("never-expires"))
119244
+ .uncheck();
119245
+ await expiryDateInput.click();
119246
+ await expect(nextYearBtn).toBeVisible();
119247
+ await expiryDateInput.pressSequentially(formattedExpiryDate, {
119248
+ delay: 250,
119249
+ });
119250
+ await Promise.all([
119251
+ expect(expiryDateInput).toHaveValue(formattedExpiryDate),
119252
+ expect(this.page.getByRole("button", { name: CALENDAR_LABELS.month })).toHaveText(normalizedDate.format(DATE_FORMATS.month)),
119253
+ expect(this.page.getByRole("button", { name: CALENDAR_LABELS.year })).toHaveText(normalizedDate.format(DATE_FORMATS.year)),
119254
+ expect(this.page.getByTitle(normalizedDate.format(DATE_FORMATS.calendarDate))).toHaveClass(RegExp(DATE_PICKER_SELECTORS.selectedDateInCalendarClass)),
119255
+ ]);
119256
+ await this.page.keyboard.press("Enter");
119257
+ await expect(nextYearBtn).toBeHidden();
119258
+ };
119212
119259
  this.fillApiKeyDetails = async ({ label, expiryDate }) => {
119213
119260
  await this.page
119214
119261
  .getByTestId(COMMON_SELECTORS.paneBody)
119215
119262
  .getByTestId(COMMON_SELECTORS.customInputField("label"))
119216
119263
  .fill(label);
119217
- if (expiryDate) {
119218
- await this.page
119219
- .getByTestId(COMMON_SELECTORS.checkboxInput("never-expires"))
119220
- .uncheck();
119221
- const expiryDateInput = this.page
119222
- .getByTestId(COMMON_SELECTORS.paneBody)
119223
- .getByTestId(ADMIN_PANEL_SELECTORS.expiryDateInput);
119224
- await expiryDateInput.click();
119225
- await expect(this.page.getByLabel(DATE_TEXTS.nextYear, { exact: true })).toBeVisible();
119226
- await expiryDateInput.pressSequentially(expiryDate, { delay: 250 });
119227
- dayjs.extend(customParseFormat);
119228
- const parsedExpiryDate = dayjs(expiryDate, DATE_FORMATS.date);
119229
- await Promise.all([
119230
- expect(expiryDateInput).toHaveValue(expiryDate),
119231
- expect(this.page.getByRole("button", { name: CALENDAR_LABELS.month })).toHaveText(parsedExpiryDate.format(DATE_FORMATS.month)),
119232
- expect(this.page.getByRole("button", { name: CALENDAR_LABELS.year })).toHaveText(parsedExpiryDate.format(DATE_FORMATS.year)),
119233
- expect(this.page.getByTitle(parsedExpiryDate.format(DATE_FORMATS.calendarDate))).toHaveClass(RegExp(DATE_PICKER_SELECTORS.selectedDateInCalendarClass)),
119234
- ]);
119235
- await this.page.keyboard.press("Enter");
119236
- await expect(this.page.getByLabel(DATE_TEXTS.nextYear, { exact: true })).toBeHidden();
119237
- }
119238
- await this.page.getByTestId(COMMON_SELECTORS.saveChangesButton).click();
119239
- await this.neetoPlaywrightUtilities.verifyToast();
119264
+ isPresent(expiryDate) && (await this.enableExpiryDate(expiryDate));
119265
+ await this.neetoPlaywrightUtilities.saveChanges({ isPane: true });
119240
119266
  };
119241
119267
  this.verifyApiKey = ({ targetRow, label, date }) => Promise.all([
119242
119268
  expect(targetRow.getByRole("cell", { name: label })).toBeVisible(),
@@ -119265,8 +119291,6 @@ class ApiKeysPage {
119265
119291
  await this.neetoPlaywrightUtilities.verifyToast();
119266
119292
  await expect(targetRow).toBeHidden();
119267
119293
  };
119268
- this.page = page;
119269
- this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
119270
119294
  this.t = getI18nInstance().t;
119271
119295
  }
119272
119296
  }
@@ -119883,6 +119907,11 @@ const TEAM_MEMBER_TEXTS = {
119883
119907
  emailSubject: "Your team members export is here",
119884
119908
  };
119885
119909
 
119910
+ const KEYBOARD_SHORTCUT_TEST_CASES = [
119911
+ { os: "windows", agent: USER_AGENTS.windows },
119912
+ { os: "mac", agent: USER_AGENTS.mac },
119913
+ ];
119914
+
119886
119915
  const PHONE_NUMBER_FORMATS = [
119887
119916
  { name: "Afghanistan", code: "+93", format: "70#######", flag: "🇦🇫" },
119888
119917
  { name: "Aland", code: "+358", format: "5####", flag: "🇦🇽" },
@@ -125308,5 +125337,5 @@ const definePlaywrightConfig = (overrides) => {
125308
125337
  });
125309
125338
  };
125310
125339
 
125311
- export { ACTIONS, ADMIN_PANEL_SELECTORS, API_KEYS_SELECTORS, API_ROUTES, AUDIT_LOGS_SELECTORS, AdminPanelPage, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, 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_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, 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_DEV_ENV, 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, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailRakeClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, 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, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, fillCredentialsAndSubmit, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, 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 };
125340
+ export { ACTIONS, ADMIN_PANEL_SELECTORS, API_KEYS_SELECTORS, API_ROUTES, AUDIT_LOGS_SELECTORS, AdminPanelPage, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, 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_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, 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_DEV_ENV, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, 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, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailRakeClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, 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, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, fillCredentialsAndSubmit, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, 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 };
125312
125341
  //# sourceMappingURL=index.js.map