@testmuai/playwright-bindings 0.1.2-beta.1 → 0.1.2-beta.3

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 (76) hide show
  1. package/README.md +3 -3
  2. package/dist/config.d.ts +2 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +6 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/configure.d.ts +5 -1
  7. package/dist/configure.d.ts.map +1 -1
  8. package/dist/configure.js +1 -0
  9. package/dist/configure.js.map +1 -1
  10. package/dist/healPatch.d.ts +9 -2
  11. package/dist/healPatch.d.ts.map +1 -1
  12. package/dist/healPatch.js +25 -8
  13. package/dist/healPatch.js.map +1 -1
  14. package/dist/helpers/assertion.d.ts.map +1 -1
  15. package/dist/helpers/assertion.js +18 -12
  16. package/dist/helpers/assertion.js.map +1 -1
  17. package/dist/helpers/drag.d.ts.map +1 -1
  18. package/dist/helpers/drag.js +2 -0
  19. package/dist/helpers/drag.js.map +1 -1
  20. package/dist/helpers/executeApi.d.ts +12 -1
  21. package/dist/helpers/executeApi.d.ts.map +1 -1
  22. package/dist/helpers/executeApi.js +108 -20
  23. package/dist/helpers/executeApi.js.map +1 -1
  24. package/dist/helpers/executeDb.js +1 -1
  25. package/dist/helpers/executeDb.js.map +1 -1
  26. package/dist/helpers/kaneCli.d.ts +10 -1
  27. package/dist/helpers/kaneCli.d.ts.map +1 -1
  28. package/dist/helpers/kaneCli.js +122 -3
  29. package/dist/helpers/kaneCli.js.map +1 -1
  30. package/dist/helpers/math.d.ts +1 -1
  31. package/dist/helpers/math.d.ts.map +1 -1
  32. package/dist/helpers/math.js +8 -6
  33. package/dist/helpers/math.js.map +1 -1
  34. package/dist/helpers/network.d.ts +4 -4
  35. package/dist/helpers/network.d.ts.map +1 -1
  36. package/dist/helpers/network.js +19 -16
  37. package/dist/helpers/network.js.map +1 -1
  38. package/dist/helpers/smartui.d.ts +5 -1
  39. package/dist/helpers/smartui.d.ts.map +1 -1
  40. package/dist/helpers/smartui.js +45 -7
  41. package/dist/helpers/smartui.js.map +1 -1
  42. package/dist/helpers/tabs.d.ts.map +1 -1
  43. package/dist/helpers/tabs.js +2 -0
  44. package/dist/helpers/tabs.js.map +1 -1
  45. package/dist/helpers/vision.d.ts +50 -7
  46. package/dist/helpers/vision.d.ts.map +1 -1
  47. package/dist/helpers/vision.js +212 -29
  48. package/dist/helpers/vision.js.map +1 -1
  49. package/dist/helpers/wait.d.ts.map +1 -1
  50. package/dist/helpers/wait.js +1 -2
  51. package/dist/helpers/wait.js.map +1 -1
  52. package/dist/index.d.ts +3 -4
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +4 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/loadEnv.d.ts +2 -0
  57. package/dist/loadEnv.d.ts.map +1 -0
  58. package/dist/loadEnv.js +12 -0
  59. package/dist/loadEnv.js.map +1 -0
  60. package/dist/relayProxy.d.ts +46 -0
  61. package/dist/relayProxy.d.ts.map +1 -0
  62. package/dist/relayProxy.js +453 -0
  63. package/dist/relayProxy.js.map +1 -0
  64. package/dist/session.d.ts +6 -0
  65. package/dist/session.d.ts.map +1 -1
  66. package/dist/session.js +130 -16
  67. package/dist/session.js.map +1 -1
  68. package/dist/step.d.ts +23 -6
  69. package/dist/step.d.ts.map +1 -1
  70. package/dist/step.js +23 -27
  71. package/dist/step.js.map +1 -1
  72. package/dist/vars.d.ts +9 -20
  73. package/dist/vars.d.ts.map +1 -1
  74. package/dist/vars.js +62 -26
  75. package/dist/vars.js.map +1 -1
  76. package/package.json +10 -5
package/dist/session.js CHANGED
@@ -1,26 +1,95 @@
1
1
  import { chromium } from 'playwright';
2
+ import { promises as fs } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join } from 'path';
2
5
  import { config } from './config.js';
6
+ import * as configure from './configure.js';
3
7
  import { _getRegistry } from './test.js';
4
8
  import { createReporter } from './reporters/index.js';
5
9
  import { LTReporter } from './reporters/lt.js';
6
- import { _setReporter, _endDanglingStep } from './step.js';
10
+ import { _setReporter } from './step.js';
7
11
  import { buildCapabilities, getCdpUrl, getViewport } from './capability.js';
8
12
  import { TestmuConfigError } from './errors.js';
9
- // Deferred: file download (_download_files) — Python downloads uploaded_files
10
- // via aiohttp after browser launch; no equivalent in TS scope yet.
11
- // Deferred: HE test-param overrides (get_test_params_override) — no testConfig
12
- // param-override integration in TS yet.
13
+ import { PlaywrightRelayProxy } from './relayProxy.js';
14
+ import { getTestParamsOverride } from './testConfig.js';
15
+ import { setVar } from './vars.js';
16
+ import { ltAuthHeader } from './http.js';
17
+ import { log } from './log.js';
18
+ import { installHealPatch } from './healPatch.js';
19
+ // Module-level session state — exposed so helpers like executeKaneCli (M12) can
20
+ // reach `relayUrl` to disconnect/reconnect mid-test. PY parity: _session.state.
21
+ export const sessionState = { relay: null, relayTask: null, relayUrl: null };
22
+ async function downloadFiles(files) {
23
+ const auth = ltAuthHeader();
24
+ if (!auth) {
25
+ log.helper('Cannot download files — no LT credentials');
26
+ return;
27
+ }
28
+ const dlDir = join(homedir(), 'Downloads');
29
+ await fs.mkdir(dlDir, { recursive: true });
30
+ for (const f of files) {
31
+ let url = f.media_url ?? '';
32
+ const name = f.name ?? '';
33
+ if (!url || !name)
34
+ continue;
35
+ if (!url.startsWith('http'))
36
+ url = `https://${url}`; // PY parity: _session.py:108-110
37
+ try {
38
+ const resp = await fetch(url, { headers: { Authorization: auth } });
39
+ if (!resp.ok)
40
+ throw new Error(`HTTP ${resp.status}`);
41
+ const buf = Buffer.from(await resp.arrayBuffer());
42
+ const dest = join(dlDir, name);
43
+ await fs.writeFile(dest, buf);
44
+ log.helper(`Downloaded: ${name} -> ${dest}`);
45
+ }
46
+ catch (e) {
47
+ log.helper(`Failed to download ${name}: ${String(e)}`);
48
+ }
49
+ }
50
+ }
13
51
  async function createBrowserAndPage() {
14
52
  const caps = await buildCapabilities();
15
53
  if (config.current.runTarget === 'cloud') {
16
- const browser = await chromium.connectOverCDP(getCdpUrl(caps));
17
- const context = browser.contexts()[0] ?? await browser.newContext();
18
- const page = context.pages()[0] ?? await context.newPage();
54
+ const cdpUrl = getCdpUrl(caps);
55
+ // Start a local relay proxy so kane-cli (M12) can hand off the browser mid-test
56
+ // and reconnect with state replay. PY parity: _session.py:54-62.
57
+ const relay = new PlaywrightRelayProxy(cdpUrl, 0);
58
+ const relayTask = relay.start();
59
+ try {
60
+ await relay.waitReady();
61
+ }
62
+ catch (e) {
63
+ // relay.start() rejected (e.g., UpstreamConnectionError). Don't leak state.
64
+ try {
65
+ relay.shutdown();
66
+ }
67
+ catch { /* ignore */ }
68
+ try {
69
+ await relayTask;
70
+ }
71
+ catch { /* ignore */ }
72
+ throw e;
73
+ }
74
+ sessionState.relay = relay;
75
+ sessionState.relayTask = relayTask;
76
+ sessionState.relayUrl = `ws://127.0.0.1:${relay.localPort}`;
77
+ log.helper(`Relay proxy listening at ${sessionState.relayUrl}`);
78
+ const browser = await chromium.connect(sessionState.relayUrl, { timeout: 120_000 });
79
+ log.helper('Connected to LT cloud via relay proxy');
80
+ const viewport = getViewport(process.env['LT_RESOLUTION']);
81
+ const headers = configure.get('customHeaders');
82
+ const ctxOpts = { viewport };
83
+ if (headers && Object.keys(headers).length)
84
+ ctxOpts.extraHTTPHeaders = headers;
85
+ const context = await browser.newContext(ctxOpts);
86
+ const page = await context.newPage();
19
87
  return { browser, context, page };
20
88
  }
21
89
  const headless = process.env['TESTMU_HEADLESS'] !== 'false';
22
90
  const browser = await chromium.launch({ headless });
23
- const context = await browser.newContext({ viewport: getViewport(process.env['LT_RESOLUTION']) });
91
+ // Local: viewport unset browser uses natural size (PY parity, _session.py:74)
92
+ const context = await browser.newContext({});
24
93
  const page = await context.newPage();
25
94
  return { browser, context, page };
26
95
  }
@@ -29,33 +98,78 @@ export async function run() {
29
98
  throw new TestmuConfigError('TESTMU_SMART=1 requires LT_USERNAME and LT_ACCESS_KEY. ' +
30
99
  'Smart helpers (vision, heal, kane-cli, SmartUI) need LT infrastructure.');
31
100
  }
101
+ // M19: diagnostic log at session start (PY parity: _session.py:126-132)
102
+ log.helper(`Mode: run_target=${config.current.runTarget}, ` +
103
+ `lt_auth=${config.current.ltAuth}, smart=${config.current.smart}`);
104
+ const varsCount = Object.keys(configure.get('variables')).length;
105
+ const paramsCount = Object.keys(configure.get('testParams')).length;
106
+ const globalsCount = configure.get('globalVariables').length;
107
+ if (varsCount || paramsCount || globalsCount) {
108
+ log.helper(`Variables: ${varsCount} test-level, ${paramsCount} params, ${globalsCount} globals`);
109
+ }
32
110
  const reporter = createReporter();
33
111
  _setReporter(reporter);
34
112
  const { browser, page } = await createBrowserAndPage();
35
113
  if (reporter instanceof LTReporter)
36
114
  reporter._setPage(page);
115
+ // Install vision-coordinate heal on Locator.prototype now that a Page exists.
116
+ // Deferred from module load because TS elides the `Locator` value-import
117
+ // (playwright .d.ts declares it as an interface). See healPatch.ts header.
118
+ installHealPatch(page);
119
+ // C9: download uploaded files to ~/Downloads/
120
+ const uploaded = configure.get('uploadedFiles');
121
+ if (uploaded.length) {
122
+ log.helper(`Downloading ${uploaded.length} uploaded file(s)...`);
123
+ await downloadFiles(uploaded);
124
+ }
125
+ // C11: apply HE test-run config overrides (dataset params)
126
+ const overrides = await getTestParamsOverride();
127
+ const nOverrides = Object.keys(overrides).length;
128
+ if (nOverrides > 0) {
129
+ for (const [k, v] of Object.entries(overrides))
130
+ setVar(k, v, { scope: 'testParams' });
131
+ log.helper(`Applied ${nOverrides} test param overrides from HE config`);
132
+ }
37
133
  try {
38
134
  for (const t of _getRegistry()) {
39
135
  await reporter.beginTest(t.name);
40
136
  try {
41
137
  await t.fn(page);
42
- await _endDanglingStep({ ok: true });
43
138
  await reporter.passTest();
44
139
  }
45
140
  catch (e) {
46
- await _endDanglingStep({ ok: false, error: e });
47
- try {
48
- await reporter.attachScreenshot(await page.screenshot());
49
- }
50
- catch { /* swallow */ }
141
+ // H35 pending PY side commented; re-enable when parity decided
142
+ // try { await reporter.attachScreenshot(await page.screenshot()); } catch { /* swallow */ }
51
143
  await reporter.failTest(e);
52
144
  throw e;
53
145
  }
54
146
  }
55
147
  }
56
148
  finally {
57
- await browser.close();
149
+ try {
150
+ await browser.close();
151
+ }
152
+ catch { /* ignore */ }
153
+ if (sessionState.relay) {
154
+ try {
155
+ sessionState.relay.shutdown();
156
+ if (sessionState.relayTask) {
157
+ let timer;
158
+ const timeout = new Promise((_, rej) => {
159
+ timer = setTimeout(() => rej(new Error('relay shutdown timeout')), 5_000);
160
+ });
161
+ await Promise.race([sessionState.relayTask, timeout]).catch(() => { });
162
+ if (timer)
163
+ clearTimeout(timer);
164
+ }
165
+ }
166
+ catch { /* ignore */ }
167
+ }
168
+ sessionState.relay = null;
169
+ sessionState.relayTask = null;
170
+ sessionState.relayUrl = null;
58
171
  _setReporter(null);
172
+ log.helper('Session closed');
59
173
  }
60
174
  }
61
175
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
package/dist/step.d.ts CHANGED
@@ -2,13 +2,30 @@ import type { Reporter } from './reporters/index.js';
2
2
  export interface StepState {
3
3
  description: string;
4
4
  }
5
+ export interface StepOpts {
6
+ onFailure?: 'continue' | 'fail';
7
+ timeoutMs?: number;
8
+ }
9
+ type StepFn = () => Promise<void>;
5
10
  export declare function _setReporter(r: Reporter | null): void;
11
+ export declare function _getReporter(): Reporter | null;
6
12
  export declare function currentStep(): StepState | null;
7
- export declare function step(description: string): void;
8
- export declare function done(): void;
9
- export declare function _endDanglingStep(opts?: {
10
- ok: boolean;
11
- error?: unknown;
12
- }): Promise<void>;
13
13
  export declare function _resetStep(): void;
14
+ /**
15
+ * Block-scoped step boundary. Mirrors PY's `async with testmu.step(...)`.
16
+ *
17
+ * Two signatures:
18
+ * step(description, async () => {...})
19
+ * step(description, opts, async () => {...})
20
+ *
21
+ * Behavior:
22
+ * - Sets currentStep() to {description} for the duration of fn (heal patch reads this).
23
+ * - Calls reporter.beginStep(description) before fn.
24
+ * - Calls reporter.endStep(description, ok) after fn — ok=true on resolve, ok=false on throw.
25
+ * - Rethrows fn errors UNLESS opts.onFailure === 'continue'.
26
+ * - Restores prior currentStep on exit (supports nesting; outer step resumes).
27
+ */
28
+ export declare function step(description: string, fn: StepFn): Promise<void>;
29
+ export declare function step(description: string, opts: StepOpts, fn: StepFn): Promise<void>;
30
+ export {};
14
31
  //# sourceMappingURL=step.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,SAAS;IAAG,WAAW,EAAE,MAAM,CAAC;CAAE;AAKnD,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAmB;AACzE,wBAAgB,WAAW,IAAI,SAAS,GAAG,IAAI,CAAqB;AAEpE,wBAAgB,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAM9C;AAED,wBAAgB,IAAI,IAAI,IAAI,CAK3B;AAED,wBAAsB,gBAAgB,CAAC,IAAI,GAAE;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3G;AAED,wBAAgB,UAAU,IAAI,IAAI,CAAuC"}
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,SAAS;IAAG,WAAW,EAAE,MAAM,CAAC;CAAE;AACnD,MAAM,WAAW,QAAQ;IAAG,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AAEjF,KAAK,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAKlC,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAmB;AACzE,wBAAgB,YAAY,IAAI,QAAQ,GAAG,IAAI,CAAsB;AACrE,wBAAgB,WAAW,IAAI,SAAS,GAAG,IAAI,CAAqB;AACpE,wBAAgB,UAAU,IAAI,IAAI,CAAuC;AAEzE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAC3E,wBAAsB,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
package/dist/step.js CHANGED
@@ -1,36 +1,32 @@
1
1
  let _current = null;
2
2
  let _reporter = null;
3
3
  export function _setReporter(r) { _reporter = r; }
4
+ export function _getReporter() { return _reporter; }
4
5
  export function currentStep() { return _current; }
5
- export function step(description) {
6
- if (_current !== null && _reporter) {
7
- void _reporter.endStep(_current.description, true);
8
- }
6
+ export function _resetStep() { _current = null; _reporter = null; }
7
+ export async function step(description, fnOrOpts, maybeFn) {
8
+ const opts = typeof fnOrOpts === 'function' ? {} : fnOrOpts;
9
+ const fn = typeof fnOrOpts === 'function' ? fnOrOpts : maybeFn;
10
+ const prev = _current;
9
11
  _current = { description };
10
12
  if (_reporter)
11
- void _reporter.beginStep(description);
12
- }
13
- export function done() {
14
- if (_current === null)
15
- return;
16
- const desc = _current.description;
17
- _current = null;
18
- if (_reporter)
19
- void _reporter.endStep(desc, true);
20
- }
21
- export async function _endDanglingStep(opts = { ok: true }) {
22
- if (_current === null)
23
- return;
24
- const desc = _current.description;
25
- _current = null;
26
- if (_reporter) {
27
- if (opts.error !== undefined) {
28
- await _reporter.endStep(desc, opts.ok, opts.error);
29
- }
30
- else {
31
- await _reporter.endStep(desc, opts.ok);
32
- }
13
+ await _reporter.beginStep(description);
14
+ let ok = true;
15
+ let thrown;
16
+ try {
17
+ await fn();
18
+ }
19
+ catch (e) {
20
+ ok = false;
21
+ thrown = e;
22
+ }
23
+ finally {
24
+ _current = prev;
25
+ if (_reporter)
26
+ await _reporter.endStep(description, ok, thrown);
27
+ }
28
+ if (!ok && opts.onFailure !== 'continue') {
29
+ throw thrown;
33
30
  }
34
31
  }
35
- export function _resetStep() { _current = null; _reporter = null; }
36
32
  //# sourceMappingURL=step.js.map
package/dist/step.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAIA,IAAI,QAAQ,GAAqB,IAAI,CAAC;AACtC,IAAI,SAAS,GAAoB,IAAI,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,CAAkB,IAAU,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;AACzE,MAAM,UAAU,WAAW,KAAuB,OAAO,QAAQ,CAAC,CAAC,CAAC;AAEpE,MAAM,UAAU,IAAI,CAAC,WAAmB;IACtC,IAAI,QAAQ,KAAK,IAAI,IAAI,SAAS,EAAE,CAAC;QACnC,KAAK,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IACD,QAAQ,GAAG,EAAE,WAAW,EAAE,CAAC;IAC3B,IAAI,SAAS;QAAE,KAAK,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC;IAClC,QAAQ,GAAG,IAAI,CAAC;IAChB,IAAI,SAAS;QAAE,KAAK,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAyC,EAAE,EAAE,EAAE,IAAI,EAAE;IAC1F,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC;IAClC,QAAQ,GAAG,IAAI,CAAC;IAChB,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,KAAW,QAAQ,GAAG,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAOA,IAAI,QAAQ,GAAqB,IAAI,CAAC;AACtC,IAAI,SAAS,GAAoB,IAAI,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,CAAkB,IAAU,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;AACzE,MAAM,UAAU,YAAY,KAAsB,OAAO,SAAS,CAAC,CAAC,CAAC;AACrE,MAAM,UAAU,WAAW,KAAuB,OAAO,QAAQ,CAAC,CAAC,CAAC;AACpE,MAAM,UAAU,UAAU,KAAW,QAAQ,GAAG,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;AAkBzE,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,WAAmB,EACnB,QAA2B,EAC3B,OAAgB;IAEhB,MAAM,IAAI,GAAa,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtE,MAAM,EAAE,GAAW,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAE,OAAkB,CAAC;IAEnF,MAAM,IAAI,GAAG,QAAQ,CAAC;IACtB,QAAQ,GAAG,EAAE,WAAW,EAAE,CAAC;IAC3B,IAAI,SAAS;QAAE,MAAM,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAEtD,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,CAAC;IACb,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,EAAE,GAAG,KAAK,CAAC;QACX,MAAM,GAAG,CAAC,CAAC;IACb,CAAC;YAAS,CAAC;QACT,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,SAAS;YAAE,MAAM,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;QACzC,MAAM,MAAM,CAAC;IACf,CAAC;AACH,CAAC"}
package/dist/vars.d.ts CHANGED
@@ -1,18 +1,16 @@
1
1
  /**
2
2
  * Variable resolution for testmu.
3
3
  *
4
- * v(template) resolves {{...}} and ${...} placeholders:
4
+ * resolveVar(template) single async entry point. Resolves:
5
5
  * - Pure {{x}} → direct lookup from userStore (type-preserving); unresolved → ""
6
6
  * - Embedded "prefix {{x}} suffix" → string interpolation; unresolved → ""
7
- * - ${x} → testParams lookup, then userStore fallback (type-preserving when pure)
8
- * - Non-string / non-template values returned as-is
9
- *
10
- * vAsync(template) additionally resolves:
7
+ * - ${x} → testParams lookup, then userStore fallback
8
+ * - {{smart.X}} local computation (no HTTP)
11
9
  * - {{global.X}} → ATMS API or TESTMU_VAR_X env fallback
12
10
  * - {{environment.X}} → ATMS API (with ENVIRONMENT_ID) or TESTMU_VAR_X env fallback
13
11
  * - {{secrets.cat.KEY}} → process.env[KEY]
14
- * - {{smart.X}} → local computation (no HTTP)
15
- * - plain {{x}} / ${x}delegates to sync v()
12
+ * - {{totp.X}} → ATMS seed + TOTP compute
13
+ * - Non-string / non-template values returned as-is
16
14
  */
17
15
  /** Shape of an entry in the global-variables list (populated by configure() in Task 15). */
18
16
  export interface GlobalVariable {
@@ -39,23 +37,14 @@ export declare function _getUserStore(): Record<string, unknown>;
39
37
  /** Append a global variable entry (called by configure() in Task 15). */
40
38
  export declare function _addGlobalVariable(g: GlobalVariable): void;
41
39
  /**
42
- * Resolve a template value.
43
- *
44
- * - Non-string → returned as-is.
45
- * - No {{...}} or ${...} → returned as-is.
46
- * - Pure {{x}} → type-preserving lookup; unresolved → "".
47
- * - Pure ${x} → testParams then userStore lookup; unresolved → "".
48
- * - Embedded (contains other text) → string interpolation; unresolved → "".
49
- */
50
- export declare function v<T = unknown>(template: unknown, opts?: VOptions): T;
51
- /**
52
- * Async variable resolution — extends v() with HTTP-backed lookups.
40
+ * Resolve a template value (async — handles both local and HTTP-backed lookups).
53
41
  *
54
42
  * - {{global.X}} → ATMS or TESTMU_VAR_X fallback
55
43
  * - {{environment.X}} → ATMS (with ENVIRONMENT_ID) or TESTMU_VAR_X fallback
56
44
  * - {{secrets.cat.KEY}} → process.env[KEY]
45
+ * - {{totp.X}} → ATMS seed + TOTP compute
57
46
  * - {{smart.X}} → local computation (no HTTP)
58
- * - plain {{x}} / ${x} → delegates to sync v()
47
+ * - plain {{x}} / ${x} / no template → delegates to module-private _resolveSync
59
48
  */
60
- export declare function vAsync<T = unknown>(template: unknown, opts?: VOptions): Promise<T>;
49
+ export declare function resolveVar<T = unknown>(template: unknown, opts?: VOptions): Promise<T>;
61
50
  //# sourceMappingURL=vars.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vars.d.ts","sourceRoot":"","sources":["../src/vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAaH,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyBD,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,OAAO,GACP,MAAM,GACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,MAAM,CAAC;AAgCX,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;CAC/B;AAED,6EAA6E;AAC7E,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,aAAkB,GACvB,IAAI,CAON;AAED,sCAAsC;AACtC,wBAAgB,WAAW,IAAI,IAAI,CAIlC;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,SAAS,cAAc,EAAE,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEvD;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,CAE1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,GAAE,QAAa,GAAG,CAAC,CA8CxE;AAqdD;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAAC,CAAC,GAAG,OAAO,EACtC,QAAQ,EAAE,OAAO,EACjB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,CAAC,CAAC,CA0EZ"}
1
+ {"version":3,"file":"vars.d.ts","sourceRoot":"","sources":["../src/vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmBH,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyBD,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,OAAO,GACP,MAAM,GACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,MAAM,CAAC;AAgCX,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;CAC/B;AAED,6EAA6E;AAC7E,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,aAAkB,GACvB,IAAI,CASN;AAED,sCAAsC;AACtC,wBAAgB,WAAW,IAAI,IAAI,CAIlC;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,SAAS,cAAc,EAAE,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEvD;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,CAE1D;AAohBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,QAAQ,EAAE,OAAO,EACjB,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,CAAC,CAAC,CA6FZ"}
package/dist/vars.js CHANGED
@@ -1,22 +1,25 @@
1
1
  /**
2
2
  * Variable resolution for testmu.
3
3
  *
4
- * v(template) resolves {{...}} and ${...} placeholders:
4
+ * resolveVar(template) single async entry point. Resolves:
5
5
  * - Pure {{x}} → direct lookup from userStore (type-preserving); unresolved → ""
6
6
  * - Embedded "prefix {{x}} suffix" → string interpolation; unresolved → ""
7
- * - ${x} → testParams lookup, then userStore fallback (type-preserving when pure)
8
- * - Non-string / non-template values returned as-is
9
- *
10
- * vAsync(template) additionally resolves:
7
+ * - ${x} → testParams lookup, then userStore fallback
8
+ * - {{smart.X}} local computation (no HTTP)
11
9
  * - {{global.X}} → ATMS API or TESTMU_VAR_X env fallback
12
10
  * - {{environment.X}} → ATMS API (with ENVIRONMENT_ID) or TESTMU_VAR_X env fallback
13
11
  * - {{secrets.cat.KEY}} → process.env[KEY]
14
- * - {{smart.X}} → local computation (no HTTP)
15
- * - plain {{x}} / ${x}delegates to sync v()
12
+ * - {{totp.X}} → ATMS seed + TOTP compute
13
+ * - Non-string / non-template values returned as-is
16
14
  */
17
15
  import { authenticator } from "otplib";
18
16
  import { fetchWithAuth, ltAuthHeader } from "./http.js";
19
- import { _registerConfigureHook } from "./configure.js";
17
+ import { _registerConfigureHook, get as getConfig } from "./configure.js";
18
+ import { log, preview } from "./log.js";
19
+ /** Mirrors PY _is_sensitive_template: only secrets/totp warrant redaction. */
20
+ function _isSensitiveTemplate(templateStr) {
21
+ return templateStr.includes("{{secrets.") || templateStr.includes("{{totp.");
22
+ }
20
23
  // ---------------------------------------------------------------------------
21
24
  // Internal stores (module-level singletons, reset via _resetStore())
22
25
  // ---------------------------------------------------------------------------
@@ -65,6 +68,8 @@ function applyTransform(value, t) {
65
68
  }
66
69
  /** Store a variable value into the given scope (default: user variables). */
67
70
  export function setVar(name, value, opts = {}) {
71
+ // PY parity: _vars.py set_var → "[set_var] name=%r value=%s"
72
+ log.helper(`[set_var] name='${name}' value=${preview(value)}`);
68
73
  const scope = opts.scope ?? "user";
69
74
  if (scope === "testParams") {
70
75
  testParamsStore.set(name, value);
@@ -92,7 +97,8 @@ export function _addGlobalVariable(g) {
92
97
  globalVariables.push(g);
93
98
  }
94
99
  /**
95
- * Resolve a template value.
100
+ * Module-private synchronous resolver — used internally by resolveVar for
101
+ * non-ATMS fast paths. Not exported.
96
102
  *
97
103
  * - Non-string → returned as-is.
98
104
  * - No {{...}} or ${...} → returned as-is.
@@ -100,7 +106,7 @@ export function _addGlobalVariable(g) {
100
106
  * - Pure ${x} → testParams then userStore lookup; unresolved → "".
101
107
  * - Embedded (contains other text) → string interpolation; unresolved → "".
102
108
  */
103
- export function v(template, opts = {}) {
109
+ function _resolveSync(template, opts = {}) {
104
110
  // Non-string: pass through unchanged (JS idiom — differs from Python's None→"")
105
111
  if (typeof template !== "string")
106
112
  return template;
@@ -472,10 +478,11 @@ function lookupTestParams(name) {
472
478
  *
473
479
  * Matches Python _atms_get_variable: always includes environment_id (0 for global).
474
480
  * Response: resp.json()["data"] — then .value from that dict.
475
- * ATMS_URL has no default (empty string if unset) — mirrors Python.
481
+ * ATMS_URL defaults to https://test-manager-api.lambdatest.com when env var
482
+ * unset (matches Python _vars.py:391,405). Cloud (HE) overrides via injection.
476
483
  */
477
484
  async function atmsGetVariable(name, environmentId = 0) {
478
- const base = (process.env["ATMS_URL"] ?? "").replace(/\/$/, "");
485
+ const base = (process.env["ATMS_URL"] ?? "https://test-manager-api.lambdatest.com").replace(/\/$/, "");
479
486
  const url = `${base}/api/v1/variables/${encodeURIComponent(name)}?environment_id=${environmentId}`;
480
487
  const resp = await fetchWithAuth(url, { method: "GET" });
481
488
  if (!resp.ok)
@@ -519,7 +526,11 @@ async function resolveSpecialAsync(name) {
519
526
  return envVal;
520
527
  }
521
528
  try {
522
- const envId = parseInt(process.env["ENVIRONMENT_ID"] ?? "0", 10);
529
+ // env var wins, then configure(environmentId), then 0 — matches PY _vars.py:227.
530
+ const envFromProc = process.env["ENVIRONMENT_ID"];
531
+ const envId = (envFromProc !== undefined && envFromProc !== "")
532
+ ? parseInt(envFromProc, 10)
533
+ : Number(getConfig("environmentId") || 0);
523
534
  return await atmsGetVariable(varName, envId);
524
535
  }
525
536
  catch (err) {
@@ -553,7 +564,7 @@ async function resolveSpecialAsync(name) {
553
564
  }
554
565
  else {
555
566
  // GET {ATMS_URL}/api/v1/variables/totp/{name} — resp.json()["data"] is the seed string
556
- const base = (process.env["ATMS_URL"] ?? "").replace(/\/$/, "");
567
+ const base = (process.env["ATMS_URL"] ?? "https://test-manager-api.lambdatest.com").replace(/\/$/, "");
557
568
  const url = `${base}/api/v1/variables/totp/${encodeURIComponent(varName)}`;
558
569
  const resp = await fetchWithAuth(url, { method: "GET" });
559
570
  if (!resp.ok)
@@ -566,17 +577,22 @@ async function resolveSpecialAsync(name) {
566
577
  throw new Error(`Unknown special variable prefix: ${name}`);
567
578
  }
568
579
  /**
569
- * Async variable resolutionextends v() with HTTP-backed lookups.
580
+ * Resolve a template value (async handles both local and HTTP-backed lookups).
570
581
  *
571
582
  * - {{global.X}} → ATMS or TESTMU_VAR_X fallback
572
583
  * - {{environment.X}} → ATMS (with ENVIRONMENT_ID) or TESTMU_VAR_X fallback
573
584
  * - {{secrets.cat.KEY}} → process.env[KEY]
585
+ * - {{totp.X}} → ATMS seed + TOTP compute
574
586
  * - {{smart.X}} → local computation (no HTTP)
575
- * - plain {{x}} / ${x} → delegates to sync v()
587
+ * - plain {{x}} / ${x} / no template → delegates to module-private _resolveSync
576
588
  */
577
- export async function vAsync(template, opts = {}) {
578
- if (typeof template !== "string")
589
+ export async function resolveVar(template, opts = {}) {
590
+ if (typeof template !== "string") {
591
+ // PY parity: _log.info(" [var] template=None → ''") — JS emits typeof
592
+ log.helper(`[var] template=${template === null ? "null" : typeof template} → passthrough`);
579
593
  return template;
594
+ }
595
+ const sensitive = _isSensitiveTemplate(template);
580
596
  let result;
581
597
  // Pure single-placeholder: {{name}}
582
598
  const pureName = extractPure(template, MUSTACHE_RE);
@@ -591,19 +607,33 @@ export async function vAsync(template, opts = {}) {
591
607
  result = await resolveSpecialAsync(pureName);
592
608
  }
593
609
  else {
594
- // Delegate to sync v() for plain variables (without transform apply below)
595
- result = v(template);
610
+ // Delegate to sync path for plain variables (transform applied below).
611
+ result = _resolveSync(template);
612
+ }
613
+ {
614
+ const finalResult = opts.transform ? applyTransform(result, opts.transform) : result;
615
+ const resolvedPreview = sensitive ? "[REDACTED]" : preview(finalResult);
616
+ const transformSuffix = opts.transform !== undefined ? ` transform=${opts.transform}` : "";
617
+ log.helper(`[var] ${preview(template)} → ${resolvedPreview}${transformSuffix}`);
618
+ return finalResult;
596
619
  }
597
- return (opts.transform ? applyTransform(result, opts.transform) : result);
598
620
  }
599
- // Pure ${x} — delegate sync (without transform apply below)
621
+ // Pure ${x} — delegate sync (transform applied below).
600
622
  const pureDollar = extractPure(template, DOLLAR_RE);
601
623
  if (pureDollar !== null) {
602
- result = v(template);
603
- return (opts.transform ? applyTransform(result, opts.transform) : result);
624
+ result = _resolveSync(template);
625
+ {
626
+ const finalResult = opts.transform ? applyTransform(result, opts.transform) : result;
627
+ const resolvedPreview = sensitive ? "[REDACTED]" : preview(finalResult);
628
+ const transformSuffix = opts.transform !== undefined ? ` transform=${opts.transform}` : "";
629
+ log.helper(`[var] ${preview(template)} → ${resolvedPreview}${transformSuffix}`);
630
+ return finalResult;
631
+ }
604
632
  }
605
633
  // Embedded template — resolve {{...}} placeholders asynchronously
606
634
  if (!MUSTACHE_RE.test(template) && !DOLLAR_RE.test(template)) {
635
+ // No placeholders → passthrough; log type-preserving exit.
636
+ log.helper(`[var] ${preview(template)} → ${sensitive ? "[REDACTED]" : preview(template)} (no-op)`);
607
637
  return template;
608
638
  }
609
639
  const matches = [...template.matchAll(MUSTACHE_RE_G)];
@@ -620,7 +650,7 @@ export async function vAsync(template, opts = {}) {
620
650
  replacements.push(await resolveSpecialAsync(inner));
621
651
  }
622
652
  else {
623
- const sync = v(`{{${inner}}}`);
653
+ const sync = _resolveSync(`{{${inner}}}`);
624
654
  replacements.push(sync === "" ? "" : String(sync));
625
655
  }
626
656
  }
@@ -634,7 +664,13 @@ export async function vAsync(template, opts = {}) {
634
664
  return val === "" ? "" : String(val);
635
665
  });
636
666
  result = out;
637
- return (opts.transform ? applyTransform(result, opts.transform) : result);
667
+ {
668
+ const finalResult = opts.transform ? applyTransform(result, opts.transform) : result;
669
+ const resolvedPreview = sensitive ? "[REDACTED]" : preview(finalResult);
670
+ const transformSuffix = opts.transform !== undefined ? ` transform=${opts.transform}` : "";
671
+ log.helper(`[var] ${preview(template)} → ${resolvedPreview}${transformSuffix}`);
672
+ return finalResult;
673
+ }
638
674
  }
639
675
  // ---------------------------------------------------------------------------
640
676
  // configure() → vars store wiring (registered once at module load)