lynkeus-protocol 0.3.0 → 0.5.0
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/lib/fixtures.d.ts +47 -0
- package/lib/fixtures.js +6 -0
- package/lib/index.d.ts +17 -1
- package/lib/index.js +1 -0
- package/lib/run.d.ts +35 -0
- package/package.json +1 -1
- package/src/fixtures.ts +41 -0
- package/src/index.ts +13 -1
- package/src/run.ts +25 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
|
|
3
|
+
* the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
|
|
4
|
+
* The full contract is docs/FIXTURES.md.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FIXTURES_PROTOCOL = 1;
|
|
7
|
+
/** One step, as lynkeus sends it: `params` as the case wrote them, `env` the same flattened to upper-case strings. */
|
|
8
|
+
export type FixtureRequest = {
|
|
9
|
+
command: string;
|
|
10
|
+
params: Record<string, unknown>;
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
/** Any JSON object; `ok: false` with an `error` when the step failed. */
|
|
14
|
+
export type FixtureAnswer = {
|
|
15
|
+
ok?: boolean;
|
|
16
|
+
error?: string;
|
|
17
|
+
} & Record<string, unknown>;
|
|
18
|
+
/** A parameter a command takes, for authors and models choosing a setup. */
|
|
19
|
+
export type FixtureParam = {
|
|
20
|
+
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
21
|
+
summary?: string;
|
|
22
|
+
/** The values it takes, when they are few. */
|
|
23
|
+
values?: (string | number | boolean)[];
|
|
24
|
+
default?: unknown;
|
|
25
|
+
required?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** What a command does, for authors and models: what state it makes or reads, its parameters, one example. */
|
|
28
|
+
export type FixtureCommand = {
|
|
29
|
+
name: string;
|
|
30
|
+
summary?: string;
|
|
31
|
+
params?: Record<string, FixtureParam>;
|
|
32
|
+
/** The params of one call that works, as a case would write them. */
|
|
33
|
+
example?: Record<string, unknown>;
|
|
34
|
+
/** What its answer carries that a later step reads (`user_id`, `api_key`…). */
|
|
35
|
+
answers?: string[];
|
|
36
|
+
/** `false` for a command that only reads: safe to call while checking a server. */
|
|
37
|
+
changes?: boolean;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The answer to `lynkeus.describe`. `commands` lists names, or descriptions, or both; a server from before
|
|
41
|
+
* descriptions answers names only, and that stays valid. `down` says the server runs but cannot serve.
|
|
42
|
+
*/
|
|
43
|
+
export type FixturesDescription = {
|
|
44
|
+
protocol?: number;
|
|
45
|
+
commands: (string | FixtureCommand)[];
|
|
46
|
+
down?: string;
|
|
47
|
+
};
|
package/lib/fixtures.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
|
|
3
|
+
* the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
|
|
4
|
+
* The full contract is docs/FIXTURES.md.
|
|
5
|
+
*/
|
|
6
|
+
export const FIXTURES_PROTOCOL = 1;
|
package/lib/index.d.ts
CHANGED
|
@@ -122,6 +122,11 @@ export type WaitForParams = {
|
|
|
122
122
|
/** Swipe the nearest scrolling container towards the target until it is in the window. */
|
|
123
123
|
scroll?: boolean;
|
|
124
124
|
timeoutMs?: number;
|
|
125
|
+
/**
|
|
126
|
+
* A trace mark (`trace().last`): a `route` the app reached after it counts as arrived, even if the app has
|
|
127
|
+
* already left it. A screen that closes itself (a success screen) can come and go while a step's frame settles.
|
|
128
|
+
*/
|
|
129
|
+
since?: number;
|
|
125
130
|
};
|
|
126
131
|
export type TraceEvent = {
|
|
127
132
|
seq: number;
|
|
@@ -180,6 +185,12 @@ export type TraceEvent = {
|
|
|
180
185
|
stack?: string;
|
|
181
186
|
route?: string;
|
|
182
187
|
});
|
|
188
|
+
/** One side of a request: its headers and body, sensitive values replaced by `…`, a long body cut. */
|
|
189
|
+
export type Exchange = {
|
|
190
|
+
headers?: Record<string, string>;
|
|
191
|
+
body?: string;
|
|
192
|
+
truncated?: boolean;
|
|
193
|
+
};
|
|
183
194
|
export type RequestRecord = {
|
|
184
195
|
id: number;
|
|
185
196
|
method: string;
|
|
@@ -188,6 +199,9 @@ export type RequestRecord = {
|
|
|
188
199
|
startedAt: number;
|
|
189
200
|
ms?: number;
|
|
190
201
|
error?: string;
|
|
202
|
+
/** Only while a driver asked for bodies (`networkBodies`). */
|
|
203
|
+
request?: Exchange;
|
|
204
|
+
response?: Exchange;
|
|
191
205
|
};
|
|
192
206
|
/** Every method the core answers. Apps add their own through `qa.register`. */
|
|
193
207
|
export type CoreMethods = {
|
|
@@ -262,7 +276,8 @@ export type CoreMethods = {
|
|
|
262
276
|
result: {
|
|
263
277
|
route?: string;
|
|
264
278
|
matched?: Target;
|
|
265
|
-
waitedMs: number
|
|
279
|
+
waitedMs: number /** The route was reached after `since` and left again. */;
|
|
280
|
+
passed?: boolean;
|
|
266
281
|
};
|
|
267
282
|
};
|
|
268
283
|
idle: {
|
|
@@ -358,3 +373,4 @@ export type AuthEvent = {
|
|
|
358
373
|
};
|
|
359
374
|
export type AgentEvent = HelloEvent | NavigationEvent;
|
|
360
375
|
export * from './run.js';
|
|
376
|
+
export * from './fixtures.js';
|
package/lib/index.js
CHANGED
package/lib/run.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RequestRecord } from './index.js';
|
|
1
2
|
/**
|
|
2
3
|
* What a run of cases leaves behind: a directory anything can read without
|
|
3
4
|
* knowing how the run was made.
|
|
@@ -62,11 +63,31 @@ export type RunStep = {
|
|
|
62
63
|
videoS?: number;
|
|
63
64
|
/** What the backend did for it, when the backend exports traces to the run. */
|
|
64
65
|
backend?: RunBackendSpan[];
|
|
66
|
+
/** The requests the app sent while it ran, with headers and bodies whose secrets are hidden. */
|
|
67
|
+
requests?: RequestRecord[];
|
|
68
|
+
/** What the app printed while it ran: its console, the errors it did not catch, its native log. */
|
|
69
|
+
logs?: RunLogLine[];
|
|
70
|
+
};
|
|
71
|
+
/** A printed line: `at` in ms since the epoch; `source` is `js`, `native` or `host`. */
|
|
72
|
+
export type RunLogLine = {
|
|
73
|
+
at: number;
|
|
74
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
75
|
+
source: string;
|
|
76
|
+
text: string;
|
|
77
|
+
stack?: string;
|
|
65
78
|
};
|
|
66
79
|
export type RunCase = {
|
|
67
80
|
id: string;
|
|
68
81
|
title?: string;
|
|
69
82
|
description?: string;
|
|
83
|
+
/** What the case says about itself: why it matters, what is true when it starts, its ticket and expected outcome. */
|
|
84
|
+
about?: {
|
|
85
|
+
description?: string;
|
|
86
|
+
why?: string;
|
|
87
|
+
given?: string;
|
|
88
|
+
ticket?: string;
|
|
89
|
+
expected?: string;
|
|
90
|
+
};
|
|
70
91
|
/** The case file, relative to where the run was started. */
|
|
71
92
|
file: string;
|
|
72
93
|
/** 1 for the first try; a case that failed and ran again has a line for each. */
|
|
@@ -99,9 +120,23 @@ export type RunManifest = {
|
|
|
99
120
|
/** Whether the app ran on a device or simulator (true) or hosted without one. */
|
|
100
121
|
native?: boolean;
|
|
101
122
|
/** Where the run was made from, when it was a git checkout. */
|
|
123
|
+
/** `remote`: the repository's web address (no credentials); `changed`: files with changes no commit has (at most 20 of `changedCount`). */
|
|
124
|
+
/**
|
|
125
|
+
* `pushed`: what of it the remote has, as the clone knew when the run began (its remote-tracking refs, not a
|
|
126
|
+
* request): the branch, and the commit on any remote branch. A report links only what is there. A branch only this
|
|
127
|
+
* machine has is replaced by the remote branch that holds the commit, and `localBranch` keeps its name.
|
|
128
|
+
*/
|
|
102
129
|
git?: {
|
|
103
130
|
branch?: string;
|
|
131
|
+
localBranch?: string;
|
|
104
132
|
commit?: string;
|
|
133
|
+
remote?: string;
|
|
134
|
+
changed?: string[];
|
|
135
|
+
changedCount?: number;
|
|
136
|
+
pushed?: {
|
|
137
|
+
branch: boolean;
|
|
138
|
+
commit: boolean;
|
|
139
|
+
};
|
|
105
140
|
};
|
|
106
141
|
/** Cases by their last attempt. */
|
|
107
142
|
totals?: {
|
package/package.json
CHANGED
package/src/fixtures.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixtures protocol: how a case prepares and reads a backend through a server the project writes. lynkeus starts
|
|
3
|
+
* the command `cases.fixtures` names and speaks JSON lines to it, one request and one answer per line.
|
|
4
|
+
* The full contract is docs/FIXTURES.md.
|
|
5
|
+
*/
|
|
6
|
+
export const FIXTURES_PROTOCOL = 1;
|
|
7
|
+
|
|
8
|
+
/** One step, as lynkeus sends it: `params` as the case wrote them, `env` the same flattened to upper-case strings. */
|
|
9
|
+
export type FixtureRequest = { command: string; params: Record<string, unknown>; env: Record<string, string> };
|
|
10
|
+
|
|
11
|
+
/** Any JSON object; `ok: false` with an `error` when the step failed. */
|
|
12
|
+
export type FixtureAnswer = { ok?: boolean; error?: string } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
/** A parameter a command takes, for authors and models choosing a setup. */
|
|
15
|
+
export type FixtureParam = {
|
|
16
|
+
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
17
|
+
summary?: string;
|
|
18
|
+
/** The values it takes, when they are few. */
|
|
19
|
+
values?: (string | number | boolean)[];
|
|
20
|
+
default?: unknown;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** What a command does, for authors and models: what state it makes or reads, its parameters, one example. */
|
|
25
|
+
export type FixtureCommand = {
|
|
26
|
+
name: string;
|
|
27
|
+
summary?: string;
|
|
28
|
+
params?: Record<string, FixtureParam>;
|
|
29
|
+
/** The params of one call that works, as a case would write them. */
|
|
30
|
+
example?: Record<string, unknown>;
|
|
31
|
+
/** What its answer carries that a later step reads (`user_id`, `api_key`…). */
|
|
32
|
+
answers?: string[];
|
|
33
|
+
/** `false` for a command that only reads: safe to call while checking a server. */
|
|
34
|
+
changes?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The answer to `lynkeus.describe`. `commands` lists names, or descriptions, or both; a server from before
|
|
39
|
+
* descriptions answers names only, and that stays valid. `down` says the server runs but cannot serve.
|
|
40
|
+
*/
|
|
41
|
+
export type FixturesDescription = { protocol?: number; commands: (string | FixtureCommand)[]; down?: string };
|
package/src/index.ts
CHANGED
|
@@ -97,6 +97,11 @@ export type WaitForParams = {
|
|
|
97
97
|
/** Swipe the nearest scrolling container towards the target until it is in the window. */
|
|
98
98
|
scroll?: boolean;
|
|
99
99
|
timeoutMs?: number;
|
|
100
|
+
/**
|
|
101
|
+
* A trace mark (`trace().last`): a `route` the app reached after it counts as arrived, even if the app has
|
|
102
|
+
* already left it. A screen that closes itself (a success screen) can come and go while a step's frame settles.
|
|
103
|
+
*/
|
|
104
|
+
since?: number;
|
|
100
105
|
};
|
|
101
106
|
|
|
102
107
|
export type TraceEvent = { seq: number; t: number } & (
|
|
@@ -114,6 +119,9 @@ export type TraceEvent = { seq: number; t: number } & (
|
|
|
114
119
|
| { kind: 'crash'; message: string; stack?: string; route?: string }
|
|
115
120
|
);
|
|
116
121
|
|
|
122
|
+
/** One side of a request: its headers and body, sensitive values replaced by `…`, a long body cut. */
|
|
123
|
+
export type Exchange = { headers?: Record<string, string>; body?: string; truncated?: boolean };
|
|
124
|
+
|
|
117
125
|
export type RequestRecord = {
|
|
118
126
|
id: number;
|
|
119
127
|
method: string;
|
|
@@ -122,6 +130,9 @@ export type RequestRecord = {
|
|
|
122
130
|
startedAt: number;
|
|
123
131
|
ms?: number;
|
|
124
132
|
error?: string;
|
|
133
|
+
/** Only while a driver asked for bodies (`networkBodies`). */
|
|
134
|
+
request?: Exchange;
|
|
135
|
+
response?: Exchange;
|
|
125
136
|
};
|
|
126
137
|
|
|
127
138
|
/** Every method the core answers. Apps add their own through `qa.register`. */
|
|
@@ -151,7 +162,7 @@ export type CoreMethods = {
|
|
|
151
162
|
back: { params: undefined; result: { route?: string } };
|
|
152
163
|
waitFor: {
|
|
153
164
|
params: WaitForParams;
|
|
154
|
-
result: { route?: string; matched?: Target; waitedMs: number };
|
|
165
|
+
result: { route?: string; matched?: Target; waitedMs: number /** The route was reached after `since` and left again. */; passed?: boolean };
|
|
155
166
|
};
|
|
156
167
|
idle: {
|
|
157
168
|
/** `after`: a commit count from before the awaited change; quiet only counts once the app has committed past it. */
|
|
@@ -195,3 +206,4 @@ export type AuthEvent = { event: 'auth'; session: string; token?: string };
|
|
|
195
206
|
export type AgentEvent = HelloEvent | NavigationEvent;
|
|
196
207
|
|
|
197
208
|
export * from './run.js';
|
|
209
|
+
export * from './fixtures.js';
|
package/src/run.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RequestRecord } from './index.js';
|
|
1
2
|
/**
|
|
2
3
|
* What a run of cases leaves behind: a directory anything can read without
|
|
3
4
|
* knowing how the run was made.
|
|
@@ -67,12 +68,21 @@ export type RunStep = {
|
|
|
67
68
|
videoS?: number;
|
|
68
69
|
/** What the backend did for it, when the backend exports traces to the run. */
|
|
69
70
|
backend?: RunBackendSpan[];
|
|
71
|
+
/** The requests the app sent while it ran, with headers and bodies whose secrets are hidden. */
|
|
72
|
+
requests?: RequestRecord[];
|
|
73
|
+
/** What the app printed while it ran: its console, the errors it did not catch, its native log. */
|
|
74
|
+
logs?: RunLogLine[];
|
|
70
75
|
};
|
|
71
76
|
|
|
77
|
+
/** A printed line: `at` in ms since the epoch; `source` is `js`, `native` or `host`. */
|
|
78
|
+
export type RunLogLine = { at: number; level: 'debug' | 'info' | 'warn' | 'error'; source: string; text: string; stack?: string };
|
|
79
|
+
|
|
72
80
|
export type RunCase = {
|
|
73
81
|
id: string;
|
|
74
82
|
title?: string;
|
|
75
83
|
description?: string;
|
|
84
|
+
/** What the case says about itself: why it matters, what is true when it starts, its ticket and expected outcome. */
|
|
85
|
+
about?: { description?: string; why?: string; given?: string; ticket?: string; expected?: string };
|
|
76
86
|
/** The case file, relative to where the run was started. */
|
|
77
87
|
file: string;
|
|
78
88
|
/** 1 for the first try; a case that failed and ran again has a line for each. */
|
|
@@ -102,7 +112,21 @@ export type RunManifest = {
|
|
|
102
112
|
/** Whether the app ran on a device or simulator (true) or hosted without one. */
|
|
103
113
|
native?: boolean;
|
|
104
114
|
/** Where the run was made from, when it was a git checkout. */
|
|
105
|
-
|
|
115
|
+
/** `remote`: the repository's web address (no credentials); `changed`: files with changes no commit has (at most 20 of `changedCount`). */
|
|
116
|
+
/**
|
|
117
|
+
* `pushed`: what of it the remote has, as the clone knew when the run began (its remote-tracking refs, not a
|
|
118
|
+
* request): the branch, and the commit on any remote branch. A report links only what is there. A branch only this
|
|
119
|
+
* machine has is replaced by the remote branch that holds the commit, and `localBranch` keeps its name.
|
|
120
|
+
*/
|
|
121
|
+
git?: {
|
|
122
|
+
branch?: string;
|
|
123
|
+
localBranch?: string;
|
|
124
|
+
commit?: string;
|
|
125
|
+
remote?: string;
|
|
126
|
+
changed?: string[];
|
|
127
|
+
changedCount?: number;
|
|
128
|
+
pushed?: { branch: boolean; commit: boolean };
|
|
129
|
+
};
|
|
106
130
|
/** Cases by their last attempt. */
|
|
107
131
|
totals?: { cases: number; passed: number; failed: number; unsupported: number; retried: number };
|
|
108
132
|
};
|