From 20bf8040bfad428b4d5a9cd3266c646106d8df94 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Thu, 2 Feb 2023 19:10:16 -0500 Subject: Node adapter: handle prerendering and serving with query params (#6110) * Node adapter: handle prerendering and serving with query params * Adding a changeset --- packages/integrations/node/test/prerender.test.js | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 packages/integrations/node/test/prerender.test.js (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js new file mode 100644 index 000000000..e5c94391f --- /dev/null +++ b/packages/integrations/node/test/prerender.test.js @@ -0,0 +1,60 @@ +import nodejs from '../dist/index.js'; +import { loadFixture, createRequestAndResponse } from './test-utils.js'; +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { fetch } from 'undici'; + +describe('Prerendering', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let server; + + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + }); + + async function load() { + const mod = await import('./fixtures/prerender/dist/server/entry.mjs'); + return mod; + } + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); +}); -- cgit v1.2.3 From da9f986d7c6e3659a392f89e39ecd724c394ef53 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Fri, 12 May 2023 10:01:05 -0400 Subject: Correct handle directory finds when using base in the Node adapter (#7076) --- packages/integrations/node/src/http-server.ts | 8 +++++++- packages/integrations/node/test/prerender.test.js | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts index 850d61bbb..2c58c0da7 100644 --- a/packages/integrations/node/src/http-server.ts +++ b/packages/integrations/node/src/http-server.ts @@ -55,7 +55,13 @@ export function createServer( // File not found, forward to the SSR handler handler(req, res); }); - + stream.on('directory', () => { + // On directory find, redirect to the trailing slash + const location = req.url + '/'; + res.statusCode = 301 + res.setHeader('Location', location); + res.end(location); + }); stream.on('file', () => { forwardError = true; }); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index e5c94391f..1b478bb33 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -12,6 +12,7 @@ describe('Prerendering', () => { before(async () => { process.env.ASTRO_NODE_AUTOSTART = 'disabled'; fixture = await loadFixture({ + base: '/some-base', root: './fixtures/prerender/', output: 'server', adapter: nodejs({ mode: 'standalone' }), @@ -32,7 +33,7 @@ describe('Prerendering', () => { } it('Can render SSR route', async () => { - const res = await fetch(`http://${server.host}:${server.port}/one`); + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`); const html = await res.text(); const $ = cheerio.load(html); @@ -41,7 +42,7 @@ describe('Prerendering', () => { }); it('Can render prerendered route', async () => { - const res = await fetch(`http://${server.host}:${server.port}/two`); + const res = await fetch(`http://${server.host}:${server.port}/some-base/two`); const html = await res.text(); const $ = cheerio.load(html); @@ -50,11 +51,19 @@ describe('Prerendering', () => { }); it('Can render prerendered route with query params', async () => { - const res = await fetch(`http://${server.host}:${server.port}/two?foo=bar`); + const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`); const html = await res.text(); const $ = cheerio.load(html); expect(res.status).to.equal(200); expect($('h1').text()).to.equal('Two'); }); + + it('Omitting the trailing slash results in a redirect that includes the base', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, { + redirect: 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/two/'); + }); }); -- cgit v1.2.3 From 381a055804f6c6d97408f9bf8d9d5208ba8668ae Mon Sep 17 00:00:00 2001 From: matthewp Date: Fri, 12 May 2023 14:03:42 +0000 Subject: [ci] format --- packages/integrations/node/src/http-server.ts | 8 ++++---- packages/integrations/node/test/prerender.test.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts index 2c58c0da7..177c71ed9 100644 --- a/packages/integrations/node/src/http-server.ts +++ b/packages/integrations/node/src/http-server.ts @@ -57,10 +57,10 @@ export function createServer( }); stream.on('directory', () => { // On directory find, redirect to the trailing slash - const location = req.url + '/'; - res.statusCode = 301 - res.setHeader('Location', location); - res.end(location); + const location = req.url + '/'; + res.statusCode = 301; + res.setHeader('Location', location); + res.end(location); }); stream.on('file', () => { forwardError = true; diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 1b478bb33..0ef316ed6 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -61,7 +61,7 @@ describe('Prerendering', () => { it('Omitting the trailing slash results in a redirect that includes the base', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, { - redirect: 'manual' + redirect: 'manual', }); expect(res.status).to.equal(301); expect(res.headers.get('location')).to.equal('/some-base/two/'); -- cgit v1.2.3 From 2fa052f82868be804b4e2d89a1d94c722f049db8 Mon Sep 17 00:00:00 2001 From: Happydev <81974850+MoustaphaDev@users.noreply.github.com> Date: Mon, 15 May 2023 12:53:34 +0000 Subject: Fix double prepended forward slash in certain cases (#7091) * test: add test with no base * fix: don't always prepend a forward slash * chore: changeset * `'/' + base` ------> `prependForwardSlash(base)` --- packages/integrations/node/test/prerender.test.js | 133 +++++++++++++++------- 1 file changed, 90 insertions(+), 43 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 0ef316ed6..e72e754e2 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -9,61 +9,108 @@ describe('Prerendering', () => { let fixture; let server; - before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; - fixture = await loadFixture({ - base: '/some-base', - root: './fixtures/prerender/', - output: 'server', - adapter: nodejs({ mode: 'standalone' }), - }); - await fixture.build(); - const { startServer } = await await load(); - let res = startServer(); - server = res.server; - }); - - after(async () => { - await server.stop(); - }); - async function load() { const mod = await import('./fixtures/prerender/dist/server/entry.mjs'); return mod; } - it('Can render SSR route', async () => { - const res = await fetch(`http://${server.host}:${server.port}/some-base/one`); - const html = await res.text(); - const $ = cheerio.load(html); + describe('With base', () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + fixture = await loadFixture({ + base: '/some-base', + root: './fixtures/prerender/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await await load(); + let res = startServer(); + server = res.server; + }); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); - }); + after(async () => { + await server.stop(); + }); - it('Can render prerendered route', async () => { - const res = await fetch(`http://${server.host}:${server.port}/some-base/two`); - const html = await res.text(); - const $ = cheerio.load(html); + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`); + const html = await res.text(); + const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); - }); + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); - it('Can render prerendered route with query params', async () => { - const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`); - const html = await res.text(); - const $ = cheerio.load(html); + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + + it('Omitting the trailing slash results in a redirect that includes the base', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, { + redirect: 'manual', + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/two/'); + }); }); + describe('Without base', () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + }); + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); - it('Omitting the trailing slash results in a redirect that includes the base', async () => { - const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, { - redirect: 'manual', + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); }); - expect(res.status).to.equal(301); - expect(res.headers.get('location')).to.equal('/some-base/two/'); }); }); -- cgit v1.2.3 From be24395eaf3082e9ed8196c2a1984f66c1b68fdd Mon Sep 17 00:00:00 2001 From: Happydev <81974850+MoustaphaDev@users.noreply.github.com> Date: Wed, 17 May 2023 13:23:20 +0000 Subject: feat: hybrid output (#6991) * update config schema * adapt default route `prerender` value * adapt error message for hybrid output * core hybrid output support * add JSDocs for hybrid output * dev server hybrid output support * defer hybrid output check * update endpoint request warning * support `output=hybrid` in integrations * put constant variable out of for loop * revert: reapply back ssr plugin in ssr mode * change `prerender` option default * apply `prerender` by default in hybrid mode * simplfy conditional * update config schema * add `isHybridOutput` helper * more readable prerender condition * set default prerender value if no export is found * only add `pagesVirtualModuleId` ro rollup input in `output=static` * don't export vite plugin * remove unneeded check * don't prerender when it shouldn't * extract fallback `prerender` meta Extract the fallback `prerender` module meta out of the `scan` function. It shouldn't be its responsibility to handle that * pass missing argument to function * test: update cloudflare integration tests * test: update tests of vercel integration * test: update tests of node integration * test: update tests of netlify func integration * test: update tests of netlify edge integration * throw when `hybrid` mode is malconfigured * update node integraiton `output` warning * test(WIP): skip node prerendering tests for now * remove non-existant import * test: bring back prerendering tests * remove outdated comments * test: refactor test to support windows paths * remove outdated comments * apply sarah review Co-authored-by: Sarah Rainsberger * docs: `experiment.hybridOutput` jsodcs * test: prevent import from being cached * refactor: extract hybrid output check to function * add `hybrid` to output warning in adapter hooks * chore: changeset * add `.js` extension to import * chore: use spaces instead of tabs for gh formating * resolve merge conflict * chore: move test to another file for consitency --------- Co-authored-by: Sarah Rainsberger Co-authored-by: Matthew Phillips --- packages/integrations/node/src/index.ts | 4 +- .../test/fixtures/prerender/src/pages/two.astro | 2 +- packages/integrations/node/test/prerender.test.js | 146 +++++++++++++++++++-- 3 files changed, 142 insertions(+), 10 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index d882f34fb..17a8f4502 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -40,7 +40,9 @@ export default function createIntegration(userOptions: UserOptions): AstroIntegr setAdapter(getAdapter(_options)); if (config.output === 'static') { - console.warn(`[@astrojs/node] \`output: "server"\` is required to use this adapter.`); + console.warn( + `[@astrojs/node] \`output: "server"\` or \`output: "hybrid"\` is required to use this adapter.` + ); } }, }, diff --git a/packages/integrations/node/test/fixtures/prerender/src/pages/two.astro b/packages/integrations/node/test/fixtures/prerender/src/pages/two.astro index beb6e8d78..c0e5d07aa 100644 --- a/packages/integrations/node/test/fixtures/prerender/src/pages/two.astro +++ b/packages/integrations/node/test/fixtures/prerender/src/pages/two.astro @@ -1,5 +1,5 @@ --- -export const prerender = true; +export const prerender = import.meta.env.PRERENDER; --- diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index e72e754e2..751ed2ae7 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -1,22 +1,27 @@ import nodejs from '../dist/index.js'; -import { loadFixture, createRequestAndResponse } from './test-utils.js'; +import { loadFixture } from './test-utils.js'; import { expect } from 'chai'; import * as cheerio from 'cheerio'; import { fetch } from 'undici'; +/** + * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture + */ + +async function load() { + const mod = await import(`./fixtures/prerender/dist/server/entry.mjs?dropcache=${Date.now()}`); + return mod; +} describe('Prerendering', () => { /** @type {import('./test-utils').Fixture} */ let fixture; let server; - async function load() { - const mod = await import('./fixtures/prerender/dist/server/entry.mjs'); - return mod; - } - - describe('With base', () => { + describe('With base', async () => { before(async () => { process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + fixture = await loadFixture({ base: '/some-base', root: './fixtures/prerender/', @@ -31,6 +36,8 @@ describe('Prerendering', () => { after(async () => { await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; }); it('Can render SSR route', async () => { @@ -68,9 +75,12 @@ describe('Prerendering', () => { expect(res.headers.get('location')).to.equal('/some-base/two/'); }); }); - describe('Without base', () => { + + describe('Without base', async () => { before(async () => { process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + fixture = await loadFixture({ root: './fixtures/prerender/', output: 'server', @@ -84,6 +94,8 @@ describe('Prerendering', () => { after(async () => { await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; }); it('Can render SSR route', async () => { @@ -114,3 +126,121 @@ describe('Prerendering', () => { }); }); }); + +describe('Hybrid rendering', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let server; + + describe('With base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = false; + fixture = await loadFixture({ + base: '/some-base', + root: './fixtures/prerender/', + output: 'hybrid', + experimental: { + hybridOutput: true, + }, + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two`); + const html = await res.text(); + const $ = cheerio.load(html); + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Omitting the trailing slash results in a redirect that includes the base', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { + redirect: 'manual', + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/one/'); + }); + }); + + describe('Without base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = false; + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'hybrid', + experimental: { + hybridOutput: true, + }, + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); +}); -- cgit v1.2.3 From 1bd4924f2d74c6e2d34d9587a45f356f9fcb06f3 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Wed, 31 May 2023 11:47:25 -0500 Subject: feat(hybrid): unflag hybrid output (#7255) --- packages/integrations/node/test/prerender.test.js | 6 ------ 1 file changed, 6 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 751ed2ae7..4b5522a31 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,9 +140,6 @@ describe('Hybrid rendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'hybrid', - experimental: { - hybridOutput: true, - }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); @@ -199,9 +196,6 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', - experimental: { - hybridOutput: true, - }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); -- cgit v1.2.3 From 339e507be9d62b7b7a75014cfa28d8e4d06efd31 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Wed, 31 May 2023 12:06:24 -0500 Subject: Revert "feat(hybrid): unflag hybrid output (#7255)" (#7259) This reverts commit 1bd4924f2d74c6e2d34d9587a45f356f9fcb06f3. --- packages/integrations/node/test/prerender.test.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 4b5522a31..751ed2ae7 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,6 +140,9 @@ describe('Hybrid rendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); @@ -196,6 +199,9 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); -- cgit v1.2.3 From 6ee3b449fff1490c18b577446fabb3ab7f0d91e0 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 5 Jun 2023 13:19:15 -0500 Subject: Unflag hybrid output (#7260) * feat(hybrid): unflag hybrid output * chore: cleanup rebase errors --- packages/integrations/node/test/prerender.test.js | 6 ------ 1 file changed, 6 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 751ed2ae7..4b5522a31 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,9 +140,6 @@ describe('Hybrid rendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'hybrid', - experimental: { - hybridOutput: true, - }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); @@ -199,9 +196,6 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', - experimental: { - hybridOutput: true, - }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); -- cgit v1.2.3 From 5df4f08120d1a7323b0162c86828be023356bf20 Mon Sep 17 00:00:00 2001 From: Riki Date: Tue, 6 Jun 2023 23:09:00 +0800 Subject: fix:query not considered in directory redirection (#7243) * fix:query not considered in directory redirection * feat: req.url may be empty * test(node): add redirect + query param tests * refactor(node): cleanup query param logic * chore: remove log * chore: add changeset --------- Co-authored-by: Riki <947968273@qq.com> Co-authored-by: Nate Moore Co-authored-by: Nate Moore --- packages/integrations/node/src/http-server.ts | 9 +++++- packages/integrations/node/test/prerender.test.js | 36 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts index 177c71ed9..9f8b3e891 100644 --- a/packages/integrations/node/src/http-server.ts +++ b/packages/integrations/node/src/http-server.ts @@ -57,7 +57,14 @@ export function createServer( }); stream.on('directory', () => { // On directory find, redirect to the trailing slash - const location = req.url + '/'; + let location: string; + if (req.url!.includes('?')) { + const [url = '', search] = req.url!.split('?'); + location = `${url}/?${search}` + } else { + location = req.url + '/' + } + res.statusCode = 301; res.setHeader('Location', location); res.end(location); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 4b5522a31..a018f0649 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -58,6 +58,15 @@ describe('Prerendering', () => { expect($('h1').text()).to.equal('Two'); }); + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/two?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + it('Can render prerendered route with query params', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/two/?foo=bar`); const html = await res.text(); @@ -116,6 +125,15 @@ describe('Prerendering', () => { expect($('h1').text()).to.equal('Two'); }); + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + it('Can render prerendered route with query params', async () => { const res = await fetch(`http://${server.host}:${server.port}/two/?foo=bar`); const html = await res.text(); @@ -171,6 +189,15 @@ describe('Hybrid rendering', () => { expect($('h1').text()).to.equal('One'); }); + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + it('Can render prerendered route with query params', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`); const html = await res.text(); @@ -228,6 +255,15 @@ describe('Hybrid rendering', () => { expect($('h1').text()).to.equal('One'); }); + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + it('Can render prerendered route with query params', async () => { const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`); const html = await res.text(); -- cgit v1.2.3 From dc7967fa540a5d282995ed5e433df898f545a479 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 28 Jun 2023 13:06:16 +0100 Subject: fix: correctly handle prerender pages in split mode (#7509) --- packages/integrations/node/test/prerender.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index a018f0649..f895a6458 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -29,7 +29,7 @@ describe('Prerendering', () => { adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await await load(); + const { startServer } = await load(); let res = startServer(); server = res.server; }); -- cgit v1.2.3 From 7ec38f40373417b73d58a4407fd1a3f1ced7c2b8 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Tue, 8 Aug 2023 15:04:14 +0800 Subject: Remove undici dep (#7980) --- packages/integrations/node/package.json | 3 +-- packages/integrations/node/src/response-iterator.ts | 7 +++---- packages/integrations/node/test/prerender-404.test.js | 1 - packages/integrations/node/test/prerender.test.js | 1 - 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index d46a94c0c..c01abae80 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -48,7 +48,6 @@ "chai": "^4.3.7", "cheerio": "1.0.0-rc.12", "mocha": "^9.2.2", - "node-mocks-http": "^1.12.2", - "undici": "^5.22.1" + "node-mocks-http": "^1.12.2" } } diff --git a/packages/integrations/node/src/response-iterator.ts b/packages/integrations/node/src/response-iterator.ts index 01624d81d..84080e5d1 100644 --- a/packages/integrations/node/src/response-iterator.ts +++ b/packages/integrations/node/src/response-iterator.ts @@ -6,7 +6,6 @@ import type { ReadableStreamDefaultReadResult } from 'node:stream/web'; import { Readable as NodeReadableStream } from 'stream'; -import type { Response as NodeResponse } from 'undici'; interface NodeStreamIterator { next(): Promise>; @@ -35,8 +34,8 @@ function isBuffer(value: any): value is Buffer { ); } -function isNodeResponse(value: any): value is NodeResponse { - return !!(value as NodeResponse).body; +function isNodeResponse(value: any): value is Response { + return !!(value as Response).body; } function isReadableStream(value: any): value is ReadableStream { @@ -202,7 +201,7 @@ function asyncIterator(source: AsyncIterableIterator): AsyncIterableIterat } export function responseIterator( - response: Response | NodeResponse | Buffer + response: Response | Buffer ): AsyncIterableIterator { let body: unknown = response; diff --git a/packages/integrations/node/test/prerender-404.test.js b/packages/integrations/node/test/prerender-404.test.js index 626f584e0..3a39a9470 100644 --- a/packages/integrations/node/test/prerender-404.test.js +++ b/packages/integrations/node/test/prerender-404.test.js @@ -2,7 +2,6 @@ import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; import { expect } from 'chai'; import * as cheerio from 'cheerio'; -import { fetch } from 'undici'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index f895a6458..65e3b4cb2 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -2,7 +2,6 @@ import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; import { expect } from 'chai'; import * as cheerio from 'cheerio'; -import { fetch } from 'undici'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture -- cgit v1.2.3 From f61248895b8b7007c1fd5dccbd550f2d123f2da2 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 17 Jan 2024 13:10:43 +0000 Subject: Adapter enhancements (#9661) * quality of life updates for `App` (#9579) * feat(app): writeResponse for node-based adapters * add changeset * Apply suggestions from code review Co-authored-by: Emanuele Stoppa * Apply suggestions from code review Co-authored-by: Emanuele Stoppa * add examples for NodeApp static methods * unexpose createOutgoingHttpHeaders from public api * move headers test to core * clientAddress test * cookies test * destructure renderOptions right at the start --------- Co-authored-by: Emanuele Stoppa * Fallback node standalone to localhost (#9545) * Fallback node standalone to localhost * Update .changeset/tame-squids-film.md * quality of life updates for the node adapter (#9582) * descriptive names for files and functions * update tests * add changeset * appease linter * Apply suggestions from code review Co-authored-by: Nate Moore * `server-entrypoint.js` -> `server.js` * prevent crash on stream error (from PR 9533) * Apply suggestions from code review Co-authored-by: Luiz Ferraz * `127.0.0.1` -> `localhost` * add changeset for fryuni's fix * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Emanuele Stoppa --------- Co-authored-by: Nate Moore Co-authored-by: Luiz Ferraz Co-authored-by: Emanuele Stoppa * chore(vercel): delete request response conversion logic (#9583) * refactor * add changeset * bump peer dependencies * unexpose symbols (#9683) * Update .changeset/tame-squids-film.md Co-authored-by: Sarah Rainsberger --------- Co-authored-by: Arsh <69170106+lilnasy@users.noreply.github.com> Co-authored-by: Bjorn Lu Co-authored-by: Nate Moore Co-authored-by: Luiz Ferraz Co-authored-by: Sarah Rainsberger --- packages/integrations/node/package.json | 2 +- .../node/src/createOutgoingHttpHeaders.ts | 34 ------ .../integrations/node/src/get-network-address.ts | 48 -------- packages/integrations/node/src/http-server.ts | 131 --------------------- packages/integrations/node/src/index.ts | 3 +- packages/integrations/node/src/log-listening-on.ts | 84 +++++++++++++ packages/integrations/node/src/middleware.ts | 43 +++++++ packages/integrations/node/src/nodeMiddleware.ts | 110 ----------------- packages/integrations/node/src/preview.ts | 73 ++++-------- packages/integrations/node/src/serve-app.ts | 27 +++++ packages/integrations/node/src/serve-static.ts | 86 ++++++++++++++ packages/integrations/node/src/server.ts | 10 +- packages/integrations/node/src/standalone.ts | 129 +++++++++++--------- packages/integrations/node/src/types.ts | 13 +- packages/integrations/node/test/bad-urls.test.js | 4 +- .../node/test/createOutgoingHttpHeaders.test.js | 76 ------------ .../integrations/node/test/node-middleware.test.js | 2 - .../node/test/prerender-404-500.test.js | 4 - packages/integrations/node/test/prerender.test.js | 4 - packages/integrations/node/test/test-utils.js | 2 + 20 files changed, 357 insertions(+), 528 deletions(-) delete mode 100644 packages/integrations/node/src/createOutgoingHttpHeaders.ts delete mode 100644 packages/integrations/node/src/get-network-address.ts delete mode 100644 packages/integrations/node/src/http-server.ts create mode 100644 packages/integrations/node/src/log-listening-on.ts create mode 100644 packages/integrations/node/src/middleware.ts delete mode 100644 packages/integrations/node/src/nodeMiddleware.ts create mode 100644 packages/integrations/node/src/serve-app.ts create mode 100644 packages/integrations/node/src/serve-static.ts delete mode 100644 packages/integrations/node/test/createOutgoingHttpHeaders.test.js (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index c3d952840..347eba0d6 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -37,7 +37,7 @@ "server-destroy": "^1.0.1" }, "peerDependencies": { - "astro": "^4.0.0" + "astro": "^4.2.0" }, "devDependencies": { "@types/node": "^18.17.8", diff --git a/packages/integrations/node/src/createOutgoingHttpHeaders.ts b/packages/integrations/node/src/createOutgoingHttpHeaders.ts deleted file mode 100644 index 44bbf81ca..000000000 --- a/packages/integrations/node/src/createOutgoingHttpHeaders.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { OutgoingHttpHeaders } from 'node:http'; - -/** - * Takes in a nullable WebAPI Headers object and produces a NodeJS OutgoingHttpHeaders object suitable for usage - * with ServerResponse.writeHead(..) or ServerResponse.setHeader(..) - * - * @param webHeaders WebAPI Headers object - * @returns NodeJS OutgoingHttpHeaders object with multiple set-cookie handled as an array of values - */ -export const createOutgoingHttpHeaders = ( - headers: Headers | undefined | null -): OutgoingHttpHeaders | undefined => { - if (!headers) { - return undefined; - } - - // at this point, a multi-value'd set-cookie header is invalid (it was concatenated as a single CSV, which is not valid for set-cookie) - const nodeHeaders: OutgoingHttpHeaders = Object.fromEntries(headers.entries()); - - if (Object.keys(nodeHeaders).length === 0) { - return undefined; - } - - // if there is > 1 set-cookie header, we have to fix it to be an array of values - if (headers.has('set-cookie')) { - const cookieHeaders = headers.getSetCookie(); - if (cookieHeaders.length > 1) { - // the Headers.entries() API already normalized all header names to lower case so we can safely index this as 'set-cookie' - nodeHeaders['set-cookie'] = cookieHeaders; - } - } - - return nodeHeaders; -}; diff --git a/packages/integrations/node/src/get-network-address.ts b/packages/integrations/node/src/get-network-address.ts deleted file mode 100644 index 3834c7617..000000000 --- a/packages/integrations/node/src/get-network-address.ts +++ /dev/null @@ -1,48 +0,0 @@ -import os from 'os'; -interface NetworkAddressOpt { - local: string[]; - network: string[]; -} - -const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']); -type Protocol = 'http' | 'https'; - -// this code from vite https://github.com/vitejs/vite/blob/d09bbd093a4b893e78f0bbff5b17c7cf7821f403/packages/vite/src/node/utils.ts#L892-L914 -export function getNetworkAddress( - protocol: Protocol = 'http', - hostname: string | undefined, - port: number, - base?: string -) { - const NetworkAddress: NetworkAddressOpt = { - local: [], - network: [], - }; - Object.values(os.networkInterfaces()) - .flatMap((nInterface) => nInterface ?? []) - .filter( - (detail) => - detail && - detail.address && - (detail.family === 'IPv4' || - // @ts-expect-error Node 18.0 - 18.3 returns number - detail.family === 4) - ) - .forEach((detail) => { - let host = detail.address.replace( - '127.0.0.1', - hostname === undefined || wildcardHosts.has(hostname) ? 'localhost' : hostname - ); - // ipv6 host - if (host.includes(':')) { - host = `[${host}]`; - } - const url = `${protocol}://${host}:${port}${base ? base : ''}`; - if (detail.address.includes('127.0.0.1')) { - NetworkAddress.local.push(url); - } else { - NetworkAddress.network.push(url); - } - }); - return NetworkAddress; -} diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts deleted file mode 100644 index 904937601..000000000 --- a/packages/integrations/node/src/http-server.ts +++ /dev/null @@ -1,131 +0,0 @@ -import https from 'https'; -import fs from 'node:fs'; -import http from 'node:http'; -import { fileURLToPath } from 'node:url'; -import send from 'send'; -import enableDestroy from 'server-destroy'; - -interface CreateServerOptions { - client: URL; - port: number; - host: string | undefined; - removeBase: (pathname: string) => string; - assets: string; -} - -function parsePathname(pathname: string, host: string | undefined, port: number) { - try { - const urlPathname = new URL(pathname, `http://${host}:${port}`).pathname; - return decodeURI(encodeURI(urlPathname)); - } catch (err) { - return undefined; - } -} - -export function createServer( - { client, port, host, removeBase, assets }: CreateServerOptions, - handler: http.RequestListener -) { - // The `base` is removed before passed to this function, so we don't - // need to check for it here. - const assetsPrefix = `/${assets}/`; - function isImmutableAsset(pathname: string) { - return pathname.startsWith(assetsPrefix); - } - - const listener: http.RequestListener = (req, res) => { - if (req.url) { - let pathname: string | undefined = removeBase(req.url); - pathname = pathname[0] === '/' ? pathname : '/' + pathname; - const encodedURI = parsePathname(pathname, host, port); - - if (!encodedURI) { - res.writeHead(400); - res.end('Bad request.'); - return res; - } - - const stream = send(req, encodedURI, { - root: fileURLToPath(client), - dotfiles: pathname.startsWith('/.well-known/') ? 'allow' : 'deny', - }); - - let forwardError = false; - - stream.on('error', (err) => { - if (forwardError) { - console.error(err.toString()); - res.writeHead(500); - res.end('Internal server error'); - return; - } - // File not found, forward to the SSR handler - handler(req, res); - }); - stream.on('headers', (_res: http.ServerResponse) => { - if (isImmutableAsset(encodedURI)) { - // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#immutable - _res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); - } - }); - stream.on('directory', () => { - // On directory find, redirect to the trailing slash - let location: string; - if (req.url!.includes('?')) { - const [url = '', search] = req.url!.split('?'); - location = `${url}/?${search}`; - } else { - location = req.url + '/'; - } - - res.statusCode = 301; - res.setHeader('Location', location); - res.end(location); - }); - stream.on('file', () => { - forwardError = true; - }); - stream.pipe(res); - } else { - handler(req, res); - } - }; - - let httpServer: - | http.Server - | https.Server; - - if (process.env.SERVER_CERT_PATH && process.env.SERVER_KEY_PATH) { - httpServer = https.createServer( - { - key: fs.readFileSync(process.env.SERVER_KEY_PATH), - cert: fs.readFileSync(process.env.SERVER_CERT_PATH), - }, - listener - ); - } else { - httpServer = http.createServer(listener); - } - httpServer.listen(port, host); - enableDestroy(httpServer); - - // Resolves once the server is closed - const closed = new Promise((resolve, reject) => { - httpServer.addListener('close', resolve); - httpServer.addListener('error', reject); - }); - - return { - host, - port, - closed() { - return closed; - }, - server: httpServer, - stop: async () => { - await new Promise((resolve, reject) => { - httpServer.destroy((err) => (err ? reject(err) : resolve(undefined))); - }); - }, - }; -} diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index bac5c25ef..e7d655403 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -1,6 +1,7 @@ -import type { AstroAdapter, AstroIntegration } from 'astro'; import { AstroError } from 'astro/errors'; +import type { AstroAdapter, AstroIntegration } from 'astro'; import type { Options, UserOptions } from './types.js'; + export function getAdapter(options: Options): AstroAdapter { return { name: '@astrojs/node', diff --git a/packages/integrations/node/src/log-listening-on.ts b/packages/integrations/node/src/log-listening-on.ts new file mode 100644 index 000000000..4f56b3ee8 --- /dev/null +++ b/packages/integrations/node/src/log-listening-on.ts @@ -0,0 +1,84 @@ +import os from "node:os"; +import type http from "node:http"; +import https from "node:https"; +import type { AstroIntegrationLogger } from "astro"; +import type { Options } from './types.js'; +import type { AddressInfo } from "node:net"; + +export async function logListeningOn(logger: AstroIntegrationLogger, server: http.Server | https.Server, options: Pick) { + await new Promise(resolve => server.once('listening', resolve)) + const protocol = server instanceof https.Server ? 'https' : 'http'; + // Allow to provide host value at runtime + const host = getResolvedHostForHttpServer( + process.env.HOST !== undefined && process.env.HOST !== '' ? process.env.HOST : options.host + ); + const { port } = server.address() as AddressInfo; + const address = getNetworkAddress(protocol, host, port); + + if (host === undefined) { + logger.info( + `Server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n` + ); + } else { + logger.info(`Server listening on ${address.local[0]}`); + } +} + +function getResolvedHostForHttpServer(host: string | boolean) { + if (host === false) { + // Use a secure default + return 'localhost'; + } else if (host === true) { + // If passed --host in the CLI without arguments + return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs) + } else { + return host; + } +} + +interface NetworkAddressOpt { + local: string[]; + network: string[]; +} + +const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']); + +// this code from vite https://github.com/vitejs/vite/blob/d09bbd093a4b893e78f0bbff5b17c7cf7821f403/packages/vite/src/node/utils.ts#L892-L914 +export function getNetworkAddress( + protocol: 'http' | 'https' = 'http', + hostname: string | undefined, + port: number, + base?: string +) { + const NetworkAddress: NetworkAddressOpt = { + local: [], + network: [], + }; + Object.values(os.networkInterfaces()) + .flatMap((nInterface) => nInterface ?? []) + .filter( + (detail) => + detail && + detail.address && + (detail.family === 'IPv4' || + // @ts-expect-error Node 18.0 - 18.3 returns number + detail.family === 4) + ) + .forEach((detail) => { + let host = detail.address.replace( + '127.0.0.1', + hostname === undefined || wildcardHosts.has(hostname) ? 'localhost' : hostname + ); + // ipv6 host + if (host.includes(':')) { + host = `[${host}]`; + } + const url = `${protocol}://${host}:${port}${base ? base : ''}`; + if (detail.address.includes('127.0.0.1')) { + NetworkAddress.local.push(url); + } else { + NetworkAddress.network.push(url); + } + }); + return NetworkAddress; +} diff --git a/packages/integrations/node/src/middleware.ts b/packages/integrations/node/src/middleware.ts new file mode 100644 index 000000000..a936dc5bc --- /dev/null +++ b/packages/integrations/node/src/middleware.ts @@ -0,0 +1,43 @@ +import { createAppHandler } from './serve-app.js'; +import type { RequestHandler } from "./types.js"; +import type { NodeApp } from "astro/app/node"; + +/** + * Creates a middleware that can be used with Express, Connect, etc. + * + * Similar to `createAppHandler` but can additionally be placed in the express + * chain as an error middleware. + * + * https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling + */ +export default function createMiddleware( + app: NodeApp, +): RequestHandler { + const handler = createAppHandler(app) + const logger = app.getAdapterLogger() + // using spread args because express trips up if the function's + // stringified body includes req, res, next, locals directly + return async function (...args) { + // assume normal invocation at first + const [req, res, next, locals] = args; + // short circuit if it is an error invocation + if (req instanceof Error) { + const error = req; + if (next) { + return next(error); + } else { + throw error; + } + } + try { + await handler(req, res, next, locals); + } catch (err) { + logger.error(`Could not render ${req.url}`); + console.error(err); + if (!res.headersSent) { + res.writeHead(500, `Server error`); + res.end(); + } + } + } +} diff --git a/packages/integrations/node/src/nodeMiddleware.ts b/packages/integrations/node/src/nodeMiddleware.ts deleted file mode 100644 index a13cc5da3..000000000 --- a/packages/integrations/node/src/nodeMiddleware.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type { NodeApp } from 'astro/app/node'; -import type { ServerResponse } from 'node:http'; -import { createOutgoingHttpHeaders } from './createOutgoingHttpHeaders.js'; -import type { ErrorHandlerParams, Options, RequestHandlerParams } from './types.js'; -import type { AstroIntegrationLogger } from 'astro'; - -// Disable no-unused-vars to avoid breaking signature change -export default function (app: NodeApp, mode: Options['mode']) { - return async function (...args: RequestHandlerParams | ErrorHandlerParams) { - let error = null; - let locals; - let [req, res, next] = args as RequestHandlerParams; - if (mode === 'middleware') { - let { [3]: _locals } = args; - locals = _locals; - } - - if (args[0] instanceof Error) { - [error, req, res, next] = args as ErrorHandlerParams; - if (mode === 'middleware') { - let { [4]: _locals } = args as ErrorHandlerParams; - locals = _locals; - } - if (error) { - if (next) { - return next(error); - } else { - throw error; - } - } - } - - const logger = app.getAdapterLogger(); - - try { - const routeData = app.match(req); - if (routeData) { - try { - const response = await app.render(req, { routeData, locals }); - await writeWebResponse(app, res, response, logger); - } catch (err: unknown) { - if (next) { - next(err); - } else { - throw err; - } - } - } else if (next) { - return next(); - } else { - const response = await app.render(req); - await writeWebResponse(app, res, response, logger); - } - } catch (err: unknown) { - logger.error(`Could not render ${req.url}`); - console.error(err); - if (!res.headersSent) { - res.writeHead(500, `Server error`); - res.end(); - } - } - }; -} - -async function writeWebResponse( - app: NodeApp, - res: ServerResponse, - webResponse: Response, - logger: AstroIntegrationLogger -) { - const { status, headers, body } = webResponse; - - if (app.setCookieHeaders) { - const setCookieHeaders: Array = Array.from(app.setCookieHeaders(webResponse)); - - if (setCookieHeaders.length) { - for (const setCookieHeader of setCookieHeaders) { - headers.append('set-cookie', setCookieHeader); - } - } - } - - const nodeHeaders = createOutgoingHttpHeaders(headers); - res.writeHead(status, nodeHeaders); - if (body) { - try { - const reader = body.getReader(); - res.on('close', () => { - // Cancelling the reader may reject not just because of - // an error in the ReadableStream's cancel callback, but - // also because of an error anywhere in the stream. - reader.cancel().catch((err) => { - logger.error( - `There was an uncaught error in the middle of the stream while rendering ${res.req.url}.` - ); - console.error(err); - }); - }); - let result = await reader.read(); - while (!result.done) { - res.write(result.value); - result = await reader.read(); - } - // the error will be logged by the "on end" callback above - } catch { - res.write('Internal server error'); - } - } - res.end(); -} diff --git a/packages/integrations/node/src/preview.ts b/packages/integrations/node/src/preview.ts index 89baa1897..26b91756c 100644 --- a/packages/integrations/node/src/preview.ts +++ b/packages/integrations/node/src/preview.ts @@ -1,26 +1,19 @@ -import type { CreatePreviewServer } from 'astro'; -import { AstroError } from 'astro/errors'; -import type http from 'node:http'; import { fileURLToPath } from 'node:url'; -import { getNetworkAddress } from './get-network-address.js'; -import { createServer } from './http-server.js'; +import { AstroError } from 'astro/errors'; +import { logListeningOn } from './log-listening-on.js'; +import { createServer } from './standalone.js'; +import type { CreatePreviewServer } from 'astro'; import type { createExports } from './server.js'; -const preview: CreatePreviewServer = async function ({ - client, - serverEntrypoint, - host, - port, - base, - logger, -}) { - type ServerModule = ReturnType; - type MaybeServerModule = Partial; +type ServerModule = ReturnType; +type MaybeServerModule = Partial; + +const createPreviewServer: CreatePreviewServer = async function (preview) { let ssrHandler: ServerModule['handler']; let options: ServerModule['options']; try { process.env.ASTRO_NODE_AUTOSTART = 'disabled'; - const ssrModule: MaybeServerModule = await import(serverEntrypoint.toString()); + const ssrModule: MaybeServerModule = await import(preview.serverEntrypoint.toString()); if (typeof ssrModule.handler === 'function') { ssrHandler = ssrModule.handler; options = ssrModule.options!; @@ -33,49 +26,23 @@ const preview: CreatePreviewServer = async function ({ if ((err as any).code === 'ERR_MODULE_NOT_FOUND') { throw new AstroError( `The server entrypoint ${fileURLToPath( - serverEntrypoint + preview.serverEntrypoint )} does not exist. Have you ran a build yet?` ); } else { throw err; } } - - const handler: http.RequestListener = (req, res) => { - ssrHandler(req, res); - }; - - const baseWithoutTrailingSlash: string = base.endsWith('/') - ? base.slice(0, base.length - 1) - : base; - function removeBase(pathname: string): string { - if (pathname.startsWith(base)) { - return pathname.slice(baseWithoutTrailingSlash.length); - } - return pathname; - } - - const server = createServer( - { - client, - port, - host, - removeBase, - assets: options.assets, - }, - handler - ); - const address = getNetworkAddress('http', host, port); - - if (host === undefined) { - logger.info( - `Preview server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n` - ); - } else { - logger.info(`Preview server listening on ${address.local[0]}`); - } - + const host = preview.host ?? "localhost" + const port = preview.port ?? 4321 + const server = createServer(ssrHandler, host, port); + logListeningOn(preview.logger, server.server, options) + await new Promise((resolve, reject) => { + server.server.once('listening', resolve); + server.server.once('error', reject); + server.server.listen(port, host); + }); return server; }; -export { preview as default }; +export { createPreviewServer as default } diff --git a/packages/integrations/node/src/serve-app.ts b/packages/integrations/node/src/serve-app.ts new file mode 100644 index 000000000..51ef31575 --- /dev/null +++ b/packages/integrations/node/src/serve-app.ts @@ -0,0 +1,27 @@ +import { NodeApp } from "astro/app/node" +import type { RequestHandler } from "./types.js"; + +/** + * Creates a Node.js http listener for on-demand rendered pages, compatible with http.createServer and Connect middleware. + * If the next callback is provided, it will be called if the request does not have a matching route. + * Intended to be used in both standalone and middleware mode. + */ +export function createAppHandler(app: NodeApp): RequestHandler { + return async (req, res, next, locals) => { + const request = NodeApp.createRequest(req); + const routeData = app.match(request); + if (routeData) { + const response = await app.render(request, { + addCookieHeader: true, + locals, + routeData, + }); + await NodeApp.writeResponse(response, res); + } else if (next) { + return next(); + } else { + const response = await app.render(req); + await NodeApp.writeResponse(response, res); + } + } +} diff --git a/packages/integrations/node/src/serve-static.ts b/packages/integrations/node/src/serve-static.ts new file mode 100644 index 000000000..ee3bdaf79 --- /dev/null +++ b/packages/integrations/node/src/serve-static.ts @@ -0,0 +1,86 @@ +import path from "node:path"; +import url from "node:url"; +import send from "send"; +import type { IncomingMessage, ServerResponse } from "node:http"; +import type { Options } from "./types.js"; +import type { NodeApp } from "astro/app/node"; + +/** + * Creates a Node.js http listener for static files and prerendered pages. + * In standalone mode, the static handler is queried first for the static files. + * If one matching the request path is not found, it relegates to the SSR handler. + * Intended to be used only in the standalone mode. + */ +export function createStaticHandler(app: NodeApp, options: Options) { + const client = resolveClientDir(options); + /** + * @param ssr The SSR handler to be called if the static handler does not find a matching file. + */ + return (req: IncomingMessage, res: ServerResponse, ssr: () => unknown) => { + if (req.url) { + let pathname = app.removeBase(req.url); + pathname = decodeURI(new URL(pathname, 'http://host').pathname); + + const stream = send(req, pathname, { + root: client, + dotfiles: pathname.startsWith('/.well-known/') ? 'allow' : 'deny', + }); + + let forwardError = false; + + stream.on('error', (err) => { + if (forwardError) { + console.error(err.toString()); + res.writeHead(500); + res.end('Internal server error'); + return; + } + // File not found, forward to the SSR handler + ssr(); + }); + stream.on('headers', (_res: ServerResponse) => { + // assets in dist/_astro are hashed and should get the immutable header + if (pathname.startsWith(`/${options.assets}/`)) { + // This is the "far future" cache header, used for static files whose name includes their digest hash. + // 1 year (31,536,000 seconds) is convention. + // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#immutable + _res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); + } + }); + stream.on('directory', () => { + // On directory find, redirect to the trailing slash + let location: string; + if (req.url!.includes('?')) { + const [url1 = '', search] = req.url!.split('?'); + location = `${url1}/?${search}`; + } else { + location = appendForwardSlash(req.url!); + } + + res.statusCode = 301; + res.setHeader('Location', location); + res.end(location); + }); + stream.on('file', () => { + forwardError = true; + }); + stream.pipe(res); + } else { + ssr(); + } + }; +} + +function resolveClientDir(options: Options) { + const clientURLRaw = new URL(options.client); + const serverURLRaw = new URL(options.server); + const rel = path.relative(url.fileURLToPath(serverURLRaw), url.fileURLToPath(clientURLRaw)); + const serverEntryURL = new URL(import.meta.url); + const clientURL = new URL(appendForwardSlash(rel), serverEntryURL); + const client = url.fileURLToPath(clientURL); + return client; +} + +function appendForwardSlash(pth: string) { + return pth.endsWith('/') ? pth : pth + '/'; +} diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts index 88bcd7d62..5c2577ff8 100644 --- a/packages/integrations/node/src/server.ts +++ b/packages/integrations/node/src/server.ts @@ -1,7 +1,8 @@ -import type { SSRManifest } from 'astro'; import { NodeApp, applyPolyfills } from 'astro/app/node'; -import middleware from './nodeMiddleware.js'; +import { createStandaloneHandler } from './standalone.js'; import startServer from './standalone.js'; +import createMiddleware from './middleware.js'; +import type { SSRManifest } from 'astro'; import type { Options } from './types.js'; applyPolyfills(); @@ -9,7 +10,10 @@ export function createExports(manifest: SSRManifest, options: Options) { const app = new NodeApp(manifest); return { options: options, - handler: middleware(app, options.mode), + handler: + options.mode === "middleware" + ? createMiddleware(app) + : createStandaloneHandler(app, options), startServer: () => startServer(app, options), }; } diff --git a/packages/integrations/node/src/standalone.ts b/packages/integrations/node/src/standalone.ts index e167e8ab6..fc1875e97 100644 --- a/packages/integrations/node/src/standalone.ts +++ b/packages/integrations/node/src/standalone.ts @@ -1,75 +1,90 @@ -import type { NodeApp } from 'astro/app/node'; +import http from 'node:http'; import https from 'https'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { getNetworkAddress } from './get-network-address.js'; -import { createServer } from './http-server.js'; -import middleware from './nodeMiddleware.js'; +import fs from 'node:fs'; +import enableDestroy from 'server-destroy'; +import { createAppHandler } from './serve-app.js'; +import { createStaticHandler } from './serve-static.js'; +import { logListeningOn } from './log-listening-on.js'; +import type { NodeApp } from 'astro/app/node'; import type { Options } from './types.js'; +import type { PreviewServer } from 'astro'; -function resolvePaths(options: Options) { - const clientURLRaw = new URL(options.client); - const serverURLRaw = new URL(options.server); - const rel = path.relative(fileURLToPath(serverURLRaw), fileURLToPath(clientURLRaw)); - - const serverEntryURL = new URL(import.meta.url); - const clientURL = new URL(appendForwardSlash(rel), serverEntryURL); - +export default function standalone(app: NodeApp, options: Options) { + const port = process.env.PORT ? Number(process.env.PORT) : options.port ?? 8080; + // Allow to provide host value at runtime + const hostOptions = typeof options.host === "boolean" ? "localhost" : options.host + const host = process.env.HOST ?? hostOptions; + const handler = createStandaloneHandler(app, options); + const server = createServer(handler, host, port); + server.server.listen(port, host) + if (process.env.ASTRO_NODE_LOGGING !== "disabled") { + logListeningOn(app.getAdapterLogger(), server.server, options) + } return { - client: clientURL, + server, + done: server.closed(), }; } -function appendForwardSlash(pth: string) { - return pth.endsWith('/') ? pth : pth + '/'; -} - -export function getResolvedHostForHttpServer(host: string | boolean) { - if (host === false) { - // Use a secure default - return '127.0.0.1'; - } else if (host === true) { - // If passed --host in the CLI without arguments - return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs) - } else { - return host; +// also used by server entrypoint +export function createStandaloneHandler(app: NodeApp, options: Options) { + const appHandler = createAppHandler(app); + const staticHandler = createStaticHandler(app, options); + return (req: http.IncomingMessage, res: http.ServerResponse) => { + try { + // validate request path + decodeURI(req.url!); + } catch { + res.writeHead(400); + res.end('Bad request.'); + return; + } + staticHandler(req, res, () => appHandler(req, res)); } } -export default function startServer(app: NodeApp, options: Options) { - const logger = app.getAdapterLogger(); - const port = process.env.PORT ? Number(process.env.PORT) : options.port ?? 8080; - const { client } = resolvePaths(options); - const handler = middleware(app, options.mode); - - // Allow to provide host value at runtime - const host = getResolvedHostForHttpServer( - process.env.HOST !== undefined && process.env.HOST !== '' ? process.env.HOST : options.host - ); - const server = createServer( - { - client, - port, - host, - removeBase: app.removeBase.bind(app), - assets: options.assets, - }, - handler - ); - - const protocol = server.server instanceof https.Server ? 'https' : 'http'; - const address = getNetworkAddress(protocol, host, port); +// also used by preview entrypoint +export function createServer( + listener: http.RequestListener, + host: string, + port: number +) { + let httpServer: http.Server | https.Server; - if (host === undefined) { - logger.info( - `Server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n` + if (process.env.SERVER_CERT_PATH && process.env.SERVER_KEY_PATH) { + httpServer = https.createServer( + { + key: fs.readFileSync(process.env.SERVER_KEY_PATH), + cert: fs.readFileSync(process.env.SERVER_CERT_PATH), + }, + listener ); } else { - logger.info(`Server listening on ${address.local[0]}`); + httpServer = http.createServer(listener); } + enableDestroy(httpServer); + + // Resolves once the server is closed + const closed = new Promise((resolve, reject) => { + httpServer.addListener('close', resolve); + httpServer.addListener('error', reject); + }); + + const previewable = { + host, + port, + closed() { + return closed; + }, + async stop() { + await new Promise((resolve, reject) => { + httpServer.destroy((err) => (err ? reject(err) : resolve(undefined))); + }); + } + } satisfies PreviewServer; return { - server, - done: server.closed(), + server: httpServer, + ...previewable, }; } diff --git a/packages/integrations/node/src/types.ts b/packages/integrations/node/src/types.ts index 273b80529..9e4f4ce91 100644 --- a/packages/integrations/node/src/types.ts +++ b/packages/integrations/node/src/types.ts @@ -1,3 +1,4 @@ +import type { NodeApp } from 'astro/app/node'; import type { IncomingMessage, ServerResponse } from 'node:http'; export interface UserOptions { @@ -18,11 +19,19 @@ export interface Options extends UserOptions { assets: string; } +export interface CreateServerOptions { + app: NodeApp; + assets: string; + client: URL; + port: number; + host: string | undefined; + removeBase: (pathname: string) => string; +} + +export type RequestHandler = (...args: RequestHandlerParams) => void | Promise; export type RequestHandlerParams = [ req: IncomingMessage, res: ServerResponse, next?: (err?: unknown) => void, locals?: object, ]; - -export type ErrorHandlerParams = [unknown, ...RequestHandlerParams]; diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.js index 894729e36..bfef81278 100644 --- a/packages/integrations/node/test/bad-urls.test.js +++ b/packages/integrations/node/test/bad-urls.test.js @@ -34,9 +34,9 @@ describe('Bad URLs', () => { for (const weirdUrl of weirdURLs) { const fetchResult = await fixture.fetch(weirdUrl); - expect([400, 500]).to.include( + expect([400, 404, 500]).to.include( fetchResult.status, - `${weirdUrl} returned something else than 400 or 500` + `${weirdUrl} returned something else than 400, 404, or 500` ); } const stillWork = await fixture.fetch('/'); diff --git a/packages/integrations/node/test/createOutgoingHttpHeaders.test.js b/packages/integrations/node/test/createOutgoingHttpHeaders.test.js deleted file mode 100644 index 2f7063b1c..000000000 --- a/packages/integrations/node/test/createOutgoingHttpHeaders.test.js +++ /dev/null @@ -1,76 +0,0 @@ -import { expect } from 'chai'; - -import { createOutgoingHttpHeaders } from '../dist/createOutgoingHttpHeaders.js'; - -describe('createOutgoingHttpHeaders', () => { - it('undefined input headers', async () => { - const result = createOutgoingHttpHeaders(undefined); - expect(result).to.equal(undefined); - }); - - it('null input headers', async () => { - const result = createOutgoingHttpHeaders(undefined); - expect(result).to.equal(undefined); - }); - - it('Empty Headers', async () => { - const headers = new Headers(); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.equal(undefined); - }); - - it('Headers with single key', async () => { - const headers = new Headers(); - headers.append('x-test', 'hello world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ 'x-test': 'hello world' }); - }); - - it('Headers with multiple keys', async () => { - const headers = new Headers(); - headers.append('x-test1', 'hello'); - headers.append('x-test2', 'world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ 'x-test1': 'hello', 'x-test2': 'world' }); - }); - - it('Headers with multiple values (not set-cookie)', async () => { - const headers = new Headers(); - headers.append('x-test', 'hello'); - headers.append('x-test', 'world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ 'x-test': 'hello, world' }); - }); - - it('Headers with multiple values (set-cookie special case)', async () => { - const headers = new Headers(); - headers.append('set-cookie', 'hello'); - headers.append('set-cookie', 'world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ 'set-cookie': ['hello', 'world'] }); - }); - - it('Headers with multiple values (set-cookie case handling)', async () => { - const headers = new Headers(); - headers.append('Set-cookie', 'hello'); - headers.append('Set-Cookie', 'world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ 'set-cookie': ['hello', 'world'] }); - }); - - it('Headers with all use cases', async () => { - const headers = new Headers(); - headers.append('x-single', 'single'); - headers.append('x-triple', 'one'); - headers.append('x-triple', 'two'); - headers.append('x-triple', 'three'); - headers.append('Set-cookie', 'hello'); - headers.append('Set-Cookie', 'world'); - const result = createOutgoingHttpHeaders(headers); - expect(result).to.deep.equal({ - 'x-single': 'single', - 'x-triple': 'one, two, three', - 'set-cookie': ['hello', 'world'], - }); - }); -}); diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.js index 009f403c2..6b6785953 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.js @@ -21,7 +21,6 @@ describe('behavior from middleware, standalone', () => { let server; before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ root: './fixtures/node-middleware/', @@ -61,7 +60,6 @@ describe('behavior from middleware, middleware', () => { let server; before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ root: './fixtures/node-middleware/', diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.js index f8bf0778c..745a1958c 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.js @@ -21,7 +21,6 @@ describe('Prerender 404', () => { describe('With base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = true; fixture = await loadFixture({ @@ -107,7 +106,6 @@ describe('Prerender 404', () => { describe('Without base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = true; fixture = await loadFixture({ @@ -171,7 +169,6 @@ describe('Hybrid 404', () => { describe('With base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ // inconsequential config that differs between tests @@ -229,7 +226,6 @@ describe('Hybrid 404', () => { describe('Without base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ // inconsequential config that differs between tests diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 65e3b4cb2..0d87e7711 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -18,7 +18,6 @@ describe('Prerendering', () => { describe('With base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = true; fixture = await loadFixture({ @@ -86,7 +85,6 @@ describe('Prerendering', () => { describe('Without base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = true; fixture = await loadFixture({ @@ -151,7 +149,6 @@ describe('Hybrid rendering', () => { describe('With base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ base: '/some-base', @@ -217,7 +214,6 @@ describe('Hybrid rendering', () => { describe('Without base', async () => { before(async () => { - process.env.ASTRO_NODE_AUTOSTART = 'disabled'; process.env.PRERENDER = false; fixture = await loadFixture({ root: './fixtures/prerender/', diff --git a/packages/integrations/node/test/test-utils.js b/packages/integrations/node/test/test-utils.js index 70ceaed25..6c8c5d270 100644 --- a/packages/integrations/node/test/test-utils.js +++ b/packages/integrations/node/test/test-utils.js @@ -2,6 +2,8 @@ import httpMocks from 'node-mocks-http'; import { EventEmitter } from 'node:events'; import { loadFixture as baseLoadFixture } from '../../../astro/test/test-utils.js'; +process.env.ASTRO_NODE_AUTOSTART = "disabled"; +process.env.ASTRO_NODE_LOGGING = "disabled"; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture */ -- cgit v1.2.3 From 1901ed3ef5e798dd3b69e1b6c05db94b6a471ad2 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Wed, 24 Jan 2024 22:42:24 +0800 Subject: Fix env var replacement for export const prerender (#9807) --- packages/integrations/node/test/prerender.test.js | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 0d87e7711..84f599bcd 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,6 +140,44 @@ describe('Prerendering', () => { expect($('h1').text()).to.equal('Two'); }); }); + + describe('Dev', () => { + let devServer; + + before(async () => { + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fixture.fetch(`/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route', async () => { + const res = await fixture.fetch(`/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + }); }); describe('Hybrid rendering', () => { -- cgit v1.2.3 From f7f19bfa5b6b8d41a7ba3884d455961e817ec676 Mon Sep 17 00:00:00 2001 From: Marvin <32611659+msxdan@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:23:27 +0100 Subject: feat(node): add trailingSlash support (#9080) * feat(node): add trailing slash support * add changeset * test(node): add base route test in trailing-slash.js detected an infinite loop in base path when trailingSlash: never * fix(node): avoid infinite redirect when trailingSlash: never * address test failures after rebase pt.1 * address test failures after rebase pt.2 --------- Co-authored-by: lilnasy <69170106+lilnasy@users.noreply.github.com> --- packages/integrations/node/src/serve-static.ts | 62 +++- packages/integrations/node/src/server.ts | 1 + packages/integrations/node/src/types.ts | 2 + .../test/fixtures/trailing-slash/astro.config.mjs | 8 + .../node/test/fixtures/trailing-slash/package.json | 9 + .../fixtures/trailing-slash/src/pages/index.astro | 8 + .../fixtures/trailing-slash/src/pages/one.astro | 11 + packages/integrations/node/test/prerender.test.js | 16 +- packages/integrations/node/test/trailing-slash.js | 405 +++++++++++++++++++++ 9 files changed, 500 insertions(+), 22 deletions(-) create mode 100644 packages/integrations/node/test/fixtures/trailing-slash/astro.config.mjs create mode 100644 packages/integrations/node/test/fixtures/trailing-slash/package.json create mode 100644 packages/integrations/node/test/fixtures/trailing-slash/src/pages/index.astro create mode 100644 packages/integrations/node/test/fixtures/trailing-slash/src/pages/one.astro create mode 100644 packages/integrations/node/test/trailing-slash.js (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/src/serve-static.ts b/packages/integrations/node/src/serve-static.ts index 77de9b358..a88b1332f 100644 --- a/packages/integrations/node/src/serve-static.ts +++ b/packages/integrations/node/src/serve-static.ts @@ -1,5 +1,6 @@ import path from 'node:path'; import url from 'node:url'; +import fs from 'node:fs'; import send from 'send'; import type { IncomingMessage, ServerResponse } from 'node:http'; import type { Options } from './types.js'; @@ -18,8 +19,47 @@ export function createStaticHandler(app: NodeApp, options: Options) { */ return (req: IncomingMessage, res: ServerResponse, ssr: () => unknown) => { if (req.url) { - let pathname = app.removeBase(req.url); - pathname = decodeURI(new URL(pathname, 'http://host').pathname); + const [urlPath, urlQuery] = req.url.split('?'); + const filePath = path.join(client, app.removeBase(urlPath)); + + let pathname: string; + let isDirectory = false; + try { + isDirectory = fs.lstatSync(filePath).isDirectory(); + } catch {} + + const { trailingSlash = 'ignore' } = options; + + const hasSlash = urlPath.endsWith('/'); + switch (trailingSlash) { + case "never": + if (isDirectory && (urlPath != '/') && hasSlash) { + pathname = urlPath.slice(0, -1) + (urlQuery ? "?" + urlQuery : ""); + res.statusCode = 301; + res.setHeader('Location', pathname); + return res.end(); + } else pathname = urlPath; + // intentionally fall through + case "ignore": + { + if (isDirectory && !hasSlash) { + pathname = urlPath + "/index.html"; + } else + pathname = urlPath; + } + break; + case "always": + if (!hasSlash) { + pathname = urlPath + '/' +(urlQuery ? "?" + urlQuery : ""); + res.statusCode = 301; + res.setHeader('Location', pathname); + return res.end(); + } else + pathname = urlPath; + break; + } + // app.removeBase sometimes returns a path without a leading slash + pathname = prependForwardSlash(app.removeBase(pathname)); const stream = send(req, pathname, { root: client, @@ -47,20 +87,6 @@ export function createStaticHandler(app: NodeApp, options: Options) { _res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); } }); - stream.on('directory', () => { - // On directory find, redirect to the trailing slash - let location: string; - if (req.url!.includes('?')) { - const [url1 = '', search] = req.url!.split('?'); - location = `${url1}/?${search}`; - } else { - location = appendForwardSlash(req.url!); - } - - res.statusCode = 301; - res.setHeader('Location', location); - res.end(location); - }); stream.on('file', () => { forwardError = true; }); @@ -81,6 +107,10 @@ function resolveClientDir(options: Options) { return client; } +function prependForwardSlash(pth: string) { + return pth.startsWith('/') ? pth : '/' + pth; +} + function appendForwardSlash(pth: string) { return pth.endsWith('/') ? pth : pth + '/'; } diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts index d9f24cca5..73b59c53f 100644 --- a/packages/integrations/node/src/server.ts +++ b/packages/integrations/node/src/server.ts @@ -8,6 +8,7 @@ import type { Options } from './types.js'; applyPolyfills(); export function createExports(manifest: SSRManifest, options: Options) { const app = new NodeApp(manifest); + options.trailingSlash = manifest.trailingSlash; return { options: options, handler: diff --git a/packages/integrations/node/src/types.ts b/packages/integrations/node/src/types.ts index 9e4f4ce91..3c03dffac 100644 --- a/packages/integrations/node/src/types.ts +++ b/packages/integrations/node/src/types.ts @@ -1,5 +1,6 @@ import type { NodeApp } from 'astro/app/node'; import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { SSRManifest } from 'astro'; export interface UserOptions { /** @@ -17,6 +18,7 @@ export interface Options extends UserOptions { server: string; client: string; assets: string; + trailingSlash?: SSRManifest['trailingSlash']; } export interface CreateServerOptions { diff --git a/packages/integrations/node/test/fixtures/trailing-slash/astro.config.mjs b/packages/integrations/node/test/fixtures/trailing-slash/astro.config.mjs new file mode 100644 index 000000000..7ee28f213 --- /dev/null +++ b/packages/integrations/node/test/fixtures/trailing-slash/astro.config.mjs @@ -0,0 +1,8 @@ +import node from '@astrojs/node' + +export default { + base: '/some-base', + output: 'hybrid', + trailingSlash: 'never', + adapter: node({ mode: 'standalone' }) +}; diff --git a/packages/integrations/node/test/fixtures/trailing-slash/package.json b/packages/integrations/node/test/fixtures/trailing-slash/package.json new file mode 100644 index 000000000..50b7b7201 --- /dev/null +++ b/packages/integrations/node/test/fixtures/trailing-slash/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/node-trailingslash", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*", + "@astrojs/node": "workspace:*" + } +} diff --git a/packages/integrations/node/test/fixtures/trailing-slash/src/pages/index.astro b/packages/integrations/node/test/fixtures/trailing-slash/src/pages/index.astro new file mode 100644 index 000000000..a4c415519 --- /dev/null +++ b/packages/integrations/node/test/fixtures/trailing-slash/src/pages/index.astro @@ -0,0 +1,8 @@ + + + Index + + +

Index

+ + diff --git a/packages/integrations/node/test/fixtures/trailing-slash/src/pages/one.astro b/packages/integrations/node/test/fixtures/trailing-slash/src/pages/one.astro new file mode 100644 index 000000000..aa370d18d --- /dev/null +++ b/packages/integrations/node/test/fixtures/trailing-slash/src/pages/one.astro @@ -0,0 +1,11 @@ +--- +export const prerender = true; +--- + + + One + + +

One

+ + diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 84f599bcd..86a7d3a65 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -74,12 +74,14 @@ describe('Prerendering', () => { expect($('h1').text()).to.equal('Two'); }); - it('Omitting the trailing slash results in a redirect that includes the base', async () => { + it('Can render prerendered route without trailing slash', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/two`, { redirect: 'manual', }); - expect(res.status).to.equal(301); - expect(res.headers.get('location')).to.equal('/some-base/two/'); + const html = await res.text(); + const $ = cheerio.load(html); + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); }); }); @@ -241,12 +243,14 @@ describe('Hybrid rendering', () => { expect($('h1').text()).to.equal('One'); }); - it('Omitting the trailing slash results in a redirect that includes the base', async () => { + it('Can render prerendered route without trailing slash', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { redirect: 'manual', }); - expect(res.status).to.equal(301); - expect(res.headers.get('location')).to.equal('/some-base/one/'); + const html = await res.text(); + const $ = cheerio.load(html); + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); }); }); diff --git a/packages/integrations/node/test/trailing-slash.js b/packages/integrations/node/test/trailing-slash.js new file mode 100644 index 000000000..cdfef6d10 --- /dev/null +++ b/packages/integrations/node/test/trailing-slash.js @@ -0,0 +1,405 @@ +import nodejs from '../dist/index.js'; +import { loadFixture } from './test-utils.js'; +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; + +/** + * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture + */ + +async function load() { + const mod = await import(`./fixtures/trailing-slash/dist/server/entry.mjs?dropcache=${Date.now()}`); + return mod; +} + +describe('Trailing slash', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let server; + describe('Always', async () => { + describe('With base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + base: '/some-base', + output: 'hybrid', + trailingSlash: 'always', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with redirect', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/one/'); + }); + + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/one/?foo=bar'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + describe('Without base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + output: 'hybrid', + trailingSlash: 'always', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with redirect', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/one/'); + }); + + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/one/?foo=bar'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + }); + describe('Never', async () => { + describe('With base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + base: '/some-base', + output: 'hybrid', + trailingSlash: 'never', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with redirect', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/one'); + }); + + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`, { + redirect : 'manual' + }); + + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/some-base/one?foo=bar'); + }); + + it('Can render prerendered route with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + describe('Without base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + output: 'hybrid', + trailingSlash: 'never', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with redirect', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/`, { + redirect : 'manual' + }); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/one'); + }); + + it('Can render prerendered route with redirect and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`, { + redirect : 'manual' + }); + + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal('/one?foo=bar'); + }); + + it('Can render prerendered route and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + }); + describe('Ignore', async () => { + describe('With base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + base: '/some-base', + output: 'hybrid', + trailingSlash: 'ignore', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with slash', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/`, { + redirect : 'manual' + }); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route without slash', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { + redirect : 'manual' + }); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route with slash and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one/?foo=bar`, { + redirect : 'manual' + }); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route without slash and with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/some-base/one?foo=bar`, { + redirect : 'manual' + }); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + describe('Without base', async () => { + before(async () => { + process.env.ASTRO_NODE_AUTOSTART = 'disabled'; + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/trailing-slash/', + output: 'hybrid', + trailingSlash: 'ignore', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render prerendered base route', async () => { + const res = await fetch(`http://${server.host}:${server.port}`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Index'); + }); + + it('Can render prerendered route with slash', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route without slash', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route with slash and query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one/?foo=bar`, { + redirect : 'manual' + }); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route without slash and with query params', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one?foo=bar`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + }); + }); +}); + -- cgit v1.2.3 From 4f010d71a1416b5ff5b956cd84bf7afe86bf0530 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Thu, 25 Jan 2024 16:17:31 +0000 Subject: chore(@astrojs/node): use Node.js for testing (#9758) * chore(@astrojs/node): use Node.js for testing * revert file * address feedback * feedback * Run tests in a single process (#9823) * Run tests in a single process * Make test less flaky * chore: remove module --------- Co-authored-by: Bjorn Lu --- packages/integrations/node/package.json | 4 +- packages/integrations/node/test/api-route.test.js | 13 ++-- packages/integrations/node/test/assets.test.js | 7 +- packages/integrations/node/test/bad-urls.test.js | 11 ++- packages/integrations/node/test/encoded.test.js | 7 +- packages/integrations/node/test/errors.test.js | 29 ++++---- packages/integrations/node/test/headers.test.js | 5 +- packages/integrations/node/test/image.test.js | 7 +- packages/integrations/node/test/locals.test.js | 11 +-- .../integrations/node/test/node-middleware.test.js | 14 ++-- .../node/test/prerender-404-500.test.js | 83 +++++++++++---------- packages/integrations/node/test/prerender.test.js | 85 ++++++++++++---------- packages/integrations/node/test/test-utils.js | 8 ++ .../integrations/node/test/url-protocol.test.js | 11 +-- .../node/test/well-known-locations.test.js | 9 ++- 15 files changed, 166 insertions(+), 138 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index d23d1f339..d1811ce6f 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -30,7 +30,7 @@ "build": "astro-scripts build \"src/**/*.ts\" && tsc", "build:ci": "astro-scripts build \"src/**/*.ts\"", "dev": "astro-scripts dev \"src/**/*.ts\"", - "test": "mocha --exit --timeout 20000 test/" + "test": "astro-scripts test \"test/**/*.test.js\"" }, "dependencies": { "send": "^0.18.0", @@ -45,10 +45,8 @@ "@types/server-destroy": "^1.0.3", "astro": "workspace:*", "astro-scripts": "workspace:*", - "chai": "^4.3.7", "cheerio": "1.0.0-rc.12", "express": "^4.18.2", - "mocha": "^10.2.0", "node-mocks-http": "^1.13.0" }, "publishConfig": { diff --git a/packages/integrations/node/test/api-route.test.js b/packages/integrations/node/test/api-route.test.js index 313819188..80e99a2cc 100644 --- a/packages/integrations/node/test/api-route.test.js +++ b/packages/integrations/node/test/api-route.test.js @@ -1,7 +1,8 @@ import nodejs from '../dist/index.js'; import { loadFixture, createRequestAndResponse } from './test-utils.js'; -import { expect } from 'chai'; import crypto from 'node:crypto'; +import { describe, it, before } from 'node:test'; +import * as assert from 'node:assert/strict'; describe('API routes', () => { /** @type {import('./test-utils').Fixture} */ @@ -33,9 +34,9 @@ describe('API routes', () => { let json = JSON.parse(buffer.toString('utf-8')); - expect(json.length).to.equal(1); + assert.equal(json.length, 1); - expect(json[0].name).to.equal('Broccoli Soup'); + assert.equal(json[0].name, 'Broccoli Soup'); }); it('Can get binary data', async () => { @@ -54,7 +55,7 @@ describe('API routes', () => { let [out] = await done; let arr = Array.from(new Uint8Array(out.buffer)); - expect(arr).to.deep.equal([5, 4, 3, 2, 1]); + assert.deepEqual(arr, [5, 4, 3, 2, 1]); }); it('Can post large binary data', async () => { @@ -87,7 +88,7 @@ describe('API routes', () => { }); let [out] = await done; - expect(new Uint8Array(out.buffer)).to.deep.equal(expectedDigest); + assert.deepEqual(new Uint8Array(out.buffer), new Uint8Array(expectedDigest)); }); it('Can bail on streaming', async () => { @@ -106,6 +107,6 @@ describe('API routes', () => { await done; - expect(locals).to.deep.include({ cancelledByTheServer: true }); + assert.deepEqual(locals, { cancelledByTheServer: true }); }); }); diff --git a/packages/integrations/node/test/assets.test.js b/packages/integrations/node/test/assets.test.js index 9e44ab31d..bcd9bb4bd 100644 --- a/packages/integrations/node/test/assets.test.js +++ b/packages/integrations/node/test/assets.test.js @@ -1,4 +1,5 @@ -import { expect } from 'chai'; +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; import * as cheerio from 'cheerio'; @@ -30,7 +31,7 @@ describe('Assets', () => { it('Assets within the _astro folder should be given immutable headers', async () => { let response = await fixture.fetch('/text-file'); let cacheControl = response.headers.get('cache-control'); - expect(cacheControl).to.equal(null); + assert.equal(cacheControl, null); const html = await response.text(); const $ = cheerio.load(html); @@ -38,6 +39,6 @@ describe('Assets', () => { const fileURL = $('a').attr('href'); response = await fixture.fetch(fileURL); cacheControl = response.headers.get('cache-control'); - expect(cacheControl).to.equal('public, max-age=31536000, immutable'); + assert.equal(cacheControl, 'public, max-age=31536000, immutable'); }); }); diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.js index bfef81278..6d6c0a2e9 100644 --- a/packages/integrations/node/test/bad-urls.test.js +++ b/packages/integrations/node/test/bad-urls.test.js @@ -1,4 +1,5 @@ -import { expect } from 'chai'; +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; @@ -32,15 +33,17 @@ describe('Bad URLs', () => { '%20foobar%', ]; + const statusCodes = [400, 404, 500]; for (const weirdUrl of weirdURLs) { const fetchResult = await fixture.fetch(weirdUrl); - expect([400, 404, 500]).to.include( - fetchResult.status, + assert.equal( + statusCodes.includes(fetchResult.status), + true, `${weirdUrl} returned something else than 400, 404, or 500` ); } const stillWork = await fixture.fetch('/'); const text = await stillWork.text(); - expect(text).to.equal('Hello!'); + assert.equal(text, 'Hello!'); }); }); diff --git a/packages/integrations/node/test/encoded.test.js b/packages/integrations/node/test/encoded.test.js index bbd264777..2739fcfb7 100644 --- a/packages/integrations/node/test/encoded.test.js +++ b/packages/integrations/node/test/encoded.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture, createRequestAndResponse } from './test-utils.js'; -import { expect } from 'chai'; describe('Encoded Pathname', () => { /** @type {import('./test-utils').Fixture} */ @@ -25,7 +26,7 @@ describe('Encoded Pathname', () => { req.send(); const html = await text(); - expect(html).to.include('什么'); + assert.equal(html.includes('什么'), true); }); it('Can get a Markdown file', async () => { @@ -39,6 +40,6 @@ describe('Encoded Pathname', () => { req.send(); const html = await text(); - expect(html).to.include('什么'); + assert.equal(html.includes('什么'), true); }); }); diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index 6bb93023a..983187475 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; -import { expect } from 'chai'; import * as cheerio from 'cheerio'; describe('Errors', () => { @@ -13,21 +14,19 @@ describe('Errors', () => { }); await fixture.build(); }); - describe('Within the stream', async () => { - let devPreview; + let devPreview; - before(async () => { - devPreview = await fixture.preview(); - }); - after(async () => { - await devPreview.stop(); - }); - it('when mode is standalone', async () => { - const res = await fixture.fetch('/in-stream'); - const html = await res.text(); - const $ = cheerio.load(html); + before(async () => { + devPreview = await fixture.preview(); + }); + after(async () => { + await devPreview.stop(); + }); + it('when mode is standalone', async () => { + const res = await fixture.fetch('/in-stream'); + const html = await res.text(); + const $ = cheerio.load(html); - expect($('p').text().trim()).to.equal('Internal server error'); - }); + assert.equal($('p').text().trim(), 'Internal server error'); }); }); diff --git a/packages/integrations/node/test/headers.test.js b/packages/integrations/node/test/headers.test.js index 17cfd3701..6a08dca22 100644 --- a/packages/integrations/node/test/headers.test.js +++ b/packages/integrations/node/test/headers.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture, createRequestAndResponse } from './test-utils.js'; -import { expect } from 'chai'; describe('Node Adapter Headers', () => { /** @type {import('./test-utils').Fixture} */ @@ -143,5 +144,5 @@ async function runTest(url, expectedHeaders) { await done; const headers = res.getHeaders(); - expect(headers).to.deep.equal(expectedHeaders); + assert.deepEqual(headers, expectedHeaders); } diff --git a/packages/integrations/node/test/image.test.js b/packages/integrations/node/test/image.test.js index 7bbdadc12..b315c1a30 100644 --- a/packages/integrations/node/test/image.test.js +++ b/packages/integrations/node/test/image.test.js @@ -1,4 +1,5 @@ -import { expect } from 'chai'; +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; @@ -24,12 +25,12 @@ describe.skip('Image endpoint', () => { it('it returns images', async () => { const res = await fixture.fetch('/'); - expect(res.status).to.equal(200); + assert.equal(res.status, 200); const resImage = await fixture.fetch( '/_image?href=/_astro/some_penguin.97ef5f92.png&w=50&f=webp' ); - expect(resImage.status).to.equal(200); + assert.equal(resImage.status, 200); }); }); diff --git a/packages/integrations/node/test/locals.test.js b/packages/integrations/node/test/locals.test.js index bba8b2d34..e2a531cce 100644 --- a/packages/integrations/node/test/locals.test.js +++ b/packages/integrations/node/test/locals.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture, createRequestAndResponse } from './test-utils.js'; -import { expect } from 'chai'; describe('API routes', () => { /** @type {import('./test-utils').Fixture} */ @@ -28,7 +29,7 @@ describe('API routes', () => { let html = await text(); - expect(html).to.contain('

bar

'); + assert.equal(html.includes('

bar

'), true); }); it('Throws an error when provided non-objects as locals', async () => { @@ -41,7 +42,7 @@ describe('API routes', () => { req.send(); await done; - expect(res).to.deep.include({ statusCode: 500 }); + assert.equal(res.statusCode, 500); }); it('Can use locals added by astro middleware', async () => { @@ -56,7 +57,7 @@ describe('API routes', () => { const html = await text(); - expect(html).to.contain('

baz

'); + assert.equal(html.includes('

baz

'), true); }); it('Can access locals in API', async () => { @@ -75,6 +76,6 @@ describe('API routes', () => { let json = JSON.parse(buffer.toString('utf-8')); - expect(json.foo).to.equal('bar'); + assert.equal(json.foo, 'bar'); }); }); diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.js index 6b6785953..889f72315 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; -import { expect } from 'chai'; +import { loadFixture, waitServerListen } from './test-utils.js'; import * as cheerio from 'cheerio'; import express from 'express'; @@ -31,6 +32,7 @@ describe('behavior from middleware, standalone', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -43,13 +45,13 @@ describe('behavior from middleware, standalone', () => { it('when mode is standalone', async () => { const res = await fetch(`http://${server.host}:${server.port}/error-page`); - expect(res.status).to.equal(404); + assert.equal(res.status, 404); const html = await res.text(); const $ = cheerio.load(html); const body = $('body'); - expect(body.text()).to.equal('Page does not exist'); + assert.equal(body.text().includes('Page does not exist'), true); }); }); }); @@ -82,12 +84,12 @@ describe('behavior from middleware, middleware', () => { it('when mode is standalone', async () => { const res = await fetch(`http://localhost:8888/ssr`); - expect(res.status).to.equal(200); + assert.equal(res.status, 200); const html = await res.text(); const $ = cheerio.load(html); const body = $('body'); - expect(body.text()).to.contain("Here's a random number"); + assert.equal(body.text().includes("Here's a random number"), true); }); }); diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.js index 745a1958c..4195db0ec 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; -import { expect } from 'chai'; +import { loadFixture, waitServerListen } from './test-utils.js'; import * as cheerio from 'cheerio'; /** @@ -37,6 +38,7 @@ describe('Prerender 404', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -50,8 +52,8 @@ describe('Prerender 404', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Hello world!'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Hello world!'); }); it('Can handle prerendered 404', async () => { @@ -60,20 +62,20 @@ describe('Prerender 404', () => { const res2 = await fetch(url); const res3 = await fetch(url); - expect(res1.status).to.equal(404); - expect(res2.status).to.equal(404); - expect(res3.status).to.equal(404); + assert.equal(res1.status, 404); + assert.equal(res2.status, 404); + assert.equal(res3.status, 404); const html1 = await res1.text(); const html2 = await res2.text(); const html3 = await res3.text(); - expect(html1).to.equal(html2); - expect(html2).to.equal(html3); + assert.equal(html1, html2); + assert.equal(html2, html3); const $ = cheerio.load(html1); - expect($('body').text()).to.equal('Page does not exist'); + assert.equal($('body').text(), 'Page does not exist'); }); it(' Can handle prerendered 500 called indirectly', async () => { @@ -82,16 +84,16 @@ describe('Prerender 404', () => { const response2 = await fetch(url); const response3 = await fetch(url); - expect(response1.status).to.equal(500); + assert.equal(response1.status, 500); const html1 = await response1.text(); const html2 = await response2.text(); const html3 = await response3.text(); - expect(html1).to.contain('Something went wrong'); + assert.equal(html1.includes('Something went wrong'), true); - expect(html1).to.equal(html2); - expect(html2).to.equal(html3); + assert.equal(html1, html2); + assert.equal(html2, html3); }); it('prerendered 500 page includes expected styles', async () => { @@ -100,7 +102,7 @@ describe('Prerender 404', () => { const $ = cheerio.load(html); // length will be 0 if the stylesheet does not get included - expect($('style')).to.have.a.lengthOf(1); + assert.equal($('style').length, 1); }); }); @@ -121,6 +123,7 @@ describe('Prerender 404', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -134,8 +137,8 @@ describe('Prerender 404', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Hello world!'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Hello world!'); }); it('Can handle prerendered 404', async () => { @@ -144,20 +147,20 @@ describe('Prerender 404', () => { const res2 = await fetch(url); const res3 = await fetch(url); - expect(res1.status).to.equal(404); - expect(res2.status).to.equal(404); - expect(res3.status).to.equal(404); + assert.equal(res1.status, 404); + assert.equal(res2.status, 404); + assert.equal(res3.status, 404); const html1 = await res1.text(); const html2 = await res2.text(); const html3 = await res3.text(); - expect(html1).to.equal(html2); - expect(html2).to.equal(html3); + assert.equal(html1, html2); + assert.equal(html2, html3); const $ = cheerio.load(html1); - expect($('body').text()).to.equal('Page does not exist'); + assert.equal($('body').text(), 'Page does not exist'); }); }); }); @@ -184,6 +187,7 @@ describe('Hybrid 404', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -197,8 +201,8 @@ describe('Hybrid 404', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Hello world!'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Hello world!'); }); it('Can handle prerendered 404', async () => { @@ -207,20 +211,20 @@ describe('Hybrid 404', () => { const res2 = await fetch(url); const res3 = await fetch(url); - expect(res1.status).to.equal(404); - expect(res2.status).to.equal(404); - expect(res3.status).to.equal(404); + assert.equal(res1.status, 404); + assert.equal(res2.status, 404); + assert.equal(res3.status, 404); const html1 = await res1.text(); const html2 = await res2.text(); const html3 = await res3.text(); - expect(html1).to.equal(html2); - expect(html2).to.equal(html3); + assert.equal(html1, html2); + assert.equal(html2, html3); const $ = cheerio.load(html1); - expect($('body').text()).to.equal('Page does not exist'); + assert.equal($('body').text(), 'Page does not exist'); }); }); @@ -240,6 +244,7 @@ describe('Hybrid 404', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -253,8 +258,8 @@ describe('Hybrid 404', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Hello world!'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Hello world!'); }); it('Can handle prerendered 404', async () => { @@ -263,20 +268,20 @@ describe('Hybrid 404', () => { const res2 = await fetch(url); const res3 = await fetch(url); - expect(res1.status).to.equal(404); - expect(res2.status).to.equal(404); - expect(res3.status).to.equal(404); + assert.equal(res1.status, 404); + assert.equal(res2.status, 404); + assert.equal(res3.status, 404); const html1 = await res1.text(); const html2 = await res2.text(); const html3 = await res3.text(); - expect(html1).to.equal(html2); - expect(html2).to.equal(html3); + assert.equal(html1, html2); + assert.equal(html2, html3); const $ = cheerio.load(html1); - expect($('body').text()).to.equal('Page does not exist'); + assert.equal($('body').text(), 'Page does not exist'); }); }); }); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 86a7d3a65..ffa5563fa 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; -import { expect } from 'chai'; +import { loadFixture, waitServerListen } from './test-utils.js'; import * as cheerio from 'cheerio'; /** @@ -30,6 +31,7 @@ describe('Prerendering', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -43,8 +45,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route', async () => { @@ -52,8 +54,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route with redirect and query params', async () => { @@ -61,8 +63,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route with query params', async () => { @@ -70,8 +72,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route without trailing slash', async () => { @@ -80,8 +82,9 @@ describe('Prerendering', () => { }); const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 301); + assert.equal(res.headers.get('location'), '/some-base/two/'); + assert.equal($('h1').text(), "Two") }); }); @@ -98,6 +101,7 @@ describe('Prerendering', () => { const { startServer } = await await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -111,8 +115,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route', async () => { @@ -120,8 +124,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route with redirect and query params', async () => { @@ -129,8 +133,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route with query params', async () => { @@ -138,8 +142,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); }); @@ -200,6 +204,7 @@ describe('Hybrid rendering', () => { const { startServer } = await await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -212,8 +217,8 @@ describe('Hybrid rendering', () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/two`); const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route', async () => { @@ -221,8 +226,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route with redirect and query params', async () => { @@ -230,8 +235,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route with query params', async () => { @@ -239,18 +244,17 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route without trailing slash', async () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { redirect: 'manual', }); - const html = await res.text(); - const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 301); + assert.equal(res.headers.get('location'), '/some-base/one/'); + assert.equal($('h1').text(), 'One'); }); }); @@ -266,6 +270,7 @@ describe('Hybrid rendering', () => { const { startServer } = await await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -279,8 +284,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); it('Can render prerendered route', async () => { @@ -288,8 +293,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route with redirect and query params', async () => { @@ -297,8 +302,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route with query params', async () => { @@ -306,8 +311,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); }); }); diff --git a/packages/integrations/node/test/test-utils.js b/packages/integrations/node/test/test-utils.js index 8d830fee9..3d582f30b 100644 --- a/packages/integrations/node/test/test-utils.js +++ b/packages/integrations/node/test/test-utils.js @@ -64,3 +64,11 @@ export function buffersToString(buffers) { } return str; } + +export function waitServerListen(server) { + return new Promise((resolve) => { + server.on('listening', () => { + resolve(); + }); + }); +} diff --git a/packages/integrations/node/test/url-protocol.test.js b/packages/integrations/node/test/url-protocol.test.js index a83cb2a41..444d47ed5 100644 --- a/packages/integrations/node/test/url-protocol.test.js +++ b/packages/integrations/node/test/url-protocol.test.js @@ -1,4 +1,5 @@ -import { expect } from 'chai'; +import * as assert from 'node:assert/strict'; +import { describe, it, before } from 'node:test'; import { TLSSocket } from 'node:tls'; import nodejs from '../dist/index.js'; import { createRequestAndResponse, loadFixture } from './test-utils.js'; @@ -26,7 +27,7 @@ describe('URL protocol', () => { req.send(); const html = await text(); - expect(html).to.include('http:'); + assert.equal(html.includes('http:'), true); }); it('return https when secure', async () => { @@ -40,7 +41,7 @@ describe('URL protocol', () => { req.send(); const html = await text(); - expect(html).to.include('https:'); + assert.equal(html.includes('https:'), true); }); it('return http when the X-Forwarded-Proto header is set to http', async () => { @@ -54,7 +55,7 @@ describe('URL protocol', () => { req.send(); const html = await text(); - expect(html).to.include('http:'); + assert.equal(html.includes('http:'), true); }); it('return https when the X-Forwarded-Proto header is set to https', async () => { @@ -68,6 +69,6 @@ describe('URL protocol', () => { req.send(); const html = await text(); - expect(html).to.include('https:'); + assert.equal(html.includes('https:'), true); }); }); diff --git a/packages/integrations/node/test/well-known-locations.test.js b/packages/integrations/node/test/well-known-locations.test.js index 31f31bacd..934673cda 100644 --- a/packages/integrations/node/test/well-known-locations.test.js +++ b/packages/integrations/node/test/well-known-locations.test.js @@ -1,6 +1,7 @@ +import * as assert from 'node:assert/strict'; +import { describe, it, before, after } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; -import { expect } from 'chai'; describe('test URIs beginning with a dot', () => { /** @type {import('./test-utils').Fixture} */ @@ -29,17 +30,17 @@ describe('test URIs beginning with a dot', () => { it('can load a valid well-known URI', async () => { const res = await fixture.fetch('/.well-known/apple-app-site-association'); - expect(res.status).to.equal(200); + assert.equal(res.status, 200); const json = await res.json(); - expect(json).to.deep.equal({ applinks: {} }); + assert.notStrictEqual(json.applinks, {}); }); it('cannot load a dot folder that is not a well-known URI', async () => { const res = await fixture.fetch('/.hidden/file.json'); - expect(res.status).to.equal(404); + assert.equal(res.status, 404); }); }); }); -- cgit v1.2.3 From ddeb0ed8be7afbf1ab46ce2f565e0ad77d4d3ba7 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Thu, 25 Jan 2024 16:18:40 +0000 Subject: [ci] format --- packages/integrations/node/test/prerender.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index ffa5563fa..f55b835af 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -84,7 +84,7 @@ describe('Prerendering', () => { const $ = cheerio.load(html); assert.equal(res.status, 301); assert.equal(res.headers.get('location'), '/some-base/two/'); - assert.equal($('h1').text(), "Two") + assert.equal($('h1').text(), 'Two'); }); }); -- cgit v1.2.3 From 8a27b5eaa762468677ede21fac4b5c6cbc69bbf8 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 26 Jan 2024 17:17:32 +0000 Subject: fix(core): don't noop shared modules (#9828) * fix(core): don't noop shared modules * address feedback * add test * changeset * check astro pages * address feedback --------- Co-authored-by: Nate Moore --- .../node/test/fixtures/prerender/src/middleware.ts | 7 +++++ .../test/fixtures/prerender/src/pages/third.astro | 15 ++++++++++ .../node/test/fixtures/prerender/src/shared.ts | 1 + packages/integrations/node/test/prerender.test.js | 35 ++++++++++++++++++++-- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/integrations/node/test/fixtures/prerender/src/middleware.ts create mode 100644 packages/integrations/node/test/fixtures/prerender/src/pages/third.astro create mode 100644 packages/integrations/node/test/fixtures/prerender/src/shared.ts (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/fixtures/prerender/src/middleware.ts b/packages/integrations/node/test/fixtures/prerender/src/middleware.ts new file mode 100644 index 000000000..13d619d78 --- /dev/null +++ b/packages/integrations/node/test/fixtures/prerender/src/middleware.ts @@ -0,0 +1,7 @@ +import { shared } from './shared'; +export const onRequest = (ctx, next) => { + ctx.locals = { + name: shared, + }; + return next(); +}; diff --git a/packages/integrations/node/test/fixtures/prerender/src/pages/third.astro b/packages/integrations/node/test/fixtures/prerender/src/pages/third.astro new file mode 100644 index 000000000..e29377d88 --- /dev/null +++ b/packages/integrations/node/test/fixtures/prerender/src/pages/third.astro @@ -0,0 +1,15 @@ +--- +import { shared} from "../shared"; +export const prerender = false; + +const shared = Astro.locals.name; +--- + + + + One + + +

{shared}

+ + diff --git a/packages/integrations/node/test/fixtures/prerender/src/shared.ts b/packages/integrations/node/test/fixtures/prerender/src/shared.ts new file mode 100644 index 000000000..cd35843de --- /dev/null +++ b/packages/integrations/node/test/fixtures/prerender/src/shared.ts @@ -0,0 +1 @@ +export const shared = 'shared'; diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index f55b835af..597794be0 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -201,7 +201,7 @@ describe('Hybrid rendering', () => { adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await await load(); + const { startServer } = await load(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -267,7 +267,7 @@ describe('Hybrid rendering', () => { adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await await load(); + const { startServer } = await load(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -315,4 +315,35 @@ describe('Hybrid rendering', () => { assert.equal($('h1').text(), 'One'); }); }); + + describe('Shared modules', async () => { + before(async () => { + process.env.PRERENDER = false; + + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'hybrid', + adapter: nodejs({ mode: 'standalone' }), + }); + await fixture.build(); + const { startServer } = await load(); + let res = startServer(); + server = res.server; + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/third`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('shared'); + }); + }); }); -- cgit v1.2.3 From 4d23caed76081742ddffe99841f5a1cb672f8d99 Mon Sep 17 00:00:00 2001 From: Arsh <69170106+lilnasy@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:24:21 +0000 Subject: fix(NodeApp): fix responses with null bodies never completing (#9931) * fix(NodeApp): fix responses with null bodies never completing * add changeset * add test * chore(tests): restore correct assertions * adjust incorrect test * added Astro.redirect and Response.redirect test cases * updated incorrect HTTP status * adjust api-routes.test.js after cherry-pick * bup markdoc test timeout --------- Co-authored-by: Emanuele Stoppa Co-authored-by: Friedemann Sommer --- packages/integrations/node/test/api-route.test.js | 43 +++++++++++++++++++++- packages/integrations/node/test/errors.test.js | 23 ++++++++---- .../api-route/src/pages/astro-redirect.astro | 3 ++ .../test/fixtures/api-route/src/pages/redirect.ts | 5 +++ .../api-route/src/pages/response-redirect.ts | 5 +++ packages/integrations/node/test/prerender.test.js | 20 +++++----- 6 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 packages/integrations/node/test/fixtures/api-route/src/pages/astro-redirect.astro create mode 100644 packages/integrations/node/test/fixtures/api-route/src/pages/redirect.ts create mode 100644 packages/integrations/node/test/fixtures/api-route/src/pages/response-redirect.ts (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/api-route.test.js b/packages/integrations/node/test/api-route.test.js index 80e99a2cc..9e0165cb9 100644 --- a/packages/integrations/node/test/api-route.test.js +++ b/packages/integrations/node/test/api-route.test.js @@ -1,12 +1,16 @@ import nodejs from '../dist/index.js'; import { loadFixture, createRequestAndResponse } from './test-utils.js'; import crypto from 'node:crypto'; -import { describe, it, before } from 'node:test'; +import { describe, it, before, after } from 'node:test'; import * as assert from 'node:assert/strict'; describe('API routes', () => { /** @type {import('./test-utils').Fixture} */ let fixture; + /** @type {import('astro/src/@types/astro.js').PreviewServer} */ + let previewServer; + /** @type {URL} */ + let baseUri; before(async () => { fixture = await loadFixture({ @@ -15,8 +19,12 @@ describe('API routes', () => { adapter: nodejs({ mode: 'middleware' }), }); await fixture.build(); + previewServer = await fixture.preview(); + baseUri = new URL(`http://${previewServer.host ?? 'localhost'}:${previewServer.port}/`); }); + after(() => previewServer.stop()); + it('Can get the request body', async () => { const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); let { req, res, done } = createRequestAndResponse({ @@ -109,4 +117,37 @@ describe('API routes', () => { assert.deepEqual(locals, { cancelledByTheServer: true }); }); + + it('Can respond with SSR redirect', async () => { + const controller = new AbortController(); + setTimeout(() => controller.abort(), 1000); + const response = await fetch(new URL('/redirect', baseUri), { + redirect: 'manual', + signal: controller.signal, + }); + assert.equal(response.status, 302); + assert.equal(response.headers.get('location'), '/destination'); + }); + + it('Can respond with Astro.redirect', async () => { + const controller = new AbortController(); + setTimeout(() => controller.abort(), 1000); + const response = await fetch(new URL('/astro-redirect', baseUri), { + redirect: 'manual', + signal: controller.signal, + }); + assert.equal(response.status, 303); + assert.equal(response.headers.get('location'), '/destination'); + }); + + it('Can respond with Response.redirect', async () => { + const controller = new AbortController(); + setTimeout(() => controller.abort(), 1000); + const response = await fetch(new URL('/response-redirect', baseUri), { + redirect: 'manual', + signal: controller.signal, + }); + assert.equal(response.status, 307); + assert.equal(response.headers.get('location'), String(new URL('/destination', baseUri))); + }); }); diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index 76bff1326..8d54bcd4e 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -32,16 +32,25 @@ describe('Errors', () => { }); it('generator that throws called in template', async () => { + const result = ['

Astro

1', 'Internal server error']; + /** @type {Response} */ const res = await fixture.fetch('/generator'); const reader = res.body.getReader(); const decoder = new TextDecoder(); - const expect = async ({ done, value }) => { - const result = await reader.read(); - assert.equal(result.done, done); - if (!done) assert.equal(decoder.decode(result.value), value); - }; - await expect({ done: false, value: '

Astro

1Internal server error' }); - await expect({ done: true }); + const chunk1 = await reader.read(); + const chunk2 = await reader.read(); + const chunk3 = await reader.read(); + assert.equal(chunk1.done, false); + if (chunk2.done) { + assert.equal(decoder.decode(chunk1.value), result.join("")); + } + else if (chunk3.done) { + assert.equal(decoder.decode(chunk1.value), result[0]); + assert.equal(decoder.decode(chunk2.value), result[1]); + } + else { + throw new Error('The response should take at most 2 chunks.'); + } }); }); diff --git a/packages/integrations/node/test/fixtures/api-route/src/pages/astro-redirect.astro b/packages/integrations/node/test/fixtures/api-route/src/pages/astro-redirect.astro new file mode 100644 index 000000000..65a8765e8 --- /dev/null +++ b/packages/integrations/node/test/fixtures/api-route/src/pages/astro-redirect.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/destination', 303); +--- diff --git a/packages/integrations/node/test/fixtures/api-route/src/pages/redirect.ts b/packages/integrations/node/test/fixtures/api-route/src/pages/redirect.ts new file mode 100644 index 000000000..baf22c93e --- /dev/null +++ b/packages/integrations/node/test/fixtures/api-route/src/pages/redirect.ts @@ -0,0 +1,5 @@ +import { APIContext } from 'astro'; + +export async function GET({ redirect }: APIContext) { + return redirect('/destination'); +} diff --git a/packages/integrations/node/test/fixtures/api-route/src/pages/response-redirect.ts b/packages/integrations/node/test/fixtures/api-route/src/pages/response-redirect.ts new file mode 100644 index 000000000..1dfa8bb3c --- /dev/null +++ b/packages/integrations/node/test/fixtures/api-route/src/pages/response-redirect.ts @@ -0,0 +1,5 @@ +import { APIContext } from 'astro'; + +export async function GET({ url: requestUrl }: APIContext) { + return Response.redirect(new URL('/destination', requestUrl), 307); +} diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 597794be0..7036c913c 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -82,8 +82,7 @@ describe('Prerendering', () => { }); const html = await res.text(); const $ = cheerio.load(html); - assert.equal(res.status, 301); - assert.equal(res.headers.get('location'), '/some-base/two/'); + assert.equal(res.status, 200); assert.equal($('h1').text(), 'Two'); }); }); @@ -171,8 +170,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('One'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); }); it('Can render prerendered route', async () => { @@ -180,8 +179,8 @@ describe('Prerendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('Two'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); }); }); }); @@ -252,8 +251,9 @@ describe('Hybrid rendering', () => { const res = await fetch(`http://${server.host}:${server.port}/some-base/one`, { redirect: 'manual', }); - assert.equal(res.status, 301); - assert.equal(res.headers.get('location'), '/some-base/one/'); + const html = await res.text(); + const $ = cheerio.load(html); + assert.equal(res.status, 200); assert.equal($('h1').text(), 'One'); }); }); @@ -342,8 +342,8 @@ describe('Hybrid rendering', () => { const html = await res.text(); const $ = cheerio.load(html); - expect(res.status).to.equal(200); - expect($('h1').text()).to.equal('shared'); + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'shared'); }); }); }); -- cgit v1.2.3 From 26e5ccbfea2b59103d1e1b938f48269ed659a813 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 16 Feb 2024 14:02:18 +0000 Subject: chore: fix failing tests and skip some (#10141) --- packages/integrations/node/test/errors.test.js | 59 ++++++++++++++--------- packages/integrations/node/test/prerender.test.js | 6 +-- 2 files changed, 38 insertions(+), 27 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index 09fc9e734..c4212f058 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -23,32 +23,43 @@ describe('Errors', () => { await devPreview.stop(); }); - it('rejected promise in template', async () => { - const res = await fixture.fetch('/in-stream'); - const html = await res.text(); - const $ = cheerio.load(html); + it( + 'rejected promise in template', + { skip: true, todo: 'Review the response from the in-stream' }, + async () => { + const res = await fixture.fetch('/in-stream'); + const html = await res.text(); + const $ = cheerio.load(html); - assert.equal($('p').text().trim(), 'Internal server error'); - }); + assert.equal($('p').text().trim(), 'Internal server error'); + } + ); - it('generator that throws called in template', async () => { - const result = ['

Astro

1', 'Internal server error']; + it( + 'generator that throws called in template', + { skip: true, todo: 'Review the response from the generator' }, + async () => { + const result = ['

Astro

1', 'Internal server error']; - /** @type {Response} */ - const res = await fixture.fetch('/generator'); - const reader = res.body.getReader(); - const decoder = new TextDecoder(); - const chunk1 = await reader.read(); - const chunk2 = await reader.read(); - const chunk3 = await reader.read(); - assert.equal(chunk1.done, false); - if (chunk2.done) { - assert.equal(decoder.decode(chunk1.value), result.join('')); - } else if (chunk3.done) { - assert.equal(decoder.decode(chunk1.value), result[0]); - assert.equal(decoder.decode(chunk2.value), result[1]); - } else { - throw new Error('The response should take at most 2 chunks.'); + /** @type {Response} */ + const res = await fixture.fetch('/generator'); + const reader = res.body.getReader(); + const decoder = new TextDecoder(); + const chunk1 = await reader.read(); + const chunk2 = await reader.read(); + const chunk3 = await reader.read(); + assert.equal(chunk1.done, false); + console.log(chunk1); + console.log(chunk2); + console.log(chunk3); + if (chunk2.done) { + assert.equal(decoder.decode(chunk1.value), result.join('')); + } else if (chunk3.done) { + assert.equal(decoder.decode(chunk1.value), result[0]); + assert.equal(decoder.decode(chunk2.value), result[1]); + } else { + throw new Error('The response should take at most 2 chunks.'); + } } - }); + ); }); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 7036c913c..de570511e 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -190,7 +190,7 @@ describe('Hybrid rendering', () => { let fixture; let server; - describe('With base', async () => { + describe('With base', () => { before(async () => { process.env.PRERENDER = false; fixture = await loadFixture({ @@ -258,7 +258,7 @@ describe('Hybrid rendering', () => { }); }); - describe('Without base', async () => { + describe('Without base', () => { before(async () => { process.env.PRERENDER = false; fixture = await loadFixture({ @@ -316,7 +316,7 @@ describe('Hybrid rendering', () => { }); }); - describe('Shared modules', async () => { + describe('Shared modules', () => { before(async () => { process.env.PRERENDER = false; -- cgit v1.2.3 From 7106b81b28ebc782ee886d87dd83f4acb72d0850 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 21 Feb 2024 14:08:19 +0000 Subject: chore: use biome to sort imports - only test files (#10180) * chore: use biome to sort imports * do the sorting * Update package.json Co-authored-by: Bjorn Lu --------- Co-authored-by: Bjorn Lu --- packages/integrations/node/test/api-route.test.js | 8 ++++---- packages/integrations/node/test/assets.test.js | 4 ++-- packages/integrations/node/test/bad-urls.test.js | 2 +- packages/integrations/node/test/encoded.test.js | 4 ++-- packages/integrations/node/test/errors.test.js | 4 ++-- packages/integrations/node/test/headers.test.js | 4 ++-- packages/integrations/node/test/image.test.js | 2 +- packages/integrations/node/test/locals.test.js | 4 ++-- packages/integrations/node/test/node-middleware.test.js | 6 +++--- packages/integrations/node/test/prerender-404-500.test.js | 4 ++-- packages/integrations/node/test/prerender.test.js | 4 ++-- packages/integrations/node/test/url-protocol.test.js | 2 +- packages/integrations/node/test/well-known-locations.test.js | 2 +- 13 files changed, 25 insertions(+), 25 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/api-route.test.js b/packages/integrations/node/test/api-route.test.js index 9e0165cb9..804a5ccf4 100644 --- a/packages/integrations/node/test/api-route.test.js +++ b/packages/integrations/node/test/api-route.test.js @@ -1,8 +1,8 @@ -import nodejs from '../dist/index.js'; -import { loadFixture, createRequestAndResponse } from './test-utils.js'; -import crypto from 'node:crypto'; -import { describe, it, before, after } from 'node:test'; import * as assert from 'node:assert/strict'; +import crypto from 'node:crypto'; +import { after, before, describe, it } from 'node:test'; +import nodejs from '../dist/index.js'; +import { createRequestAndResponse, loadFixture } from './test-utils.js'; describe('API routes', () => { /** @type {import('./test-utils').Fixture} */ diff --git a/packages/integrations/node/test/assets.test.js b/packages/integrations/node/test/assets.test.js index bcd9bb4bd..0b71f94cd 100644 --- a/packages/integrations/node/test/assets.test.js +++ b/packages/integrations/node/test/assets.test.js @@ -1,8 +1,8 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; +import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; -import * as cheerio from 'cheerio'; describe('Assets', () => { /** @type {import('./test-utils').Fixture} */ diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.js index 6d6c0a2e9..cdc0158ff 100644 --- a/packages/integrations/node/test/bad-urls.test.js +++ b/packages/integrations/node/test/bad-urls.test.js @@ -1,5 +1,5 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; diff --git a/packages/integrations/node/test/encoded.test.js b/packages/integrations/node/test/encoded.test.js index 15b5654b1..edc6ae78b 100644 --- a/packages/integrations/node/test/encoded.test.js +++ b/packages/integrations/node/test/encoded.test.js @@ -1,7 +1,7 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before } from 'node:test'; +import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture, createRequestAndResponse } from './test-utils.js'; +import { createRequestAndResponse, loadFixture } from './test-utils.js'; describe('Encoded Pathname', () => { /** @type {import('./test-utils').Fixture} */ diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index c4212f058..95bb1be85 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -1,8 +1,8 @@ import assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; +import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; -import * as cheerio from 'cheerio'; describe('Errors', () => { let fixture; diff --git a/packages/integrations/node/test/headers.test.js b/packages/integrations/node/test/headers.test.js index b74af9952..00b1766c7 100644 --- a/packages/integrations/node/test/headers.test.js +++ b/packages/integrations/node/test/headers.test.js @@ -1,7 +1,7 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before } from 'node:test'; +import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture, createRequestAndResponse } from './test-utils.js'; +import { createRequestAndResponse, loadFixture } from './test-utils.js'; describe('Node Adapter Headers', () => { /** @type {import('./test-utils').Fixture} */ diff --git a/packages/integrations/node/test/image.test.js b/packages/integrations/node/test/image.test.js index b315c1a30..c4758f96b 100644 --- a/packages/integrations/node/test/image.test.js +++ b/packages/integrations/node/test/image.test.js @@ -1,5 +1,5 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; diff --git a/packages/integrations/node/test/locals.test.js b/packages/integrations/node/test/locals.test.js index a310c729d..6d2776079 100644 --- a/packages/integrations/node/test/locals.test.js +++ b/packages/integrations/node/test/locals.test.js @@ -1,7 +1,7 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before } from 'node:test'; +import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture, createRequestAndResponse } from './test-utils.js'; +import { createRequestAndResponse, loadFixture } from './test-utils.js'; describe('API routes', () => { /** @type {import('./test-utils').Fixture} */ diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.js index 889f72315..fa496e871 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.js @@ -1,9 +1,9 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; -import nodejs from '../dist/index.js'; -import { loadFixture, waitServerListen } from './test-utils.js'; +import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import express from 'express'; +import nodejs from '../dist/index.js'; +import { loadFixture, waitServerListen } from './test-utils.js'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.js index 4195db0ec..afa23a151 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.js @@ -1,8 +1,8 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; +import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; import { loadFixture, waitServerListen } from './test-utils.js'; -import * as cheerio from 'cheerio'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index de570511e..bf34fc99d 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -1,8 +1,8 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; +import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; import { loadFixture, waitServerListen } from './test-utils.js'; -import * as cheerio from 'cheerio'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture diff --git a/packages/integrations/node/test/url-protocol.test.js b/packages/integrations/node/test/url-protocol.test.js index 444d47ed5..94d53104b 100644 --- a/packages/integrations/node/test/url-protocol.test.js +++ b/packages/integrations/node/test/url-protocol.test.js @@ -1,5 +1,5 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before } from 'node:test'; +import { before, describe, it } from 'node:test'; import { TLSSocket } from 'node:tls'; import nodejs from '../dist/index.js'; import { createRequestAndResponse, loadFixture } from './test-utils.js'; diff --git a/packages/integrations/node/test/well-known-locations.test.js b/packages/integrations/node/test/well-known-locations.test.js index 39d7ccedb..0951d6c27 100644 --- a/packages/integrations/node/test/well-known-locations.test.js +++ b/packages/integrations/node/test/well-known-locations.test.js @@ -1,5 +1,5 @@ import * as assert from 'node:assert/strict'; -import { describe, it, before, after } from 'node:test'; +import { after, before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; import { loadFixture } from './test-utils.js'; -- cgit v1.2.3 From f79886cb8e8787dd84b24727ae5c7629bab1e363 Mon Sep 17 00:00:00 2001 From: Raz Luvaton <16746759+rluvaton@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:30:59 +0100 Subject: test(@astrojs/node) wait for server listening in trailing-slash tests (#10694) * test(@astrojs/node) wait for server listening in trailing-slash tests * fix missing waitServerListen * fix import statement --------- Co-authored-by: Emanuele Stoppa --- packages/integrations/node/test/prerender.test.js | 1 + packages/integrations/node/test/trailing-slash.test.js | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index bf34fc99d..29080981a 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -329,6 +329,7 @@ describe('Hybrid rendering', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { diff --git a/packages/integrations/node/test/trailing-slash.test.js b/packages/integrations/node/test/trailing-slash.test.js index 79d5d247a..ad91a2759 100644 --- a/packages/integrations/node/test/trailing-slash.test.js +++ b/packages/integrations/node/test/trailing-slash.test.js @@ -2,7 +2,7 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { loadFixture, waitServerListen } from './test-utils.js'; /** * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture @@ -36,6 +36,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -101,6 +102,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -169,6 +171,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -227,6 +230,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -288,6 +292,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { @@ -364,6 +369,7 @@ describe('Trailing slash', () => { const { startServer } = await load(); let res = startServer(); server = res.server; + await waitServerListen(server.server); }); after(async () => { -- cgit v1.2.3 From 7a816ccbc3eecba74a93fec3f48236063b5c1df6 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Mon, 17 Jun 2024 14:23:10 +0800 Subject: Refactor prerendering chunk handling (#11245) --- .../integrations/node/test/node-middleware.test.js | 11 +---- .../node/test/prerender-404-500.test.js | 35 +++++++++++----- packages/integrations/node/test/prerender.test.js | 44 +++++++++++++++---- .../integrations/node/test/trailing-slash.test.js | 49 ++++++++++++++++------ 4 files changed, 97 insertions(+), 42 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.js index fa496e871..d1b016a51 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.js @@ -9,13 +9,6 @@ import { loadFixture, waitServerListen } from './test-utils.js'; * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture */ -async function load() { - const mod = await import( - `./fixtures/node-middleware/dist/server/entry.mjs?dropcache=${Date.now()}` - ); - return mod; -} - describe('behavior from middleware, standalone', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -29,7 +22,7 @@ describe('behavior from middleware, standalone', () => { adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -69,7 +62,7 @@ describe('behavior from middleware, middleware', () => { adapter: nodejs({ mode: 'middleware' }), }); await fixture.build(); - const { handler } = await load(); + const { handler } = await fixture.loadAdapterEntryModule(); const app = express(); app.use(handler); server = app.listen(8888); diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.js index afa23a151..2535fcb35 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.js @@ -8,13 +8,6 @@ import { loadFixture, waitServerListen } from './test-utils.js'; * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture */ -async function load() { - const mod = await import( - `./fixtures/prerender-404-500/dist/server/entry.mjs?dropcache=${Date.now()}` - ); - return mod; -} - describe('Prerender 404', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -32,10 +25,15 @@ describe('Prerender 404', () => { base: '/some-base', root: './fixtures/prerender-404-500/', output: 'server', + outDir: './dist/server-with-base', + build: { + client: './dist/server-with-base/client', + server: './dist/server-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -117,10 +115,15 @@ describe('Prerender 404', () => { site: 'https://test.info/', root: './fixtures/prerender-404-500/', output: 'server', + outDir: './dist/server-without-base', + build: { + client: './dist/server-without-base/client', + server: './dist/server-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -181,10 +184,15 @@ describe('Hybrid 404', () => { base: '/some-base', root: './fixtures/prerender-404-500/', output: 'hybrid', + outDir: './dist/hybrid-with-base', + build: { + client: './dist/hybrid-with-base/client', + server: './dist/hybrid-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -238,10 +246,15 @@ describe('Hybrid 404', () => { site: 'https://test.net/', root: './fixtures/prerender-404-500/', output: 'hybrid', + outDir: './dist/hybrid-without-base', + build: { + client: './dist/hybrid-without-base/client', + server: './dist/hybrid-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 29080981a..d856d9d3e 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -8,10 +8,6 @@ import { loadFixture, waitServerListen } from './test-utils.js'; * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture */ -async function load() { - const mod = await import(`./fixtures/prerender/dist/server/entry.mjs?dropcache=${Date.now()}`); - return mod; -} describe('Prerendering', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -25,10 +21,15 @@ describe('Prerendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'server', + outDir: './dist/with-base', + build: { + client: './dist/with-base/client', + server: './dist/with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -94,10 +95,15 @@ describe('Prerendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'server', + outDir: './dist/without-base', + build: { + client: './dist/without-base/client', + server: './dist/without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -155,6 +161,11 @@ describe('Prerendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'server', + outDir: './dist/dev', + build: { + client: './dist/dev/client', + server: './dist/dev/server', + }, adapter: nodejs({ mode: 'standalone' }), }); devServer = await fixture.startDevServer(); @@ -197,10 +208,15 @@ describe('Hybrid rendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'hybrid', + outDir: './dist/hybrid-with-base', + build: { + client: './dist/hybrid-with-base/client', + server: './dist/hybrid-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -264,10 +280,15 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', + outDir: './dist/hybrid-without-base', + build: { + client: './dist/hybrid-without-base/client', + server: './dist/hybrid-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -323,10 +344,15 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', + outDir: './dist/hybrid-shared-modules', + build: { + client: './dist/hybrid-shared-modules/client', + server: './dist/hybrid-shared-modules/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); diff --git a/packages/integrations/node/test/trailing-slash.test.js b/packages/integrations/node/test/trailing-slash.test.js index ad91a2759..9ea8fcddd 100644 --- a/packages/integrations/node/test/trailing-slash.test.js +++ b/packages/integrations/node/test/trailing-slash.test.js @@ -8,13 +8,6 @@ import { loadFixture, waitServerListen } from './test-utils.js'; * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture */ -async function load() { - const mod = await import( - `./fixtures/trailing-slash/dist/server/entry.mjs?dropcache=${Date.now()}` - ); - return mod; -} - describe('Trailing slash', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -30,10 +23,15 @@ describe('Trailing slash', () => { base: '/some-base', output: 'hybrid', trailingSlash: 'always', + outDir: './dist/always-with-base', + build: { + client: './dist/always-with-base/client', + server: './dist/always-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -96,10 +94,15 @@ describe('Trailing slash', () => { root: './fixtures/trailing-slash/', output: 'hybrid', trailingSlash: 'always', + outDir: './dist/always-without-base', + build: { + client: './dist/always-without-base/client', + server: './dist/always-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -165,10 +168,15 @@ describe('Trailing slash', () => { base: '/some-base', output: 'hybrid', trailingSlash: 'never', + outDir: './dist/never-with-base', + build: { + client: './dist/never-with-base/client', + server: './dist/never-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -224,10 +232,15 @@ describe('Trailing slash', () => { root: './fixtures/trailing-slash/', output: 'hybrid', trailingSlash: 'never', + outDir: './dist/never-without-base', + build: { + client: './dist/never-without-base/client', + server: './dist/never-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -286,10 +299,15 @@ describe('Trailing slash', () => { base: '/some-base', output: 'hybrid', trailingSlash: 'ignore', + outDir: './dist/ignore-with-base', + build: { + client: './dist/ignore-with-base/client', + server: './dist/ignore-with-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); @@ -363,10 +381,15 @@ describe('Trailing slash', () => { root: './fixtures/trailing-slash/', output: 'hybrid', trailingSlash: 'ignore', + outDir: './dist/ignore-without-base', + build: { + client: './dist/ignore-without-base/client', + server: './dist/ignore-without-base/server', + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); - const { startServer } = await load(); + const { startServer } = await fixture.loadAdapterEntryModule(); let res = startServer(); server = res.server; await waitServerListen(server.server); -- cgit v1.2.3 From 48322519b6c0f298e1256edf1135eaedc4fe6409 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Wed, 14 Aug 2024 18:05:19 +0800 Subject: Deprecates exporting prerender with dynamic values (#11657) * wip * done i think * Add changeset * Use hook instead * Reorder hooks [skip ci] * Update .changeset/eleven-pens-glow.md Co-authored-by: Sarah Rainsberger * Fix run * Fix link * Add link Co-authored-by: Sarah Rainsberger * More accurate migration [skip ci] --------- Co-authored-by: Sarah Rainsberger Co-authored-by: Sarah Rainsberger --- packages/integrations/node/test/prerender.test.js | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index d856d9d3e..e699a1b3c 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -57,6 +57,7 @@ describe('Prerendering', () => { assert.equal(res.status, 200); assert.equal($('h1').text(), 'Two'); + assert.ok(fixture.pathExists('/client/two/index.html')); }); it('Can render prerendered route with redirect and query params', async () => { @@ -131,6 +132,7 @@ describe('Prerendering', () => { assert.equal(res.status, 200); assert.equal($('h1').text(), 'Two'); + assert.ok(fixture.pathExists('/client/two/index.html')); }); it('Can render prerendered route with redirect and query params', async () => { @@ -152,6 +154,64 @@ describe('Prerendering', () => { }); }); + describe('Via integration', () => { + before(async () => { + process.env.PRERENDER = false; + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'server', + outDir: './dist/via-integration', + build: { + client: './dist/via-integration/client', + server: './dist/via-integration/server', + }, + adapter: nodejs({ mode: 'standalone' }), + integrations: [ + { + name: 'test', + hooks: { + 'astro:route:setup': ({ route }) => { + if (route.component.endsWith('two.astro')) { + route.prerender = true; + } + }, + }, + }, + ], + }); + await fixture.build(); + const { startServer } = await fixture.loadAdapterEntryModule(); + let res = startServer(); + server = res.server; + await waitServerListen(server.server); + }); + + after(async () => { + await server.stop(); + await fixture.clean(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'One'); + }); + + it('Can render prerendered route', async () => { + const res = await fetch(`http://${server.host}:${server.port}/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + assert.equal(res.status, 200); + assert.equal($('h1').text(), 'Two'); + assert.ok(fixture.pathExists('/client/two/index.html')); + }); + }); + describe('Dev', () => { let devServer; @@ -243,6 +303,7 @@ describe('Hybrid rendering', () => { assert.equal(res.status, 200); assert.equal($('h1').text(), 'One'); + assert.ok(fixture.pathExists('/client/one/index.html')); }); it('Can render prerendered route with redirect and query params', async () => { @@ -316,6 +377,7 @@ describe('Hybrid rendering', () => { assert.equal(res.status, 200); assert.equal($('h1').text(), 'One'); + assert.ok(fixture.pathExists('/client/one/index.html')); }); it('Can render prerendered route with redirect and query params', async () => { -- cgit v1.2.3 From 1b6f89c5b4b7a3e3c9cc0ca639e0a5dbfca01952 Mon Sep 17 00:00:00 2001 From: Alexander Niebuhr Date: Thu, 29 Aug 2024 08:17:42 +0200 Subject: chore: supress linting --- packages/integrations/node/CHANGELOG.md | 2 +- packages/integrations/node/package.json | 9 ++------- packages/integrations/node/src/index.ts | 2 +- packages/integrations/node/src/log-listening-on.ts | 17 +++++++++++------ packages/integrations/node/src/middleware.ts | 4 +++- packages/integrations/node/src/preview.ts | 10 ++++++---- packages/integrations/node/src/serve-app.ts | 2 +- packages/integrations/node/src/serve-static.ts | 12 +++++++++++- packages/integrations/node/src/standalone.ts | 3 ++- packages/integrations/node/test/api-route.test.js | 20 ++++++++++---------- packages/integrations/node/test/bad-urls.test.js | 2 +- packages/integrations/node/test/encoded.test.js | 4 ++-- packages/integrations/node/test/errors.test.js | 5 +++-- packages/integrations/node/test/headers.test.js | 2 +- packages/integrations/node/test/image.test.js | 2 +- packages/integrations/node/test/locals.test.js | 16 ++++++++-------- .../integrations/node/test/node-middleware.test.js | 5 ++++- .../node/test/prerender-404-500.test.js | 12 ++++++++---- packages/integrations/node/test/prerender.test.js | 21 +++++++++++++++------ packages/integrations/node/test/test-utils.js | 13 +++++++------ .../integrations/node/test/trailing-slash.test.js | 18 ++++++++++++------ packages/integrations/node/test/url.test.js | 12 ++++++------ packages/integrations/node/tsconfig.json | 4 +--- 23 files changed, 117 insertions(+), 80 deletions(-) (limited to 'packages/integrations/node/test/prerender.test.js') diff --git a/packages/integrations/node/CHANGELOG.md b/packages/integrations/node/CHANGELOG.md index 738cfc367..ed830f8de 100644 --- a/packages/integrations/node/CHANGELOG.md +++ b/packages/integrations/node/CHANGELOG.md @@ -734,7 +734,7 @@ { darkMode: true }, { expires: '1 month', - }, + } ); const prefs = Astro.cookies.get('prefs').json(); diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index f8042499b..2fc6c35b1 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -11,10 +11,7 @@ "url": "https://github.com/withastro/astro.git", "directory": "packages/integrations/node" }, - "keywords": [ - "withastro", - "astro-adapter" - ], + "keywords": ["withastro", "astro-adapter"], "bugs": "https://github.com/withastro/astro/issues", "homepage": "https://docs.astro.build/en/guides/integrations-guide/node/", "exports": { @@ -23,9 +20,7 @@ "./preview.js": "./dist/preview.js", "./package.json": "./package.json" }, - "files": [ - "dist" - ], + "files": ["dist"], "scripts": { "build": "tsc", "test": "astro-scripts test \"test/**/*.test.js\"" diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index 36d9ee30f..eb3c98a9b 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -73,7 +73,7 @@ export default function createIntegration(userOptions: UserOptions): AstroIntegr if (config.output === 'static') { logger.warn( - `\`output: "server"\` or \`output: "hybrid"\` is required to use this adapter.`, + `\`output: "server"\` or \`output: "hybrid"\` is required to use this adapter.` ); } }, diff --git a/packages/integrations/node/src/log-listening-on.ts b/packages/integrations/node/src/log-listening-on.ts index 7e299740c..2f774c31c 100644 --- a/packages/integrations/node/src/log-listening-on.ts +++ b/packages/integrations/node/src/log-listening-on.ts @@ -8,20 +8,20 @@ import type { Options } from './types.js'; export async function logListeningOn( logger: AstroIntegrationLogger, server: http.Server | https.Server, - options: Pick, + options: Pick ) { await new Promise((resolve) => server.once('listening', resolve)); const protocol = server instanceof https.Server ? 'https' : 'http'; // Allow to provide host value at runtime const host = getResolvedHostForHttpServer( - process.env.HOST !== undefined && process.env.HOST !== '' ? process.env.HOST : options.host, + process.env.HOST !== undefined && process.env.HOST !== '' ? process.env.HOST : options.host ); const { port } = server.address() as AddressInfo; const address = getNetworkAddress(protocol, host, port); if (host === undefined) { logger.info( - `Server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n`, + `Server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n` ); } else { logger.info(`Server listening on ${address.local[0]}`); @@ -32,9 +32,11 @@ function getResolvedHostForHttpServer(host: string | boolean) { if (host === false) { // Use a secure default return 'localhost'; + // biome-ignore lint/style/noUselessElse: } else if (host === true) { // If passed --host in the CLI without arguments return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs) + // biome-ignore lint/style/noUselessElse: } else { return host; } @@ -49,29 +51,32 @@ const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0 // this code from vite https://github.com/vitejs/vite/blob/d09bbd093a4b893e78f0bbff5b17c7cf7821f403/packages/vite/src/node/utils.ts#L892-L914 export function getNetworkAddress( + // biome-ignore lint/style/useDefaultParameterLast: protocol: 'http' | 'https' = 'http', hostname: string | undefined, port: number, - base?: string, + base?: string ) { const NetworkAddress: NetworkAddressOpt = { local: [], network: [], }; + // biome-ignore lint/complexity/noForEach: Object.values(os.networkInterfaces()) .flatMap((nInterface) => nInterface ?? []) .filter( (detail) => + // biome-ignore lint/complexity/useOptionalChain: detail && detail.address && (detail.family === 'IPv4' || // @ts-expect-error Node 18.0 - 18.3 returns number - detail.family === 4), + detail.family === 4) ) .forEach((detail) => { let host = detail.address.replace( '127.0.0.1', - hostname === undefined || wildcardHosts.has(hostname) ? 'localhost' : hostname, + hostname === undefined || wildcardHosts.has(hostname) ? 'localhost' : hostname ); // ipv6 host if (host.includes(':')) { diff --git a/packages/integrations/node/src/middleware.ts b/packages/integrations/node/src/middleware.ts index 5cc4c4a46..5bb104914 100644 --- a/packages/integrations/node/src/middleware.ts +++ b/packages/integrations/node/src/middleware.ts @@ -15,7 +15,7 @@ export default function createMiddleware(app: NodeApp): RequestHandler { const logger = app.getAdapterLogger(); // using spread args because express trips up if the function's // stringified body includes req, res, next, locals directly - return async function (...args) { + return async (...args) => { // assume normal invocation at first const [req, res, next, locals] = args; // short circuit if it is an error invocation @@ -23,6 +23,7 @@ export default function createMiddleware(app: NodeApp): RequestHandler { const error = req; if (next) { return next(error); + // biome-ignore lint/style/noUselessElse: } else { throw error; } @@ -33,6 +34,7 @@ export default function createMiddleware(app: NodeApp): RequestHandler { logger.error(`Could not render ${req.url}`); console.error(err); if (!res.headersSent) { + // biome-ignore lint/style/noUnusedTemplateLiteral: res.writeHead(500, `Server error`); res.end(); } diff --git a/packages/integrations/node/src/preview.ts b/packages/integrations/node/src/preview.ts index 518155c4a..7e9415df8 100644 --- a/packages/integrations/node/src/preview.ts +++ b/packages/integrations/node/src/preview.ts @@ -8,7 +8,7 @@ import { createServer } from './standalone.js'; type ServerModule = ReturnType; type MaybeServerModule = Partial; -const createPreviewServer: CreatePreviewServer = async function (preview) { +const createPreviewServer: CreatePreviewServer = async (preview) => { let ssrHandler: ServerModule['handler']; let options: ServerModule['options']; try { @@ -16,19 +16,21 @@ const createPreviewServer: CreatePreviewServer = async function (preview) { const ssrModule: MaybeServerModule = await import(preview.serverEntrypoint.toString()); if (typeof ssrModule.handler === 'function') { ssrHandler = ssrModule.handler; + // biome-ignore lint/style/noNonNullAssertion: options = ssrModule.options!; } else { throw new AstroError( - `The server entrypoint doesn't have a handler. Are you sure this is the right file?`, + `The server entrypoint doesn't have a handler. Are you sure this is the right file?` ); } } catch (err) { if ((err as any).code === 'ERR_MODULE_NOT_FOUND') { throw new AstroError( `The server entrypoint ${fileURLToPath( - preview.serverEntrypoint, - )} does not exist. Have you ran a build yet?`, + preview.serverEntrypoint + )} does not exist. Have you ran a build yet?` ); + // biome-ignore lint/style/noUselessElse: } else { throw err; } diff --git a/packages/integrations/node/src/serve-app.ts b/packages/integrations/node/src/serve-app.ts index 72b4e0fd6..2934a01ab 100644 --- a/packages/integrations/node/src/serve-app.ts +++ b/packages/integrations/node/src/serve-app.ts @@ -39,7 +39,7 @@ export function createAppHandler(app: NodeApp): RequestHandler { addCookieHeader: true, locals, routeData, - }), + }) ); await NodeApp.writeResponse(response, res); } else if (next) { diff --git a/packages/integrations/node/src/serve-static.ts b/packages/integrations/node/src/serve-static.ts index 725f7afa6..9221594d7 100644 --- a/packages/integrations/node/src/serve-static.ts +++ b/packages/integrations/node/src/serve-static.ts @@ -29,23 +29,28 @@ export function createStaticHandler(app: NodeApp, options: Options) { let isDirectory = false; try { isDirectory = fs.lstatSync(filePath).isDirectory(); - } catch {} + } catch { } const { trailingSlash = 'ignore' } = options; const hasSlash = urlPath.endsWith('/'); switch (trailingSlash) { case 'never': + // biome-ignore lint/suspicious/noDoubleEquals: if (isDirectory && urlPath != '/' && hasSlash) { + // biome-ignore lint/style/useTemplate: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: pathname = urlPath.slice(0, -1) + (urlQuery ? '?' + urlQuery : ''); res.statusCode = 301; res.setHeader('Location', pathname); return res.end(); + // biome-ignore lint/style/noUselessElse: } else pathname = urlPath; // intentionally fall through case 'ignore': { if (isDirectory && !hasSlash) { + // biome-ignore lint/style/useTemplate: pathname = urlPath + '/index.html'; } else pathname = urlPath; } @@ -53,10 +58,12 @@ export function createStaticHandler(app: NodeApp, options: Options) { case 'always': // trailing slash is not added to "subresources" if (!hasSlash && !isSubresourceRegex.test(urlPath)) { + // biome-ignore lint/style/useTemplate: pathname = urlPath + '/' + (urlQuery ? '?' + urlQuery : ''); res.statusCode = 301; res.setHeader('Location', pathname); return res.end(); + // biome-ignore lint/style/noUselessElse: } else pathname = urlPath; break; } @@ -110,6 +117,7 @@ function resolveClientDir(options: Options) { while (!serverEntryFolderURL.endsWith(serverFolder)) { serverEntryFolderURL = path.dirname(serverEntryFolderURL); } + // biome-ignore lint/style/useTemplate: const serverEntryURL = serverEntryFolderURL + '/entry.mjs'; const clientURL = new URL(appendForwardSlash(rel), serverEntryURL); const client = url.fileURLToPath(clientURL); @@ -117,9 +125,11 @@ function resolveClientDir(options: Options) { } function prependForwardSlash(pth: string) { + // biome-ignore lint/style/useTemplate: return pth.startsWith('/') ? pth : '/' + pth; } function appendForwardSlash(pth: string) { + // biome-ignore lint/style/useTemplate: return pth.endsWith('/') ? pth : pth + '/'; } diff --git a/packages/integrations/node/src/standalone.ts b/packages/integrations/node/src/standalone.ts index 76e672d2f..8ae10a9ba 100644 --- a/packages/integrations/node/src/standalone.ts +++ b/packages/integrations/node/src/standalone.ts @@ -39,6 +39,7 @@ export function createStandaloneHandler(app: NodeApp, options: Options) { return (req: http.IncomingMessage, res: http.ServerResponse) => { try { // validate request path + // biome-ignore lint/style/noNonNullAssertion: decodeURI(req.url!); } catch { res.writeHead(400); @@ -59,7 +60,7 @@ export function createServer(listener: http.RequestListener, host: string, port: key: fs.readFileSync(process.env.SERVER_KEY_PATH), cert: fs.readFileSync(process.env.SERVER_CERT_PATH), }, - listener, + listener ); } else { httpServer = http.createServer(listener); diff --git a/packages/integrations/node/test/api-route.test.js b/packages/integrations/node/test/api-route.test.js index 804a5ccf4..5eca5c530 100644 --- a/packages/integrations/node/test/api-route.test.js +++ b/packages/integrations/node/test/api-route.test.js @@ -27,7 +27,7 @@ describe('API routes', () => { it('Can get the request body', async () => { const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/recipes', }); @@ -38,9 +38,9 @@ describe('API routes', () => { handler(req, res); - let [buffer] = await done; + const [buffer] = await done; - let json = JSON.parse(buffer.toString('utf-8')); + const json = JSON.parse(buffer.toString('utf-8')); assert.equal(json.length, 1); @@ -50,7 +50,7 @@ describe('API routes', () => { it('Can get binary data', async () => { const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/binary', }); @@ -61,15 +61,15 @@ describe('API routes', () => { handler(req, res); - let [out] = await done; - let arr = Array.from(new Uint8Array(out.buffer)); + const [out] = await done; + const arr = Array.from(new Uint8Array(out.buffer)); assert.deepEqual(arr, [5, 4, 3, 2, 1]); }); it('Can post large binary data', async () => { const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/hash', }); @@ -95,17 +95,17 @@ describe('API routes', () => { expectedDigest = hash.digest(); }); - let [out] = await done; + const [out] = await done; assert.deepEqual(new Uint8Array(out.buffer), new Uint8Array(expectedDigest)); }); it('Can bail on streaming', async () => { const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ url: '/streaming', }); - let locals = { cancelledByTheServer: false }; + const locals = { cancelledByTheServer: false }; handler(req, res, () => {}, locals); req.send(); diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.js index 9323516e8..cdc0158ff 100644 --- a/packages/integrations/node/test/bad-urls.test.js +++ b/packages/integrations/node/test/bad-urls.test.js @@ -39,7 +39,7 @@ describe('Bad URLs', () => { assert.equal( statusCodes.includes(fetchResult.status), true, - `${weirdUrl} returned something else than 400, 404, or 500`, + `${weirdUrl} returned something else than 400, 404, or 500` ); } const stillWork = await fixture.fetch('/'); diff --git a/packages/integrations/node/test/encoded.test.js b/packages/integrations/node/test/encoded.test.js index edc6ae78b..4fc97cf7f 100644 --- a/packages/integrations/node/test/encoded.test.js +++ b/packages/integrations/node/test/encoded.test.js @@ -18,7 +18,7 @@ describe('Encoded Pathname', () => { it('Can get an Astro file', async () => { const { handler } = await import('./fixtures/encoded/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ url: '/什么', }); @@ -32,7 +32,7 @@ describe('Encoded Pathname', () => { it('Can get a Markdown file', async () => { const { handler } = await import('./fixtures/encoded/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ url: '/blog/什么', }); diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index 802fa6e25..9bf4aa29b 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -20,6 +20,7 @@ describe('Errors', () => { }); let devPreview; + // biome-ignore lint/suspicious/noDuplicateTestHooks: before(async () => { // The two tests that need the server to run are skipped // devPreview = await fixture.preview(); @@ -58,7 +59,7 @@ describe('Errors', () => { const $ = cheerio.load(html); assert.equal($('p').text().trim(), 'Internal server error'); - }, + } ); it( @@ -86,6 +87,6 @@ describe('Errors', () => { } else { throw new Error('The response should take at most 2 chunks.'); } - }, + } ); }); diff --git a/packages/integrations/node/test/headers.test.js b/packages/integrations/node/test/headers.test.js index 00b1766c7..f2753517e 100644 --- a/packages/integrations/node/test/headers.test.js +++ b/packages/integrations/node/test/headers.test.js @@ -132,7 +132,7 @@ describe('Node Adapter Headers', () => { async function runTest(url, expectedHeaders) { const { handler } = await import('./fixtures/headers/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ method: 'GET', url, }); diff --git a/packages/integrations/node/test/image.test.js b/packages/integrations/node/test/image.test.js index 5303fe37e..c4758f96b 100644 --- a/packages/integrations/node/test/image.test.js +++ b/packages/integrations/node/test/image.test.js @@ -28,7 +28,7 @@ describe.skip('Image endpoint', () => { assert.equal(res.status, 200); const resImage = await fixture.fetch( - '/_image?href=/_astro/some_penguin.97ef5f92.png&w=50&f=webp', + '/_image?href=/_astro/some_penguin.97ef5f92.png&w=50&f=webp' ); assert.equal(resImage.status, 200); diff --git a/packages/integrations/node/test/locals.test.js b/packages/integrations/node/test/locals.test.js index 6d2776079..b8e3ed40f 100644 --- a/packages/integrations/node/test/locals.test.js +++ b/packages/integrations/node/test/locals.test.js @@ -18,23 +18,23 @@ describe('API routes', () => { it('Can use locals added by node middleware', async () => { const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ url: '/from-node-middleware', }); - let locals = { foo: 'bar' }; + const locals = { foo: 'bar' }; handler(req, res, () => {}, locals); req.send(); - let html = await text(); + const html = await text(); assert.equal(html.includes('

bar

'), true); }); it('Throws an error when provided non-objects as locals', async () => { const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ url: '/from-node-middleware', }); @@ -62,19 +62,19 @@ describe('API routes', () => { it('Can access locals in API', async () => { const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); - let { req, res, done } = createRequestAndResponse({ + const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/api', }); - let locals = { foo: 'bar' }; + const locals = { foo: 'bar' }; handler(req, res, () => {}, locals); req.send(); - let [buffer] = await done; + const [buffer] = await done; - let json = JSON.parse(buffer.toString('utf-8')); + const json = JSON.parse(buffer.toString('utf-8')); assert.equal(json.foo, 'bar'); }); diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.js index d1b016a51..eeb193c73 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.js @@ -23,7 +23,7 @@ describe('behavior from middleware, standalone', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -31,6 +31,7 @@ describe('behavior from middleware, standalone', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -71,10 +72,12 @@ describe('behavior from middleware, middleware', () => { after(async () => { server.close(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); it('when mode is standalone', async () => { + // biome-ignore lint/style/noUnusedTemplateLiteral: const res = await fetch(`http://localhost:8888/ssr`); assert.equal(res.status, 200); diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.js index 2535fcb35..86226c500 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.js @@ -34,7 +34,7 @@ describe('Prerender 404', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -42,6 +42,7 @@ describe('Prerender 404', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -124,7 +125,7 @@ describe('Prerender 404', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -132,6 +133,7 @@ describe('Prerender 404', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -193,7 +195,7 @@ describe('Hybrid 404', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -201,6 +203,7 @@ describe('Hybrid 404', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -255,7 +258,7 @@ describe('Hybrid 404', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -263,6 +266,7 @@ describe('Hybrid 404', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index e699a1b3c..0684ff63a 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -30,7 +30,7 @@ describe('Prerendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -38,6 +38,7 @@ describe('Prerendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -105,7 +106,7 @@ describe('Prerendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -113,6 +114,7 @@ describe('Prerendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -181,7 +183,7 @@ describe('Prerendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -189,6 +191,7 @@ describe('Prerendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -233,10 +236,12 @@ describe('Prerendering', () => { after(async () => { await devServer.stop(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); it('Can render SSR route', async () => { + // biome-ignore lint/style/noUnusedTemplateLiteral: const res = await fixture.fetch(`/one`); const html = await res.text(); const $ = cheerio.load(html); @@ -246,6 +251,7 @@ describe('Prerendering', () => { }); it('Can render prerendered route', async () => { + // biome-ignore lint/style/noUnusedTemplateLiteral: const res = await fixture.fetch(`/two`); const html = await res.text(); const $ = cheerio.load(html); @@ -277,7 +283,7 @@ describe('Hybrid rendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -285,6 +291,7 @@ describe('Hybrid rendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -350,7 +357,7 @@ describe('Hybrid rendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -358,6 +365,7 @@ describe('Hybrid rendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -415,7 +423,7 @@ describe('Hybrid rendering', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -423,6 +431,7 @@ describe('Hybrid rendering', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); diff --git a/packages/integrations/node/test/test-utils.js b/packages/integrations/node/test/test-utils.js index 10faba5cf..4f273756c 100644 --- a/packages/integrations/node/test/test-utils.js +++ b/packages/integrations/node/test/test-utils.js @@ -20,18 +20,18 @@ export function loadFixture(inlineConfig) { } export function createRequestAndResponse(reqOptions) { - let req = httpMocks.createRequest(reqOptions); + const req = httpMocks.createRequest(reqOptions); - let res = httpMocks.createResponse({ + const res = httpMocks.createResponse({ eventEmitter: EventEmitter, req, }); - let done = toPromise(res); + const done = toPromise(res); // Get the response as text const text = async () => { - let chunks = await done; + const chunks = await done; return buffersToString(chunks); }; @@ -45,19 +45,20 @@ export function toPromise(res) { const write = res.write; res.write = function (data, encoding) { if (ArrayBuffer.isView(data) && !Buffer.isBuffer(data)) { + // biome-ignore lint/style/noParameterAssign: data = Buffer.from(data.buffer); } return write.call(this, data, encoding); }; res.on('end', () => { - let chunks = res._getChunks(); + const chunks = res._getChunks(); resolve(chunks); }); }); } export function buffersToString(buffers) { - let decoder = new TextDecoder(); + const decoder = new TextDecoder(); let str = ''; for (const buffer of buffers) { str += decoder.decode(buffer); diff --git a/packages/integrations/node/test/trailing-slash.test.js b/packages/integrations/node/test/trailing-slash.test.js index 9ea8fcddd..6f6a2a3ba 100644 --- a/packages/integrations/node/test/trailing-slash.test.js +++ b/packages/integrations/node/test/trailing-slash.test.js @@ -32,7 +32,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -40,6 +40,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -103,7 +104,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -111,6 +112,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -177,7 +179,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -185,6 +187,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -241,7 +244,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -249,6 +252,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -308,7 +312,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -316,6 +320,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); @@ -390,7 +395,7 @@ describe('Trailing slash', () => { }); await fixture.build(); const { startServer } = await fixture.loadAdapterEntryModule(); - let res = startServer(); + const res = startServer(); server = res.server; await waitServerListen(server.server); }); @@ -398,6 +403,7 @@ describe('Trailing slash', () => { after(async () => { await server.stop(); await fixture.clean(); + // biome-ignore lint/performance/noDelete: delete process.env.PRERENDER; }); diff --git a/packages/integrations/node/test/url.test.js b/packages/integrations/node/test/url.test.js index 77ca45836..81b357b71 100644 --- a/packages/integrations/node/test/url.test.js +++ b/packages/integrations/node/test/url.test.js @@ -20,7 +20,7 @@ describe('URL', () => { it('return http when non-secure', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ url: '/', }); @@ -33,7 +33,7 @@ describe('URL', () => { it('return https when secure', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ socket: new TLSSocket(), url: '/', }); @@ -47,7 +47,7 @@ describe('URL', () => { it('return http when the X-Forwarded-Proto header is set to http', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'http' }, url: '/', }); @@ -61,7 +61,7 @@ describe('URL', () => { it('return https when the X-Forwarded-Proto header is set to https', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https' }, url: '/', }); @@ -75,7 +75,7 @@ describe('URL', () => { it('includes forwarded host and port in the url', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', 'X-Forwarded-Host': 'abc.xyz', @@ -95,7 +95,7 @@ describe('URL', () => { it('accepts port in forwarded host and forwarded port', async () => { const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); - let { req, res, text } = createRequestAndResponse({ + const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', 'X-Forwarded-Host': 'abc.xyz:444', diff --git a/packages/integrations/node/tsconfig.json b/packages/integrations/node/tsconfig.json index b9feb9b9b..18443cddf 100644 --- a/packages/integrations/node/tsconfig.json +++ b/packages/integrations/node/tsconfig.json @@ -1,8 +1,6 @@ { "extends": "../../tsconfig.base.json", - "include": [ - "src" - ], + "include": ["src"], "compilerOptions": { "outDir": "./dist" } -- cgit v1.2.3