Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset url before updating page store #5039

Merged
merged 15 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/old-comics-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: page store correct after navigation when an identical route with a different hash had been prefetched
4 changes: 4 additions & 0 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ export function create_client({ target, session, base, trailing_slash }) {
if (started) {
current = navigation_result.state;

if (navigation_result.props.page) {
navigation_result.props.page.url = url;
}

root.$set(navigation_result.props);
} else {
initialize(navigation_result);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script context="module">
let load_calls = 0;

export const load = () => {
load_calls += 1;
return { props: { calls: load_calls } };
};
</script>

<script>
import { onMount } from 'svelte';
import { page } from '$app/stores';

export let calls;

const modal_contents = {
'please-dont-show-me': {
title: 'Oopsie'
},
'please-dont-show-me-jr': {
title: 'Oopsie Jr.'
}
};

let modal = undefined;

const show_modal = () => {
const hash = $page.url.hash.substring(1);
modal = modal_contents[hash];
};

onMount(show_modal);
</script>

<svelte:window on:popstate={show_modal} />

<h1>{modal?.title ?? ''}</h1>
<p>Loaded {calls} times.</p>
119 changes: 82 additions & 37 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,88 @@ test.describe.parallel('Redirects', () => {
});
});

test.describe.parallel('Prefetching', () => {
test('prefetches programmatically', async ({ baseURL, page, app, javaScriptEnabled }) => {
if (javaScriptEnabled) {
await page.goto('/routing/a');

/** @type {string[]} */
let requests = [];
page.on('request', (r) => requests.push(r.url()));

// also wait for network processing to complete, see
// https://playwright.dev/docs/network#network-events
await Promise.all([
page.waitForResponse(`${baseURL}/routing/prefetched.json`),
app.prefetch('/routing/prefetched')
]);

// svelte request made is environment dependent
if (process.env.DEV) {
expect(requests.filter((req) => req.endsWith('index.svelte')).length).toBe(1);
} else {
expect(requests.filter((req) => req.endsWith('.js')).length).toBe(1);
}

expect(requests.includes(`${baseURL}/routing/prefetched.json`)).toBe(true);

requests = [];
await app.goto('/routing/prefetched');
expect(requests).toEqual([]);

try {
await app.prefetch('https://example.com');
throw new Error('Error was not thrown');
} catch (/** @type {any} */ e) {
expect(e.message).toMatch('Attempted to prefetch a URL that does not belong to this app');
}
}
});

test('chooses correct route when hash route is prefetched but regular route is clicked', async ({
app,
page,
javaScriptEnabled
}) => {
if (javaScriptEnabled) {
await page.goto('/routing/a');
await app.prefetch('/routing/prefetched/hash-route#please-dont-show-me');
await app.goto('/routing/prefetched/hash-route');
await expect(page.locator('h1')).not.toHaveText('Oopsie');
}
});

test('does not rerun load on calls to duplicate preload hash route', async ({
app,
page,
javaScriptEnabled
}) => {
if (javaScriptEnabled) {
await page.goto('/routing/a');

await app.prefetch('/routing/prefetched/hash-route#please-dont-show-me');
await app.prefetch('/routing/prefetched/hash-route#please-dont-show-me');
await app.goto('/routing/prefetched/hash-route#please-dont-show-me');
await expect(page.locator('p')).toHaveText('Loaded 1 times.');
}
});

test('does not rerun load on calls to different preload hash route', async ({
app,
page,
javaScriptEnabled
}) => {
if (javaScriptEnabled) {
await page.goto('/routing/a');

await app.prefetch('/routing/prefetched/hash-route#please-dont-show-me');
await app.prefetch('/routing/prefetched/hash-route#please-dont-show-me-jr');
await app.goto('/routing/prefetched/hash-route#please-dont-show-me');
await expect(page.locator('p')).toHaveText('Loaded 1 times.');
}
});
});

test.describe.parallel('Routing', () => {
test('redirects from /routing/ to /routing', async ({
baseURL,
Expand Down Expand Up @@ -2113,43 +2195,6 @@ test.describe.parallel('Routing', () => {
}
});

test('prefetches programmatically', async ({ baseURL, page, app, javaScriptEnabled }) => {
if (javaScriptEnabled) {
await page.goto('/routing/a');

/** @type {string[]} */
let requests = [];
page.on('request', (r) => requests.push(r.url()));

// also wait for network processing to complete, see
// https://playwright.dev/docs/network#network-events
await Promise.all([
page.waitForResponse(`${baseURL}/routing/prefetched.json`),
app.prefetch('/routing/prefetched')
]);

// svelte request made is environment dependent
if (process.env.DEV) {
expect(requests.filter((req) => req.endsWith('index.svelte')).length).toBe(1);
} else {
expect(requests.filter((req) => req.endsWith('.js')).length).toBe(1);
}

expect(requests.includes(`${baseURL}/routing/prefetched.json`)).toBe(true);

requests = [];
await app.goto('/routing/prefetched');
expect(requests).toEqual([]);

try {
await app.prefetch('https://example.com');
throw new Error('Error was not thrown');
} catch (/** @type {any} */ e) {
expect(e.message).toMatch('Attempted to prefetch a URL that does not belong to this app');
}
}
});

test('does not attempt client-side navigation to server routes', async ({ page }) => {
await page.goto('/routing');
await page.click('[href="/routing/ambiguous/ok.json"]');
Expand Down