svelte-ag 1.0.58 → 1.0.59
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/query/query.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAGnH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"query.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/query/query.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAGnH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AA2BnE,qBAAa,KAAK,CAChB,GAAG,SAAS,YAAY,EACxB,IAAI,SAAS,GAAG,CAAC,MAAM,CAAC,EACxB,MAAM,SAAS,OAAO,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,QAAQ,CAAC;;gBAyBzC,EACV,IAAI,EACJ,MAAM,EACN,KAAK,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACL,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACnC,SAAS,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,CAAC,EAAE;YACL,KAAK,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC1C,CAAC;KACH;IAgBK,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAyCxD,IAAI,QAAQ,WAEX;IACD,IAAI,QAAQ,YAEX;IACD,UAAU;IAMV,IAAI,MAAM,gBAET;IACD,IAAI,IAAI,IAAI,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAEnD;IACD,IAAI,SAAS,IAAI,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAEtD;CACF;AAED,qBAAa,SAAS,CACpB,GAAG,SAAS,YAAY,EACxB,IAAI,SAAS,GAAG,CAAC,MAAM,CAAC,EACxB,MAAM,SAAS,OAAO,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,QAAQ,CAAC;;gBA6BnD,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAChC,MAAM,EAAE,KAAK,EACb,YAAY,CAAC,EAAE,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC;YAelC,KAAK;IAOnB;;;OAGG;YACW,eAAe;IA2BvB,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;CAmB3F"}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { stringify } from 'devalue';
|
|
2
2
|
import { cacheKey } from './utils.svelte.js';
|
|
3
3
|
import { RateLimiter } from './rate.svelte';
|
|
4
|
+
function copyOwnOverrides(source, target) {
|
|
5
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
6
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
7
|
+
if (!descriptor)
|
|
8
|
+
continue;
|
|
9
|
+
Object.defineProperty(target, key, descriptor);
|
|
10
|
+
}
|
|
11
|
+
return target;
|
|
12
|
+
}
|
|
4
13
|
function cloneResponse(response) {
|
|
5
14
|
if (response !== null &&
|
|
6
15
|
typeof response === 'object' &&
|
|
7
16
|
'clone' in response &&
|
|
8
17
|
typeof response.clone === 'function') {
|
|
9
|
-
|
|
18
|
+
const source = response;
|
|
19
|
+
return copyOwnOverrides(source, response.clone());
|
|
10
20
|
}
|
|
11
21
|
return response;
|
|
12
22
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createApiRequest } from 'ts-ag';
|
|
2
3
|
import { Cache } from './cache.svelte.js';
|
|
3
4
|
import { Query, Requestor } from './query.svelte.js';
|
|
5
|
+
import { stringify } from 'devalue';
|
|
6
|
+
import * as v from 'valibot';
|
|
4
7
|
function getSingleId(input) {
|
|
5
8
|
return 'id' in input ? input.id : input.ids[0];
|
|
6
9
|
}
|
|
@@ -10,6 +13,23 @@ function jsonResponse(body, status = 200) {
|
|
|
10
13
|
headers: { 'content-type': 'application/json' }
|
|
11
14
|
});
|
|
12
15
|
}
|
|
16
|
+
function devalueFetchResponse(body, status = 200) {
|
|
17
|
+
return new Response(stringify(body), {
|
|
18
|
+
status,
|
|
19
|
+
headers: { 'content-type': 'application/devalue' }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function withResponseOverrides(response) {
|
|
23
|
+
Object.defineProperty(response, 'extra', {
|
|
24
|
+
configurable: true,
|
|
25
|
+
value: () => 'copied'
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(response, 'meta', {
|
|
28
|
+
configurable: true,
|
|
29
|
+
value: { source: 'custom' }
|
|
30
|
+
});
|
|
31
|
+
return response;
|
|
32
|
+
}
|
|
13
33
|
function deferred() {
|
|
14
34
|
let resolve;
|
|
15
35
|
let reject;
|
|
@@ -27,6 +47,7 @@ describe('Requestor', () => {
|
|
|
27
47
|
afterEach(() => {
|
|
28
48
|
vi.useRealTimers();
|
|
29
49
|
vi.restoreAllMocks();
|
|
50
|
+
vi.unstubAllGlobals();
|
|
30
51
|
});
|
|
31
52
|
it('passes through non-batched requests', async () => {
|
|
32
53
|
const requestMock = vi.fn(async () => jsonResponse({ id: 1 }));
|
|
@@ -37,6 +58,23 @@ describe('Requestor', () => {
|
|
|
37
58
|
expect(requestMock).toHaveBeenCalledWith('/users', 'GET', { id: 1 });
|
|
38
59
|
await expect(response.json()).resolves.toEqual({ id: 1 });
|
|
39
60
|
});
|
|
61
|
+
it('devalue response', async () => {
|
|
62
|
+
const fetchMock = vi.fn(async () => devalueFetchResponse({ id: 1 }));
|
|
63
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
64
|
+
const request = createApiRequest({
|
|
65
|
+
'/users': {
|
|
66
|
+
GET: v.object({ id: v.number() })
|
|
67
|
+
}
|
|
68
|
+
}, 'https://api.example.test', 'test');
|
|
69
|
+
const requestor = new Requestor('/users', 'GET', request, new Cache());
|
|
70
|
+
const response = await requestor.request({ id: 1 });
|
|
71
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(fetchMock).toHaveBeenCalledWith('https://api.example.test//users?id=1', expect.objectContaining({
|
|
73
|
+
method: 'GET',
|
|
74
|
+
credentials: 'include'
|
|
75
|
+
}));
|
|
76
|
+
await expect(response.json()).resolves.toEqual({ id: 1 });
|
|
77
|
+
});
|
|
40
78
|
it('batches requests with the same batch id and preserves response order', async () => {
|
|
41
79
|
const requestMock = vi.fn(async () => jsonResponse({ ok: true }));
|
|
42
80
|
const request = requestMock;
|
|
@@ -164,6 +202,58 @@ describe('Query', () => {
|
|
|
164
202
|
await expect(first.json()).resolves.toEqual({ id: 1, name: 'Ada' });
|
|
165
203
|
await expect(second.json()).resolves.toEqual({ id: 1, name: 'Ada' });
|
|
166
204
|
});
|
|
205
|
+
it('preserves devalue parsing for query state, returned responses, and cache hits', async () => {
|
|
206
|
+
const fetchMock = vi.fn(async () => devalueFetchResponse({ id: 1, createdAt: new Date('2024-01-01T00:00:00.000Z') }));
|
|
207
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
208
|
+
const request = createApiRequest({
|
|
209
|
+
'/users': {
|
|
210
|
+
GET: v.object({ id: v.number() })
|
|
211
|
+
}
|
|
212
|
+
}, 'https://api.example.test', 'test');
|
|
213
|
+
const requestor = new Requestor('/users', 'GET', request, new Cache());
|
|
214
|
+
const query = new Query({
|
|
215
|
+
path: '/users',
|
|
216
|
+
method: 'GET',
|
|
217
|
+
input: { id: 1 },
|
|
218
|
+
requestor,
|
|
219
|
+
cache: new Cache()
|
|
220
|
+
});
|
|
221
|
+
const firstResponse = await query.request();
|
|
222
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
223
|
+
expect(query.status).toBe('success');
|
|
224
|
+
expect(query.data).toEqual({ id: 1, createdAt: new Date('2024-01-01T00:00:00.000Z') });
|
|
225
|
+
await expect(firstResponse.json()).resolves.toEqual({
|
|
226
|
+
id: 1,
|
|
227
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
228
|
+
});
|
|
229
|
+
const cachedResponse = await query.request();
|
|
230
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
231
|
+
await expect(cachedResponse.json()).resolves.toEqual({
|
|
232
|
+
id: 1,
|
|
233
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
it('preserves arbitrary response overrides across query clones and cache hits', async () => {
|
|
237
|
+
const customResponse = withResponseOverrides(jsonResponse({ id: 1 }));
|
|
238
|
+
const requestMock = vi.fn().mockResolvedValue(customResponse);
|
|
239
|
+
const requestor = {
|
|
240
|
+
request: requestMock
|
|
241
|
+
};
|
|
242
|
+
const query = new Query({
|
|
243
|
+
path: '/users',
|
|
244
|
+
method: 'GET',
|
|
245
|
+
input: { id: 1 },
|
|
246
|
+
requestor,
|
|
247
|
+
cache: new Cache()
|
|
248
|
+
});
|
|
249
|
+
const first = (await query.request());
|
|
250
|
+
const second = (await query.request());
|
|
251
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
252
|
+
expect(first.extra()).toBe('copied');
|
|
253
|
+
expect(first.meta).toEqual({ source: 'custom' });
|
|
254
|
+
expect(second.extra()).toBe('copied');
|
|
255
|
+
expect(second.meta).toEqual({ source: 'custom' });
|
|
256
|
+
});
|
|
167
257
|
it('updates success state from successful responses', async () => {
|
|
168
258
|
const requestMock = vi.fn().mockResolvedValue(jsonResponse({ id: 1, active: true }));
|
|
169
259
|
const requestor = {
|
package/package.json
CHANGED
|
@@ -9,6 +9,17 @@ import { RateLimiter } from './rate.svelte';
|
|
|
9
9
|
|
|
10
10
|
export type QueryStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
11
11
|
|
|
12
|
+
function copyOwnOverrides<T extends object>(source: T, target: T): T {
|
|
13
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
14
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
15
|
+
if (!descriptor) continue;
|
|
16
|
+
|
|
17
|
+
Object.defineProperty(target, key, descriptor);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return target;
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
function cloneResponse<T>(response: T): T {
|
|
13
24
|
if (
|
|
14
25
|
response !== null &&
|
|
@@ -16,7 +27,8 @@ function cloneResponse<T>(response: T): T {
|
|
|
16
27
|
'clone' in response &&
|
|
17
28
|
typeof response.clone === 'function'
|
|
18
29
|
) {
|
|
19
|
-
|
|
30
|
+
const source = response as T & object;
|
|
31
|
+
return copyOwnOverrides(source, response.clone() as T & object) as T;
|
|
20
32
|
}
|
|
21
33
|
|
|
22
34
|
return response;
|
|
@@ -240,8 +252,8 @@ export class Requestor<
|
|
|
240
252
|
if (batchId !== false) {
|
|
241
253
|
return new Promise((resolve, reject) => {
|
|
242
254
|
if (!this.#batchQueue[batchId]) this.#batchQueue[batchId] = [];
|
|
243
|
-
|
|
244
255
|
this.#batchQueue[batchId].push({ input, resolve, reject });
|
|
256
|
+
|
|
245
257
|
if (!this.#batchTimers[batchId]) {
|
|
246
258
|
this.#batchTimers[batchId] = setTimeout(() => {
|
|
247
259
|
void this.flushBatchQueue(batchId).finally(() => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import type
|
|
2
|
+
import { createApiRequest, type ApiEndpoints, type ApiRequestFunction } from 'ts-ag';
|
|
3
3
|
import { Cache } from './cache.svelte.js';
|
|
4
4
|
import { Query, Requestor } from './query.svelte.js';
|
|
5
|
+
import { stringify } from 'devalue';
|
|
6
|
+
import * as v from 'valibot';
|
|
5
7
|
|
|
6
8
|
type PlainUserInput = { id: number };
|
|
7
9
|
type BatchedUserInput = { id: number; group?: string };
|
|
@@ -40,6 +42,34 @@ function jsonResponse(body: unknown, status = 200): TestResponse {
|
|
|
40
42
|
}) as TestResponse;
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
function devalueFetchResponse(body: unknown, status = 200): Response {
|
|
46
|
+
return new Response(stringify(body), {
|
|
47
|
+
status,
|
|
48
|
+
headers: { 'content-type': 'application/devalue' }
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function withResponseOverrides<T extends Response>(
|
|
53
|
+
response: T
|
|
54
|
+
): T & {
|
|
55
|
+
extra: () => string;
|
|
56
|
+
meta: { source: string };
|
|
57
|
+
} {
|
|
58
|
+
Object.defineProperty(response, 'extra', {
|
|
59
|
+
configurable: true,
|
|
60
|
+
value: () => 'copied'
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(response, 'meta', {
|
|
63
|
+
configurable: true,
|
|
64
|
+
value: { source: 'custom' }
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return response as T & {
|
|
68
|
+
extra: () => string;
|
|
69
|
+
meta: { source: string };
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
43
73
|
function deferred<T>() {
|
|
44
74
|
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
45
75
|
let reject!: (reason?: unknown) => void;
|
|
@@ -60,6 +90,7 @@ describe('Requestor', () => {
|
|
|
60
90
|
afterEach(() => {
|
|
61
91
|
vi.useRealTimers();
|
|
62
92
|
vi.restoreAllMocks();
|
|
93
|
+
vi.unstubAllGlobals();
|
|
63
94
|
});
|
|
64
95
|
|
|
65
96
|
it('passes through non-batched requests', async () => {
|
|
@@ -74,6 +105,34 @@ describe('Requestor', () => {
|
|
|
74
105
|
await expect(response.json()).resolves.toEqual({ id: 1 });
|
|
75
106
|
});
|
|
76
107
|
|
|
108
|
+
it('devalue response', async () => {
|
|
109
|
+
const fetchMock = vi.fn(async () => devalueFetchResponse({ id: 1 }));
|
|
110
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
111
|
+
|
|
112
|
+
const request = createApiRequest<PlainUsersApi>(
|
|
113
|
+
{
|
|
114
|
+
'/users': {
|
|
115
|
+
GET: v.object({ id: v.number() })
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
'https://api.example.test',
|
|
119
|
+
'test'
|
|
120
|
+
);
|
|
121
|
+
const requestor = new Requestor<PlainUsersApi, '/users', 'GET'>('/users', 'GET', request, new Cache());
|
|
122
|
+
|
|
123
|
+
const response = await requestor.request({ id: 1 });
|
|
124
|
+
|
|
125
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
127
|
+
'https://api.example.test//users?id=1',
|
|
128
|
+
expect.objectContaining({
|
|
129
|
+
method: 'GET',
|
|
130
|
+
credentials: 'include'
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
await expect(response.json()).resolves.toEqual({ id: 1 });
|
|
134
|
+
});
|
|
135
|
+
|
|
77
136
|
it('batches requests with the same batch id and preserves response order', async () => {
|
|
78
137
|
const requestMock = vi.fn(async () => jsonResponse({ ok: true }));
|
|
79
138
|
const request = requestMock as unknown as BatchedUsersRequest;
|
|
@@ -235,6 +294,80 @@ describe('Query', () => {
|
|
|
235
294
|
await expect(second.json()).resolves.toEqual({ id: 1, name: 'Ada' });
|
|
236
295
|
});
|
|
237
296
|
|
|
297
|
+
it('preserves devalue parsing for query state, returned responses, and cache hits', async () => {
|
|
298
|
+
const fetchMock = vi.fn(async () =>
|
|
299
|
+
devalueFetchResponse({ id: 1, createdAt: new Date('2024-01-01T00:00:00.000Z') })
|
|
300
|
+
);
|
|
301
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
302
|
+
|
|
303
|
+
const request = createApiRequest<PlainUsersApi>(
|
|
304
|
+
{
|
|
305
|
+
'/users': {
|
|
306
|
+
GET: v.object({ id: v.number() })
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
'https://api.example.test',
|
|
310
|
+
'test'
|
|
311
|
+
);
|
|
312
|
+
const requestor = new Requestor<PlainUsersApi, '/users', 'GET'>('/users', 'GET', request, new Cache());
|
|
313
|
+
const query = new Query<PlainUsersApi, '/users', 'GET'>({
|
|
314
|
+
path: '/users',
|
|
315
|
+
method: 'GET',
|
|
316
|
+
input: { id: 1 },
|
|
317
|
+
requestor,
|
|
318
|
+
cache: new Cache()
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const firstResponse = await query.request();
|
|
322
|
+
|
|
323
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
324
|
+
expect(query.status).toBe('success');
|
|
325
|
+
expect(query.data).toEqual({ id: 1, createdAt: new Date('2024-01-01T00:00:00.000Z') });
|
|
326
|
+
await expect(firstResponse.json()).resolves.toEqual({
|
|
327
|
+
id: 1,
|
|
328
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const cachedResponse = await query.request();
|
|
332
|
+
|
|
333
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
334
|
+
await expect(cachedResponse.json()).resolves.toEqual({
|
|
335
|
+
id: 1,
|
|
336
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('preserves arbitrary response overrides across query clones and cache hits', async () => {
|
|
341
|
+
const customResponse = withResponseOverrides(jsonResponse({ id: 1 }) as Response);
|
|
342
|
+
const requestMock = vi.fn().mockResolvedValue(customResponse);
|
|
343
|
+
const requestor = {
|
|
344
|
+
request: requestMock as PlainUsersRequest
|
|
345
|
+
} as unknown as PlainUsersRequestor;
|
|
346
|
+
|
|
347
|
+
const query = new Query<PlainUsersApi, '/users', 'GET'>({
|
|
348
|
+
path: '/users',
|
|
349
|
+
method: 'GET',
|
|
350
|
+
input: { id: 1 },
|
|
351
|
+
requestor,
|
|
352
|
+
cache: new Cache()
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const first = (await query.request()) as Response & {
|
|
356
|
+
extra: () => string;
|
|
357
|
+
meta: { source: string };
|
|
358
|
+
};
|
|
359
|
+
const second = (await query.request()) as Response & {
|
|
360
|
+
extra: () => string;
|
|
361
|
+
meta: { source: string };
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
365
|
+
expect(first.extra()).toBe('copied');
|
|
366
|
+
expect(first.meta).toEqual({ source: 'custom' });
|
|
367
|
+
expect(second.extra()).toBe('copied');
|
|
368
|
+
expect(second.meta).toEqual({ source: 'custom' });
|
|
369
|
+
});
|
|
370
|
+
|
|
238
371
|
it('updates success state from successful responses', async () => {
|
|
239
372
|
const requestMock = vi.fn().mockResolvedValue(jsonResponse({ id: 1, active: true }));
|
|
240
373
|
const requestor = {
|