Skip to content

Commit 5dcd624

Browse files
committed
Add tests
1 parent 8547bda commit 5dcd624

File tree

6 files changed

+138
-18
lines changed

6 files changed

+138
-18
lines changed

packages/kit/src/runtime/app/server/remote/query.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ export function query(validate_or_fn, maybe_fn) {
7272

7373
const { event, state } = get_request_store();
7474

75-
const get_remote_function_result = () => run_remote_function(event, state, false, arg, validate, fn);
75+
const get_remote_function_result = () =>
76+
run_remote_function(event, state, false, arg, validate, fn);
7677

7778
/** @type {Promise<any> & Partial<RemoteQuery<any>>} */
7879
const promise = get_response(__, arg, state, get_remote_function_result);
@@ -90,11 +91,11 @@ export function query(validate_or_fn, maybe_fn) {
9091
);
9192
}
9293

93-
// TODO: Shouldn't this throw to signify that non-exported queries can't be set? Or still update the cache without touching refreshes?
9494
if (__.id) {
95-
const cache = get_cache(__, state);
9695
const key = stringify_remote_arg(arg, state.transport);
97-
refreshes[create_remote_cache_key(__.id, key)] = cache[key] = Promise.resolve(value);
96+
const cache_key = create_remote_cache_key(__.id, key);
97+
const cache = get_cache(__, state);
98+
cache[key] = refreshes[cache_key] = Promise.resolve(value);
9899
}
99100
};
100101

@@ -271,9 +272,10 @@ function batch(validate_or_fn, maybe_fn) {
271272
if (__.id) {
272273
const key = stringify_remote_arg(arg, state.transport);
273274
const cache_key = create_remote_cache_key(__.id, key);
274-
refreshes[cache_key] = Promise.resolve(value);
275+
const cache = get_cache(__, state);
276+
cache[key] = refreshes[cache_key] = Promise.resolve(value);
275277
}
276-
}
278+
};
277279

278280
promise.refresh = () => {
279281
const { state } = get_request_store();

packages/kit/test/apps/basics/src/routes/remote/+page.svelte

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
get_count,
77
set_count,
88
set_count_server_refresh,
9+
set_count_server_refresh_after_read,
910
set_count_server_set,
1011
resolve_deferreds
1112
} from './query-command.remote.js';
@@ -67,6 +68,14 @@
6768
>
6869
command (query server refresh)
6970
</button>
71+
<button
72+
onclick={async () => {
73+
command_result = await set_count_server_refresh_after_read(6);
74+
}}
75+
id="multiply-server-refresh-after-read-btn"
76+
>
77+
command (query server refresh after read)
78+
</button>
7079
<button
7180
onclick={async () => {
7281
// slow, else test will not be able to see the override

packages/kit/test/apps/basics/src/routes/remote/batch/+page.svelte

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
<script>
2-
import { get_todo } from './batch.remote.js';
2+
import {
3+
get_todo,
4+
set_todo_title_server_refresh,
5+
reset_todos,
6+
set_todo_title
7+
} from './batch.remote.js';
38
49
const todoIds = ['1', '2', '1', 'error'];
10+
const todos = todoIds.map((id) => ({ id, promise: get_todo(id) }));
511
</script>
612

713
<h1>Query Batch Test</h1>
814

915
<ul>
10-
{#each todoIds as id, idx}
16+
{#each todos as { id, promise }, idx (idx)}
1117
<li>
12-
{#await get_todo(id)}
18+
{#await promise}
1319
<span id="batch-result-{idx + 1}">Loading todo {id}...</span>
1420
{:then todo}
1521
<span id="batch-result-{idx + 1}">{todo.title}</span>
@@ -21,3 +27,27 @@
2127
</ul>
2228

2329
<button onclick={() => todoIds.forEach((id) => get_todo(id).refresh())}>refresh</button>
30+
<button
31+
onclick={async () => {
32+
await set_todo_title({ id: '1', title: 'Buy cat food' });
33+
}}
34+
id="batch-set-btn"
35+
>
36+
set first todo
37+
</button>
38+
<button
39+
onclick={async () => {
40+
await set_todo_title_server_refresh({ id: '2', title: 'Walk the dog (refreshed)' });
41+
}}
42+
id="batch-refresh-btn"
43+
>
44+
refresh second todo via command
45+
</button>
46+
<button
47+
onclick={async () => {
48+
await reset_todos();
49+
}}
50+
id="batch-reset-btn"
51+
>
52+
reset todos
53+
</button>
Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,43 @@
1-
import { query } from '$app/server';
1+
import { command, query } from '$app/server';
22
import { error } from '@sveltejs/kit';
33

4+
/** @type {Array<[string, { id: string; title: string }]>} **/
5+
const INITIAL_TODOS = [
6+
['1', { id: '1', title: 'Buy groceries' }],
7+
['2', { id: '2', title: 'Walk the dog' }]
8+
];
9+
10+
let todos = new Map(INITIAL_TODOS);
11+
412
export const get_todo = query.batch('unchecked', (ids) => {
5-
if (JSON.stringify(ids) !== JSON.stringify(['1', '2', 'error'])) {
6-
throw new Error(`Expected 3 IDs (deduplicated), got ${JSON.stringify(ids)}`);
13+
if (new Set(ids).size !== ids.length) {
14+
throw new Error(`batch queries must be deduplicated, but got ${JSON.stringify(ids)}`);
715
}
816

9-
return (id) =>
10-
id === '1'
11-
? { id: '1', title: 'Buy groceries' }
12-
: id === '2'
13-
? { id: '2', title: 'Walk the dog' }
14-
: error(404, { message: 'Not found' });
17+
return (id) => {
18+
if (id === 'error') return error(404, { message: 'Not found' });
19+
20+
return todos.get(id);
21+
};
22+
});
23+
24+
export const set_todo_title = command('unchecked', ({ id, title }) => {
25+
const todo = { id, title };
26+
todos.set(id, todo);
27+
get_todo(id).set(todo);
28+
return todo;
29+
});
30+
31+
export const set_todo_title_server_refresh = command('unchecked', ({ id, title }) => {
32+
const todo = { id, title };
33+
todos.set(id, todo);
34+
get_todo(id).refresh();
35+
return todo;
36+
});
37+
38+
export const reset_todos = command(() => {
39+
todos = new Map(INITIAL_TODOS);
40+
for (const [id, todo] of todos) {
41+
get_todo(id).set({ ...todo });
42+
}
1543
});

packages/kit/test/apps/basics/src/routes/remote/query-command.remote.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ export const set_count_server_refresh = command('unchecked', (c) => {
3636
return c;
3737
});
3838

39+
export const set_count_server_refresh_after_read = command('unchecked', async (c) => {
40+
await get_count();
41+
count = c;
42+
await get_count().refresh();
43+
return c;
44+
});
45+
3946
export const set_count_server_set = command('unchecked', async (c) => {
4047
get_count_called = false;
4148
count = c;

packages/kit/test/apps/basics/test/client.test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,20 @@ test.describe('remote functions', () => {
18601860
expect(request_count).toBe(1); // no query refreshes, since that happens as part of the command response
18611861
});
18621862

1863+
test('command refresh after reading query reruns the query', async ({ page }) => {
1864+
await page.goto('/remote');
1865+
await expect(page.locator('#count-result')).toHaveText('0 / 0 (false)');
1866+
1867+
let request_count = 0;
1868+
page.on('request', (r) => (request_count += r.url().includes('/_app/remote') ? 1 : 0));
1869+
1870+
await page.click('#multiply-server-refresh-after-read-btn');
1871+
await expect(page.locator('#command-result')).toHaveText('6');
1872+
await expect(page.locator('#count-result')).toHaveText('6 / 6 (false)');
1873+
await page.waitForTimeout(100); // allow all requests to finish (in case there are query refreshes which shouldn't happen)
1874+
expect(request_count).toBe(1);
1875+
});
1876+
18631877
test('command does server-initiated single flight mutation (set)', async ({ page }) => {
18641878
await page.goto('/remote');
18651879
await expect(page.locator('#count-result')).toHaveText('0 / 0 (false)');
@@ -2027,6 +2041,36 @@ test.describe('remote functions', () => {
20272041
expect(request_count).toBe(1);
20282042
});
20292043

2044+
test('query.batch set updates cache without extra request', async ({ page }) => {
2045+
await page.goto('/remote/batch');
2046+
await page.click('#batch-reset-btn');
2047+
await expect(page.locator('#batch-result-1')).toHaveText('Buy groceries');
2048+
2049+
let request_count = 0;
2050+
const handler = (r) => (request_count += r.url().includes('/_app/remote') ? 1 : 0);
2051+
page.on('request', handler);
2052+
2053+
await page.click('#batch-set-btn');
2054+
await expect(page.locator('#batch-result-1')).toHaveText('Buy cat food');
2055+
await page.waitForTimeout(100); // allow all requests to finish
2056+
expect(request_count).toBe(1); // only the command request
2057+
});
2058+
2059+
test('query.batch refresh in command reuses single flight', async ({ page }) => {
2060+
await page.goto('/remote/batch');
2061+
await page.click('#batch-reset-btn');
2062+
await expect(page.locator('#batch-result-2')).toHaveText('Walk the dog');
2063+
2064+
let request_count = 0;
2065+
const handler = (r) => (request_count += r.url().includes('/_app/remote') ? 1 : 0);
2066+
page.on('request', handler);
2067+
2068+
await page.click('#batch-refresh-btn');
2069+
await expect(page.locator('#batch-result-2')).toHaveText('Walk the dog (refreshed)');
2070+
await page.waitForTimeout(100); // allow all requests to finish
2071+
expect(request_count).toBe(1); // only the command request
2072+
});
2073+
20302074
// TODO ditto
20312075
test('query works with transport', async ({ page }) => {
20322076
await page.goto('/remote/transport');

0 commit comments

Comments
 (0)