c8y-nitro 0.10.3 → 0.11.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/README.md +2 -0
- package/dist/{apiClient-kxv5KHYJ.mjs → apiClient-GMQqcgQe.mjs} +2 -3
- package/dist/{autoBootstrap-DUjHuHe_.mjs → autoBootstrap-D4vEytWW.mjs} +6 -8
- package/dist/{bootstrap-DrMjty-k.mjs → bootstrap-DpYAhM7C.mjs} +6 -7
- package/dist/cli/index.mjs +6 -7
- package/dist/{config-BVQHqlgV.mjs → config-Dozrdw3A.mjs} +11 -8
- package/dist/{credentials-eKnJ7m9Y.d.mts → credentials-C_3m4LVX.d.mts} +0 -2
- package/dist/defaults-CrrCinRJ.mjs +20 -0
- package/dist/{c8y-api-DSs1xIIh.mjs → env-fUAhIWsI.mjs} +76 -3
- package/dist/{env-file-BrOTmVjA.mjs → env-file-DWbaFlIp.mjs} +1 -2
- package/dist/{index-BEFoDy-y.d.mts → index-CmIQfBpj.d.mts} +56 -22
- package/dist/index.d.mts +4 -6
- package/dist/index.mjs +20 -21
- package/dist/{logging-BUYT8Z2V.mjs → logging-B1PuWdiF.mjs} +1 -2
- package/dist/{manifest-DV3UW9Dl.mjs → manifest-BhrHDm8Y.mjs} +4 -6
- package/dist/{options-54uJmuUV.mjs → options-CgTptIpI.mjs} +5 -6
- package/dist/{package-Dqlz6AoZ.mjs → package-y3p_br3i.mjs} +2 -3
- package/dist/{roles-CNCObfa3.mjs → roles-DEIHe2Xt.mjs} +4 -5
- package/dist/runtime/handlers/invalidateTenantOptions.mjs +2 -408
- package/dist/runtime/handlers/liveness-readiness.mjs +1 -2
- package/dist/runtime/handlers/openapi.mjs +4 -5
- package/dist/runtime/handlers/rewriteRequestUrl.mjs +3 -4
- package/dist/runtime/middlewares/c8y-client.mjs +3 -4
- package/dist/runtime/middlewares/dev-user.dev.mjs +2 -3
- package/dist/runtime/plugins/c8y-variables.dev.mjs +2 -3
- package/dist/runtime/plugins/enrich-logs.mjs +2 -3
- package/dist/scope-CxEPZ74p.mjs +2763 -0
- package/dist/{client-BmSKIcuq.mjs → tenant-0MBgBY_o.mjs} +115 -139
- package/dist/testing/setup.d.mts +1 -0
- package/dist/testing/setup.mjs +62 -0
- package/dist/testing/vite.d.mts +26 -0
- package/dist/testing/vite.mjs +58 -0
- package/dist/testing-D5VjeD-F.mjs +14 -0
- package/dist/testing.d.mts +521 -0
- package/dist/testing.mjs +494 -0
- package/dist/{typegen-BO_AkyNc.mjs → typegen-Bw4VxFmA.mjs} +4 -5
- package/dist/types-D663gk80.d.mts +140 -0
- package/dist/types.d.mts +3 -3
- package/dist/utils.d.mts +48 -66
- package/dist/utils.mjs +16 -27
- package/package.json +36 -19
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { a as C8yTestRole, c as C8yTestUser, i as C8yTestOptions, l as C8yUnhandledRequest, n as C8yRequestContext, o as C8yTestState, r as C8yRequestHandler, s as C8yTestSubscription, t as C8yRequest, u as UnhandledRequestStrategy } from "./types-D663gk80.mjs";
|
|
2
|
+
import { serverFetch as serverFetch$1 } from "nitro";
|
|
3
|
+
import { C8YTenantOptionKey } from "c8y-nitro/types";
|
|
4
|
+
/**
|
|
5
|
+
* Enum values from the spec.
|
|
6
|
+
*/
|
|
7
|
+
declare const C8Y_ENUMS: {
|
|
8
|
+
readonly alarmSeverity: readonly ["CRITICAL", "MAJOR", "MINOR", "WARNING"];
|
|
9
|
+
readonly alarmStatus: readonly ["ACTIVE", "ACKNOWLEDGED", "CLEARED"];
|
|
10
|
+
readonly operationStatus: readonly ["SUCCESSFUL", "FAILED", "EXECUTING", "PENDING"];
|
|
11
|
+
readonly seriesAggregationType: readonly ["DAILY", "HOURLY", "MINUTELY"];
|
|
12
|
+
readonly seriesAggregationFunction: readonly ["min", "max", "avg", "sum", "count", "stdDevPop", "stdDevSamp"];
|
|
13
|
+
};
|
|
14
|
+
type C8yAlarmSeverity = typeof C8Y_ENUMS.alarmSeverity[number];
|
|
15
|
+
type C8yAlarmStatus = typeof C8Y_ENUMS.alarmStatus[number];
|
|
16
|
+
type C8yOperationStatus = typeof C8Y_ENUMS.operationStatus[number];
|
|
17
|
+
/**
|
|
18
|
+
* A managed object created by `c8y.device()` or `c8y.managedObject()`. Its
|
|
19
|
+
* `id` exists while a test runs (the object is rebuilt before every test).
|
|
20
|
+
*/
|
|
21
|
+
interface C8yRef {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A managed object id, a ref from `c8y.device()`, or `{ id }`.
|
|
26
|
+
*/
|
|
27
|
+
type C8yIdInput = string | C8yRef | {
|
|
28
|
+
id: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Input of `c8y.managedObject()` and `c8y.device()`.
|
|
32
|
+
*/
|
|
33
|
+
interface C8yManagedObjectInput {
|
|
34
|
+
name?: string;
|
|
35
|
+
type?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Defaults to the current user.
|
|
38
|
+
*/
|
|
39
|
+
owner?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Child devices (references in `childDevices`).
|
|
42
|
+
*/
|
|
43
|
+
children?: C8yRef[];
|
|
44
|
+
/**
|
|
45
|
+
* Child assets (references in `childAssets`).
|
|
46
|
+
*/
|
|
47
|
+
assets?: C8yRef[];
|
|
48
|
+
/**
|
|
49
|
+
* Child additions (references in `childAdditions`).
|
|
50
|
+
*/
|
|
51
|
+
additions?: C8yRef[];
|
|
52
|
+
/**
|
|
53
|
+
* External ids by type, e.g. `{ c8y_Serial: 'SN-1' }`.
|
|
54
|
+
*/
|
|
55
|
+
externalIds?: Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Tenant to create it in. Defaults to the deployed tenant.
|
|
58
|
+
*/
|
|
59
|
+
tenant?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Any fragments, e.g. `c8y_Hardware: { serialNumber: 'SN-1' }`.
|
|
62
|
+
*/
|
|
63
|
+
[fragment: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
interface SourcedInput {
|
|
66
|
+
source: C8yIdInput;
|
|
67
|
+
type: string;
|
|
68
|
+
/**
|
|
69
|
+
* Defaults to now.
|
|
70
|
+
*/
|
|
71
|
+
time?: string;
|
|
72
|
+
[fragment: string]: unknown;
|
|
73
|
+
}
|
|
74
|
+
interface C8yMeasurementInput extends SourcedInput {}
|
|
75
|
+
interface C8yEventInput extends SourcedInput {
|
|
76
|
+
/**
|
|
77
|
+
* Defaults to `type`.
|
|
78
|
+
*/
|
|
79
|
+
text?: string;
|
|
80
|
+
}
|
|
81
|
+
interface C8yAlarmInput extends SourcedInput {
|
|
82
|
+
/**
|
|
83
|
+
* Defaults to `type`.
|
|
84
|
+
*/
|
|
85
|
+
text?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Defaults to `MAJOR`.
|
|
88
|
+
*/
|
|
89
|
+
severity?: C8yAlarmSeverity;
|
|
90
|
+
/**
|
|
91
|
+
* Defaults to `ACTIVE`.
|
|
92
|
+
*/
|
|
93
|
+
status?: C8yAlarmStatus;
|
|
94
|
+
}
|
|
95
|
+
interface C8yOperationInput {
|
|
96
|
+
deviceId: C8yIdInput;
|
|
97
|
+
/**
|
|
98
|
+
* Defaults to `PENDING`.
|
|
99
|
+
*/
|
|
100
|
+
status?: C8yOperationStatus;
|
|
101
|
+
failureReason?: string;
|
|
102
|
+
[fragment: string]: unknown;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Input of `c8y.seed()`.
|
|
106
|
+
*/
|
|
107
|
+
interface C8ySeed {
|
|
108
|
+
measurements?: C8yMeasurementInput[];
|
|
109
|
+
events?: C8yEventInput[];
|
|
110
|
+
alarms?: C8yAlarmInput[];
|
|
111
|
+
operations?: C8yOperationInput[];
|
|
112
|
+
/**
|
|
113
|
+
* Tenant to seed. Defaults to the deployed tenant.
|
|
114
|
+
*/
|
|
115
|
+
tenant?: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Input of `c8y.binary()`.
|
|
119
|
+
*/
|
|
120
|
+
interface C8yBinaryInput {
|
|
121
|
+
/**
|
|
122
|
+
* File name.
|
|
123
|
+
*/
|
|
124
|
+
name: string;
|
|
125
|
+
/**
|
|
126
|
+
* File content.
|
|
127
|
+
*/
|
|
128
|
+
content: string | Uint8Array;
|
|
129
|
+
/**
|
|
130
|
+
* Content type. Defaults to `text/plain` for strings, `application/octet-stream` otherwise.
|
|
131
|
+
*/
|
|
132
|
+
contentType?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Tenant to create it in. Defaults to the deployed tenant.
|
|
135
|
+
*/
|
|
136
|
+
tenant?: string;
|
|
137
|
+
/**
|
|
138
|
+
* Any other managed object fragments.
|
|
139
|
+
*/
|
|
140
|
+
[fragment: string]: unknown;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Stored file content, as read by `c8y.db.binaries.content()`.
|
|
144
|
+
*/
|
|
145
|
+
interface C8yBinaryContent {
|
|
146
|
+
name: string;
|
|
147
|
+
contentType: string;
|
|
148
|
+
bytes: Uint8Array;
|
|
149
|
+
/**
|
|
150
|
+
* The content decoded as UTF-8.
|
|
151
|
+
*/
|
|
152
|
+
text: () => string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Filter for `c8y.db.*.find()`: partial match, or a predicate.
|
|
156
|
+
*/
|
|
157
|
+
type C8yDbFilter = Record<string, unknown> | ((document: Record<string, any>) => boolean);
|
|
158
|
+
/**
|
|
159
|
+
* Read access to one collection of the fake tenant.
|
|
160
|
+
*/
|
|
161
|
+
interface C8yDbCollection<T> {
|
|
162
|
+
/**
|
|
163
|
+
* Object by id (or ref).
|
|
164
|
+
*/
|
|
165
|
+
get: (id: C8yIdInput) => T | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Objects matching a partial object (refs and ids match `source`/`deviceId`) or a predicate, in creation order.
|
|
168
|
+
*/
|
|
169
|
+
find: (filter?: C8yDbFilter) => T[];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Read (and limited write) access to the fake tenant's data.
|
|
173
|
+
*/
|
|
174
|
+
interface C8yDb {
|
|
175
|
+
managedObjects: C8yDbCollection<Record<string, any>>;
|
|
176
|
+
measurements: C8yDbCollection<Record<string, any>>;
|
|
177
|
+
events: C8yDbCollection<Record<string, any>> & {
|
|
178
|
+
/**
|
|
179
|
+
* Attachment (binary) of an event.
|
|
180
|
+
*/
|
|
181
|
+
attachment: (id: C8yIdInput) => C8yBinaryContent | undefined;
|
|
182
|
+
};
|
|
183
|
+
binaries: C8yDbCollection<Record<string, any>> & {
|
|
184
|
+
/**
|
|
185
|
+
* Content of an inventory binary.
|
|
186
|
+
*/
|
|
187
|
+
content: (id: C8yIdInput) => C8yBinaryContent | undefined;
|
|
188
|
+
};
|
|
189
|
+
alarms: C8yDbCollection<Record<string, any>>;
|
|
190
|
+
operations: C8yDbCollection<Record<string, any>> & {
|
|
191
|
+
/**
|
|
192
|
+
* Updates an operation like a device agent would, e.g.
|
|
193
|
+
* `{ status: 'SUCCESSFUL' }` or `{ status: 'FAILED', failureReason }`.
|
|
194
|
+
*/
|
|
195
|
+
update: (id: C8yIdInput, update: {
|
|
196
|
+
status: C8yOperationStatus;
|
|
197
|
+
failureReason?: string;
|
|
198
|
+
[fragment: string]: unknown;
|
|
199
|
+
}) => void;
|
|
200
|
+
};
|
|
201
|
+
externalIds: {
|
|
202
|
+
/**
|
|
203
|
+
* External ids, optionally of one managed object.
|
|
204
|
+
*/
|
|
205
|
+
find: (managedObject?: C8yIdInput) => Array<{
|
|
206
|
+
type: string;
|
|
207
|
+
externalId: string;
|
|
208
|
+
managedObjectId: string;
|
|
209
|
+
}>;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* The same views for another tenant's data.
|
|
213
|
+
*/
|
|
214
|
+
tenant: (tenant: string) => Omit<C8yDb, 'tenant'>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Notification 2.0 subscription as stored by the fake.
|
|
218
|
+
*/
|
|
219
|
+
interface FakeSubscription {
|
|
220
|
+
id: string;
|
|
221
|
+
tenant: string;
|
|
222
|
+
context: 'mo' | 'tenant';
|
|
223
|
+
subscription: string;
|
|
224
|
+
source?: {
|
|
225
|
+
id: string;
|
|
226
|
+
};
|
|
227
|
+
subscriptionFilter?: {
|
|
228
|
+
apis?: string[];
|
|
229
|
+
typeFilter?: string;
|
|
230
|
+
};
|
|
231
|
+
fragmentsToCopy?: string[];
|
|
232
|
+
nonPersistent?: boolean;
|
|
233
|
+
}
|
|
234
|
+
type TenantOptionKeyInput = C8YTenantOptionKey | (string & {});
|
|
235
|
+
/**
|
|
236
|
+
* Where a tenant option lives. Defaults: own settings category, deployed tenant.
|
|
237
|
+
*/
|
|
238
|
+
export interface C8yTenantOptionScope {
|
|
239
|
+
category?: string;
|
|
240
|
+
tenant?: string;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Options of the `toHaveReceived()` matcher.
|
|
244
|
+
*/
|
|
245
|
+
export interface ToHaveReceivedOptions {
|
|
246
|
+
/**
|
|
247
|
+
* Exact number of matching requests. Default: at least one.
|
|
248
|
+
*/
|
|
249
|
+
times?: number;
|
|
250
|
+
}
|
|
251
|
+
declare module 'vitest' {
|
|
252
|
+
interface Matchers<R extends void | Promise<void> = void | Promise<void>, T = unknown> {
|
|
253
|
+
/**
|
|
254
|
+
* Asserts that the microservice sent a matching request to the fake
|
|
255
|
+
* Cumulocity platform in this test. Use it on `c8y`.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* expect(c8y).toHaveReceived('PUT /tenant/options/**')
|
|
260
|
+
* expect(c8y).toHaveReceived('GET /inventory/managedObjects/42', { times: 1 })
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
toHaveReceived: (pattern: string, options?: ToHaveReceivedOptions) => R;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The fake Cumulocity tenant your microservice talks to in tests. Requires the
|
|
268
|
+
* `c8yTest()` plugin from `c8y-nitro/testing/vite`.
|
|
269
|
+
*
|
|
270
|
+
* Arrange calls are **scope-aware**: at the top of a file they apply to every
|
|
271
|
+
* test in the file, inside `describe` to the tests of that `describe` (inner
|
|
272
|
+
* scopes override outer ones), and inside a test only to that test. Before
|
|
273
|
+
* every test the tenant is rebuilt from the plugin baseline, the call log is
|
|
274
|
+
* cleared, and c8y-nitro's caches are invalidated, so tests are independent.
|
|
275
|
+
*
|
|
276
|
+
* Arrange the platform as data: users, subscriptions, tenant options,
|
|
277
|
+
* managed objects (`device()`), and measurements, events, alarms, and
|
|
278
|
+
* operations (`seed()`). Your service reads and writes them through the real
|
|
279
|
+
* `@c8y/client`; assert on its responses and on `c8y.db`.
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* import { c8y, definePersona, serverFetch } from 'c8y-nitro/testing'
|
|
284
|
+
*
|
|
285
|
+
* const pump = c8y.device({ name: 'Pump', externalIds: { c8y_Serial: 'SN-1' } }) // seed the platform
|
|
286
|
+
* const visitor = definePersona({ userName: 'visitor', roles: [] })
|
|
287
|
+
*
|
|
288
|
+
* it('returns the pump', async () => {
|
|
289
|
+
* expect((await serverFetch('/pumps/SN-1')).status).toBe(200) // as the default user
|
|
290
|
+
* expect((await serverFetch('/pumps/SN-1', { as: visitor })).status).toBe(403) // as another user
|
|
291
|
+
* })
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export declare const c8y: {
|
|
295
|
+
/**
|
|
296
|
+
* Tenant the microservice is deployed in (the bootstrap tenant).
|
|
297
|
+
*/
|
|
298
|
+
readonly tenant: string;
|
|
299
|
+
/**
|
|
300
|
+
* Every request the microservice sent to the platform in this test, in order.
|
|
301
|
+
*/
|
|
302
|
+
readonly calls: readonly C8yRequest[];
|
|
303
|
+
/**
|
|
304
|
+
* Requests in this test the fake tenant could not answer (not emulated, and
|
|
305
|
+
* no `override()`). With the default `onUnhandledRequest: 'error'`, the test
|
|
306
|
+
* fails after it ran if this is not empty.
|
|
307
|
+
*/
|
|
308
|
+
readonly unhandled: readonly C8yUnhandledRequest[];
|
|
309
|
+
/**
|
|
310
|
+
* The fake tenant's data, to assert on what your service wrote (and to
|
|
311
|
+
* drive operation status like a device would).
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```ts
|
|
315
|
+
* expect(c8y.db.alarms.find({ source: pump, type: 'overdue' })).toMatchObject([{ severity: 'MAJOR' }])
|
|
316
|
+
* c8y.db.operations.update(operationId, { status: 'SUCCESSFUL' })
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
db: C8yDb;
|
|
320
|
+
/**
|
|
321
|
+
* Creates a managed object in the fake tenant (in the current scope).
|
|
322
|
+
* Returns a ref whose `id` is available while a test runs.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* const gateway = c8y.managedObject({ name: 'Gateway', type: 'c8y_Gateway', children: [c8y.device({ name: 'Pump' })] })
|
|
327
|
+
* ```
|
|
328
|
+
* @param input - Fragments, plus `children`/`assets`/`additions`, `externalIds`, and `tenant`
|
|
329
|
+
*/
|
|
330
|
+
managedObject(input?: C8yManagedObjectInput): C8yRef;
|
|
331
|
+
/**
|
|
332
|
+
* Creates a device (a managed object with `c8y_IsDevice`) in the fake tenant.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```ts
|
|
336
|
+
* const pump = c8y.device({ name: 'Pump', externalIds: { c8y_Serial: 'SN-1' } })
|
|
337
|
+
* it('…', async () => {
|
|
338
|
+
* await serverFetch(`/devices/${pump.id}`)
|
|
339
|
+
* })
|
|
340
|
+
* ```
|
|
341
|
+
* @param input - Fragments, plus `children`/`assets`/`additions`, `externalIds`, and `tenant`
|
|
342
|
+
*/
|
|
343
|
+
device(input?: C8yManagedObjectInput): C8yRef;
|
|
344
|
+
/**
|
|
345
|
+
* Creates an inventory binary (a file) in the fake tenant (in the current
|
|
346
|
+
* scope). Returns a ref whose `id` is available while a test runs.
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```ts
|
|
350
|
+
* const manual = c8y.binary({ name: 'manual.txt', content: 'Turn it off and on again.' })
|
|
351
|
+
* ```
|
|
352
|
+
* @param input - Name, content, optional content type, tenant, and fragments
|
|
353
|
+
*/
|
|
354
|
+
binary(input: C8yBinaryInput): C8yRef;
|
|
355
|
+
/**
|
|
356
|
+
* Seeds measurements, events, alarms, and operations (in the current scope).
|
|
357
|
+
* They are validated like API writes (required fields, enums, existing
|
|
358
|
+
* source), and alarms are deduplicated like on the platform.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* c8y.seed({
|
|
363
|
+
* measurements: [{ source: pump, type: 'c8y_Temperature', c8y_Temperature: { T: { value: 21.5, unit: 'C' } } }],
|
|
364
|
+
* alarms: [{ source: pump, type: 'c8y_Overheating', severity: 'CRITICAL' }],
|
|
365
|
+
* })
|
|
366
|
+
* ```
|
|
367
|
+
* @param seed - Data to seed
|
|
368
|
+
*/
|
|
369
|
+
seed(seed: C8ySeed): void;
|
|
370
|
+
/**
|
|
371
|
+
* Tenants subscribed to the microservice and their service users.
|
|
372
|
+
*/
|
|
373
|
+
subscriptions: {
|
|
374
|
+
/**
|
|
375
|
+
* Current subscriptions.
|
|
376
|
+
*/
|
|
377
|
+
list(): readonly C8yTestSubscription[];
|
|
378
|
+
/**
|
|
379
|
+
* Adds a subscription, or replaces the one of the same tenant.
|
|
380
|
+
* @param subscription - Tenant and service user credentials
|
|
381
|
+
*/
|
|
382
|
+
add(subscription: C8yTestSubscription): void;
|
|
383
|
+
/**
|
|
384
|
+
* Removes the subscription of a tenant.
|
|
385
|
+
* @param tenant - Tenant id
|
|
386
|
+
*/
|
|
387
|
+
remove(tenant: string): void;
|
|
388
|
+
/**
|
|
389
|
+
* Replaces all subscriptions.
|
|
390
|
+
* @param subscriptions - The new subscriptions
|
|
391
|
+
*/
|
|
392
|
+
set(subscriptions: C8yTestSubscription[]): void;
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Tenant options stored in the fake platform. These are platform values, not
|
|
396
|
+
* caches: a cached read keeps its value until it expires or is invalidated.
|
|
397
|
+
*/
|
|
398
|
+
tenantOptions: {
|
|
399
|
+
/**
|
|
400
|
+
* Sets an option value (merged with the outer scope's options).
|
|
401
|
+
* @param key - Option key
|
|
402
|
+
* @param value - Option value
|
|
403
|
+
* @param scope - Category and tenant, default own category in the deployed tenant
|
|
404
|
+
*/
|
|
405
|
+
set(key: TenantOptionKeyInput, value: string, scope?: C8yTenantOptionScope): void;
|
|
406
|
+
/**
|
|
407
|
+
* Deletes an option in this scope.
|
|
408
|
+
* @param key - Option key
|
|
409
|
+
* @param scope - Category and tenant
|
|
410
|
+
*/
|
|
411
|
+
delete(key: TenantOptionKeyInput, scope?: C8yTenantOptionScope): void;
|
|
412
|
+
/**
|
|
413
|
+
* Reads an option value from the platform.
|
|
414
|
+
* @param key - Option key
|
|
415
|
+
* @param scope - Category and tenant
|
|
416
|
+
*/
|
|
417
|
+
get(key: TenantOptionKeyInput, scope?: C8yTenantOptionScope): string | undefined;
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* Overrides the platform's answer for requests matching `pattern`. Use it
|
|
421
|
+
* for failures (errors, timeouts) and for APIs the fake tenant does not
|
|
422
|
+
* emulate; arrange normal data with `device()`/`seed()` instead, so tests do
|
|
423
|
+
* not depend on which endpoints your service calls. Overrides stack: inner
|
|
424
|
+
* scopes and newer overrides win over everything else.
|
|
425
|
+
*
|
|
426
|
+
* Patterns are `"[METHOD ]/path"` with `:param`, `*` (one segment), and `**`
|
|
427
|
+
* (rest of the path).
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* c8y.override('GET /inventory/**', () => Response.json({ message: 'Unavailable' }, { status: 503 }))
|
|
432
|
+
* c8y.override('GET /tenant/statistics/summary', () => ({ deviceCount: 3 }))
|
|
433
|
+
* ```
|
|
434
|
+
* @param pattern - Route pattern
|
|
435
|
+
* @param handler - Returns a `Response`, a JSON value (`200`), or nothing (`204`)
|
|
436
|
+
* @param options - Handler options
|
|
437
|
+
* @param options.once - Answer only the first matching request
|
|
438
|
+
*/
|
|
439
|
+
override(pattern: string, handler: C8yRequestHandler, options?: {
|
|
440
|
+
once?: boolean;
|
|
441
|
+
}): void;
|
|
442
|
+
/**
|
|
443
|
+
* Applies several arrange settings at once, in the current scope. Callers
|
|
444
|
+
* are not part of the state: use `serverFetch(path, { as })`.
|
|
445
|
+
* @param state - Partial tenant state
|
|
446
|
+
*/
|
|
447
|
+
apply(state: Partial<Omit<C8yTestState, "user">>): void;
|
|
448
|
+
/**
|
|
449
|
+
* Notification 2.0 (realtime) in the fake tenant. Writes from your service,
|
|
450
|
+
* `c8y.seed()`/`c8y.device()` inside a test, and `c8y.db.operations.update()`
|
|
451
|
+
* are published to the subscriptions your service created.
|
|
452
|
+
*/
|
|
453
|
+
notifications: {
|
|
454
|
+
/**
|
|
455
|
+
* Waits until every notification delivered to your service's realtime
|
|
456
|
+
* handlers has been processed (acknowledged), including notifications
|
|
457
|
+
* caused by the handlers' own writes.
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```ts
|
|
461
|
+
* c8y.seed({ measurements: [{ source: pump, type: 'c8y_Temperature', c8y_Temperature: { T: { value: 95, unit: 'C' } } }] })
|
|
462
|
+
* await c8y.notifications.settled()
|
|
463
|
+
* expect(c8y.db.alarms.find({ source: pump })).toHaveLength(1)
|
|
464
|
+
* ```
|
|
465
|
+
* @param options - Options
|
|
466
|
+
* @param options.timeout - Milliseconds to wait before failing (default 5000)
|
|
467
|
+
*/
|
|
468
|
+
settled(options?: {
|
|
469
|
+
timeout?: number;
|
|
470
|
+
}): Promise<void>;
|
|
471
|
+
/**
|
|
472
|
+
* Notification 2.0 subscriptions your service created (all tenants).
|
|
473
|
+
*/
|
|
474
|
+
subscriptions(): readonly FakeSubscription[];
|
|
475
|
+
};
|
|
476
|
+
/**
|
|
477
|
+
* Recorded requests matching a route pattern (same syntax as `override()`).
|
|
478
|
+
* @param pattern - Route pattern, e.g. `'GET /tenant/options/**'`
|
|
479
|
+
*/
|
|
480
|
+
callsTo(pattern: string): C8yRequest[];
|
|
481
|
+
};
|
|
482
|
+
/**
|
|
483
|
+
* Request options of `serverFetch()`: Nitro's options plus `as`.
|
|
484
|
+
*/
|
|
485
|
+
export type C8yServerFetchInit = NonNullable<Parameters<typeof serverFetch$1>[1]> & {
|
|
486
|
+
/**
|
|
487
|
+
* The user calling the route, e.g. a persona from `definePersona()` or an
|
|
488
|
+
* inline user. `null` is a caller without a valid login. Without `as`, the
|
|
489
|
+
* default `user` from the `c8yTest()` config calls.
|
|
490
|
+
*/
|
|
491
|
+
as?: C8yTestUser | null;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Types a user that calls your service in tests, so it can be defined once
|
|
495
|
+
* and reused (role names autocomplete). Pass it to `serverFetch(path, { as })`.
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```ts
|
|
499
|
+
* const operator = definePersona({ userName: 'operator', roles: ['ROLE_ALARM_ADMIN'] })
|
|
500
|
+
* const partner = definePersona({ userName: 'eve', roles: [], tenant: 't99999' })
|
|
501
|
+
* ```
|
|
502
|
+
* @param user - The user
|
|
503
|
+
*/
|
|
504
|
+
export declare function definePersona(user: C8yTestUser): C8yTestUser;
|
|
505
|
+
/**
|
|
506
|
+
* Calls a route of your service, like `serverFetch()` from `nitro`. With
|
|
507
|
+
* `as`, the request is sent as that user: the platform answers
|
|
508
|
+
* `GET /user/currentUser` with it during the request.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```ts
|
|
512
|
+
* await serverFetch('/pumps/SN-1') // default user
|
|
513
|
+
* await serverFetch('/pumps/SN-1/check', { method: 'POST', as: operator }) // a persona
|
|
514
|
+
* await serverFetch('/pumps/SN-1', { as: { userName: 'visitor', roles: [] } }) // inline
|
|
515
|
+
* await serverFetch('/user', { as: null }) // not logged in
|
|
516
|
+
* ```
|
|
517
|
+
* @param path - Route path, including the query
|
|
518
|
+
* @param init - Request options, plus `as`
|
|
519
|
+
*/
|
|
520
|
+
export declare function serverFetch(path: string, init?: C8yServerFetchInit): Promise<Response>;
|
|
521
|
+
export type { C8yAlarmInput, C8yAlarmSeverity, C8yAlarmStatus, C8yBinaryContent, C8yBinaryInput, C8yDb, C8yDbCollection, C8yDbFilter, C8yEventInput, C8yIdInput, C8yManagedObjectInput, C8yMeasurementInput, FakeSubscription as C8yNotificationSubscription, C8yOperationInput, C8yOperationStatus, C8yRef, C8yRequest, C8yRequestContext, C8yRequestHandler, C8ySeed, C8yTestOptions, C8yTestRole, C8yTestState, C8yTestSubscription, C8yTestUser, C8yUnhandledRequest, UnhandledRequestStrategy };
|