@thinkwise/testwise 0.2.105 → 0.2.111

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.
Files changed (100) hide show
  1. package/artifact-builder/CustomActionBarGenerator.ts +210 -0
  2. package/artifact-builder/InterfaceGenerator.ts +4 -1
  3. package/artifact-builder/ScreenInterfaceRefiner.ts +7 -1
  4. package/artifact-builder/SubjectComponentGenerator.ts +7 -1
  5. package/artifact-builder/SubjectRegistration.ts +4 -1
  6. package/artifact-builder/TaskDataBuilder.ts +71 -0
  7. package/artifact-builder/helpers/DataRetriever.ts +11 -0
  8. package/artifact-builder/helpers/PipelinePaths.ts +5 -0
  9. package/artifact-builder/index.ts +2 -0
  10. package/components/action-bar/ActionBarObjects.ts +3 -1
  11. package/components/filter/FilterPopup.ts +77 -14
  12. package/components/filter/FilterPopupObjects.ts +25 -4
  13. package/components/grid/Grid.ts +40 -2
  14. package/components/grid/GridObjects.ts +18 -3
  15. package/components/pop-up/AllRowsPopUp.ts +4 -1
  16. package/controls/DateControl.ts +26 -13
  17. package/controls/DateControlObjects.ts +1 -1
  18. package/controls/FormComboBoxObjects.ts +2 -2
  19. package/controls/GridColumnControl.ts +10 -0
  20. package/dist/artifact-builder/CustomActionBarGenerator.d.ts +82 -0
  21. package/dist/artifact-builder/CustomActionBarGenerator.js +175 -0
  22. package/dist/artifact-builder/CustomActionBarGenerator.js.map +1 -0
  23. package/dist/artifact-builder/InterfaceGenerator.js +4 -1
  24. package/dist/artifact-builder/InterfaceGenerator.js.map +1 -1
  25. package/dist/artifact-builder/ScreenInterfaceRefiner.js +7 -1
  26. package/dist/artifact-builder/ScreenInterfaceRefiner.js.map +1 -1
  27. package/dist/artifact-builder/SubjectComponentGenerator.js +5 -1
  28. package/dist/artifact-builder/SubjectComponentGenerator.js.map +1 -1
  29. package/dist/artifact-builder/SubjectRegistration.js +4 -1
  30. package/dist/artifact-builder/SubjectRegistration.js.map +1 -1
  31. package/dist/artifact-builder/TaskDataBuilder.d.ts +21 -0
  32. package/dist/artifact-builder/TaskDataBuilder.js +60 -0
  33. package/dist/artifact-builder/TaskDataBuilder.js.map +1 -0
  34. package/dist/artifact-builder/helpers/DataRetriever.d.ts +2 -0
  35. package/dist/artifact-builder/helpers/DataRetriever.js +7 -0
  36. package/dist/artifact-builder/helpers/DataRetriever.js.map +1 -1
  37. package/dist/artifact-builder/helpers/PipelinePaths.d.ts +2 -0
  38. package/dist/artifact-builder/helpers/PipelinePaths.js +4 -0
  39. package/dist/artifact-builder/helpers/PipelinePaths.js.map +1 -1
  40. package/dist/artifact-builder/index.d.ts +2 -0
  41. package/dist/artifact-builder/index.js +2 -0
  42. package/dist/artifact-builder/index.js.map +1 -1
  43. package/dist/components/action-bar/ActionBarObjects.js +2 -1
  44. package/dist/components/action-bar/ActionBarObjects.js.map +1 -1
  45. package/dist/components/filter/FilterPopup.d.ts +50 -2
  46. package/dist/components/filter/FilterPopup.js +69 -15
  47. package/dist/components/filter/FilterPopup.js.map +1 -1
  48. package/dist/components/filter/FilterPopupObjects.d.ts +4 -2
  49. package/dist/components/filter/FilterPopupObjects.js +18 -4
  50. package/dist/components/filter/FilterPopupObjects.js.map +1 -1
  51. package/dist/components/grid/Grid.d.ts +22 -0
  52. package/dist/components/grid/Grid.js +36 -2
  53. package/dist/components/grid/Grid.js.map +1 -1
  54. package/dist/components/grid/GridObjects.d.ts +2 -0
  55. package/dist/components/grid/GridObjects.js +12 -2
  56. package/dist/components/grid/GridObjects.js.map +1 -1
  57. package/dist/components/pop-up/AllRowsPopUp.js +4 -1
  58. package/dist/components/pop-up/AllRowsPopUp.js.map +1 -1
  59. package/dist/controls/DateControl.d.ts +18 -10
  60. package/dist/controls/DateControl.js +21 -8
  61. package/dist/controls/DateControl.js.map +1 -1
  62. package/dist/controls/DateControlObjects.js +1 -1
  63. package/dist/controls/DateControlObjects.js.map +1 -1
  64. package/dist/controls/FormComboBoxObjects.js +2 -2
  65. package/dist/controls/FormComboBoxObjects.js.map +1 -1
  66. package/dist/controls/GridColumnControl.d.ts +2 -0
  67. package/dist/controls/GridColumnControl.js +6 -0
  68. package/dist/controls/GridColumnControl.js.map +1 -1
  69. package/dist/helpers/DateFormat.d.ts +69 -0
  70. package/dist/helpers/DateFormat.js +100 -0
  71. package/dist/helpers/DateFormat.js.map +1 -0
  72. package/dist/helpers/DateLocaleHelper.d.ts +17 -0
  73. package/dist/helpers/DateLocaleHelper.js +52 -0
  74. package/dist/helpers/DateLocaleHelper.js.map +1 -0
  75. package/dist/helpers/LoginHelper.js +2 -1
  76. package/dist/helpers/LoginHelper.js.map +1 -1
  77. package/dist/helpers/Poll.d.ts +24 -2
  78. package/dist/helpers/Poll.js +87 -5
  79. package/dist/helpers/Poll.js.map +1 -1
  80. package/dist/helpers/UserSimulationHelper.js +2 -1
  81. package/dist/helpers/UserSimulationHelper.js.map +1 -1
  82. package/dist/interfaces/ITabTask.d.ts +21 -0
  83. package/dist/interfaces/ITabTask.js +2 -0
  84. package/dist/interfaces/ITabTask.js.map +1 -0
  85. package/dist/services/IndiciumApi.service.d.ts +7 -0
  86. package/dist/services/IndiciumApi.service.js +19 -0
  87. package/dist/services/IndiciumApi.service.js.map +1 -1
  88. package/dist/types/PollTypes.d.ts +5 -0
  89. package/helpers/DateFormat.ts +123 -0
  90. package/helpers/DateLocaleHelper.ts +57 -0
  91. package/helpers/LoginHelper.ts +2 -1
  92. package/helpers/Poll.ts +108 -5
  93. package/helpers/UserSimulationHelper.ts +2 -1
  94. package/interfaces/ITabTask.ts +21 -0
  95. package/package.json +3 -1
  96. package/promptCredentials.js +124 -124
  97. package/scripts/checkPackageContents.js +39 -0
  98. package/scripts/sync.js +14 -0
  99. package/services/IndiciumApi.service.ts +21 -0
  100. package/types/PollTypes.ts +5 -0
@@ -1,27 +1,109 @@
1
+ const maxDescribedLength = 200;
2
+ /**
3
+ * Thrown when `pollUntil` exceeds its timeout.
4
+ *
5
+ * The message states what was awaited, how many attempts were made and the last value
6
+ * the polled function returned, so a timeout is diagnosable from a test report alone.
7
+ * The same details are exposed as properties for programmatic inspection.
8
+ */
9
+ export class PollTimeoutError extends Error {
10
+ constructor(details) {
11
+ const waitingFor = details.description ? ` waiting for ${details.description}` : '';
12
+ super(`pollUntil timeout after ${details.timeout}ms${waitingFor}; ` +
13
+ `${details.attempts} attempts over ${details.elapsedMs}ms, ` +
14
+ `last value: ${describePolledValue(details.lastValue)}`);
15
+ this.name = 'PollTimeoutError';
16
+ this.timeout = details.timeout;
17
+ this.elapsedMs = details.elapsedMs;
18
+ this.attempts = details.attempts;
19
+ this.lastValue = details.lastValue;
20
+ this.description = details.description;
21
+ }
22
+ }
23
+ function truncate(text) {
24
+ return text.length > maxDescribedLength ? `${text.slice(0, maxDescribedLength)}… (${text.length} chars)` : text;
25
+ }
26
+ /**
27
+ * Renders any polled value as a short, single-line string. Never throws, so a bad
28
+ * value can never mask the timeout it was meant to explain.
29
+ */
30
+ function describePolledValue(value) {
31
+ if (value === null) {
32
+ return 'null';
33
+ }
34
+ if (value === undefined) {
35
+ return 'undefined';
36
+ }
37
+ if (typeof value === 'bigint') {
38
+ return `${value}n`;
39
+ }
40
+ if (typeof value === 'function') {
41
+ return `[Function ${value.name || 'anonymous'}]`;
42
+ }
43
+ if (typeof value === 'string') {
44
+ return truncate(JSON.stringify(value));
45
+ }
46
+ if (typeof value === 'object') {
47
+ return truncate(stringifyObject(value));
48
+ }
49
+ return truncate(String(value));
50
+ }
51
+ function stringifyObject(value) {
52
+ const seen = new WeakSet();
53
+ try {
54
+ const json = JSON.stringify(value, (_key, nested) => {
55
+ if (typeof nested === 'bigint') {
56
+ return `${nested}n`;
57
+ }
58
+ if (typeof nested !== 'object' || nested === null) {
59
+ return nested;
60
+ }
61
+ if (seen.has(nested)) {
62
+ return '[Circular]';
63
+ }
64
+ seen.add(nested);
65
+ return nested;
66
+ });
67
+ return json ?? Object.prototype.toString.call(value);
68
+ }
69
+ catch {
70
+ return Object.prototype.toString.call(value);
71
+ }
72
+ }
1
73
  /**
2
74
  * Repeatedly calls `fn` at a configurable interval until the optional `predicate` returns
3
- * truthy or the `timeout` is exceeded, at which point it throws.
75
+ * truthy or the `timeout` is exceeded, at which point it throws a {@link PollTimeoutError}.
4
76
  * `onTick` is called with the last value and elapsed time after each failing attempt.
5
77
  * @param fn - The async or sync function to poll.
6
78
  * @param opts.timeout - Maximum wait time in milliseconds (default `10 000`).
7
79
  * @param opts.interval - Polling interval in milliseconds (default `200`).
8
80
  * @param opts.predicate - Returns `true` when the result is acceptable (default: truthy check).
9
81
  * @param opts.onTick - Called after each failing attempt with the last value and elapsed ms.
82
+ * @param opts.description - What is being waited for, quoted in the timeout message.
10
83
  * @returns The first value for which `predicate` returns `true`.
11
- * @throws If `timeout` is exceeded before `predicate` returns `true`.
84
+ * @throws {PollTimeoutError} If `timeout` is exceeded before `predicate` returns `true`.
12
85
  */
13
86
  export async function pollUntil(fn, opts = {}) {
14
87
  const timeout = opts.timeout ?? 10000;
15
88
  const interval = opts.interval ?? 200;
16
89
  const ok = opts.predicate ?? ((v) => Boolean(v));
17
90
  const start = Date.now();
91
+ let attempts = 0;
18
92
  while (true) {
19
93
  const val = await fn();
94
+ attempts++;
20
95
  if (ok(val))
21
96
  return val;
22
- opts.onTick?.(val, Date.now() - start);
23
- if (Date.now() - start >= timeout) {
24
- throw new Error(`pollUntil timeout after ${timeout}ms`);
97
+ const elapsedMs = Date.now() - start;
98
+ opts.onTick?.(val, elapsedMs);
99
+ if (elapsedMs >= timeout) {
100
+ throw new PollTimeoutError({
101
+ timeout,
102
+ elapsedMs,
103
+ attempts,
104
+ lastValue: val,
105
+ description: opts.description
106
+ });
25
107
  }
26
108
  await new Promise((r) => setTimeout(r, interval));
27
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Poll.js","sourceRoot":"","sources":["../../helpers/Poll.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,EAAwB,EAAE,OAAuB,EAAE;IACpF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAM,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC;IACtC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAI,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,EAAE,EAAE,CAAC;QACvB,IAAI,EAAE,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;QAExB,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,IAAI,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"Poll.js","sourceRoot":"","sources":["../../helpers/Poll.ts"],"names":[],"mappings":"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"}
@@ -52,7 +52,8 @@ export class UserSimulationHelper {
52
52
  await pollUntil(() => this.getSimulatedUser(), {
53
53
  timeout: 5000,
54
54
  interval: 200,
55
- predicate: (val) => val === ''
55
+ predicate: (val) => val === '',
56
+ description: 'user simulation to stop and clear the simulated user'
56
57
  });
57
58
  }
58
59
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"UserSimulationHelper.js","sourceRoot":"","sources":["../../helpers/UserSimulationHelper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,oBAAoB;IAI/B,YAAY,IAAU;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC,GAAG,CAAS,gCAAgC,CAAC,CAAC;QAElF,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QAExG,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,gBAAgB;QAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEhG,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,GAAG;gBACN,OAAO,CAAC,IAAI,CAAC,4BAA4B,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC9D,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG;gBACN,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC;YAChD;gBACE,MAAM,IAAI,KAAK,CAAC,kDAAkD,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,cAAc;QACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEnG,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,+CAA+C,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE;YAC7C,OAAO,EAAE,IAAK;YACd,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE;SAC/B,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY,CAAC,QAAgB;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,EAAE;YAChG,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,cAAc,EAAE,QAAQ;aACzB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"UserSimulationHelper.js","sourceRoot":"","sources":["../../helpers/UserSimulationHelper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,oBAAoB;IAI/B,YAAY,IAAU;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC,GAAG,CAAS,gCAAgC,CAAC,CAAC;QAElF,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QAExG,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,gBAAgB;QAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEhG,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,GAAG;gBACN,OAAO,CAAC,IAAI,CAAC,4BAA4B,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC9D,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG;gBACN,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC;YAChD;gBACE,MAAM,IAAI,KAAK,CAAC,kDAAkD,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,cAAc;QACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEnG,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,+CAA+C,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE;YAC7C,OAAO,EAAE,IAAK;YACd,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE;YAC9B,WAAW,EAAE,sDAAsD;SACpE,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY,CAAC,QAAgB;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,EAAE;YAChG,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,cAAc,EAAE,QAAQ;aACzB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Represents a single subject+variant combination that has qualifying task
3
+ * buttons, as stored in `seed-data/tab-tasks.json` after the
4
+ * `TaskDataBuilder` pipeline step.
5
+ *
6
+ * Tasks with `custom_display_type === 4` are stripped at fetch time and never
7
+ * appear here. If all tasks for a subject+variant had that type, the entry is
8
+ * omitted entirely and that subject receives a plain `ActionBar`.
9
+ */
10
+ export interface ITabTask {
11
+ /** Thinkwise subject identifier (matches `ISubject.subject`). */
12
+ subject: string;
13
+ /** Subject variant identifier (matches `ISubject.variant`). */
14
+ variant: string;
15
+ /**
16
+ * Ordered list of qualifying task IDs.
17
+ * Each entry becomes a named getter on the generated custom ActionBar class.
18
+ * e.g. `"supplier-item-add"` → `get supplierItemAddButton(): Locator`
19
+ */
20
+ tasks: string[];
21
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ITabTask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITabTask.js","sourceRoot":"","sources":["../../interfaces/ITabTask.ts"],"names":[],"mappings":""}
@@ -44,6 +44,13 @@ export declare class IndiciumApiService {
44
44
  * @returns An array of screen component objects, or an empty array if not verified or on error.
45
45
  */
46
46
  getScreenComponents(): Promise<any[]>;
47
+ /**
48
+ * Fetches all task button records (`i_ui_tab_task`) for the verified GUI application.
49
+ * Results include all tasks regardless of `custom_display_type`; callers are
50
+ * responsible for filtering out `custom_display_type === 4` entries.
51
+ * @returns An array of tab task objects, or an empty array if not verified or on error.
52
+ */
53
+ getTabTasks(): Promise<any[]>;
47
54
  /**
48
55
  * Returns the verified GUI Application ID.
49
56
  * Throws an error if verification failed or the alias was not found.
@@ -153,6 +153,25 @@ export class IndiciumApiService {
153
153
  return [];
154
154
  }
155
155
  }
156
+ /**
157
+ * Fetches all task button records (`i_ui_tab_task`) for the verified GUI application.
158
+ * Results include all tasks regardless of `custom_display_type`; callers are
159
+ * responsible for filtering out `custom_display_type === 4` entries.
160
+ * @returns An array of tab task objects, or an empty array if not verified or on error.
161
+ */
162
+ async getTabTasks() {
163
+ await this.ensureReady();
164
+ if (!this.isVerified || !this.guiApplId)
165
+ return [];
166
+ try {
167
+ const response = await this.axiosInstance.get(`/iam/${this.metaEndpoint}/i_ui_tab_task?$filter=gui_appl_id%20eq%20${this.guiApplId}`);
168
+ return response.data?.value || [];
169
+ }
170
+ catch (error) {
171
+ console.error(`IndiciumApiService: Failed to fetch tab tasks: ${IndiciumApiService.extractMessage(error)}`);
172
+ return [];
173
+ }
174
+ }
156
175
  /**
157
176
  * Returns the verified GUI Application ID.
158
177
  * Throws an error if verification failed or the alias was not found.
@@ -1 +1 @@
1
- {"version":3,"file":"IndiciumApi.service.js","sourceRoot":"","sources":["../../services/IndiciumApi.service.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,0EAA0E;AAC1E,8EAA8E;AAC9E,OAAO,KAA8C,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,OAAO,kBAAkB;IAO7B;QANQ,kBAAa,GAAyB,IAAI,CAAC;QAC3C,iBAAY,GAAkB,IAAI,CAAC;QACnC,cAAS,GAAkB,IAAI,CAAC;QAChC,eAAU,GAAG,KAAK,CAAC;QAIzB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,WAAW;QACvB,MAAM,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEO,MAAM,CAAC,cAAc,CAAC,KAAc;QAC1C,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,KAAmB,CAAC;YACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;YACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;YACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;YACvC,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,MAAM,IAAI,UAAU,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC7E,CAAC;QACD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAS,gCAAgC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5F,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAS,kCAAkC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACnH,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAS,8BAA8B,CAAC,CAAC;QACpE,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAS,sCAAsC,CAAC,CAAC;QACpF,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAS,kCAAkC,CAAC,CAAC;QAE5E,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ,IAAI,CAAC,gBAAgB,IAAI,CAAC,YAAY,EAAE,CAAC;YACpF,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC;YAChC,OAAO,EAAE,UAAU;YACnB,OAAO,EAAE;gBACP,aAAa,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;gBAC3F,MAAM,EAAE,KAAK;aACd;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,WAAmB;QAChD,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAEtD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,YAAY,gBAAgB,CAAC,CAAC;YACzF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CACpG,CAAC;YAEF,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC;gBACtC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,2DAA2D,WAAW,EAAE,CAAC,CAAC;YACzF,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,4CAA4C,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,mBAAmB;QAC9B,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,oBAAoB;QAC/B,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY;QACvB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAc,CAAC,GAAG,CAC5C,QAAQ,IAAI,CAAC,YAAY,wCAAwC,IAAI,CAAC,SAAS,EAAE,CAClF,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+CAA+C,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzG,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,aAAa;QACxB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAc,CAAC,GAAG,CAC5C,QAAQ,IAAI,CAAC,YAAY,wCAAwC,IAAI,CAAC,SAAS,EAAE,CAClF,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gDAAgD,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1G,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,UAAU;QACrB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAc,CAAC,GAAG,CAC5C,QAAQ,IAAI,CAAC,YAAY,gDAAgD,IAAI,CAAC,SAAS,EAAE,CAC1F,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gDAAgD,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1G,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,mBAAmB;QAC9B,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAc,CAAC,GAAG,CAC5C,QAAQ,IAAI,CAAC,YAAY,qDAAqD,IAAI,CAAC,SAAS,EAAE,CAC/F,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,0DAA0D,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CACrG,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY;QACvB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAEzB,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC/C,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;QAED,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC,GAAG,CAAS,kCAAkC,CAAC,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,uEAAuE,KAAK,IAAI,CAAC,CAAC;IACpG,CAAC;CACF;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"IndiciumApi.service.js","sourceRoot":"","sources":["../../services/IndiciumApi.service.ts"],"names":[],"mappings":"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"}
@@ -11,4 +11,9 @@ export type PollOptions<T = unknown> = {
11
11
  interval?: number;
12
12
  predicate?: (v: T) => boolean;
13
13
  onTick?: (v: T, elapsedMs: number) => void;
14
+ /**
15
+ * What is being waited for, phrased to follow "waiting for ...". Included in the
16
+ * timeout message, so a failure reads as a sentence rather than a bare timeout.
17
+ */
18
+ description?: string;
14
19
  };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Pure, page-independent helpers for turning a canonical ISO date/time into the
3
+ * digit sequence a Thinkwise date picker expects for a given locale.
4
+ *
5
+ * **Why this exists:** Thinkwise renders dates in the field order dictated by the
6
+ * logged-in user's `dateLocale` (e.g. `DD/MM/YYYY` for en-GB, `MM/DD/YYYY` for
7
+ * en-US, `YYYY-MM-DD` for sv-SE). The date picker applies its own separators when
8
+ * digits are typed sequentially, so all we must do is emit the day/month/year
9
+ * digits in the locale's order. These functions have no Playwright dependency and
10
+ * are unit-testable in isolation.
11
+ */
12
+
13
+ export type DateParts = {
14
+ year: string;
15
+ month: string;
16
+ day: string;
17
+ hour?: string;
18
+ minute?: string;
19
+ second?: string;
20
+ };
21
+
22
+ export type DateFieldOrder = ('year' | 'month' | 'day')[];
23
+
24
+ // A fixed reference date whose parts are all distinct and unambiguous, used to
25
+ // probe a locale's field order via Intl. Day 7 / month 5 keeps it well inside
26
+ // valid ranges for every calendar.
27
+ const referenceDate = new Date(Date.UTC(2026, 4, 7));
28
+
29
+ const isoDateTimePattern =
30
+ /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})(?:[ T](?<hour>\d{2}):(?<minute>\d{2})(?::(?<second>\d{2}))?)?$/;
31
+
32
+ /**
33
+ * Parse a canonical ISO date/time string into its component parts.
34
+ *
35
+ * Accepts `YYYY-MM-DD` and `YYYY-MM-DD HH:mm[:ss]` (a `T` separator also works).
36
+ * Throws a descriptive error on any other input so test authors get a clear
37
+ * message rather than a silently wrong date.
38
+ *
39
+ * @param iso - Canonical ISO date or date-time string.
40
+ * @returns The parsed, zero-padded date (and optional time) parts.
41
+ */
42
+ export function parseIsoDateTime(iso: string): DateParts {
43
+ const match = isoDateTimePattern.exec(iso.trim());
44
+
45
+ if (!match?.groups) {
46
+ throw new Error(`Invalid date "${iso}". Expected canonical ISO format "YYYY-MM-DD" or "YYYY-MM-DD HH:mm:ss".`);
47
+ }
48
+
49
+ const { year, month, day, hour, minute, second } = match.groups;
50
+
51
+ return {
52
+ year,
53
+ month,
54
+ day,
55
+ ...(hour !== undefined ? { hour, minute, second: second ?? '00' } : {})
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Whether a value is a canonical ISO date or date-time that {@link parseIsoDateTime} accepts.
61
+ *
62
+ * @param value - The value to test.
63
+ * @returns `true` for `YYYY-MM-DD` and `YYYY-MM-DD HH:mm[:ss]` (a `T` separator also works).
64
+ */
65
+ export function isIsoDateTime(value: string): boolean {
66
+ return isoDateTimePattern.test(value.trim());
67
+ }
68
+
69
+ /**
70
+ * Determine the day/month/year ordering a locale uses to display dates.
71
+ *
72
+ * Derives the order from `Intl.DateTimeFormat` rather than a hardcoded table, so
73
+ * any locale the app supports is handled. Falls back to day/month/year when the
74
+ * locale is empty or unrecognised.
75
+ *
76
+ * @param locale - A BCP-47 locale tag (e.g. `en-GB`, `en-US`, `sv-SE`).
77
+ * @returns The order of date fields for that locale.
78
+ */
79
+ export function fieldOrderForLocale(locale: string): DateFieldOrder {
80
+ const fallback: DateFieldOrder = ['day', 'month', 'year'];
81
+
82
+ if (!locale) return fallback;
83
+
84
+ try {
85
+ const order = new Intl.DateTimeFormat(locale)
86
+ .formatToParts(referenceDate)
87
+ .map((part) => part.type)
88
+ .filter((type): type is 'year' | 'month' | 'day' => type === 'year' || type === 'month' || type === 'day');
89
+
90
+ return order.length === 3 ? order : fallback;
91
+ } catch {
92
+ return fallback;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Produce the sequence of digits to type into a date picker for the given locale
98
+ * order. Date digits come first in `order`, followed by any time digits (always
99
+ * `HHmmss`). No separators are emitted — the picker inserts its own.
100
+ *
101
+ * @param parts - Parsed date/time parts.
102
+ * @param order - The locale's day/month/year ordering.
103
+ * @returns The digit string to type sequentially.
104
+ */
105
+ export function toDigitSequence(parts: DateParts, order: DateFieldOrder): string {
106
+ const dateDigits = order.map((field) => parts[field]).join('');
107
+ const timeDigits = parts.hour !== undefined ? `${parts.hour}${parts.minute ?? '00'}${parts.second ?? '00'}` : '';
108
+
109
+ return `${dateDigits}${timeDigits}`;
110
+ }
111
+
112
+ /**
113
+ * Convenience helper combining {@link parseIsoDateTime}, {@link fieldOrderForLocale}
114
+ * and {@link toDigitSequence}: turn a canonical ISO date into the digit sequence
115
+ * for a locale.
116
+ *
117
+ * @param iso - Canonical ISO date or date-time string.
118
+ * @param locale - A BCP-47 locale tag; empty falls back to day/month/year order.
119
+ * @returns The digit string to type sequentially into the picker.
120
+ */
121
+ export function isoToLocaleDigits(iso: string, locale: string): string {
122
+ return toDigitSequence(parseIsoDateTime(iso), fieldOrderForLocale(locale));
123
+ }
@@ -0,0 +1,57 @@
1
+ import type { Page } from '@playwright/test';
2
+
3
+ /**
4
+ * Reads the logged-in user's active date locale from the Thinkwise web app.
5
+ *
6
+ * **Why this exists:** Date pickers render dates in the field order dictated by the
7
+ * user's `dateLocale` preference. Testwise needs that locale to type dates in the
8
+ * correct order regardless of the browser locale. The value lives in the Redux
9
+ * store the app exposes on `window.__REDUX_STORE__` (see the front-end change that
10
+ * added it):
11
+ *
12
+ * ```ts
13
+ * window.__REDUX_STORE__.getState().auth.user.dateLocale
14
+ * ```
15
+ *
16
+ * The store is populated asynchronously after config load and login, so callers
17
+ * must only rely on this once past the login screen. Before then (or if the shape
18
+ * ever changes) this resolves to an empty string, letting callers fall back to a
19
+ * sensible default order.
20
+ */
21
+
22
+ // Cache the resolved locale per page so repeated date fills don't re-evaluate.
23
+ const localeCache = new WeakMap<Page, string>();
24
+
25
+ /**
26
+ * Retrieve the app's active date locale (e.g. `en-GB`, `sv-SE`), caching the
27
+ * result per page. Returns `''` when the Redux store is not yet available or does
28
+ * not expose a locale.
29
+ *
30
+ * @param page - The Playwright page bound to a logged-in Thinkwise session.
31
+ * @returns The BCP-47 date locale tag, or `''` if it cannot be determined.
32
+ */
33
+ export async function getDateLocale(page: Page): Promise<string> {
34
+ const cached = localeCache.get(page);
35
+ if (cached !== undefined) return cached;
36
+
37
+ const locale = await page
38
+ .evaluate(() => {
39
+ const store = (window as unknown as { __REDUX_STORE__?: { getState(): unknown } }).__REDUX_STORE__;
40
+ const state = store?.getState() as { auth?: { user?: { dateLocale?: string } } } | undefined;
41
+ return state?.auth?.user?.dateLocale ?? '';
42
+ })
43
+ .catch(() => '');
44
+
45
+ localeCache.set(page, locale);
46
+ return locale;
47
+ }
48
+
49
+ /**
50
+ * Clear any cached date locale for a page. Useful after a re-login or a user
51
+ * preference change that alters the active `dateLocale` within the same page.
52
+ *
53
+ * @param page - The page whose cached locale should be discarded.
54
+ */
55
+ export function clearDateLocaleCache(page: Page): void {
56
+ localeCache.delete(page);
57
+ }
@@ -89,7 +89,8 @@ export class LoginHelper {
89
89
  await pollUntil(async () => this._page.url().includes('#application='), {
90
90
  timeout,
91
91
  interval: 200,
92
- predicate: (ok: boolean) => ok === true
92
+ predicate: (ok: boolean) => ok === true,
93
+ description: 'the URL to carry #application= after login'
93
94
  });
94
95
  }
95
96
 
package/helpers/Poll.ts CHANGED
@@ -1,30 +1,133 @@
1
1
  import type { PollOptions } from '../types/PollTypes.js';
2
2
 
3
+ const maxDescribedLength = 200;
4
+
5
+ /**
6
+ * Thrown when `pollUntil` exceeds its timeout.
7
+ *
8
+ * The message states what was awaited, how many attempts were made and the last value
9
+ * the polled function returned, so a timeout is diagnosable from a test report alone.
10
+ * The same details are exposed as properties for programmatic inspection.
11
+ */
12
+ export class PollTimeoutError extends Error {
13
+ public readonly timeout: number;
14
+ public readonly elapsedMs: number;
15
+ public readonly attempts: number;
16
+ public readonly lastValue: unknown;
17
+ public readonly description?: string;
18
+
19
+ constructor(details: {
20
+ timeout: number;
21
+ elapsedMs: number;
22
+ attempts: number;
23
+ lastValue: unknown;
24
+ description?: string;
25
+ }) {
26
+ const waitingFor = details.description ? ` waiting for ${details.description}` : '';
27
+ super(
28
+ `pollUntil timeout after ${details.timeout}ms${waitingFor}; ` +
29
+ `${details.attempts} attempts over ${details.elapsedMs}ms, ` +
30
+ `last value: ${describePolledValue(details.lastValue)}`
31
+ );
32
+
33
+ this.name = 'PollTimeoutError';
34
+ this.timeout = details.timeout;
35
+ this.elapsedMs = details.elapsedMs;
36
+ this.attempts = details.attempts;
37
+ this.lastValue = details.lastValue;
38
+ this.description = details.description;
39
+ }
40
+ }
41
+
42
+ function truncate(text: string): string {
43
+ return text.length > maxDescribedLength ? `${text.slice(0, maxDescribedLength)}… (${text.length} chars)` : text;
44
+ }
45
+
46
+ /**
47
+ * Renders any polled value as a short, single-line string. Never throws, so a bad
48
+ * value can never mask the timeout it was meant to explain.
49
+ */
50
+ function describePolledValue(value: unknown): string {
51
+ if (value === null) {
52
+ return 'null';
53
+ }
54
+ if (value === undefined) {
55
+ return 'undefined';
56
+ }
57
+ if (typeof value === 'bigint') {
58
+ return `${value}n`;
59
+ }
60
+ if (typeof value === 'function') {
61
+ return `[Function ${value.name || 'anonymous'}]`;
62
+ }
63
+ if (typeof value === 'string') {
64
+ return truncate(JSON.stringify(value));
65
+ }
66
+ if (typeof value === 'object') {
67
+ return truncate(stringifyObject(value));
68
+ }
69
+ return truncate(String(value));
70
+ }
71
+
72
+ function stringifyObject(value: object): string {
73
+ const seen = new WeakSet<object>();
74
+
75
+ try {
76
+ const json = JSON.stringify(value, (_key, nested) => {
77
+ if (typeof nested === 'bigint') {
78
+ return `${nested}n`;
79
+ }
80
+ if (typeof nested !== 'object' || nested === null) {
81
+ return nested;
82
+ }
83
+ if (seen.has(nested)) {
84
+ return '[Circular]';
85
+ }
86
+ seen.add(nested);
87
+ return nested;
88
+ });
89
+
90
+ return json ?? Object.prototype.toString.call(value);
91
+ } catch {
92
+ return Object.prototype.toString.call(value);
93
+ }
94
+ }
95
+
3
96
  /**
4
97
  * Repeatedly calls `fn` at a configurable interval until the optional `predicate` returns
5
- * truthy or the `timeout` is exceeded, at which point it throws.
98
+ * truthy or the `timeout` is exceeded, at which point it throws a {@link PollTimeoutError}.
6
99
  * `onTick` is called with the last value and elapsed time after each failing attempt.
7
100
  * @param fn - The async or sync function to poll.
8
101
  * @param opts.timeout - Maximum wait time in milliseconds (default `10 000`).
9
102
  * @param opts.interval - Polling interval in milliseconds (default `200`).
10
103
  * @param opts.predicate - Returns `true` when the result is acceptable (default: truthy check).
11
104
  * @param opts.onTick - Called after each failing attempt with the last value and elapsed ms.
105
+ * @param opts.description - What is being waited for, quoted in the timeout message.
12
106
  * @returns The first value for which `predicate` returns `true`.
13
- * @throws If `timeout` is exceeded before `predicate` returns `true`.
107
+ * @throws {PollTimeoutError} If `timeout` is exceeded before `predicate` returns `true`.
14
108
  */
15
109
  export async function pollUntil<T>(fn: () => Promise<T> | T, opts: PollOptions<T> = {}): Promise<T> {
16
110
  const timeout = opts.timeout ?? 10_000;
17
111
  const interval = opts.interval ?? 200;
18
112
  const ok = opts.predicate ?? ((v: T) => Boolean(v));
19
113
  const start = Date.now();
114
+ let attempts = 0;
20
115
 
21
116
  while (true) {
22
117
  const val = await fn();
118
+ attempts++;
23
119
  if (ok(val)) return val;
24
120
 
25
- opts.onTick?.(val, Date.now() - start);
26
- if (Date.now() - start >= timeout) {
27
- throw new Error(`pollUntil timeout after ${timeout}ms`);
121
+ const elapsedMs = Date.now() - start;
122
+ opts.onTick?.(val, elapsedMs);
123
+ if (elapsedMs >= timeout) {
124
+ throw new PollTimeoutError({
125
+ timeout,
126
+ elapsedMs,
127
+ attempts,
128
+ lastValue: val,
129
+ description: opts.description
130
+ });
28
131
  }
29
132
  await new Promise((r) => setTimeout(r, interval));
30
133
  }
@@ -63,7 +63,8 @@ export class UserSimulationHelper {
63
63
  await pollUntil(() => this.getSimulatedUser(), {
64
64
  timeout: 5_000,
65
65
  interval: 200,
66
- predicate: (val) => val === ''
66
+ predicate: (val) => val === '',
67
+ description: 'user simulation to stop and clear the simulated user'
67
68
  });
68
69
  }
69
70
 
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Represents a single subject+variant combination that has qualifying task
3
+ * buttons, as stored in `seed-data/tab-tasks.json` after the
4
+ * `TaskDataBuilder` pipeline step.
5
+ *
6
+ * Tasks with `custom_display_type === 4` are stripped at fetch time and never
7
+ * appear here. If all tasks for a subject+variant had that type, the entry is
8
+ * omitted entirely and that subject receives a plain `ActionBar`.
9
+ */
10
+ export interface ITabTask {
11
+ /** Thinkwise subject identifier (matches `ISubject.subject`). */
12
+ subject: string;
13
+ /** Subject variant identifier (matches `ISubject.variant`). */
14
+ variant: string;
15
+ /**
16
+ * Ordered list of qualifying task IDs.
17
+ * Each entry becomes a named getter on the generated custom ActionBar class.
18
+ * e.g. `"supplier-item-add"` → `get supplierItemAddButton(): Locator`
19
+ */
20
+ tasks: string[];
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkwise/testwise",
3
- "version": "0.2.105",
3
+ "version": "0.2.111",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,8 @@
11
11
  "lint": "eslint ./ --cache --ignore-pattern .gitignore",
12
12
  "format:fix": "run-s \"lint --fix\" && biome check --fix --unsafe",
13
13
  "format:check": "run-s \"lint \" && biome check",
14
+ "build": "tsc",
15
+ "prepack": "rimraf dist && tsc && node scripts/checkPackageContents.js",
14
16
  "postinstall": "node scripts/main.js postinstall",
15
17
  "test": "vitest run",
16
18
  "test:watch": "vitest",