diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index 5cb51db93982..6cc8081b3e04 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -27,7 +27,14 @@ process.env.ASTRO_TELEMETRY_DISABLED = true; * @typedef {import('../src/cli/check/index').CheckPayload} CheckPayload * @typedef {import('http').IncomingMessage} NodeRequest * @typedef {import('http').ServerResponse} NodeResponse + * `RequestHandler` is defined in `@astrojs/node` so we cannot import it directly. + * See https://github.com/withastro/astro/blob/astro@6.0.0/packages/integrations/node/src/types.ts#L44-L50 + * @typedef {(req: NodeRequest, res: NodeResponse, next?: (err?: unknown) => void, locals?: object) => void | Promise} RequestHandler * + * `startServer` is defined in `@astrojs/node` so we cannot import it directly. + * See https://github.com/withastro/astro/blob/astro@6.0.0/packages/integrations/node/src/server.ts#L21 + * @typedef {PreviewServer & { server: import('http').Server }} AdapterServer + * @typedef {() => ({server: AdapterServer, stop: Promise})} AdapterStartServer * * @typedef {Object} Fixture * @property {(extraInlineConfig?: Parameters[0], options?: Parameters[1]) => Promise} build @@ -43,7 +50,8 @@ process.env.ASTRO_TELEMETRY_DISABLED = true; * @property {() => Promise} clean * @property {(streaming?: boolean) => Promise} loadTestAdapterApp * @property {(streaming?: boolean) => Promise} loadSelfAdapterApp - * @property {() => Promise<(req: NodeRequest, res: NodeResponse) => void>} loadNodeAdapterHandler + * @property {() => Promise<{ handler: RequestHandler; startServer: AdapterStartServer }>} loadAdapterEntryModule + * @property {() => Promise} loadNodeAdapterHandler * @property {(timeout?: number) => Promise} onNextDataStoreChange * @property {typeof check} check * @property {typeof sync} sync diff --git a/packages/astro/test/units/test-utils.ts b/packages/astro/test/units/test-utils.ts index 519a1e6d6dbd..fb8ee5b13f15 100644 --- a/packages/astro/test/units/test-utils.ts +++ b/packages/astro/test/units/test-utils.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'node:events'; import { fileURLToPath } from 'node:url'; +import type { IncomingMessage, ServerResponse } from 'node:http'; import { createFixture as _createFixture, type FileTree } from 'fs-fixture'; import httpMocks from 'node-mocks-http'; import { getDefaultClientDirectives } from '../../dist/core/client-directive/index.js'; @@ -39,10 +40,10 @@ export async function createFixture(tree: FileTree) { } export function createRequestAndResponse(reqOptions: httpMocks.RequestOptions = {}) { - const req = httpMocks.createRequest(reqOptions); + const req: IncomingMessage = httpMocks.createRequest(reqOptions); req.headers.host ||= 'localhost'; - const res = httpMocks.createResponse({ + const res: ServerResponse = httpMocks.createResponse({ eventEmitter: EventEmitter, req, }); diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index 6a2d98e91fe2..e07cf38ff22a 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -30,7 +30,7 @@ "dev": "astro-scripts dev \"src/**/*.ts\"", "build": "astro-scripts build \"src/**/*.ts\" && tsc", "build:ci": "astro-scripts build \"src/**/*.ts\"", - "test": "astro-scripts test \"test/**/*.test.js\" \"test/**/*.test.ts\"", + "test": "astro-scripts test \"test/**/*.test.ts\"", "typecheck:tests": "tsc --build tsconfig.test.json" }, "dependencies": { @@ -44,6 +44,7 @@ "devDependencies": { "@fastify/middie": "^9.1.0", "@fastify/static": "^9.0.0", + "@types/express": "^5.0.6", "@types/node": "^22.10.6", "@types/send": "^1.2.1", "@types/server-destroy": "^1.0.4", diff --git a/packages/integrations/node/test/api-route.test.js b/packages/integrations/node/test/api-route.test.ts similarity index 85% rename from packages/integrations/node/test/api-route.test.js rename to packages/integrations/node/test/api-route.test.ts index 05cdcd637bdf..26e26d0fe8bc 100644 --- a/packages/integrations/node/test/api-route.test.js +++ b/packages/integrations/node/test/api-route.test.ts @@ -1,16 +1,14 @@ import * as assert from 'node:assert/strict'; import crypto from 'node:crypto'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; describe('API routes', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - /** @type {import('../../../astro/src/types/public/preview.js').PreviewServer} */ - let previewServer; - /** @type {URL} */ - let baseUri; + let fixture: Fixture; + let previewServer: PreviewServer; + let baseUri: URL; before(async () => { fixture = await loadFixture({ @@ -26,7 +24,7 @@ describe('API routes', () => { after(() => previewServer.stop()); it('Can get the request body', async () => { - const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/recipes', @@ -48,7 +46,7 @@ describe('API routes', () => { }); it('Can get binary data', async () => { - const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'POST', @@ -67,7 +65,7 @@ describe('API routes', () => { }); it('Can post large binary data', async () => { - const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'POST', @@ -76,7 +74,7 @@ describe('API routes', () => { handler(req, res); - let expectedDigest = null; + let expectedDigest: Buffer | null = null; req.once('async_iterator', () => { // Send 256MB of garbage data in 256KB chunks. This should be fast (< 1sec). let remainingBytes = 256 * 1024 * 1024; @@ -96,11 +94,11 @@ describe('API routes', () => { }); const [out] = await done; - assert.deepEqual(new Uint8Array(out.buffer), new Uint8Array(expectedDigest)); + 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'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ url: '/streaming', }); diff --git a/packages/integrations/node/test/assets.test.js b/packages/integrations/node/test/assets.test.ts similarity index 88% rename from packages/integrations/node/test/assets.test.js rename to packages/integrations/node/test/assets.test.ts index c6159c863a0e..e7682ef7b65e 100644 --- a/packages/integrations/node/test/assets.test.js +++ b/packages/integrations/node/test/assets.test.ts @@ -1,14 +1,14 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import { fileURLToPath } from 'node:url'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; -import { fileURLToPath } from 'node:url'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Assets', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let devPreview; + let fixture: Fixture; + let devPreview: PreviewServer; before(async () => { const root = new URL('./fixtures/image/', import.meta.url); @@ -39,7 +39,7 @@ describe('Assets', () => { const $ = cheerio.load(html); // Fetch the asset - const fileURL = $('a').attr('href'); + const fileURL = $('a').attr('href')!; response = await fixture.fetch(fileURL); cacheControl = response.headers.get('cache-control'); assert.equal(cacheControl, 'public, max-age=31536000, immutable'); @@ -50,7 +50,7 @@ describe('Assets', () => { let response = await fixture.fetch('/text-file'); const html = await response.text(); const $ = cheerio.load(html); - const fileURL = $('a').attr('href'); + const fileURL = $('a').attr('href')!; // Send a request with a malformed If-Match header that won't match the ETag response = await fixture.fetch(fileURL, { diff --git a/packages/integrations/node/test/bad-urls.test.js b/packages/integrations/node/test/bad-urls.test.ts similarity index 88% rename from packages/integrations/node/test/bad-urls.test.js rename to packages/integrations/node/test/bad-urls.test.ts index 2e3e3ad28c18..fc45bef3fa4a 100644 --- a/packages/integrations/node/test/bad-urls.test.js +++ b/packages/integrations/node/test/bad-urls.test.ts @@ -1,12 +1,12 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Bad URLs', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let devPreview; + let fixture: Fixture; + let devPreview: PreviewServer; before(async () => { fixture = await loadFixture({ diff --git a/packages/integrations/node/test/encoded.test.js b/packages/integrations/node/test/encoded.test.ts similarity index 74% rename from packages/integrations/node/test/encoded.test.js rename to packages/integrations/node/test/encoded.test.ts index 4fc97cf7fd09..657119e6d0b2 100644 --- a/packages/integrations/node/test/encoded.test.js +++ b/packages/integrations/node/test/encoded.test.ts @@ -1,11 +1,10 @@ import * as assert from 'node:assert/strict'; import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; describe('Encoded Pathname', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ @@ -17,7 +16,7 @@ describe('Encoded Pathname', () => { }); it('Can get an Astro file', async () => { - const { handler } = await import('./fixtures/encoded/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ url: '/什么', }); @@ -30,7 +29,7 @@ describe('Encoded Pathname', () => { }); it('Can get a Markdown file', async () => { - const { handler } = await import('./fixtures/encoded/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ url: '/blog/什么', diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.ts similarity index 73% rename from packages/integrations/node/test/errors.test.js rename to packages/integrations/node/test/errors.test.ts index 99aff386bf00..c9b7fb92d8ea 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.ts @@ -1,12 +1,11 @@ import assert from 'node:assert/strict'; -import { after, before, describe, it } from 'node:test'; +import { before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Errors', () => { - /** @type {import('./test-utils.js').Fixture} */ - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ @@ -16,15 +15,6 @@ describe('Errors', () => { }); await fixture.build(); }); - let devPreview; - - // The two tests that need the server to run are skipped - // before(async () => { - // devPreview = await fixture.preview(); - // }); - after(async () => { - await devPreview?.stop(); - }); it('rejected promise in template', { skip: true, @@ -43,9 +33,8 @@ describe('Errors', () => { }, async () => { const result = ['

Astro

1', 'Internal server error']; - /** @type {Response} */ - const res = await fixture.fetch('/generator'); - const reader = res.body.getReader(); + const res: Response = await fixture.fetch('/generator'); + const reader = res.body!.getReader(); const decoder = new TextDecoder(); const chunk1 = await reader.read(); const chunk2 = await reader.read(); diff --git a/packages/integrations/node/test/headers.test.js b/packages/integrations/node/test/headers.test.ts similarity index 92% rename from packages/integrations/node/test/headers.test.js rename to packages/integrations/node/test/headers.test.ts index 15f52a434d25..e9a5faa9c353 100644 --- a/packages/integrations/node/test/headers.test.js +++ b/packages/integrations/node/test/headers.test.ts @@ -1,12 +1,11 @@ import * as assert from 'node:assert/strict'; import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; -describe('Node Adapter Headers', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; +let fixture: Fixture; +describe('Node Adapter Headers', () => { describe('streaming', () => { before(async () => { fixture = await loadFixture({ @@ -131,7 +130,7 @@ describe('Node Adapter Headers', () => { // TODO: needs e2e tests to check real headers it('sends several chunks', async () => { - const { handler } = await import('./fixtures/headers/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'GET', @@ -159,7 +158,7 @@ describe('Node Adapter Headers', () => { // TODO: needs e2e tests to check real headers it('sends a single chunk', async () => { - const { handler } = await import('./fixtures/headers/dist/server/entry.mjs?cachebust=0'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'GET', @@ -176,8 +175,8 @@ describe('Node Adapter Headers', () => { }); }); -async function runTest(url, expectedHeaders) { - const { handler } = await import('./fixtures/headers/dist/server/entry.mjs'); +async function runTest(url: string, expectedHeaders: Record) { + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'GET', diff --git a/packages/integrations/node/test/image.test.js b/packages/integrations/node/test/image.test.ts similarity index 96% rename from packages/integrations/node/test/image.test.js rename to packages/integrations/node/test/image.test.ts index 0426a7605c0f..f6d4389423f5 100644 --- a/packages/integrations/node/test/image.test.js +++ b/packages/integrations/node/test/image.test.ts @@ -1,16 +1,16 @@ import * as assert from 'node:assert/strict'; import { cp, rm } from 'node:fs/promises'; import { after, before, describe, it } from 'node:test'; +import { fileURLToPath } from 'node:url'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import { inferRemoteSize } from 'astro/assets/utils/inferRemoteSize.js'; import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; -import { fileURLToPath } from 'node:url'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Image endpoint', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let devPreview; + let fixture: Fixture; + let devPreview: PreviewServer; before(async () => { const root = new URL('./fixtures/image/', import.meta.url); diff --git a/packages/integrations/node/test/locals.test.js b/packages/integrations/node/test/locals.test.ts similarity index 78% rename from packages/integrations/node/test/locals.test.js rename to packages/integrations/node/test/locals.test.ts index b8e3ed40fc4b..d588d4ac3e69 100644 --- a/packages/integrations/node/test/locals.test.js +++ b/packages/integrations/node/test/locals.test.ts @@ -1,11 +1,10 @@ import * as assert from 'node:assert/strict'; import { before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; describe('API routes', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ @@ -17,7 +16,7 @@ describe('API routes', () => { }); it('Can use locals added by node middleware', async () => { - const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ url: '/from-node-middleware', }); @@ -33,11 +32,12 @@ describe('API routes', () => { }); it('Throws an error when provided non-objects as locals', async () => { - const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ url: '/from-node-middleware', }); + // @ts-expect-error - intentionally passing a non-object to test error handling handler(req, res, undefined, 'locals'); req.send(); @@ -46,7 +46,7 @@ describe('API routes', () => { }); it('Can use locals added by astro middleware', async () => { - const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ url: '/from-astro-middleware', @@ -61,7 +61,7 @@ describe('API routes', () => { }); it('Can access locals in API', async () => { - const { handler } = await import('./fixtures/locals/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'POST', url: '/api', diff --git a/packages/integrations/node/test/node-middleware-listener-cleanup.test.js b/packages/integrations/node/test/node-middleware-listener-cleanup.test.ts similarity index 82% rename from packages/integrations/node/test/node-middleware-listener-cleanup.test.js rename to packages/integrations/node/test/node-middleware-listener-cleanup.test.ts index 2e3d3adfed5d..5684b426a7cd 100644 --- a/packages/integrations/node/test/node-middleware-listener-cleanup.test.js +++ b/packages/integrations/node/test/node-middleware-listener-cleanup.test.ts @@ -3,14 +3,13 @@ import { after, before, describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; import fastifyMiddie from '@fastify/middie'; import fastifyStatic from '@fastify/static'; -import Fastify from 'fastify'; +import Fastify, { type FastifyInstance } from 'fastify'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Node middleware socket listener cleanup', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: FastifyInstance; before(async () => { fixture = await loadFixture({ @@ -43,7 +42,7 @@ describe('Node middleware socket listener cleanup', () => { }); let listenerWarningEmitted = false; - const warningListener = (warning) => { + const warningListener = (warning: Error) => { if (warning.name === 'MaxListenersExceededWarning') { listenerWarningEmitted = true; } @@ -54,6 +53,7 @@ describe('Node middleware socket listener cleanup', () => { // Make multiple back-to-back requests to a static page for (let i = 0; i < 30; i++) { const response = await fetch('http://localhost:8890', { + // @ts-expect-error: it seems that Node.js `fetch` doesn't accept `agent` here. Should we use dispatcher instead? https://stackoverflow.com/a/76069981 agent, headers: { Connection: 'keep-alive', diff --git a/packages/integrations/node/test/node-middleware.test.js b/packages/integrations/node/test/node-middleware.test.ts similarity index 93% rename from packages/integrations/node/test/node-middleware.test.js rename to packages/integrations/node/test/node-middleware.test.ts index 128837c31fd2..cef931d083d9 100644 --- a/packages/integrations/node/test/node-middleware.test.js +++ b/packages/integrations/node/test/node-middleware.test.ts @@ -1,3 +1,4 @@ +import type { Server } from 'node:http'; import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; @@ -5,18 +6,13 @@ import fastifyMiddie from '@fastify/middie'; import fastifyStatic from '@fastify/static'; import * as cheerio from 'cheerio'; import express from 'express'; -import Fastify from 'fastify'; +import Fastify, { type FastifyInstance } from 'fastify'; import nodejs from '../dist/index.js'; -import { loadFixture, waitServerListen } from './test-utils.js'; - -/** - * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture - */ +import { type Fixture, loadFixture, waitServerListen, type AdapterServer } from './test-utils.ts'; describe('behavior from middleware, standalone', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; before(async () => { fixture = await loadFixture({ @@ -52,9 +48,8 @@ describe('behavior from middleware, standalone', () => { }); describe('behavior from middleware, middleware with express', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: Server; before(async () => { fixture = await loadFixture({ @@ -134,9 +129,8 @@ describe('behavior from middleware, middleware with express', () => { }); describe('behavior from middleware, middleware with fastify', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: FastifyInstance; before(async () => { fixture = await loadFixture({ @@ -216,9 +210,8 @@ describe('behavior from middleware, middleware with fastify', () => { // the Node adapter in middleware mode can identify them as static files and NOT // match them against catch-all routes. describe('middleware with fastify and catch-all route: SSR assets in manifest', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: FastifyInstance; before(async () => { fixture = await loadFixture({ diff --git a/packages/integrations/node/test/prerender-404-500.test.js b/packages/integrations/node/test/prerender-404-500.test.ts similarity index 96% rename from packages/integrations/node/test/prerender-404-500.test.js rename to packages/integrations/node/test/prerender-404-500.test.ts index d873064ae090..c2b41fec2d50 100644 --- a/packages/integrations/node/test/prerender-404-500.test.js +++ b/packages/integrations/node/test/prerender-404-500.test.ts @@ -2,16 +2,11 @@ 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, waitServerListen } from './test-utils.js'; - -/** - * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture - */ +import { type Fixture, loadFixture, waitServerListen, type AdapterServer } from './test-utils.ts'; describe('Prerender 404', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; describe('With base', async () => { before(async () => { @@ -155,9 +150,8 @@ describe('Prerender 404', () => { }); describe('Hybrid 404', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; describe('With base', async () => { before(async () => { diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.ts similarity index 97% rename from packages/integrations/node/test/prerender.test.js rename to packages/integrations/node/test/prerender.test.ts index a56828c8609f..9a873ab0a3b6 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.ts @@ -2,16 +2,17 @@ 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, waitServerListen } from './test-utils.js'; - -/** - * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture - */ +import { + type Fixture, + loadFixture, + waitServerListen, + type AdapterServer, + type DevServer, +} from './test-utils.ts'; describe('Prerendering', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; describe('With base', async () => { before(async () => { @@ -223,7 +224,7 @@ describe('Prerendering', () => { }); describe('Dev', () => { - let devServer; + let devServer: DevServer; before(async () => { fixture = await loadFixture({ @@ -260,9 +261,8 @@ describe('Prerendering', () => { }); describe('Hybrid rendering', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; describe('With base', () => { before(async () => { diff --git a/packages/integrations/node/test/prerendered-error-page-fetch.test.js b/packages/integrations/node/test/prerendered-error-page-fetch.test.ts similarity index 77% rename from packages/integrations/node/test/prerendered-error-page-fetch.test.js rename to packages/integrations/node/test/prerendered-error-page-fetch.test.ts index b66482b85595..9fb6c6110f89 100644 --- a/packages/integrations/node/test/prerendered-error-page-fetch.test.js +++ b/packages/integrations/node/test/prerendered-error-page-fetch.test.ts @@ -1,18 +1,14 @@ -// @ts-check import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import node from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('prerenderedErrorPageFetch', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - /** @type {import('astro').PreviewServer} */ - let devPreview; - /** @type {typeof globalThis.fetch} */ - let originalFetch; - /** @type {Array} */ - let urls; + let fixture: Fixture; + let devPreview: PreviewServer; + let originalFetch: typeof globalThis.fetch; + let urls: Array = []; before(async () => { fixture = await loadFixture({ @@ -20,11 +16,10 @@ describe('prerenderedErrorPageFetch', () => { adapter: node({ mode: 'standalone' }), }); await fixture.clean(); - await fixture.build({}); - devPreview = await fixture.preview({}); + await fixture.build(); + devPreview = await fixture.preview(); originalFetch = globalThis.fetch; globalThis.fetch = (...args) => { - urls ??= []; if (typeof args[0] === 'string') { urls.push(args[0]); } diff --git a/packages/integrations/node/test/preview-headers.test.js b/packages/integrations/node/test/preview-headers.test.ts similarity index 80% rename from packages/integrations/node/test/preview-headers.test.js rename to packages/integrations/node/test/preview-headers.test.ts index 3fd9d0508d6e..449d9657b4c3 100644 --- a/packages/integrations/node/test/preview-headers.test.js +++ b/packages/integrations/node/test/preview-headers.test.ts @@ -1,12 +1,12 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture } from './test-utils.ts'; describe('Astro preview headers', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let devPreview; + let fixture: Fixture; + let devPreview: PreviewServer; const headers = { astro: 'test', }; diff --git a/packages/integrations/node/test/preview-host.test.js b/packages/integrations/node/test/preview-host.test.ts similarity index 97% rename from packages/integrations/node/test/preview-host.test.js rename to packages/integrations/node/test/preview-host.test.ts index fec925e677f3..f601fc235772 100644 --- a/packages/integrations/node/test/preview-host.test.js +++ b/packages/integrations/node/test/preview-host.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { loadFixture } from './test-utils.ts'; describe('Astro preview host', () => { it('defaults to localhost', async () => { diff --git a/packages/integrations/node/test/redirects.test.js b/packages/integrations/node/test/redirects.test.ts similarity index 91% rename from packages/integrations/node/test/redirects.test.js rename to packages/integrations/node/test/redirects.test.ts index 0688414faa3d..b46a4f2e7da0 100644 --- a/packages/integrations/node/test/redirects.test.js +++ b/packages/integrations/node/test/redirects.test.ts @@ -1,12 +1,11 @@ import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture, waitServerListen } from './test-utils.js'; +import { type Fixture, loadFixture, waitServerListen, type AdapterServer } from './test-utils.ts'; describe('Redirects', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; before(async () => { fixture = await loadFixture({ @@ -25,7 +24,7 @@ describe('Redirects', () => { await fixture.clean(); }); - function fetchEndpoint(url, options = {}) { + function fetchEndpoint(url: string, options: RequestInit = {}) { return fetch(`http://${server.host}:${server.port}/${url}`, { ...options, redirect: 'manual' }); } diff --git a/packages/integrations/node/test/server-host.test.js b/packages/integrations/node/test/server-host.test.ts similarity index 100% rename from packages/integrations/node/test/server-host.test.js rename to packages/integrations/node/test/server-host.test.ts diff --git a/packages/integrations/node/test/sessions.test.js b/packages/integrations/node/test/sessions.test.ts similarity index 93% rename from packages/integrations/node/test/sessions.test.js rename to packages/integrations/node/test/sessions.test.ts index 5abd5a566c5d..9cee8bae9403 100644 --- a/packages/integrations/node/test/sessions.test.js +++ b/packages/integrations/node/test/sessions.test.ts @@ -1,16 +1,14 @@ -// @ts-check import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import * as devalue from 'devalue'; import nodejs from '../dist/index.js'; -import { loadFixture } from './test-utils.js'; +import { type Fixture, loadFixture, type DevServer } from './test-utils.ts'; describe('Astro.session', () => { describe('Production', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - /** @type {import('../../../astro/src/types/public/preview.js').PreviewServer} */ - let app; + let fixture: Fixture; + let app: PreviewServer; before(async () => { fixture = await loadFixture({ @@ -18,8 +16,8 @@ describe('Astro.session', () => { output: 'server', adapter: nodejs({ mode: 'middleware' }), }); - await fixture.build({}); - app = await fixture.preview({}); + await fixture.build(); + app = await fixture.preview(); }); after(async () => { @@ -95,9 +93,8 @@ describe('Astro.session', () => { }); describe('Development', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let devServer; + let fixture: Fixture; + let devServer: DevServer; before(async () => { fixture = await loadFixture({ root: './fixtures/sessions/', diff --git a/packages/integrations/node/test/static-headers.test.js b/packages/integrations/node/test/static-headers.test.ts similarity index 82% rename from packages/integrations/node/test/static-headers.test.js rename to packages/integrations/node/test/static-headers.test.ts index 3dc3d98f4c37..68bfb82b089b 100644 --- a/packages/integrations/node/test/static-headers.test.js +++ b/packages/integrations/node/test/static-headers.test.ts @@ -1,10 +1,12 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import nodejs from '../dist/index.js'; -import { loadFixture, waitServerListen } from './test-utils.js'; +import { type Fixture, loadFixture, waitServerListen, type AdapterServer } from './test-utils.ts'; + +type StaticHeaderEntry = { pathname: string; headers: Array<{ key: string; value: string }> }; describe('Static headers', () => { - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ root: './fixtures/static-headers' }); @@ -12,11 +14,13 @@ describe('Static headers', () => { }); it('CSP headers are added when CSP is enabled', async () => { - const headers = JSON.parse(await fixture.readFile('../dist/_headers.json')); + const headers: StaticHeaderEntry[] = JSON.parse( + await fixture.readFile('../dist/_headers.json'), + ); const csp = headers - .find((x) => x.pathname === '/') - .headers.find((x) => x.key === 'Content-Security-Policy'); + .find((x) => x.pathname === '/')! + .headers.find((x) => x.key === 'Content-Security-Policy')!; assert.notEqual(csp, undefined, 'the index must have CSP headers'); assert.ok( @@ -29,9 +33,8 @@ describe('Static headers', () => { }); describe('Static headers', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; before(async () => { fixture = await loadFixture({ @@ -55,7 +58,7 @@ describe('Static headers', () => { it('CSP headers are added to the request', async () => { const res = await fetch(`http://${server.host}:${server.port}/`); - const cps = res.headers.get('Content-Security-Policy'); + const cps = res.headers.get('Content-Security-Policy')!; assert.ok( cps.includes('script-src'), 'should contain script-src directive due to server island', @@ -64,7 +67,7 @@ describe('Static headers', () => { it('CSP headers are added to dynamic orute', async () => { const res = await fetch(`http://${server.host}:${server.port}/one`); - const cps = res.headers.get('Content-Security-Policy'); + const cps = res.headers.get('Content-Security-Policy')!; assert.ok( cps.includes('script-src'), 'should contain script-src directive due to server island', @@ -73,9 +76,8 @@ describe('Static headers', () => { }); describe('Static headers with non-root base', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; before(async () => { fixture = await loadFixture({ diff --git a/packages/integrations/node/test/test-utils.js b/packages/integrations/node/test/test-utils.js deleted file mode 100644 index 8553a159e09c..000000000000 --- a/packages/integrations/node/test/test-utils.js +++ /dev/null @@ -1,82 +0,0 @@ -import { EventEmitter } from 'node:events'; -import httpMocks from 'node-mocks-http'; -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 - */ - -export function loadFixture(inlineConfig) { - if (!inlineConfig?.root) throw new Error("Must provide { root: './fixtures/...' }"); - - // resolve the relative root (i.e. "./fixtures/tailwindcss") to a full filepath - // without this, the main `loadFixture` helper will resolve relative to `packages/astro/test` - return baseLoadFixture({ - ...inlineConfig, - root: new URL(inlineConfig.root, import.meta.url).toString(), - }); -} - -export function createRequestAndResponse(reqOptions) { - const req = httpMocks.createRequest(reqOptions); - - const res = httpMocks.createResponse({ - eventEmitter: EventEmitter, - req, - }); - - const done = toPromise(res); - - // Get the response as text - const text = async () => { - const chunks = await done; - return buffersToString(chunks); - }; - - return { req, res, done, text }; -} - -/** @returns {Promise>} */ -function toPromise(res) { - return new Promise((resolve) => { - // node-mocks-http doesn't correctly handle non-Buffer typed arrays, - // so override the write method to fix it. - const write = res.write; - res.write = function (data, encoding) { - if (ArrayBuffer.isView(data) && !Buffer.isBuffer(data)) { - data = Buffer.from(data.buffer); - } - return write.call(this, data, encoding); - }; - res.on('end', () => { - const chunks = res._getChunks(); - resolve(chunks); - }); - }); -} - -function buffersToString(buffers) { - const decoder = new TextDecoder(); - let str = ''; - for (const buffer of buffers) { - str += decoder.decode(buffer); - } - return str; -} - -export function waitServerListen(server) { - return new Promise((resolve, reject) => { - function onListen() { - server.off('error', onError); - resolve(); - } - function onError(error) { - server.off('listening', onListen); - reject(error); - } - server.once('listening', onListen); - server.once('error', onError); - }); -} diff --git a/packages/integrations/node/test/test-utils.ts b/packages/integrations/node/test/test-utils.ts new file mode 100644 index 000000000000..3fea903844cd --- /dev/null +++ b/packages/integrations/node/test/test-utils.ts @@ -0,0 +1,94 @@ +import { EventEmitter } from 'node:events'; +import type { Server, ServerResponse } from 'node:http'; +import * as httpMocks from 'node-mocks-http'; +import { + type AstroInlineConfig, + type Fixture, + type AdapterServer, + type DevServer, + loadFixture as baseLoadFixture, +} from '../../../astro/test/test-utils.js'; +import type * as express from 'express'; + +process.env.ASTRO_NODE_AUTOSTART = 'disabled'; +process.env.ASTRO_NODE_LOGGING = 'disabled'; + +export type { AstroInlineConfig, Fixture, AdapterServer, DevServer }; + +export function loadFixture(inlineConfig: AstroInlineConfig) { + if (!inlineConfig?.root) throw new Error("Must provide { root: './fixtures/...' }"); + + // resolve the relative root (i.e. "./fixtures/tailwindcss") to a full filepath + // without this, the main `loadFixture` helper will resolve relative to `packages/astro/test` + return baseLoadFixture({ + ...inlineConfig, + root: new URL(inlineConfig.root as string, import.meta.url).toString(), + }); +} + +export function createRequestAndResponse(reqOptions?: httpMocks.RequestOptions): { + req: httpMocks.MockRequest; + res: httpMocks.MockResponse; + done: Promise[]>; + text: () => Promise; +} { + const req: httpMocks.MockRequest = + httpMocks.createRequest(reqOptions); + + const res: httpMocks.MockResponse = httpMocks.createResponse({ + eventEmitter: EventEmitter, + req, + }); + + const done: Promise[]> = toPromise(res); + + // Get the response as text + const text: () => Promise = async () => { + const chunks = await done; + return buffersToString(chunks); + }; + + return { req, res, done, text }; +} + +function toPromise(res: httpMocks.MockResponse): Promise> { + return new Promise((resolve) => { + // node-mocks-http doesn't correctly handle non-Buffer typed arrays, + // so override the write method to fix it. + const write = res.write; + res.write = function (data: any, encoding?: any) { + if (ArrayBuffer.isView(data) && !Buffer.isBuffer(data)) { + data = Buffer.from(data.buffer); + } + return write.call(this, data, encoding); + }; + res.on('end', () => { + const chunks = (res as any)._getChunks(); + resolve(chunks); + }); + }); +} + +function buffersToString(buffers: Array) { + const decoder = new TextDecoder(); + let str = ''; + for (const buffer of buffers) { + str += decoder.decode(buffer); + } + return str; +} + +export function waitServerListen(server: Server): Promise { + return new Promise((resolve, reject) => { + function onListen() { + server.off('error', onError); + resolve(); + } + function onError(error: Error) { + server.off('listening', onListen); + reject(error); + } + server.once('listening', onListen); + server.once('error', onError); + }); +} diff --git a/packages/integrations/node/test/trailing-slash.test.js b/packages/integrations/node/test/trailing-slash.test.ts similarity index 98% rename from packages/integrations/node/test/trailing-slash.test.js rename to packages/integrations/node/test/trailing-slash.test.ts index 8bd0be007c3e..ef375823761d 100644 --- a/packages/integrations/node/test/trailing-slash.test.js +++ b/packages/integrations/node/test/trailing-slash.test.ts @@ -2,16 +2,11 @@ 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, waitServerListen } from './test-utils.js'; - -/** - * @typedef {import('../../../astro/test/test-utils').Fixture} Fixture - */ +import { type Fixture, loadFixture, waitServerListen, type AdapterServer } from './test-utils.ts'; describe('Trailing slash', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - let server; + let fixture: Fixture; + let server: AdapterServer; describe('Always', async () => { describe('With base', async () => { before(async () => { diff --git a/packages/integrations/node/test/url.test.js b/packages/integrations/node/test/url.test.ts similarity index 82% rename from packages/integrations/node/test/url.test.js rename to packages/integrations/node/test/url.test.ts index c3e90ead56f9..2c7b4fbac32f 100644 --- a/packages/integrations/node/test/url.test.js +++ b/packages/integrations/node/test/url.test.ts @@ -1,13 +1,13 @@ import * as assert from 'node:assert/strict'; +import { Socket } from 'node:net'; import { before, describe, it } from 'node:test'; import { TLSSocket } from 'node:tls'; import * as cheerio from 'cheerio'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; describe('URL', () => { - /** @type {import('./test-utils.js').Fixture} */ - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ @@ -19,7 +19,7 @@ describe('URL', () => { }); it('return http when non-secure', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ url: '/', }); @@ -27,26 +27,28 @@ describe('URL', () => { handler(req, res); req.send(); - const html = await text(); + const html: string = await text(); assert.equal(html.includes('http:'), true); + assert.equal(html.includes('https:'), false); }); it('return https when secure', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ - socket: new TLSSocket(), + socket: new TLSSocket(new Socket()), url: '/', }); handler(req, res); req.send(); - const html = await text(); + const html: string = await text(); + assert.equal(html.includes('http:'), false); assert.equal(html.includes('https:'), true); }); it('return http when the X-Forwarded-Proto header is set to http', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'http' }, url: '/', @@ -60,7 +62,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'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https' }, url: '/', @@ -74,7 +76,7 @@ describe('URL', () => { }); it('includes forwarded host and port in the url', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', @@ -95,7 +97,7 @@ describe('URL', () => { }); it('accepts port in forwarded host and forwarded port', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', @@ -115,7 +117,7 @@ describe('URL', () => { }); it('ignores X-Forwarded-Host when no allowedDomains configured', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', @@ -136,7 +138,7 @@ describe('URL', () => { }); it('rejects port in forwarded host when port not in allowedDomains', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', @@ -157,7 +159,7 @@ describe('URL', () => { }); it('rejects empty X-Forwarded-Host with allowedDomains configured', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', @@ -178,7 +180,7 @@ describe('URL', () => { }); it('rejects X-Forwarded-Host with path injection attempt', async () => { - const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, text } = createRequestAndResponse({ headers: { 'X-Forwarded-Proto': 'https', diff --git a/packages/integrations/node/test/well-known-locations.test.js b/packages/integrations/node/test/well-known-locations.test.ts similarity index 84% rename from packages/integrations/node/test/well-known-locations.test.js rename to packages/integrations/node/test/well-known-locations.test.ts index 57082f28ad6e..a8afdd1519b4 100644 --- a/packages/integrations/node/test/well-known-locations.test.js +++ b/packages/integrations/node/test/well-known-locations.test.ts @@ -1,11 +1,11 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; +import type { PreviewServer } from '../../../astro/src/types/public/preview.js'; import nodejs from '../dist/index.js'; -import { createRequestAndResponse, loadFixture } from './test-utils.js'; +import { createRequestAndResponse, type Fixture, loadFixture } from './test-utils.ts'; describe('test URIs beginning with a dot', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; + let fixture: Fixture; before(async () => { fixture = await loadFixture({ @@ -17,7 +17,7 @@ describe('test URIs beginning with a dot', () => { }); describe('can load well-known URIs', async () => { - let devPreview; + let devPreview: PreviewServer; before(async () => { devPreview = await fixture.preview(); @@ -46,7 +46,7 @@ describe('test URIs beginning with a dot', () => { describe('dotfile access via unnormalized paths', async () => { it('denies dotfile access when path contains .well-known/../ traversal', async () => { - const { handler } = await import('./fixtures/well-known-locations/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'GET', url: '/.well-known/../.hidden-file', @@ -64,7 +64,7 @@ describe('test URIs beginning with a dot', () => { }); it('denies dotfolder file access when path contains .well-known/../ traversal', async () => { - const { handler } = await import('./fixtures/well-known-locations/dist/server/entry.mjs'); + const handler = await fixture.loadNodeAdapterHandler(); const { req, res, done } = createRequestAndResponse({ method: 'GET', url: '/.well-known/../.hidden/file.json', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7deedf8b21b..b1dbd3ac3ad9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -729,7 +729,7 @@ importers: version: 3.2.0 node-mocks-http: specifier: ^1.17.2 - version: 1.17.2(@types/node@25.2.3) + version: 1.17.2(@types/express@5.0.6)(@types/node@25.2.3) parse-srcset: specifier: ^1.0.2 version: 1.0.2 @@ -5651,6 +5651,9 @@ importers: '@fastify/static': specifier: ^9.0.0 version: 9.0.0 + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 '@types/node': specifier: ^22.10.6 version: 22.19.11 @@ -5680,7 +5683,7 @@ importers: version: 5.8.3 node-mocks-http: specifier: ^1.17.2 - version: 1.17.2(@types/node@22.19.11) + version: 1.17.2(@types/express@5.0.6)(@types/node@22.19.11) packages/integrations/node/test/fixtures/api-route: dependencies: @@ -9875,12 +9878,18 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + '@types/canvas-confetti@1.9.0': resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -9896,6 +9905,12 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/express-serve-static-core@5.1.1': + resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} + + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -9905,6 +9920,9 @@ packages: '@types/http-cache-semantics@4.2.0': resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -9977,6 +9995,12 @@ packages: '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/qs@6.15.0': + resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/react-dom@18.3.7': resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} peerDependencies: @@ -10000,6 +10024,9 @@ packages: '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + '@types/server-destroy@1.0.4': resolution: {integrity: sha512-+x8oAQ4Xp1wtDi2Hlmi7gUNXZNVhB5EoSQpi0qEmINdDN5Ab724WLGAalEdT1SudVY/NzMhbfZO7vU+klT0R+A==} @@ -18784,6 +18811,11 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 25.2.3 + '@types/canvas-confetti@1.9.0': {} '@types/chai@5.2.3': @@ -18791,6 +18823,10 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/connect@3.4.38': + dependencies: + '@types/node': 25.2.3 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -18805,6 +18841,19 @@ snapshots: '@types/estree@1.0.8': {} + '@types/express-serve-static-core@5.1.1': + dependencies: + '@types/node': 25.2.3 + '@types/qs': 6.15.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + + '@types/express@5.0.6': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.1 + '@types/serve-static': 2.2.0 + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -18813,6 +18862,8 @@ snapshots: '@types/http-cache-semantics@4.2.0': {} + '@types/http-errors@2.0.5': {} + '@types/istanbul-lib-coverage@2.0.6': {} '@types/js-yaml@4.0.9': {} @@ -18881,6 +18932,10 @@ snapshots: '@types/prop-types@15.7.15': {} + '@types/qs@6.15.0': {} + + '@types/range-parser@1.2.7': {} + '@types/react-dom@18.3.7(@types/react@18.3.28)': dependencies: '@types/react': 18.3.28 @@ -18904,6 +18959,11 @@ snapshots: dependencies: '@types/node': 25.2.3 + '@types/serve-static@2.2.0': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 25.2.3 + '@types/server-destroy@1.0.4': dependencies: '@types/node': 25.2.3 @@ -22945,7 +23005,7 @@ snapshots: node-mock-http@1.0.4: {} - node-mocks-http@1.17.2(@types/node@22.19.11): + node-mocks-http@1.17.2(@types/express@5.0.6)(@types/node@22.19.11): dependencies: accepts: 1.3.8 content-disposition: 0.5.4 @@ -22958,9 +23018,10 @@ snapshots: range-parser: 1.2.1 type-is: 1.6.18 optionalDependencies: + '@types/express': 5.0.6 '@types/node': 22.19.11 - node-mocks-http@1.17.2(@types/node@25.2.3): + node-mocks-http@1.17.2(@types/express@5.0.6)(@types/node@25.2.3): dependencies: accepts: 1.3.8 content-disposition: 0.5.4 @@ -22973,6 +23034,7 @@ snapshots: range-parser: 1.2.1 type-is: 1.6.18 optionalDependencies: + '@types/express': 5.0.6 '@types/node': 25.2.3 node-releases@2.0.27: {}