@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.cjs.js CHANGED
@@ -5046,7 +5046,6 @@ const generateStagingData = (product = "invoice") => {
5046
5046
  };
5047
5047
  };
5048
5048
 
5049
- /* eslint-disable playwright/no-skipped-test */
5050
5049
  const execCommand = (command) => child_process.execSync(command)
5051
5050
  .toString("utf-8")
5052
5051
  .replace(/[\n\r\s]+$/, "");
@@ -5211,7 +5210,7 @@ const globalShortcuts = (t) => [
5211
5210
  },
5212
5211
  {
5213
5212
  description: t("neetoMolecules.keyboardShortcuts.global.openProductSwitcher"),
5214
- sequence: "ctrl+e",
5213
+ sequence: "ctrl+u",
5215
5214
  },
5216
5215
  ];
5217
5216
  const generatePhoneNumber = () => `${"+91"} 9${faker.faker.string.numeric(4)} ${faker.faker.string.numeric(5)}`;
@@ -5377,8 +5376,9 @@ const NEETO_FILTERS_SELECTORS = {
5377
5376
  };
5378
5377
 
5379
5378
  const HELP_CENTER_SELECTORS = {
5379
+ helpMenuBtn: "help-menu-button",
5380
5380
  helpButton: "help-button",
5381
- documentationButton: "help-link-help-center-button",
5381
+ documentationButton: "help-link-help-articles-button",
5382
5382
  keyboardShortcutButton: "help-link-keyboard-shortcut-button",
5383
5383
  chatButton: "help-link-live-chat-button",
5384
5384
  whatsNewButton: "help-link-engage-button",
@@ -29096,9 +29096,10 @@ function requireAddressparser () {
29096
29096
  * Converts tokens for a single address into an address object
29097
29097
  *
29098
29098
  * @param {Array} tokens Tokens object
29099
+ * @param {Number} depth Current recursion depth for nested group protection
29099
29100
  * @return {Object} Address object
29100
29101
  */
29101
- function _handleAddress(tokens) {
29102
+ function _handleAddress(tokens, depth) {
29102
29103
  let isGroup = false;
29103
29104
  let state = 'text';
29104
29105
  let address;
@@ -29179,7 +29180,7 @@ function requireAddressparser () {
29179
29180
  // Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
29180
29181
  let groupMembers = [];
29181
29182
  if (data.group.length) {
29182
- let parsedGroup = addressparser(data.group.join(','));
29183
+ let parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
29183
29184
  // Flatten: if any member is itself a group, extract its members into the sequence
29184
29185
  parsedGroup.forEach(member => {
29185
29186
  if (member.group) {
@@ -29389,6 +29390,13 @@ function requireAddressparser () {
29389
29390
  }
29390
29391
  }
29391
29392
 
29393
+ /**
29394
+ * Maximum recursion depth for parsing nested groups.
29395
+ * RFC 5322 doesn't allow nested groups, so this is a safeguard against
29396
+ * malicious input that could cause stack overflow.
29397
+ */
29398
+ const MAX_NESTED_GROUP_DEPTH = 50;
29399
+
29392
29400
  /**
29393
29401
  * Parses structured e-mail addresses from an address field
29394
29402
  *
@@ -29401,10 +29409,18 @@ function requireAddressparser () {
29401
29409
  * [{name: 'Name', address: 'address@domain'}]
29402
29410
  *
29403
29411
  * @param {String} str Address field
29412
+ * @param {Object} options Optional options object
29413
+ * @param {Number} options._depth Internal recursion depth counter (do not set manually)
29404
29414
  * @return {Array} An array of address objects
29405
29415
  */
29406
29416
  function addressparser(str, options) {
29407
29417
  options = options || {};
29418
+ let depth = options._depth || 0;
29419
+
29420
+ // Prevent stack overflow from deeply nested groups (DoS protection)
29421
+ if (depth > MAX_NESTED_GROUP_DEPTH) {
29422
+ return [];
29423
+ }
29408
29424
 
29409
29425
  let tokenizer = new Tokenizer(str);
29410
29426
  let tokens = tokenizer.tokenize();
@@ -29429,7 +29445,7 @@ function requireAddressparser () {
29429
29445
  }
29430
29446
 
29431
29447
  addresses.forEach(address => {
29432
- address = _handleAddress(address);
29448
+ address = _handleAddress(address, depth);
29433
29449
  if (address.length) {
29434
29450
  parsedAddresses = parsedAddresses.concat(address);
29435
29451
  }
@@ -40941,6 +40957,8 @@ function requireStreams () {
40941
40957
  return streams;
40942
40958
  }
40943
40959
 
40960
+ lib$a.exports;
40961
+
40944
40962
  var hasRequiredLib$a;
40945
40963
 
40946
40964
  function requireLib$a () {
@@ -40952,22 +40970,21 @@ function requireLib$a () {
40952
40970
 
40953
40971
  var bomHandling = requireBomHandling();
40954
40972
  var mergeModules = requireMergeExports();
40955
- var iconv = module.exports;
40956
40973
 
40957
40974
  // All codecs and aliases are kept here, keyed by encoding name/alias.
40958
40975
  // They are lazy loaded in `iconv.getCodec` from `encodings/index.js`.
40959
40976
  // Cannot initialize with { __proto__: null } because Boolean({ __proto__: null }) === true
40960
- iconv.encodings = null;
40977
+ module.exports.encodings = null;
40961
40978
 
40962
40979
  // Characters emitted in case of error.
40963
- iconv.defaultCharUnicode = "�";
40964
- iconv.defaultCharSingleByte = "?";
40980
+ module.exports.defaultCharUnicode = "�";
40981
+ module.exports.defaultCharSingleByte = "?";
40965
40982
 
40966
40983
  // Public API.
40967
- iconv.encode = function encode (str, encoding, options) {
40984
+ module.exports.encode = function encode (str, encoding, options) {
40968
40985
  str = "" + (str || ""); // Ensure string.
40969
40986
 
40970
- var encoder = iconv.getEncoder(encoding, options);
40987
+ var encoder = module.exports.getEncoder(encoding, options);
40971
40988
 
40972
40989
  var res = encoder.write(str);
40973
40990
  var trail = encoder.end();
@@ -40975,17 +40992,17 @@ function requireLib$a () {
40975
40992
  return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res
40976
40993
  };
40977
40994
 
40978
- iconv.decode = function decode (buf, encoding, options) {
40995
+ module.exports.decode = function decode (buf, encoding, options) {
40979
40996
  if (typeof buf === "string") {
40980
- if (!iconv.skipDecodeWarning) {
40997
+ if (!module.exports.skipDecodeWarning) {
40981
40998
  console.error("Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding");
40982
- iconv.skipDecodeWarning = true;
40999
+ module.exports.skipDecodeWarning = true;
40983
41000
  }
40984
41001
 
40985
41002
  buf = Buffer.from("" + (buf || ""), "binary"); // Ensure buffer.
40986
41003
  }
40987
41004
 
40988
- var decoder = iconv.getDecoder(encoding, options);
41005
+ var decoder = module.exports.getDecoder(encoding, options);
40989
41006
 
40990
41007
  var res = decoder.write(buf);
40991
41008
  var trail = decoder.end();
@@ -40993,9 +41010,9 @@ function requireLib$a () {
40993
41010
  return trail ? (res + trail) : res
40994
41011
  };
40995
41012
 
40996
- iconv.encodingExists = function encodingExists (enc) {
41013
+ module.exports.encodingExists = function encodingExists (enc) {
40997
41014
  try {
40998
- iconv.getCodec(enc);
41015
+ module.exports.getCodec(enc);
40999
41016
  return true
41000
41017
  } catch (e) {
41001
41018
  return false
@@ -41003,31 +41020,31 @@ function requireLib$a () {
41003
41020
  };
41004
41021
 
41005
41022
  // Legacy aliases to convert functions
41006
- iconv.toEncoding = iconv.encode;
41007
- iconv.fromEncoding = iconv.decode;
41023
+ module.exports.toEncoding = module.exports.encode;
41024
+ module.exports.fromEncoding = module.exports.decode;
41008
41025
 
41009
41026
  // Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache.
41010
- iconv._codecDataCache = { __proto__: null };
41027
+ module.exports._codecDataCache = { __proto__: null };
41011
41028
 
41012
- iconv.getCodec = function getCodec (encoding) {
41013
- if (!iconv.encodings) {
41029
+ module.exports.getCodec = function getCodec (encoding) {
41030
+ if (!module.exports.encodings) {
41014
41031
  var raw = requireEncodings();
41015
41032
  // TODO: In future versions when old nodejs support is removed can use object.assign
41016
- iconv.encodings = { __proto__: null }; // Initialize as empty object.
41017
- mergeModules(iconv.encodings, raw);
41033
+ module.exports.encodings = { __proto__: null }; // Initialize as empty object.
41034
+ mergeModules(module.exports.encodings, raw);
41018
41035
  }
41019
41036
 
41020
41037
  // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
41021
- var enc = iconv._canonicalizeEncoding(encoding);
41038
+ var enc = module.exports._canonicalizeEncoding(encoding);
41022
41039
 
41023
41040
  // Traverse iconv.encodings to find actual codec.
41024
41041
  var codecOptions = {};
41025
41042
  while (true) {
41026
- var codec = iconv._codecDataCache[enc];
41043
+ var codec = module.exports._codecDataCache[enc];
41027
41044
 
41028
41045
  if (codec) { return codec }
41029
41046
 
41030
- var codecDef = iconv.encodings[enc];
41047
+ var codecDef = module.exports.encodings[enc];
41031
41048
 
41032
41049
  switch (typeof codecDef) {
41033
41050
  case "string": // Direct alias to other encoding.
@@ -41048,9 +41065,9 @@ function requireLib$a () {
41048
41065
  // The codec function must load all tables and return object with .encoder and .decoder methods.
41049
41066
  // It'll be called only once (for each different options object).
41050
41067
  //
41051
- codec = new codecDef(codecOptions, iconv);
41068
+ codec = new codecDef(codecOptions, module.exports);
41052
41069
 
41053
- iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.
41070
+ module.exports._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.
41054
41071
  return codec
41055
41072
 
41056
41073
  default:
@@ -41059,13 +41076,13 @@ function requireLib$a () {
41059
41076
  }
41060
41077
  };
41061
41078
 
41062
- iconv._canonicalizeEncoding = function (encoding) {
41079
+ module.exports._canonicalizeEncoding = function (encoding) {
41063
41080
  // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.
41064
41081
  return ("" + encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "")
41065
41082
  };
41066
41083
 
41067
- iconv.getEncoder = function getEncoder (encoding, options) {
41068
- var codec = iconv.getCodec(encoding);
41084
+ module.exports.getEncoder = function getEncoder (encoding, options) {
41085
+ var codec = module.exports.getCodec(encoding);
41069
41086
  var encoder = new codec.encoder(options, codec);
41070
41087
 
41071
41088
  if (codec.bomAware && options && options.addBOM) { encoder = new bomHandling.PrependBOM(encoder, options); }
@@ -41073,8 +41090,8 @@ function requireLib$a () {
41073
41090
  return encoder
41074
41091
  };
41075
41092
 
41076
- iconv.getDecoder = function getDecoder (encoding, options) {
41077
- var codec = iconv.getCodec(encoding);
41093
+ module.exports.getDecoder = function getDecoder (encoding, options) {
41094
+ var codec = module.exports.getCodec(encoding);
41078
41095
  var decoder = new codec.decoder(options, codec);
41079
41096
 
41080
41097
  if (codec.bomAware && !(options && options.stripBOM === false)) { decoder = new bomHandling.StripBOM(decoder, options); }
@@ -41087,26 +41104,26 @@ function requireLib$a () {
41087
41104
  // up to 100Kb to the output bundle. To avoid unnecessary code bloat, we don't enable Streaming API in browser by default.
41088
41105
  // If you would like to enable it explicitly, please add the following code to your app:
41089
41106
  // > iconv.enableStreamingAPI(require('stream'));
41090
- iconv.enableStreamingAPI = function enableStreamingAPI (streamModule) {
41091
- if (iconv.supportsStreams) { return }
41107
+ module.exports.enableStreamingAPI = function enableStreamingAPI (streamModule) {
41108
+ if (module.exports.supportsStreams) { return }
41092
41109
 
41093
41110
  // Dependency-inject stream module to create IconvLite stream classes.
41094
41111
  var streams = requireStreams()(streamModule);
41095
41112
 
41096
41113
  // Not public API yet, but expose the stream classes.
41097
- iconv.IconvLiteEncoderStream = streams.IconvLiteEncoderStream;
41098
- iconv.IconvLiteDecoderStream = streams.IconvLiteDecoderStream;
41114
+ module.exports.IconvLiteEncoderStream = streams.IconvLiteEncoderStream;
41115
+ module.exports.IconvLiteDecoderStream = streams.IconvLiteDecoderStream;
41099
41116
 
41100
41117
  // Streaming API.
41101
- iconv.encodeStream = function encodeStream (encoding, options) {
41102
- return new iconv.IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options)
41118
+ module.exports.encodeStream = function encodeStream (encoding, options) {
41119
+ return new module.exports.IconvLiteEncoderStream(module.exports.getEncoder(encoding, options), options)
41103
41120
  };
41104
41121
 
41105
- iconv.decodeStream = function decodeStream (encoding, options) {
41106
- return new iconv.IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options)
41122
+ module.exports.decodeStream = function decodeStream (encoding, options) {
41123
+ return new module.exports.IconvLiteDecoderStream(module.exports.getDecoder(encoding, options), options)
41107
41124
  };
41108
41125
 
41109
- iconv.supportsStreams = true;
41126
+ module.exports.supportsStreams = true;
41110
41127
  };
41111
41128
 
41112
41129
  // Enable Streaming API automatically if 'stream' module is available and non-empty (the majority of environments).
@@ -41116,10 +41133,10 @@ function requireLib$a () {
41116
41133
  } catch (e) {}
41117
41134
 
41118
41135
  if (streamModule && streamModule.Transform) {
41119
- iconv.enableStreamingAPI(streamModule);
41136
+ module.exports.enableStreamingAPI(streamModule);
41120
41137
  } else {
41121
41138
  // In rare cases where 'stream' module is not available by default, throw a helpful exception.
41122
- iconv.encodeStream = iconv.decodeStream = function () {
41139
+ module.exports.encodeStream = module.exports.decodeStream = function () {
41123
41140
  throw new Error("iconv-lite Streaming API is not enabled. Use iconv.enableStreamingAPI(require('stream')); to enable it.")
41124
41141
  };
41125
41142
  }
@@ -51196,7 +51213,6 @@ var require$$11 = [
51196
51213
  "drive",
51197
51214
  "dtv",
51198
51215
  "dubai",
51199
- "dunlop",
51200
51216
  "dupont",
51201
51217
  "durban",
51202
51218
  "dvag",
@@ -53428,7 +53444,11 @@ function requireMailParser () {
53428
53444
  result.push(textPart);
53429
53445
  }
53430
53446
 
53431
- result.push(`<a href="${link.url}">${link.text}</a>`);
53447
+ // Escape quotes in URL to prevent XSS
53448
+ let safeUrl = link.url.replace(/"/g, '&quot;');
53449
+ // Escape HTML entities in link text
53450
+ let safeText = he.encode(link.text, { useNamedReferences: true });
53451
+ result.push(`<a href="${safeUrl}">${safeText}</a>`);
53432
53452
 
53433
53453
  last = link.lastIndex;
53434
53454
  });
@@ -114396,29 +114416,21 @@ const THEMES_TEXTS = {
114396
114416
 
114397
114417
  class HelpAndProfilePage {
114398
114418
  constructor({ page, neetoPlaywrightUtilities, chatApiBaseURL, kbDocsBaseURL, changelogBaseURL, }) {
114399
- this.hoverOnBody = () => this.page.locator("body").hover({ timeout: 10000 });
114400
114419
  this.openHelpCenter = async () => {
114420
+ const floatingActionMenuBtn = this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton);
114401
114421
  await test.expect(async () => {
114402
- await this.hoverOnBody();
114403
- const floatingActionMenuButton = this.page.getByTestId(COMMON_SELECTORS.floatingActionMenuButton);
114404
- await floatingActionMenuButton.scrollIntoViewIfNeeded();
114405
- await floatingActionMenuButton.hover();
114406
- await test.expect(this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton)).toBeVisible();
114422
+ await floatingActionMenuBtn.scrollIntoViewIfNeeded();
114423
+ await floatingActionMenuBtn.hover();
114424
+ await test.expect(this.page.getByTestId(HELP_CENTER_SELECTORS.whatsNewButton)).toBeVisible();
114407
114425
  }).toPass({ timeout: 60000 });
114408
114426
  };
114409
- this.openLiveChatAndVerify = async (widgetVisibilityTimeout = 10000) => {
114410
- await test.expect(async () => {
114411
- await this.openHelpCenter();
114412
- await this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton).click();
114413
- await test.expect(this.neetoChatWidget).toBeVisible({
114414
- timeout: widgetVisibilityTimeout,
114415
- });
114416
- await test.expect(this.neetoChatSpinner).toBeHidden({ timeout: 20 * 1000 });
114417
- await test.expect(this.neetoChatWidget).toBeVisible({
114418
- timeout: widgetVisibilityTimeout,
114419
- });
114420
- }).toPass({ timeout: 35000 + widgetVisibilityTimeout * 2 });
114421
- };
114427
+ this.openLiveChatAndVerify = () => test.expect(async () => {
114428
+ await this.openHelpCenter();
114429
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114430
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.chatButton).click();
114431
+ await test.expect(this.neetoChatSpinner).toBeHidden({ timeout: 20000 });
114432
+ await test.expect(this.neetoChatWidget).toBeVisible({ timeout: 10000 });
114433
+ }).toPass({ timeout: 60000 });
114422
114434
  /**
114423
114435
  * @deprecated This method is deprecated. Use openAndVerifyChatWidget instead.
114424
114436
  */
@@ -114438,7 +114450,7 @@ class HelpAndProfilePage {
114438
114450
  this.openAndVerifyChatWidget = async () => {
114439
114451
  await this.page.reload();
114440
114452
  await this.neetoPlaywrightUtilities.waitForPageLoad();
114441
- await test.test.step("1: Open live chat and verify iframe", () => this.openLiveChatAndVerify());
114453
+ await test.test.step("1: Open live chat", this.openLiveChatAndVerify);
114442
114454
  await test.test.step("2: Close and reopen live chat frame", async () => {
114443
114455
  await this.page.getByTestId(CHAT_WIDGET_SELECTORS.closeChat).click();
114444
114456
  await test.expect(this.neetoChatWidget).toBeHidden({ timeout: 35000 });
@@ -114467,6 +114479,7 @@ class HelpAndProfilePage {
114467
114479
  this.openAndVerifyHelpArticles = async () => {
114468
114480
  await test.test.step("1: Open Help Center links", this.openHelpCenter);
114469
114481
  await test.test.step("2: Open and verify help articles link", async () => {
114482
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114470
114483
  const helpArticlesPromise = this.page.waitForEvent("popup");
114471
114484
  await this.page
114472
114485
  .getByTestId(HELP_CENTER_SELECTORS.documentationButton)
@@ -114507,7 +114520,7 @@ class HelpAndProfilePage {
114507
114520
  });
114508
114521
  };
114509
114522
  this.openAndVerifyChangelog = async () => {
114510
- await test.test.step("1: Open Help Center links and changelog", this.openChangelogPane);
114523
+ await test.test.step("1: Open changelog", this.openChangelogPane);
114511
114524
  await test.test.step("2: Close and reopen changelog pane", async () => {
114512
114525
  await this.page
114513
114526
  .getByTestId(CHANGELOG_WIDGET_SELECTORS.closeButton)
@@ -114524,8 +114537,10 @@ class HelpAndProfilePage {
114524
114537
  await this.neetoPlaywrightUtilities.waitForPageLoad({
114525
114538
  customPageContext: changelogPage,
114526
114539
  });
114527
- await test.expect(changelogPage.getByRole("button", { name: ENGAGE_TEXTS.subscribe })).toBeVisible({ timeout: 10000 });
114528
- await test.expect(changelogPage).toHaveURL(this.changelogBaseURL);
114540
+ await Promise.all([
114541
+ test.expect(changelogPage).toHaveURL(this.changelogBaseURL),
114542
+ test.expect(changelogPage.getByRole("button", { name: ENGAGE_TEXTS.subscribe })).toBeVisible({ timeout: 10000 }),
114543
+ ]);
114529
114544
  await changelogPage.close();
114530
114545
  });
114531
114546
  };
@@ -114644,21 +114659,21 @@ class HelpAndProfilePage {
114644
114659
  await test.expect(this.page.getByTestId(COMMON_SELECTORS.appSwitcherWrapper)).toBeVisible();
114645
114660
  }).toPass({ timeout: 45000 }));
114646
114661
  await test.test.step("2: Verify search functionality", async () => {
114647
- const playdashAppLink = this.page.getByTestId(COMMON_SELECTORS.appLink(productName));
114648
- const replayAppLink = this.page.getByTestId(COMMON_SELECTORS.appLink("Replay"));
114662
+ const playdash = this.page.getByTestId(COMMON_SELECTORS.appLink(productName));
114663
+ const replay = this.page.getByTestId(COMMON_SELECTORS.appLink("Replay"));
114649
114664
  const searchInput = this.page.getByTestId(COMMON_SELECTORS.productSwitcherSearchInput);
114650
114665
  await searchInput.fill(faker.faker.word.words(3));
114651
114666
  //TODO: Use data-testid label when this https://github.com/bigbinary/neeto-molecules/issues/2114 is resolved
114652
114667
  await test.expect(this.page.getByText(this.t("neetoMolecules.productSwitcher.noApps"))).toBeVisible();
114653
114668
  await searchInput.fill(searchQueryPartial);
114654
114669
  await Promise.all([
114655
- test.expect(playdashAppLink).toBeVisible(),
114656
- test.expect(replayAppLink).toBeVisible(),
114670
+ test.expect(playdash).toBeVisible(),
114671
+ test.expect(replay).toBeVisible(),
114657
114672
  ]);
114658
114673
  await searchInput.fill(searchQueryFull);
114659
114674
  await Promise.all([
114660
- test.expect(playdashAppLink).toBeVisible(),
114661
- test.expect(replayAppLink).toBeHidden(),
114675
+ test.expect(playdash).toBeVisible(),
114676
+ test.expect(replay).toBeHidden(),
114662
114677
  ]);
114663
114678
  });
114664
114679
  };
@@ -114685,7 +114700,7 @@ class HelpAndProfilePage {
114685
114700
  this.verifyLogout = async () => {
114686
114701
  if (shouldSkipSetupAndTeardown())
114687
114702
  return;
114688
- await test.test.step("1: Open Help center and verify", this.openHelpCenter);
114703
+ await test.test.step("1: Open Help center", this.openHelpCenter);
114689
114704
  await test.test.step("2: Click logout and verify", async () => {
114690
114705
  await this.page
114691
114706
  .getByTestId(PROFILE_SECTION_SELECTORS.logoutButton)
@@ -114767,6 +114782,7 @@ class HelpAndProfilePage {
114767
114782
  this.openAndVerifyStatus = async (appName) => {
114768
114783
  await test.test.step("1: Open Help Center links", this.openHelpCenter);
114769
114784
  await test.test.step("2: Open and verify status page", async () => {
114785
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114770
114786
  const statusPagePromise = this.page.waitForEvent("popup");
114771
114787
  await this.page.getByTestId(HELP_CENTER_SELECTORS.statusButton).click();
114772
114788
  const statusPage = await statusPagePromise;
@@ -114780,6 +114796,7 @@ class HelpAndProfilePage {
114780
114796
  this.openAndVerifyCommunity = async () => {
114781
114797
  await test.test.step("1: Open Help Center links", this.openHelpCenter);
114782
114798
  await test.test.step("2: Open and verify community", async () => {
114799
+ await this.page.getByTestId(HELP_CENTER_SELECTORS.helpMenuBtn).click();
114783
114800
  const communityPagePromise = this.page.waitForEvent("popup");
114784
114801
  await this.page
114785
114802
  .getByTestId(HELP_CENTER_SELECTORS.communityButton)
@@ -119228,36 +119245,45 @@ class OrganizationPage {
119228
119245
  }
119229
119246
  }
119230
119247
 
119248
+ dayjs.extend(customParseFormat);
119231
119249
  class ApiKeysPage {
119232
119250
  constructor(page, neetoPlaywrightUtilities) {
119251
+ this.page = page;
119252
+ this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
119253
+ this.enableExpiryDate = async (expiryDate) => {
119254
+ const userProps = await getGlobalUserProps(this.page);
119255
+ const normalizedDate = dayjs(expiryDate, DATE_FORMATS.date);
119256
+ const formattedExpiryDate = normalizedDate.format(userProps === null || userProps === void 0 ? void 0 : userProps.dateFormat);
119257
+ const expiryDateInput = this.page
119258
+ .getByTestId(COMMON_SELECTORS.paneBody)
119259
+ .getByTestId(ADMIN_PANEL_SELECTORS.expiryDateInput);
119260
+ const nextYearBtn = this.page.getByLabel(DATE_TEXTS.nextYear, {
119261
+ exact: true,
119262
+ });
119263
+ await this.page
119264
+ .getByTestId(COMMON_SELECTORS.checkboxInput("never-expires"))
119265
+ .uncheck();
119266
+ await expiryDateInput.click();
119267
+ await test.expect(nextYearBtn).toBeVisible();
119268
+ await expiryDateInput.pressSequentially(formattedExpiryDate, {
119269
+ delay: 250,
119270
+ });
119271
+ await Promise.all([
119272
+ test.expect(expiryDateInput).toHaveValue(formattedExpiryDate),
119273
+ test.expect(this.page.getByRole("button", { name: CALENDAR_LABELS.month })).toHaveText(normalizedDate.format(DATE_FORMATS.month)),
119274
+ test.expect(this.page.getByRole("button", { name: CALENDAR_LABELS.year })).toHaveText(normalizedDate.format(DATE_FORMATS.year)),
119275
+ test.expect(this.page.getByTitle(normalizedDate.format(DATE_FORMATS.calendarDate))).toHaveClass(RegExp(DATE_PICKER_SELECTORS.selectedDateInCalendarClass)),
119276
+ ]);
119277
+ await this.page.keyboard.press("Enter");
119278
+ await test.expect(nextYearBtn).toBeHidden();
119279
+ };
119233
119280
  this.fillApiKeyDetails = async ({ label, expiryDate }) => {
119234
119281
  await this.page
119235
119282
  .getByTestId(COMMON_SELECTORS.paneBody)
119236
119283
  .getByTestId(COMMON_SELECTORS.customInputField("label"))
119237
119284
  .fill(label);
119238
- if (expiryDate) {
119239
- await this.page
119240
- .getByTestId(COMMON_SELECTORS.checkboxInput("never-expires"))
119241
- .uncheck();
119242
- const expiryDateInput = this.page
119243
- .getByTestId(COMMON_SELECTORS.paneBody)
119244
- .getByTestId(ADMIN_PANEL_SELECTORS.expiryDateInput);
119245
- await expiryDateInput.click();
119246
- await test.expect(this.page.getByLabel(DATE_TEXTS.nextYear, { exact: true })).toBeVisible();
119247
- await expiryDateInput.pressSequentially(expiryDate, { delay: 250 });
119248
- dayjs.extend(customParseFormat);
119249
- const parsedExpiryDate = dayjs(expiryDate, DATE_FORMATS.date);
119250
- await Promise.all([
119251
- test.expect(expiryDateInput).toHaveValue(expiryDate),
119252
- test.expect(this.page.getByRole("button", { name: CALENDAR_LABELS.month })).toHaveText(parsedExpiryDate.format(DATE_FORMATS.month)),
119253
- test.expect(this.page.getByRole("button", { name: CALENDAR_LABELS.year })).toHaveText(parsedExpiryDate.format(DATE_FORMATS.year)),
119254
- test.expect(this.page.getByTitle(parsedExpiryDate.format(DATE_FORMATS.calendarDate))).toHaveClass(RegExp(DATE_PICKER_SELECTORS.selectedDateInCalendarClass)),
119255
- ]);
119256
- await this.page.keyboard.press("Enter");
119257
- await test.expect(this.page.getByLabel(DATE_TEXTS.nextYear, { exact: true })).toBeHidden();
119258
- }
119259
- await this.page.getByTestId(COMMON_SELECTORS.saveChangesButton).click();
119260
- await this.neetoPlaywrightUtilities.verifyToast();
119285
+ neetoCist.isPresent(expiryDate) && (await this.enableExpiryDate(expiryDate));
119286
+ await this.neetoPlaywrightUtilities.saveChanges({ isPane: true });
119261
119287
  };
119262
119288
  this.verifyApiKey = ({ targetRow, label, date }) => Promise.all([
119263
119289
  test.expect(targetRow.getByRole("cell", { name: label })).toBeVisible(),
@@ -119286,8 +119312,6 @@ class ApiKeysPage {
119286
119312
  await this.neetoPlaywrightUtilities.verifyToast();
119287
119313
  await test.expect(targetRow).toBeHidden();
119288
119314
  };
119289
- this.page = page;
119290
- this.neetoPlaywrightUtilities = neetoPlaywrightUtilities;
119291
119315
  this.t = playwrightI18nextFixture.getI18nInstance().t;
119292
119316
  }
119293
119317
  }
@@ -119904,6 +119928,11 @@ const TEAM_MEMBER_TEXTS = {
119904
119928
  emailSubject: "Your team members export is here",
119905
119929
  };
119906
119930
 
119931
+ const KEYBOARD_SHORTCUT_TEST_CASES = [
119932
+ { os: "windows", agent: USER_AGENTS.windows },
119933
+ { os: "mac", agent: USER_AGENTS.mac },
119934
+ ];
119935
+
119907
119936
  const PHONE_NUMBER_FORMATS = [
119908
119937
  { name: "Afghanistan", code: "+93", format: "70#######", flag: "🇦🇫" },
119909
119938
  { name: "Aland", code: "+358", format: "5####", flag: "🇦🇽" },
@@ -125393,6 +125422,7 @@ exports.ImageUploader = ImageUploader;
125393
125422
  exports.IntegrationBase = IntegrationBase;
125394
125423
  exports.IpRestrictionsApi = IpRestrictionsApi;
125395
125424
  exports.KEYBOARD_SHORTCUTS_SELECTORS = KEYBOARD_SHORTCUTS_SELECTORS;
125425
+ exports.KEYBOARD_SHORTCUT_TEST_CASES = KEYBOARD_SHORTCUT_TEST_CASES;
125396
125426
  exports.LIST_MODIFIER_SELECTORS = LIST_MODIFIER_SELECTORS;
125397
125427
  exports.LIST_MODIFIER_TAGS = LIST_MODIFIER_TAGS;
125398
125428
  exports.LOGIN_SELECTORS = LOGIN_SELECTORS;