@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.
- package/README.md +3 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -1
- package/dist/config.js.map +1 -1
- package/dist/configure.d.ts +5 -1
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +1 -0
- package/dist/configure.js.map +1 -1
- package/dist/healPatch.d.ts +9 -2
- package/dist/healPatch.d.ts.map +1 -1
- package/dist/healPatch.js +25 -8
- package/dist/healPatch.js.map +1 -1
- package/dist/helpers/assertion.d.ts.map +1 -1
- package/dist/helpers/assertion.js +18 -12
- package/dist/helpers/assertion.js.map +1 -1
- package/dist/helpers/drag.d.ts.map +1 -1
- package/dist/helpers/drag.js +2 -0
- package/dist/helpers/drag.js.map +1 -1
- package/dist/helpers/executeApi.d.ts +12 -1
- package/dist/helpers/executeApi.d.ts.map +1 -1
- package/dist/helpers/executeApi.js +108 -20
- package/dist/helpers/executeApi.js.map +1 -1
- package/dist/helpers/executeDb.js +1 -1
- package/dist/helpers/executeDb.js.map +1 -1
- package/dist/helpers/kaneCli.d.ts +10 -1
- package/dist/helpers/kaneCli.d.ts.map +1 -1
- package/dist/helpers/kaneCli.js +122 -3
- package/dist/helpers/kaneCli.js.map +1 -1
- package/dist/helpers/math.d.ts +1 -1
- package/dist/helpers/math.d.ts.map +1 -1
- package/dist/helpers/math.js +8 -6
- package/dist/helpers/math.js.map +1 -1
- package/dist/helpers/network.d.ts +4 -4
- package/dist/helpers/network.d.ts.map +1 -1
- package/dist/helpers/network.js +19 -16
- package/dist/helpers/network.js.map +1 -1
- package/dist/helpers/smartui.d.ts +5 -1
- package/dist/helpers/smartui.d.ts.map +1 -1
- package/dist/helpers/smartui.js +45 -7
- package/dist/helpers/smartui.js.map +1 -1
- package/dist/helpers/tabs.d.ts.map +1 -1
- package/dist/helpers/tabs.js +2 -0
- package/dist/helpers/tabs.js.map +1 -1
- package/dist/helpers/vision.d.ts +50 -7
- package/dist/helpers/vision.d.ts.map +1 -1
- package/dist/helpers/vision.js +212 -29
- package/dist/helpers/vision.js.map +1 -1
- package/dist/helpers/wait.d.ts.map +1 -1
- package/dist/helpers/wait.js +1 -2
- package/dist/helpers/wait.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/loadEnv.d.ts +2 -0
- package/dist/loadEnv.d.ts.map +1 -0
- package/dist/loadEnv.js +12 -0
- package/dist/loadEnv.js.map +1 -0
- package/dist/relayProxy.d.ts +46 -0
- package/dist/relayProxy.d.ts.map +1 -0
- package/dist/relayProxy.js +453 -0
- package/dist/relayProxy.js.map +1 -0
- package/dist/session.d.ts +6 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +130 -16
- package/dist/session.js.map +1 -1
- package/dist/step.d.ts +23 -6
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +23 -27
- package/dist/step.js.map +1 -1
- package/dist/vars.d.ts +9 -20
- package/dist/vars.d.ts.map +1 -1
- package/dist/vars.js +62 -26
- package/dist/vars.js.map +1 -1
- 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
|
|
10
|
+
import { _setReporter } from './step.js';
|
|
7
11
|
import { buildCapabilities, getCdpUrl, getViewport } from './capability.js';
|
|
8
12
|
import { TestmuConfigError } from './errors.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgD,MAAM,YAAY,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,
|
|
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
|
package/dist/step.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
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":"
|
|
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
|
-
*
|
|
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
|
|
8
|
-
* -
|
|
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
|
-
* - {{
|
|
15
|
-
* -
|
|
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
|
|
47
|
+
* - plain {{x}} / ${x} / no template → delegates to module-private _resolveSync
|
|
59
48
|
*/
|
|
60
|
-
export declare function
|
|
49
|
+
export declare function resolveVar<T = unknown>(template: unknown, opts?: VOptions): Promise<T>;
|
|
61
50
|
//# sourceMappingURL=vars.d.ts.map
|
package/dist/vars.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vars.d.ts","sourceRoot":"","sources":["../src/vars.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
*
|
|
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
|
|
8
|
-
* -
|
|
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
|
-
* - {{
|
|
15
|
-
* -
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
587
|
+
* - plain {{x}} / ${x} / no template → delegates to module-private _resolveSync
|
|
576
588
|
*/
|
|
577
|
-
export async function
|
|
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
|
|
595
|
-
result =
|
|
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 (
|
|
621
|
+
// Pure ${x} — delegate sync (transform applied below).
|
|
600
622
|
const pureDollar = extractPure(template, DOLLAR_RE);
|
|
601
623
|
if (pureDollar !== null) {
|
|
602
|
-
result =
|
|
603
|
-
|
|
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 =
|
|
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
|
-
|
|
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)
|