feat(scenario): add context.assert() API for script assertions
- Add context.assert(fn, description) for function assertions - Logs outcome on success/failure, throws on assertion failure - Bump package version from 1.8.0 to 1.9.0
This commit is contained in:
@@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 1.9.0 - 2026-09-15
|
||||||
|
|
||||||
|
Changes since 1.8.0:
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `context.assert(fn, description)` for scenario/snippet script steps: runs the given function, requires it to return `true`, logs the outcome (`log` on success, `error` on failure or exception), and throws to stop the step on failure.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Documented `context.assert` in `docs/scenario.md`.
|
||||||
|
|
||||||
## 1.8.0 - 2026-09-15
|
## 1.8.0 - 2026-09-15
|
||||||
|
|
||||||
Changes since 1.7.1:
|
Changes since 1.7.1:
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ Available in scope:
|
|||||||
- `context.getStepOutput(order)`: prior step output by absolute order (`1`, `2`, ...) or relative (`-1` = previous step)
|
- `context.getStepOutput(order)`: prior step output by absolute order (`1`, `2`, ...) or relative (`-1` = previous step)
|
||||||
- `context.dumpDom(selector?)`: simplified DOM snapshot
|
- `context.dumpDom(selector?)`: simplified DOM snapshot
|
||||||
- `context.log(...args)`, `context.warn(...args)`, `context.error(...args)`: structured step logs
|
- `context.log(...args)`, `context.warn(...args)`, `context.error(...args)`: structured step logs
|
||||||
|
- `context.assert(() => boolean, description)`: runs the arrow function and requires it to return `true`. Logs `description` (as a `log` entry on success, as an `error` entry on failure or exception), then throws to stop the step if the function returned anything other than `true` or threw
|
||||||
- `context.runSnippet(name, ...args)`: execute stored snippet code with the same context
|
- `context.runSnippet(name, ...args)`: execute stored snippet code with the same context
|
||||||
- `context.getScenarioFiles(opts?)`: list files uploaded to the scenario (`limit`, `offset`)
|
- `context.getScenarioFiles(opts?)`: list files uploaded to the scenario (`limit`, `offset`)
|
||||||
- `context.downloadFile(url, opts?)`: fetch `url` and save the result as a run artifact (requires a real scenario run — throws when invoked ad hoc, e.g. via the `exec_code` MCP tool). `opts` may include `method`, `headers`, `body`, `filename`. `url` also accepts a `data:` URI (`data:<mediaType>;base64,<data>` or `data:<mediaType>,<percent-encoded data>`) to save content generated in-script (e.g. a credential JWT) directly, without an actual network fetch.
|
- `context.downloadFile(url, opts?)`: fetch `url` and save the result as a run artifact (requires a real scenario run — throws when invoked ad hoc, e.g. via the `exec_code` MCP tool). `opts` may include `method`, `headers`, `body`, `filename`. `url` also accepts a `data:` URI (`data:<mediaType>;base64,<data>` or `data:<mediaType>,<percent-encoded data>`) to save content generated in-script (e.g. a credential JWT) directly, without an actual network fetch.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "liqa",
|
"name": "liqa",
|
||||||
"version": "1.8.0",
|
"version": "1.9.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"server",
|
"server",
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ export interface ScriptContext {
|
|||||||
log: (...args: unknown[]) => void;
|
log: (...args: unknown[]) => void;
|
||||||
warn: (...args: unknown[]) => void;
|
warn: (...args: unknown[]) => void;
|
||||||
error: (...args: unknown[]) => void;
|
error: (...args: unknown[]) => void;
|
||||||
|
/**
|
||||||
|
* Runs `fn` and requires it to return `true`. Logs the outcome under
|
||||||
|
* `description`, then throws if `fn` returned anything other than `true`
|
||||||
|
* or threw an exception.
|
||||||
|
*/
|
||||||
|
assert: (
|
||||||
|
fn: () => boolean | Promise<boolean>,
|
||||||
|
description: string,
|
||||||
|
) => Promise<void>;
|
||||||
/** Runs a named snippet with the same context, plus any extra positional args. */
|
/** Runs a named snippet with the same context, plus any extra positional args. */
|
||||||
runSnippet: (alias: string, ...args: unknown[]) => Promise<unknown>;
|
runSnippet: (alias: string, ...args: unknown[]) => Promise<unknown>;
|
||||||
/** Returns metadata + absolute disk path for files attached to the current scenario. */
|
/** Returns metadata + absolute disk path for files attached to the current scenario. */
|
||||||
@@ -141,6 +150,28 @@ export class CodeExecutorService {
|
|||||||
log: (...args: unknown[]) => scriptLog("log", toStr(args)),
|
log: (...args: unknown[]) => scriptLog("log", toStr(args)),
|
||||||
warn: (...args: unknown[]) => scriptLog("warn", toStr(args)),
|
warn: (...args: unknown[]) => scriptLog("warn", toStr(args)),
|
||||||
error: (...args: unknown[]) => scriptLog("error", toStr(args)),
|
error: (...args: unknown[]) => scriptLog("error", toStr(args)),
|
||||||
|
assert: async (
|
||||||
|
fn: () => boolean | Promise<boolean>,
|
||||||
|
description: string,
|
||||||
|
): Promise<void> => {
|
||||||
|
let passed: boolean;
|
||||||
|
let failureReason: string | undefined;
|
||||||
|
try {
|
||||||
|
passed = (await fn()) === true;
|
||||||
|
} catch (err) {
|
||||||
|
passed = false;
|
||||||
|
failureReason = (err as Error).message;
|
||||||
|
}
|
||||||
|
if (passed) {
|
||||||
|
scriptLog("log", `Assertion passed: ${description}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = failureReason
|
||||||
|
? `Assertion failed: ${description} (${failureReason})`
|
||||||
|
: `Assertion failed: ${description}`;
|
||||||
|
scriptLog("error", message);
|
||||||
|
throw new Error(message);
|
||||||
|
},
|
||||||
getStepOutput: getStepOutput ?? (() => Promise.resolve(null)),
|
getStepOutput: getStepOutput ?? (() => Promise.resolve(null)),
|
||||||
getCredential: (alias: string): unknown => {
|
getCredential: (alias: string): unknown => {
|
||||||
if (!(alias in credMap)) {
|
if (!(alias in credMap)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user