diff --git a/.changeset/itchy-trains-allow.md b/.changeset/itchy-trains-allow.md new file mode 100644 index 000000000000..6a53bca2f25a --- /dev/null +++ b/.changeset/itchy-trains-allow.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a case where setting the status of a page to `404` in development would show the default 404 page (or custom one if provided) instead of using the current page diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 51b7537bfc4a..108b53273b20 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -241,7 +241,13 @@ export async function handleRoute({ ); } - if (statusCode === 404 && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no') { + if ( + statusCode === 404 && + // If the body isn't null, that means the user sets the 404 status + // but uses the current route to handle the 404 + response.body === null && + response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no' + ) { const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline); if (fourOhFourRoute) { renderContext = await RenderContext.create({ diff --git a/packages/astro/test/astro-response.test.js b/packages/astro/test/astro-response.test.js index 87313a76a26f..2440c7362b22 100644 --- a/packages/astro/test/astro-response.test.js +++ b/packages/astro/test/astro-response.test.js @@ -1,9 +1,11 @@ +// @ts-check import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import { loadFixture } from './test-utils.js'; // Asset bundling describe('Returning responses', () => { + /** @type {Awaited>} */ let fixture; /** @type {import('./test-utils').DevServer} */ let devServer; @@ -21,7 +23,23 @@ describe('Returning responses', () => { }); it('Works from a page', async () => { - let response = await fixture.fetch('/not-found'); + const response = await fixture.fetch('/not-found'); assert.equal(response.status, 404); }); + + it('Returns the default 404 is body is null', async () => { + const response = await fixture.fetch('/not-found'); + const html = await response.text(); + + assert.equal(response.status, 404); + assert.equal(html.includes('
Path: /not-found
'), true); + }); + + it('Returns the page is body is not null', async () => { + const response = await fixture.fetch('/not-found-custom'); + const html = await response.text(); + + assert.equal(response.status, 404); + assert.equal(html.includes('Custom 404'), true); + }); }); diff --git a/packages/astro/test/fixtures/astro-response/src/pages/not-found-custom.astro b/packages/astro/test/fixtures/astro-response/src/pages/not-found-custom.astro new file mode 100644 index 000000000000..482331ebc5da --- /dev/null +++ b/packages/astro/test/fixtures/astro-response/src/pages/not-found-custom.astro @@ -0,0 +1,4 @@ +--- +Astro.response.status = 404 +--- +
Custom 404
\ No newline at end of file diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index fca78b0837a1..c33e43ca36b0 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -34,12 +34,12 @@ process.env.ASTRO_TELEMETRY_DISABLED = true; * @property {typeof build} build * @property {(url: string) => string} resolveUrl * @property {(path: string) => Promise} pathExists - * @property {(url: string, opts: Parameters[1]) => Promise} fetch + * @property {(url: string, opts?: Parameters[1]) => Promise} fetch * @property {(path: string) => Promise} readFile * @property {(path: string, updater: (content: string) => string) => Promise} editFile * @property {(path: string) => Promise} readdir * @property {(pattern: string) => Promise} glob - * @property {typeof dev} startDevServer + * @property {(inlineConfig?: Parameters[0]) => ReturnType} startDevServer * @property {typeof preview} preview * @property {() => Promise} clean * @property {() => Promise} loadTestAdapterApp