@elench/testkit 0.1.77 → 0.1.79
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 +24 -1
- package/lib/app/doctor.mjs +43 -0
- package/lib/cli/presentation/colors.mjs +21 -4
- package/lib/cli/presentation/discovery-reporter.mjs +33 -12
- package/lib/cli/presentation/run-reporter.mjs +90 -10
- package/lib/cli/presentation/run-reporter.test.mjs +3 -2
- package/lib/config-api/index.d.ts +189 -16
- package/lib/config-api/index.mjs +14 -170
- package/lib/config-api/index.test.mjs +282 -4
- package/lib/config-api/profiles.mjs +640 -0
- package/lib/runner/orchestrator.mjs +1 -0
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +6 -5
package/lib/config-api/index.mjs
CHANGED
|
@@ -3,21 +3,23 @@ import {
|
|
|
3
3
|
clearRuntimeContext,
|
|
4
4
|
getRepoConfig,
|
|
5
5
|
getRuntimeContext,
|
|
6
|
-
getRuntimeEnv,
|
|
7
6
|
registerRepoConfig,
|
|
8
7
|
registerRuntimeContext,
|
|
9
8
|
runtimeHttp,
|
|
10
9
|
runtimeJson,
|
|
11
10
|
} from "./runtime.mjs";
|
|
11
|
+
import {
|
|
12
|
+
customProfile,
|
|
13
|
+
localJsonProfile,
|
|
14
|
+
multiActorProfile,
|
|
15
|
+
rawProfile,
|
|
16
|
+
sessionProfile,
|
|
17
|
+
} from "./profiles.mjs";
|
|
12
18
|
|
|
13
19
|
export function defineConfig(config) {
|
|
14
20
|
return config || {};
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
export function defineHttpProfile(profile) {
|
|
18
|
-
return profile || {};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
23
|
export function defineFile(metadata) {
|
|
22
24
|
return metadata || {};
|
|
23
25
|
}
|
|
@@ -262,73 +264,13 @@ export const toolchain = {
|
|
|
262
264
|
node: nodeToolchain,
|
|
263
265
|
};
|
|
264
266
|
|
|
265
|
-
export
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
setup() {
|
|
273
|
-
return resolveClerkSession({
|
|
274
|
-
apiBase,
|
|
275
|
-
secretKey: envValue(secretKeyEnv),
|
|
276
|
-
needsAuth,
|
|
277
|
-
});
|
|
278
|
-
},
|
|
279
|
-
headers(setupData) {
|
|
280
|
-
return getClerkAuthHeaders(setupData, { apiBase });
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export function jsonSessionProfile(options = {}) {
|
|
287
|
-
const loginPath = options.loginPath || "/api/auth/login";
|
|
288
|
-
const cookieName = options.cookieName || "session";
|
|
289
|
-
const body =
|
|
290
|
-
typeof options.body === "function"
|
|
291
|
-
? options.body
|
|
292
|
-
: () => ({
|
|
293
|
-
username: envValue(options.usernameEnv || "TESTKIT_USERNAME"),
|
|
294
|
-
password: envValue(options.passwordEnv || "TESTKIT_PASSWORD"),
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
return defineHttpProfile({
|
|
298
|
-
auth: {
|
|
299
|
-
setup({ env }) {
|
|
300
|
-
const requestBody = body({ env });
|
|
301
|
-
const res = runtimeHttp.post(`${env.BASE}${loginPath}`, JSON.stringify(requestBody), {
|
|
302
|
-
headers: {
|
|
303
|
-
"Content-Type": "application/json",
|
|
304
|
-
...(env.routeParams || {}),
|
|
305
|
-
...(options.headers || {}),
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
if (res.status !== (options.successStatus || 200)) {
|
|
310
|
-
throw new Error(`Login failed (${res.status}): ${res.body}`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const cookie = res.cookies?.[cookieName]?.[0]?.value ?? null;
|
|
314
|
-
if (!cookie) {
|
|
315
|
-
throw new Error(`No ${cookieName} cookie returned from login`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return {
|
|
319
|
-
cookie,
|
|
320
|
-
body: safeJson(res),
|
|
321
|
-
};
|
|
322
|
-
},
|
|
323
|
-
headers(session) {
|
|
324
|
-
if (!session?.cookie) return {};
|
|
325
|
-
return {
|
|
326
|
-
Cookie: `${cookieName}=${session.cookie}`,
|
|
327
|
-
};
|
|
328
|
-
},
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
}
|
|
267
|
+
export const profiles = {
|
|
268
|
+
custom: customProfile,
|
|
269
|
+
localJson: localJsonProfile,
|
|
270
|
+
multiActor: multiActorProfile,
|
|
271
|
+
raw: rawProfile,
|
|
272
|
+
session: sessionProfile,
|
|
273
|
+
};
|
|
332
274
|
|
|
333
275
|
export {
|
|
334
276
|
clearRepoConfig,
|
|
@@ -430,101 +372,3 @@ function compiledEntryFromSource(entry, outDir) {
|
|
|
430
372
|
const relative = compiled.startsWith("src/") ? compiled.slice(4) : compiled;
|
|
431
373
|
return `${outDir}/${relative}`.replace(/\/+/g, "/");
|
|
432
374
|
}
|
|
433
|
-
|
|
434
|
-
function envValue(name) {
|
|
435
|
-
const env = getRuntimeEnv();
|
|
436
|
-
const value = env?.rawEnv?.[name] || env?.[name];
|
|
437
|
-
if (!value) {
|
|
438
|
-
throw new Error(`Missing required env var "${name}" for testkit config`);
|
|
439
|
-
}
|
|
440
|
-
return value;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function safeJson(response) {
|
|
444
|
-
try {
|
|
445
|
-
return runtimeJson(response);
|
|
446
|
-
} catch {
|
|
447
|
-
return null;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function resolveClerkSession({ apiBase, secretKey, needsAuth }) {
|
|
452
|
-
if (!needsAuth) {
|
|
453
|
-
return { jwt: null };
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const headers = { Authorization: `Bearer ${secretKey}` };
|
|
457
|
-
const usersRes = runtimeHttp.get(`${apiBase}/users?limit=1&order_by=-created_at`, {
|
|
458
|
-
headers,
|
|
459
|
-
});
|
|
460
|
-
if (usersRes.status !== 200) {
|
|
461
|
-
throw new Error(`Clerk list users failed (${usersRes.status}): ${usersRes.body}`);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const users = runtimeJson(usersRes);
|
|
465
|
-
if (!users.length) {
|
|
466
|
-
throw new Error("No Clerk users found for testkit Clerk auth profile");
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const userId = users[0].id;
|
|
470
|
-
const sessionsRes = runtimeHttp.get(
|
|
471
|
-
`${apiBase}/sessions?user_id=${userId}&status=active&limit=1`,
|
|
472
|
-
{ headers }
|
|
473
|
-
);
|
|
474
|
-
if (sessionsRes.status !== 200) {
|
|
475
|
-
throw new Error(`Clerk list sessions failed (${sessionsRes.status}): ${sessionsRes.body}`);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const sessions = runtimeJson(sessionsRes);
|
|
479
|
-
if (!sessions?.length) {
|
|
480
|
-
throw new Error("No active Clerk session found for testkit Clerk auth profile");
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
const sessionId = sessions[0].id;
|
|
484
|
-
const tokenRes = runtimeHttp.post(`${apiBase}/sessions/${sessionId}/tokens`, null, {
|
|
485
|
-
headers: {
|
|
486
|
-
...headers,
|
|
487
|
-
"Content-Type": "application/json",
|
|
488
|
-
},
|
|
489
|
-
});
|
|
490
|
-
if (tokenRes.status !== 200) {
|
|
491
|
-
throw new Error(`Clerk create token failed (${tokenRes.status}): ${tokenRes.body}`);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
return {
|
|
495
|
-
jwt: runtimeJson(tokenRes).jwt,
|
|
496
|
-
sessionId,
|
|
497
|
-
secretKey,
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
function getClerkAuthHeaders(setupData, { apiBase }) {
|
|
502
|
-
if (!setupData?.jwt) return {};
|
|
503
|
-
|
|
504
|
-
if (!setupData.sessionId || !setupData.secretKey) {
|
|
505
|
-
return {
|
|
506
|
-
Authorization: `Bearer ${setupData.jwt}`,
|
|
507
|
-
"Content-Type": "application/json",
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
const tokenRes = runtimeHttp.post(`${apiBase}/sessions/${setupData.sessionId}/tokens`, null, {
|
|
512
|
-
headers: {
|
|
513
|
-
Authorization: `Bearer ${setupData.secretKey}`,
|
|
514
|
-
"Content-Type": "application/json",
|
|
515
|
-
},
|
|
516
|
-
});
|
|
517
|
-
if (tokenRes.status !== 200) {
|
|
518
|
-
return {
|
|
519
|
-
Authorization: `Bearer ${setupData.jwt}`,
|
|
520
|
-
"Content-Type": "application/json",
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const nextJwt = runtimeJson(tokenRes).jwt;
|
|
525
|
-
setupData.jwt = nextJwt;
|
|
526
|
-
return {
|
|
527
|
-
Authorization: `Bearer ${nextJwt}`,
|
|
528
|
-
"Content-Type": "application/json",
|
|
529
|
-
};
|
|
530
|
-
}
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
database,
|
|
5
5
|
defineConfig,
|
|
6
6
|
defineFile,
|
|
7
|
-
|
|
7
|
+
profiles,
|
|
8
8
|
toolchain,
|
|
9
9
|
} from "./index.mjs";
|
|
10
|
+
import { clearRuntimeContext, registerRuntimeContext } from "./runtime.mjs";
|
|
10
11
|
|
|
11
12
|
describe("config api", () => {
|
|
12
13
|
it("defines repo config plainly", () => {
|
|
@@ -15,9 +16,286 @@ describe("config api", () => {
|
|
|
15
16
|
});
|
|
16
17
|
});
|
|
17
18
|
|
|
18
|
-
it("
|
|
19
|
-
const profile =
|
|
20
|
-
|
|
19
|
+
it("builds raw HTTP profiles with deterministic forwarded headers", () => {
|
|
20
|
+
const profile = profiles.raw({
|
|
21
|
+
headers: {
|
|
22
|
+
contentTypeJson: true,
|
|
23
|
+
forwardedFor: "deterministic",
|
|
24
|
+
values: { "X-Testkit-Mode": "raw" },
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const headers = profile.headers?.(null, { env: { BASE: "http://api.test" } });
|
|
29
|
+
const rawHeaders = profile.rawHeaders?.(null, { env: { BASE: "http://api.test" } });
|
|
30
|
+
|
|
31
|
+
expect(headers).toMatchObject({
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
"X-Testkit-Mode": "raw",
|
|
34
|
+
});
|
|
35
|
+
expect(headers["X-Forwarded-For"]).toMatch(/^10\.\d+\.\d+\.\d+$/);
|
|
36
|
+
expect(rawHeaders).toEqual(headers);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("builds session profiles that perform bootstrap/login and derive auth/session headers", () => {
|
|
40
|
+
const requests = [];
|
|
41
|
+
registerRuntimeContext({
|
|
42
|
+
env: {
|
|
43
|
+
BASE: "http://api.test",
|
|
44
|
+
routeParams: { "x-route": "route-a" },
|
|
45
|
+
},
|
|
46
|
+
http: {
|
|
47
|
+
post(url, body, params) {
|
|
48
|
+
requests.push({ url, body, params });
|
|
49
|
+
if (url.endsWith("/signup")) {
|
|
50
|
+
return {
|
|
51
|
+
status: 201,
|
|
52
|
+
body: JSON.stringify({ data: { organizations: [{ id: "org-signup" }] } }),
|
|
53
|
+
headers: {
|
|
54
|
+
"set-cookie": ["fixture_session=signup-token; Path=/", "fixture_refresh=signup-refresh; Path=/"],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
status: 200,
|
|
60
|
+
body: JSON.stringify({ data: { organizations: [{ id: "org-123" }] } }),
|
|
61
|
+
headers: {
|
|
62
|
+
"set-cookie": ["fixture_session=jwt-123; Path=/", "fixture_refresh=refresh-123; Path=/"],
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const profile = profiles.session({
|
|
70
|
+
actor: {
|
|
71
|
+
bootstrap: {
|
|
72
|
+
path: "/signup",
|
|
73
|
+
expect: [201, 409],
|
|
74
|
+
body: ({ actor }) => ({ email: `${actor}@example.com` }),
|
|
75
|
+
},
|
|
76
|
+
login: {
|
|
77
|
+
path: "/login",
|
|
78
|
+
expect: 200,
|
|
79
|
+
body: ({ actor }) => ({ email: `${actor}@example.com` }),
|
|
80
|
+
},
|
|
81
|
+
session: {
|
|
82
|
+
cookies: {
|
|
83
|
+
jwt: "fixture_session",
|
|
84
|
+
refreshToken: "fixture_refresh",
|
|
85
|
+
},
|
|
86
|
+
fields: {
|
|
87
|
+
organizationId: "data.organizations[0].id",
|
|
88
|
+
},
|
|
89
|
+
auth: {
|
|
90
|
+
source: { key: "jwt" },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
headers: {
|
|
95
|
+
contentTypeJson: true,
|
|
96
|
+
forwardedFor: "deterministic",
|
|
97
|
+
fromSession: [{ header: "X-Organization-Id", field: "organizationId" }],
|
|
98
|
+
values: ({ actor }) => ({ "X-Testkit-Actor": actor || "primary" }),
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const session = profile.auth.setup({
|
|
103
|
+
env: { BASE: "http://api.test", routeParams: { "x-route": "route-a" } },
|
|
104
|
+
});
|
|
105
|
+
const authHeaders = profile.auth.headers(session, { env: { BASE: "http://api.test" } });
|
|
106
|
+
const requestHeaders = profile.headers(session, { env: { BASE: "http://api.test" } });
|
|
107
|
+
|
|
108
|
+
expect(requests).toHaveLength(2);
|
|
109
|
+
expect(requests[0].params.headers["x-route"]).toBe("route-a");
|
|
110
|
+
expect(session).toEqual({
|
|
111
|
+
jwt: "jwt-123",
|
|
112
|
+
refreshToken: "refresh-123",
|
|
113
|
+
organizationId: "org-123",
|
|
114
|
+
});
|
|
115
|
+
expect(authHeaders).toEqual({
|
|
116
|
+
Authorization: "Bearer jwt-123",
|
|
117
|
+
});
|
|
118
|
+
expect(requestHeaders).toMatchObject({
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"X-Organization-Id": "org-123",
|
|
121
|
+
"X-Testkit-Actor": "primary",
|
|
122
|
+
});
|
|
123
|
+
expect(requestHeaders["X-Forwarded-For"]).toMatch(/^10\.\d+\.\d+\.\d+$/);
|
|
124
|
+
clearRuntimeContext();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("builds local-json profile presets that derive session, multi-actor, and raw variants", () => {
|
|
128
|
+
const requests = [];
|
|
129
|
+
registerRuntimeContext({
|
|
130
|
+
env: {
|
|
131
|
+
BASE: "http://api.test",
|
|
132
|
+
},
|
|
133
|
+
http: {
|
|
134
|
+
post(url, body) {
|
|
135
|
+
const payload = JSON.parse(body);
|
|
136
|
+
requests.push({ url, payload });
|
|
137
|
+
const actor = payload.email.startsWith("primary")
|
|
138
|
+
? "primary"
|
|
139
|
+
: payload.email.startsWith("user-a")
|
|
140
|
+
? "userA"
|
|
141
|
+
: "userB";
|
|
142
|
+
return {
|
|
143
|
+
status: url.endsWith("/signup") ? 201 : 200,
|
|
144
|
+
body: JSON.stringify({
|
|
145
|
+
data: {
|
|
146
|
+
organizations: [{ id: `org-${actor}` }],
|
|
147
|
+
},
|
|
148
|
+
}),
|
|
149
|
+
headers: {
|
|
150
|
+
"set-cookie": [
|
|
151
|
+
`fixture_session=jwt-${actor}; Path=/`,
|
|
152
|
+
`fixture_refresh=refresh-${actor}; Path=/`,
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const auth = profiles.localJson({
|
|
161
|
+
password: "TestkitPass2026",
|
|
162
|
+
identities: {
|
|
163
|
+
primary: {
|
|
164
|
+
email: "primary@example.com",
|
|
165
|
+
name: "Primary User",
|
|
166
|
+
organizationName: "Primary Org",
|
|
167
|
+
},
|
|
168
|
+
userA: {
|
|
169
|
+
email: "user-a@example.com",
|
|
170
|
+
name: "User A",
|
|
171
|
+
organizationName: "Org A",
|
|
172
|
+
},
|
|
173
|
+
userB: {
|
|
174
|
+
email: "user-b@example.com",
|
|
175
|
+
name: "User B",
|
|
176
|
+
organizationName: "Org B",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
session: {
|
|
180
|
+
authCookie: "fixture_session",
|
|
181
|
+
refreshCookie: "fixture_refresh",
|
|
182
|
+
organizationIdPath: "data.organizations[0].id",
|
|
183
|
+
},
|
|
184
|
+
headers: {
|
|
185
|
+
contentTypeJson: true,
|
|
186
|
+
forwardedFor: "deterministic",
|
|
187
|
+
organization: "X-Organization-Id",
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const defaultProfile = auth.session();
|
|
192
|
+
const defaultSetup = defaultProfile.auth.setup({ env: { BASE: "http://api.test" } });
|
|
193
|
+
expect(defaultSetup).toEqual({
|
|
194
|
+
jwt: "jwt-primary",
|
|
195
|
+
refreshToken: "refresh-primary",
|
|
196
|
+
organizationId: "org-primary",
|
|
197
|
+
});
|
|
198
|
+
expect(defaultProfile.auth.headers(defaultSetup)).toEqual({
|
|
199
|
+
Authorization: "Bearer jwt-primary",
|
|
200
|
+
});
|
|
201
|
+
expect(defaultProfile.headers(defaultSetup, { env: { BASE: "http://api.test" } })).toMatchObject({
|
|
202
|
+
"Content-Type": "application/json",
|
|
203
|
+
"X-Organization-Id": "org-primary",
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const dualProfile = auth.multiActor({
|
|
207
|
+
primaryActor: "userA",
|
|
208
|
+
actors: ["userA", "userB"],
|
|
209
|
+
});
|
|
210
|
+
const dualSetup = dualProfile.auth.setup({ env: { BASE: "http://api.test" } });
|
|
211
|
+
expect(dualSetup.userA.organizationId).toBe("org-userA");
|
|
212
|
+
expect(dualSetup.userB.organizationId).toBe("org-userB");
|
|
213
|
+
expect(dualProfile.auth.headers(dualSetup)).toEqual({
|
|
214
|
+
Authorization: "Bearer jwt-userA",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const rawProfile = auth.raw();
|
|
218
|
+
expect(rawProfile.rawHeaders(null, { env: { BASE: "http://api.test" } })).toMatchObject({
|
|
219
|
+
"Content-Type": "application/json",
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(requests.map((entry) => entry.url)).toEqual([
|
|
223
|
+
"http://api.test/api/v1/auth/signup",
|
|
224
|
+
"http://api.test/api/v1/auth/login",
|
|
225
|
+
"http://api.test/api/v1/auth/signup",
|
|
226
|
+
"http://api.test/api/v1/auth/login",
|
|
227
|
+
"http://api.test/api/v1/auth/signup",
|
|
228
|
+
"http://api.test/api/v1/auth/login",
|
|
229
|
+
]);
|
|
230
|
+
clearRuntimeContext();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("builds multi-actor profiles and derives headers from the primary actor by default", () => {
|
|
234
|
+
const responses = {
|
|
235
|
+
alpha: {
|
|
236
|
+
status: 200,
|
|
237
|
+
body: JSON.stringify({ data: { organizations: [{ id: "org-alpha" }] } }),
|
|
238
|
+
headers: { "set-cookie": "fixture_session=token-alpha; Path=/" },
|
|
239
|
+
},
|
|
240
|
+
beta: {
|
|
241
|
+
status: 200,
|
|
242
|
+
body: JSON.stringify({ data: { organizations: [{ id: "org-beta" }] } }),
|
|
243
|
+
headers: { "set-cookie": "fixture_session=token-beta; Path=/" },
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
registerRuntimeContext({
|
|
247
|
+
env: {
|
|
248
|
+
BASE: "http://api.test",
|
|
249
|
+
},
|
|
250
|
+
http: {
|
|
251
|
+
post(_url, body) {
|
|
252
|
+
const payload = JSON.parse(body);
|
|
253
|
+
return payload.email.startsWith("alpha") ? responses.alpha : responses.beta;
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const profile = profiles.multiActor({
|
|
259
|
+
primaryActor: "userA",
|
|
260
|
+
actors: {
|
|
261
|
+
userA: {
|
|
262
|
+
login: {
|
|
263
|
+
path: "/login",
|
|
264
|
+
body: () => ({ email: "alpha@example.com" }),
|
|
265
|
+
},
|
|
266
|
+
session: {
|
|
267
|
+
cookies: { jwt: "fixture_session" },
|
|
268
|
+
fields: { organizationId: "data.organizations[0].id" },
|
|
269
|
+
auth: { source: { key: "jwt" } },
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
userB: {
|
|
273
|
+
login: {
|
|
274
|
+
path: "/login",
|
|
275
|
+
body: () => ({ email: "beta@example.com" }),
|
|
276
|
+
},
|
|
277
|
+
session: {
|
|
278
|
+
cookies: { jwt: "fixture_session" },
|
|
279
|
+
fields: { organizationId: "data.organizations[0].id" },
|
|
280
|
+
auth: { source: { key: "jwt" } },
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
headers: {
|
|
285
|
+
fromSession: [{ header: "X-Organization-Id", field: "organizationId" }],
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const setupData = profile.auth.setup({ env: { BASE: "http://api.test" } });
|
|
290
|
+
expect(setupData.userA.organizationId).toBe("org-alpha");
|
|
291
|
+
expect(setupData.userB.organizationId).toBe("org-beta");
|
|
292
|
+
expect(profile.auth.headers(setupData)).toEqual({
|
|
293
|
+
Authorization: "Bearer token-alpha",
|
|
294
|
+
});
|
|
295
|
+
expect(profile.headers(setupData, { env: { BASE: "http://api.test" } })).toMatchObject({
|
|
296
|
+
"X-Organization-Id": "org-alpha",
|
|
297
|
+
});
|
|
298
|
+
clearRuntimeContext();
|
|
21
299
|
});
|
|
22
300
|
|
|
23
301
|
it("defines file-local metadata plainly", () => {
|