diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json
index 5cbe0a5c6bbd..a8b9bca7ab39 100644
--- a/packages/integrations/netlify/package.json
+++ b/packages/integrations/netlify/package.json
@@ -33,10 +33,11 @@
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"test": "pnpm run test-fn && pnpm run test-static && pnpm run test:dev",
- "test-fn": "astro-scripts test \"test/functions/*.test.js\"",
- "test:dev": "astro-scripts test \"test/development/*.test.js\"",
- "test-static": "astro-scripts test \"test/static/*.test.js\"",
- "test:hosted": "astro-scripts test \"test/hosted/*.test.js\""
+ "test-fn": "astro-scripts test \"test/functions/*.test.ts\"",
+ "test:dev": "astro-scripts test \"test/development/*.test.ts\"",
+ "test-static": "astro-scripts test \"test/static/*.test.ts\"",
+ "test:hosted": "astro-scripts test \"test/hosted/*.test.js\"",
+ "typecheck:tests": "tsc --build tsconfig.test.json"
},
"dependencies": {
"@astrojs/internal-helpers": "workspace:*",
diff --git a/packages/integrations/netlify/test/development/primitives.test.js b/packages/integrations/netlify/test/development/primitives.test.ts
similarity index 88%
rename from packages/integrations/netlify/test/development/primitives.test.js
rename to packages/integrations/netlify/test/development/primitives.test.ts
index 016305e42cae..a8fa8ae4db67 100644
--- a/packages/integrations/netlify/test/development/primitives.test.js
+++ b/packages/integrations/netlify/test/development/primitives.test.ts
@@ -2,14 +2,13 @@ import assert from 'node:assert/strict';
import { after, afterEach, before, describe, it } from 'node:test';
import * as cheerio from 'cheerio';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
+import { type DevServer, type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
import netlifyAdapter from '../../dist/index.js';
describe('Netlify primitives', () => {
describe('Development', () => {
- /** @type {import('../../../../astro/test/test-utils').Fixture} */
- let fixture;
- let devServer;
+ let fixture: Fixture;
+ let devServer: DevServer;
before(async () => {
fixture = await loadFixture({
root: new URL('./fixtures/primitives/', import.meta.url),
@@ -65,9 +64,11 @@ describe('Netlify primitives', () => {
it('loads images in development', async () => {
const imgResponse = await fixture.fetch('/astronaut');
const $img = cheerio.load(await imgResponse.text());
- const images = $img('img').map((_i, el) => {
- return $img(el).attr('src');
- });
+ const images = $img('img')
+ .map((_i, el) => {
+ return $img(el).attr('src');
+ })
+ .toArray();
for (const imgSrc of images) {
assert(imgSrc.startsWith('/.netlify/images'));
@@ -89,9 +90,11 @@ describe('Netlify primitives', () => {
try {
const imgResponse = await cdnDisabledFixture.fetch('/astronaut');
const $img = cheerio.load(await imgResponse.text());
- const images = $img('img').map((_i, el) => {
- return $img(el).attr('src');
- });
+ const images = $img('img')
+ .map((_i, el) => {
+ return $img(el).attr('src');
+ })
+ .toArray();
for (const imgSrc of images) {
assert(
@@ -101,7 +104,7 @@ describe('Netlify primitives', () => {
}
} finally {
await cdnDisabledServer.stop();
- process.env.DISABLE_IMAGE_CDN = undefined;
+ delete process.env.DISABLE_IMAGE_CDN;
}
});
});
diff --git a/packages/integrations/netlify/test/functions/cookies.test.js b/packages/integrations/netlify/test/functions/cookies.test.js
deleted file mode 100644
index 6ef16763ed5d..000000000000
--- a/packages/integrations/netlify/test/functions/cookies.test.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-
-describe(
- 'Cookies',
- () => {
- let fixture;
-
- before(async () => {
- fixture = await loadFixture({ root: new URL('./fixtures/cookies/', import.meta.url) });
- await fixture.build();
- });
-
- it('Can set multiple', async () => {
- const entryURL = new URL(
- './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(
- new Request('http://example.com/login', { method: 'POST', body: '{}' }),
- {},
- );
- assert.equal(resp.status, 301);
- assert.equal(resp.headers.get('location'), '/');
- assert.deepEqual(resp.headers.getSetCookie(), ['foo=foo; HttpOnly', 'bar=bar; HttpOnly']);
- });
-
- it('Can set partitioned cookie', async () => {
- const entryURL = new URL(
- './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(new Request('http://example.com/partitioned'), {});
- assert.equal(resp.status, 200);
- const cookie = resp.headers.getSetCookie()[0];
- assert.ok(cookie.includes('Partitioned'), 'Cookie should include Partitioned attribute');
- });
-
- it('renders dynamic 404 page', async () => {
- const entryURL = new URL(
- './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(
- new Request('http://example.com/nonexistant-page', {
- headers: {
- 'x-test': 'bar',
- },
- }),
- {},
- );
- assert.equal(resp.status, 404);
- const text = await resp.text();
- assert.equal(text.includes('This is my custom 404 page'), true);
- assert.equal(text.includes('x-test: bar'), true);
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/cookies.test.ts b/packages/integrations/netlify/test/functions/cookies.test.ts
new file mode 100644
index 000000000000..d3c0f7d434db
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/cookies.test.ts
@@ -0,0 +1,59 @@
+import * as assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
+
+describe('Cookies', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ before(async () => {
+ fixture = await loadFixture({ root: new URL('./fixtures/cookies/', import.meta.url) });
+ await fixture.build({});
+ });
+
+ it('Can set multiple', async () => {
+ const entryURL = new URL(
+ './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(
+ new Request('http://example.com/login', { method: 'POST', body: '{}' }),
+ {},
+ );
+ assert.equal(resp.status, 301);
+ assert.equal(resp.headers.get('location'), '/');
+ assert.deepEqual(resp.headers.getSetCookie(), ['foo=foo; HttpOnly', 'bar=bar; HttpOnly']);
+ });
+
+ it('Can set partitioned cookie', async () => {
+ const entryURL = new URL(
+ './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(new Request('http://example.com/partitioned'), {});
+ assert.equal(resp.status, 200);
+ const cookie = resp.headers.getSetCookie()[0];
+ assert.ok(cookie.includes('Partitioned'), 'Cookie should include Partitioned attribute');
+ });
+
+ it('renders dynamic 404 page', async () => {
+ const entryURL = new URL(
+ './fixtures/cookies/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(
+ new Request('http://example.com/nonexistant-page', {
+ headers: {
+ 'x-test': 'bar',
+ },
+ }),
+ {},
+ );
+ assert.equal(resp.status, 404);
+ const text = await resp.text();
+ assert.equal(text.includes('This is my custom 404 page'), true);
+ assert.equal(text.includes('x-test: bar'), true);
+ });
+});
diff --git a/packages/integrations/netlify/test/functions/edge-middleware.test.js b/packages/integrations/netlify/test/functions/edge-middleware.test.js
deleted file mode 100644
index 6d255f4dc7f9..000000000000
--- a/packages/integrations/netlify/test/functions/edge-middleware.test.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { after, before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-
-describe(
- 'Middleware',
- () => {
- const root = new URL('./fixtures/middleware/', import.meta.url);
-
- describe('middlewareMode: classic', () => {
- let fixture;
- before(async () => {
- process.env.EDGE_MIDDLEWARE = 'false';
- fixture = await loadFixture({ root });
- await fixture.build();
- });
-
- it('emits no edge function', async () => {
- assert.equal(
- fixture.pathExists('../.netlify/v1/edge-functions/middleware/middleware.mjs'),
- false,
- );
- });
-
- it('applies middleware to static files at build-time', async () => {
- // prerendered page has middleware applied at build time
- const prerenderedPage = await fixture.readFile('prerender/index.html');
- assert.equal(prerenderedPage.includes('
Middleware'), true);
- });
-
- after(async () => {
- process.env.EDGE_MIDDLEWARE = undefined;
- await fixture.clean();
- });
- });
-
- describe('middlewareMode: edge', () => {
- let fixture;
- before(async () => {
- process.env.EDGE_MIDDLEWARE = 'true';
- fixture = await loadFixture({ root });
- await fixture.build();
- });
-
- it('emits an edge function', async () => {
- const contents = await fixture.readFile(
- '../.netlify/v1/edge-functions/middleware/middleware.mjs',
- );
- assert.equal(contents.includes('"Hello world"'), false);
- });
-
- it.skip('does not apply middleware during prerendering', async () => {
- const prerenderedPage = await fixture.readFile('prerender/index.html');
- assert.equal(prerenderedPage.includes(''), true);
- });
-
- after(async () => {
- process.env.EDGE_MIDDLEWARE = undefined;
- await fixture.clean();
- });
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/edge-middleware.test.ts b/packages/integrations/netlify/test/functions/edge-middleware.test.ts
new file mode 100644
index 000000000000..e1a667c83924
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/edge-middleware.test.ts
@@ -0,0 +1,60 @@
+import * as assert from 'node:assert/strict';
+import { after, before, describe, it } from 'node:test';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
+
+describe('Middleware', { timeout: 120000 }, () => {
+ const root = new URL('./fixtures/middleware/', import.meta.url);
+
+ describe('middlewareMode: classic', () => {
+ let fixture: Fixture;
+ before(async () => {
+ process.env.EDGE_MIDDLEWARE = 'false';
+ fixture = await loadFixture({ root });
+ await fixture.build({});
+ });
+
+ it('emits no edge function', async () => {
+ assert.equal(
+ fixture.pathExists('../.netlify/v1/edge-functions/middleware/middleware.mjs'),
+ false,
+ );
+ });
+
+ it('applies middleware to static files at build-time', async () => {
+ // prerendered page has middleware applied at build time
+ const prerenderedPage = await fixture.readFile('prerender/index.html');
+ assert.equal(prerenderedPage.includes('Middleware'), true);
+ });
+
+ after(async () => {
+ delete process.env.EDGE_MIDDLEWARE;
+ await fixture.clean();
+ });
+ });
+
+ describe('middlewareMode: edge', () => {
+ let fixture: Fixture;
+ before(async () => {
+ process.env.EDGE_MIDDLEWARE = 'true';
+ fixture = await loadFixture({ root });
+ await fixture.build({});
+ });
+
+ it('emits an edge function', async () => {
+ const contents = await fixture.readFile(
+ '../.netlify/v1/edge-functions/middleware/middleware.mjs',
+ );
+ assert.equal(contents.includes('"Hello world"'), false);
+ });
+
+ it.skip('does not apply middleware during prerendering', async () => {
+ const prerenderedPage = await fixture.readFile('prerender/index.html');
+ assert.equal(prerenderedPage.includes(''), true);
+ });
+
+ after(async () => {
+ delete process.env.EDGE_MIDDLEWARE;
+ await fixture.clean();
+ });
+ });
+});
diff --git a/packages/integrations/netlify/test/functions/image-cdn.test.js b/packages/integrations/netlify/test/functions/image-cdn.test.js
deleted file mode 100644
index 8d6196817607..000000000000
--- a/packages/integrations/netlify/test/functions/image-cdn.test.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { after, before, describe, it } from 'node:test';
-import { remotePatternToRegex } from '@astrojs/netlify';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-import imageService from '../../dist/image-service.js';
-
-describe(
- 'Image CDN',
- () => {
- const root = new URL('./fixtures/middleware/', import.meta.url);
-
- describe('configuration', () => {
- after(() => {
- process.env.DISABLE_IMAGE_CDN = undefined;
- });
-
- it('enables Netlify Image CDN', async () => {
- const fixture = await loadFixture({ root });
- await fixture.build();
-
- const astronautPage = await fixture.readFile('astronaut/index.html');
- assert.equal(astronautPage.includes(`src="/.netlify/image`), true);
- });
-
- it('respects image CDN opt-out', async () => {
- process.env.DISABLE_IMAGE_CDN = 'true';
- const fixture = await loadFixture({ root });
- await fixture.build();
-
- const astronautPage = await fixture.readFile('astronaut/index.html');
- assert.equal(astronautPage.includes(`src="/_astro/astronaut.`), true);
- });
- });
-
- describe('remote image config', () => {
- let regexes;
-
- before(async () => {
- const fixture = await loadFixture({ root });
- await fixture.build();
-
- const config = await fixture.readFile('../.netlify/v1/config.json');
- if (config) {
- regexes = JSON.parse(config).images.remote_images.map((pattern) => new RegExp(pattern));
- }
- });
-
- it('generates remote image config patterns', async () => {
- assert.equal(regexes?.length, 3);
- });
-
- it('generates correct config for domains', async () => {
- const domain = regexes[0];
- assert.equal(domain.test('https://example.net/image.jpg'), true);
- assert.equal(
- domain.test('https://www.example.net/image.jpg'),
- false,
- 'subdomain should not match',
- );
- assert.equal(domain.test('http://example.net/image.jpg'), true, 'http should match');
- assert.equal(
- domain.test('https://example.net/subdomain/image.jpg'),
- true,
- 'subpath should match',
- );
- const subdomain = regexes[1];
- assert.equal(
- subdomain.test('https://secret.example.edu/image.jpg'),
- true,
- 'should match subdomains',
- );
- assert.equal(
- subdomain.test('https://secretxexample.edu/image.jpg'),
- false,
- 'should not use dots in domains as wildcards',
- );
- });
-
- it('generates correct config for remotePatterns', async () => {
- const patterns = regexes[2];
- assert.equal(
- patterns.test('https://example.org/images/1.jpg'),
- true,
- 'should match domain',
- );
- assert.equal(
- patterns.test('https://www.example.org/images/2.jpg'),
- true,
- 'www subdomain should match',
- );
- assert.equal(
- patterns.test('https://www.subdomain.example.org/images/2.jpg'),
- false,
- 'second level subdomain should not match',
- );
- assert.equal(
- patterns.test('https://example.org/not-images/2.jpg'),
- false,
- 'wrong path should not match',
- );
- });
-
- it('warns when remotepatterns generates an invalid regex', async (t) => {
- const logger = {
- warn: t.mock.fn(),
- };
- const regex = remotePatternToRegex(
- {
- hostname: '*.examp[le.org',
- pathname: '/images/*',
- },
- logger,
- );
- assert.strictEqual(regex, undefined);
- const calls = logger.warn.mock.calls;
- assert.strictEqual(calls.length, 1);
- assert.equal(
- calls[0].arguments[0],
- 'Could not generate a valid regex from the remotePattern "{"hostname":"*.examp[le.org","pathname":"/images/*"}". Please check the syntax.',
- );
- });
- });
-
- describe('fit parameter', () => {
- it('includes fit parameter in image URL', () => {
- const url = imageService.getURL({
- src: 'images/astronaut.jpg',
- width: 300,
- height: 400,
- fit: 'cover',
- format: 'webp',
- });
- assert.ok(url.includes('fit=cover'), `Expected fit=cover in URL, got: ${url}`);
- });
-
- it('maps Astro fit values to Netlify equivalents', () => {
- const cases = [
- ['contain', 'contain'],
- ['cover', 'cover'],
- ['fill', 'fill'],
- ['inside', 'contain'],
- ['outside', 'cover'],
- ['scale-down', 'contain'],
- ];
- for (const [astroFit, netlifyFit] of cases) {
- const url = imageService.getURL({
- src: 'img.jpg',
- width: 100,
- height: 100,
- fit: astroFit,
- });
- assert.ok(
- url.includes(`fit=${netlifyFit}`),
- `Expected fit=${netlifyFit} for astro fit="${astroFit}", got: ${url}`,
- );
- }
- });
-
- it('omits fit parameter when fit is none or unset', () => {
- const withNone = imageService.getURL({
- src: 'img.jpg',
- width: 100,
- height: 100,
- fit: 'none',
- });
- assert.ok(
- !withNone.includes('fit='),
- `Expected no fit param for fit="none", got: ${withNone}`,
- );
-
- const withoutFit = imageService.getURL({ src: 'img.jpg', width: 100, height: 100 });
- assert.ok(
- !withoutFit.includes('fit='),
- `Expected no fit param when unset, got: ${withoutFit}`,
- );
- });
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/image-cdn.test.ts b/packages/integrations/netlify/test/functions/image-cdn.test.ts
new file mode 100644
index 000000000000..4b8ed3783568
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/image-cdn.test.ts
@@ -0,0 +1,179 @@
+import * as assert from 'node:assert/strict';
+import { after, before, describe, it } from 'node:test';
+import type { AstroIntegrationLogger } from 'astro';
+import { remotePatternToRegex } from '@astrojs/netlify';
+import { loadFixture } from '../../../../astro/test/test-utils.js';
+import imageService from '../../dist/image-service.js';
+
+describe('Image CDN', { timeout: 120000 }, () => {
+ const root = new URL('./fixtures/middleware/', import.meta.url);
+
+ describe('configuration', () => {
+ after(() => {
+ delete process.env.DISABLE_IMAGE_CDN;
+ });
+
+ it('enables Netlify Image CDN', async () => {
+ const fixture = await loadFixture({ root });
+ await fixture.build({});
+
+ const astronautPage = await fixture.readFile('astronaut/index.html');
+ assert.equal(astronautPage.includes(`src="/.netlify/image`), true);
+ });
+
+ it('respects image CDN opt-out', async () => {
+ process.env.DISABLE_IMAGE_CDN = 'true';
+ const fixture = await loadFixture({ root });
+ await fixture.build({});
+
+ const astronautPage = await fixture.readFile('astronaut/index.html');
+ assert.equal(astronautPage.includes(`src="/_astro/astronaut.`), true);
+ });
+ });
+
+ describe('remote image config', () => {
+ let regexes: RegExp[] | undefined;
+
+ before(async () => {
+ const fixture = await loadFixture({ root });
+ await fixture.build({});
+
+ const config = await fixture.readFile('../.netlify/v1/config.json');
+ if (config) {
+ regexes = JSON.parse(config).images.remote_images.map(
+ (pattern: string) => new RegExp(pattern),
+ );
+ }
+ });
+
+ it('generates remote image config patterns', async () => {
+ assert.equal(regexes?.length, 3);
+ });
+
+ it('generates correct config for domains', async () => {
+ const domain = regexes![0];
+ assert.equal(domain.test('https://example.net/image.jpg'), true);
+ assert.equal(
+ domain.test('https://www.example.net/image.jpg'),
+ false,
+ 'subdomain should not match',
+ );
+ assert.equal(domain.test('http://example.net/image.jpg'), true, 'http should match');
+ assert.equal(
+ domain.test('https://example.net/subdomain/image.jpg'),
+ true,
+ 'subpath should match',
+ );
+ const subdomain = regexes![1];
+ assert.equal(
+ subdomain.test('https://secret.example.edu/image.jpg'),
+ true,
+ 'should match subdomains',
+ );
+ assert.equal(
+ subdomain.test('https://secretxexample.edu/image.jpg'),
+ false,
+ 'should not use dots in domains as wildcards',
+ );
+ });
+
+ it('generates correct config for remotePatterns', async () => {
+ const patterns = regexes![2];
+ assert.equal(patterns.test('https://example.org/images/1.jpg'), true, 'should match domain');
+ assert.equal(
+ patterns.test('https://www.example.org/images/2.jpg'),
+ true,
+ 'www subdomain should match',
+ );
+ assert.equal(
+ patterns.test('https://www.subdomain.example.org/images/2.jpg'),
+ false,
+ 'second level subdomain should not match',
+ );
+ assert.equal(
+ patterns.test('https://example.org/not-images/2.jpg'),
+ false,
+ 'wrong path should not match',
+ );
+ });
+
+ it('warns when remotepatterns generates an invalid regex', async (t) => {
+ const warnFn = t.mock.fn();
+ const logger = { warn: warnFn } as unknown as AstroIntegrationLogger;
+ const regex = remotePatternToRegex(
+ {
+ hostname: '*.examp[le.org',
+ pathname: '/images/*',
+ },
+ logger,
+ );
+ assert.strictEqual(regex, undefined);
+ const calls = warnFn.mock.calls;
+ assert.strictEqual(calls.length, 1);
+ assert.equal(
+ calls[0].arguments[0],
+ 'Could not generate a valid regex from the remotePattern "{"hostname":"*.examp[le.org","pathname":"/images/*"}". Please check the syntax.',
+ );
+ });
+ });
+
+ describe('fit parameter', () => {
+ // imageService.getURL is typed as returning string | Promise, but this
+ // implementation always returns a string synchronously
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const getURL = (options: any): string => imageService.getURL(options, {} as any) as string;
+
+ it('includes fit parameter in image URL', () => {
+ const url = getURL({
+ src: 'images/astronaut.jpg',
+ width: 300,
+ height: 400,
+ fit: 'cover',
+ format: 'webp',
+ });
+ assert.ok(url.includes('fit=cover'), `Expected fit=cover in URL, got: ${url}`);
+ });
+
+ it('maps Astro fit values to Netlify equivalents', () => {
+ const cases = [
+ ['contain', 'contain'],
+ ['cover', 'cover'],
+ ['fill', 'fill'],
+ ['inside', 'contain'],
+ ['outside', 'cover'],
+ ['scale-down', 'contain'],
+ ];
+ for (const [astroFit, netlifyFit] of cases) {
+ const url = getURL({
+ src: 'img.jpg',
+ width: 100,
+ height: 100,
+ fit: astroFit,
+ });
+ assert.ok(
+ url.includes(`fit=${netlifyFit}`),
+ `Expected fit=${netlifyFit} for astro fit="${astroFit}", got: ${url}`,
+ );
+ }
+ });
+
+ it('omits fit parameter when fit is none or unset', () => {
+ const withNone = getURL({
+ src: 'img.jpg',
+ width: 100,
+ height: 100,
+ fit: 'none',
+ });
+ assert.ok(
+ !withNone.includes('fit='),
+ `Expected no fit param for fit="none", got: ${withNone}`,
+ );
+
+ const withoutFit = getURL({ src: 'img.jpg', width: 100, height: 100 });
+ assert.ok(
+ !withoutFit.includes('fit='),
+ `Expected no fit param when unset, got: ${withoutFit}`,
+ );
+ });
+ });
+});
diff --git a/packages/integrations/netlify/test/functions/include-files.test.js b/packages/integrations/netlify/test/functions/include-files.test.js
deleted file mode 100644
index e54e116a78c3..000000000000
--- a/packages/integrations/netlify/test/functions/include-files.test.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { existsSync } from 'node:fs';
-import { after, before, describe, it } from 'node:test';
-import netlify from '@astrojs/netlify';
-import * as cheerio from 'cheerio';
-import { globSync } from 'tinyglobby';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-
-describe(
- 'Included vite assets files',
- () => {
- let fixture;
-
- const root = new URL('./fixtures/includes/', import.meta.url);
- const expectedCwd = new URL('.netlify/v1/functions/ssr/packages/integrations/netlify/', root);
-
- const expectedAssetsInclude = ['./*.json'];
- const excludedAssets = ['./files/exclude-asset.json'];
-
- before(async () => {
- fixture = await loadFixture({
- root,
- vite: {
- assetsInclude: expectedAssetsInclude,
- },
- adapter: netlify({
- excludeFiles: excludedAssets,
- }),
- });
- await fixture.build();
- });
-
- it('Emits vite assets files', async () => {
- for (const pattern of expectedAssetsInclude) {
- const files = globSync(pattern);
- for (const file of files) {
- assert.ok(
- existsSync(new URL(file, expectedCwd)),
- `Expected file ${pattern} to exist in build`,
- );
- }
- }
- });
-
- it('Does not include vite assets files when excluded', async () => {
- for (const file of excludedAssets) {
- assert.ok(
- !existsSync(new URL(file, expectedCwd)),
- `Expected file ${file} to not exist in build`,
- );
- }
- });
-
- after(async () => {
- await fixture.clean();
- });
- },
- {
- timeout: 120000,
- },
-);
-
-describe(
- 'Included files',
- () => {
- let fixture;
-
- const root = new URL('./fixtures/includes/', import.meta.url);
- const expectedCwd = new URL(
- '.netlify/v1/functions/ssr/packages/integrations/netlify/test/functions/fixtures/includes/',
- root,
- );
-
- const expectedFiles = [
- './files/include-this.txt',
- './files/also-this.csv',
- './files/subdirectory/and-this.csv',
- ];
-
- before(async () => {
- fixture = await loadFixture({
- root,
- adapter: netlify({
- includeFiles: expectedFiles,
- }),
- });
- await fixture.build();
- });
-
- it('Emits include files', async () => {
- for (const file of expectedFiles) {
- assert.ok(existsSync(new URL(file, expectedCwd)), `Expected file ${file} to exist`);
- }
- });
-
- it('Can load included files correctly', async () => {
- const entryURL = new URL(
- './fixtures/includes/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(new Request('http://example.com/?file=include-this.txt'), {});
- const html = await resp.text();
- const $ = cheerio.load(html);
- assert.equal($('h1').text(), 'hello');
- });
-
- it('Includes traced node modules with symlinks', async () => {
- const expected = new URL(
- '.netlify/v1/functions/ssr/node_modules/.pnpm/cowsay@1.6.0/node_modules/cowsay/cows/happy-whale.cow',
- root,
- );
- assert.ok(existsSync(expected, 'Expected excluded file to exist in default build'));
- });
-
- after(async () => {
- await fixture.clean();
- });
- },
- {
- timeout: 120000,
- },
-);
-
-describe(
- 'Excluded files',
- () => {
- let fixture;
-
- const root = new URL('./fixtures/includes/', import.meta.url);
- const expectedCwd = new URL(
- '.netlify/v1/functions/ssr/packages/integrations/netlify/test/functions/fixtures/includes/',
- root,
- );
-
- const includeFiles = ['./files/**/*.txt'];
- const excludedTxt = ['./files/subdirectory/not-this.txt', './files/subdirectory/or-this.txt'];
- const excludeFiles = [...excludedTxt, '../../../../../../../node_modules/.pnpm/cowsay@*/**'];
-
- before(async () => {
- fixture = await loadFixture({
- root,
- adapter: netlify({
- includeFiles: includeFiles,
- excludeFiles: excludeFiles,
- }),
- });
- await fixture.build();
- });
-
- it('Excludes traced node modules', async () => {
- const expected = new URL(
- '.netlify/v1/functions/ssr/node_modules/.pnpm/cowsay@1.6.0/node_modules/cowsay/cows/happy-whale.cow',
- root,
- );
- assert.ok(!existsSync(expected), 'Expected excluded file to not exist in build');
- });
-
- it('Does not include files when excluded', async () => {
- for (const pattern of includeFiles) {
- const files = globSync(pattern, { ignore: excludedTxt });
- for (const file of files) {
- assert.ok(
- existsSync(new URL(file, expectedCwd)),
- `Expected file ${pattern} to exist in build`,
- );
- }
- }
- for (const file of excludedTxt) {
- assert.ok(
- !existsSync(new URL(file, expectedCwd)),
- `Expected file ${file} to not exist in build`,
- );
- }
- });
-
- after(async () => {
- await fixture.clean();
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/include-files.test.ts b/packages/integrations/netlify/test/functions/include-files.test.ts
new file mode 100644
index 000000000000..487298342eb5
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/include-files.test.ts
@@ -0,0 +1,166 @@
+import * as assert from 'node:assert/strict';
+import { existsSync } from 'node:fs';
+import { after, before, describe, it } from 'node:test';
+import netlify from '@astrojs/netlify';
+import * as cheerio from 'cheerio';
+import { globSync } from 'tinyglobby';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
+
+describe('Included vite assets files', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ const root = new URL('./fixtures/includes/', import.meta.url);
+ const expectedCwd = new URL('.netlify/v1/functions/ssr/packages/integrations/netlify/', root);
+
+ const expectedAssetsInclude = ['./*.json'];
+ const excludedAssets = ['./files/exclude-asset.json'];
+
+ before(async () => {
+ fixture = await loadFixture({
+ root,
+ vite: {
+ assetsInclude: expectedAssetsInclude,
+ },
+ adapter: netlify({
+ excludeFiles: excludedAssets,
+ }),
+ });
+ await fixture.build({});
+ });
+
+ it('Emits vite assets files', async () => {
+ for (const pattern of expectedAssetsInclude) {
+ const files = globSync(pattern);
+ for (const file of files) {
+ assert.ok(
+ existsSync(new URL(file, expectedCwd)),
+ `Expected file ${pattern} to exist in build`,
+ );
+ }
+ }
+ });
+
+ it('Does not include vite assets files when excluded', async () => {
+ for (const file of excludedAssets) {
+ assert.ok(
+ !existsSync(new URL(file, expectedCwd)),
+ `Expected file ${file} to not exist in build`,
+ );
+ }
+ });
+
+ after(async () => {
+ await fixture.clean();
+ });
+});
+
+describe('Included files', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ const root = new URL('./fixtures/includes/', import.meta.url);
+ const expectedCwd = new URL(
+ '.netlify/v1/functions/ssr/packages/integrations/netlify/test/functions/fixtures/includes/',
+ root,
+ );
+
+ const expectedFiles = [
+ './files/include-this.txt',
+ './files/also-this.csv',
+ './files/subdirectory/and-this.csv',
+ ];
+
+ before(async () => {
+ fixture = await loadFixture({
+ root,
+ adapter: netlify({
+ includeFiles: expectedFiles,
+ }),
+ });
+ await fixture.build({});
+ });
+
+ it('Emits include files', async () => {
+ for (const file of expectedFiles) {
+ assert.ok(existsSync(new URL(file, expectedCwd)), `Expected file ${file} to exist`);
+ }
+ });
+
+ it('Can load included files correctly', async () => {
+ const entryURL = new URL(
+ './fixtures/includes/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(new Request('http://example.com/?file=include-this.txt'), {});
+ const html = await resp.text();
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'hello');
+ });
+
+ it('Includes traced node modules with symlinks', async () => {
+ const expected = new URL(
+ '.netlify/v1/functions/ssr/node_modules/.pnpm/cowsay@1.6.0/node_modules/cowsay/cows/happy-whale.cow',
+ root,
+ );
+ assert.ok(existsSync(expected), 'Expected excluded file to exist in default build');
+ });
+
+ after(async () => {
+ await fixture.clean();
+ });
+});
+
+describe('Excluded files', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ const root = new URL('./fixtures/includes/', import.meta.url);
+ const expectedCwd = new URL(
+ '.netlify/v1/functions/ssr/packages/integrations/netlify/test/functions/fixtures/includes/',
+ root,
+ );
+
+ const includeFiles = ['./files/**/*.txt'];
+ const excludedTxt = ['./files/subdirectory/not-this.txt', './files/subdirectory/or-this.txt'];
+ const excludeFiles = [...excludedTxt, '../../../../../../../node_modules/.pnpm/cowsay@*/**'];
+
+ before(async () => {
+ fixture = await loadFixture({
+ root,
+ adapter: netlify({
+ includeFiles: includeFiles,
+ excludeFiles: excludeFiles,
+ }),
+ });
+ await fixture.build({});
+ });
+
+ it('Excludes traced node modules', async () => {
+ const expected = new URL(
+ '.netlify/v1/functions/ssr/node_modules/.pnpm/cowsay@1.6.0/node_modules/cowsay/cows/happy-whale.cow',
+ root,
+ );
+ assert.ok(!existsSync(expected), 'Expected excluded file to not exist in build');
+ });
+
+ it('Does not include files when excluded', async () => {
+ for (const pattern of includeFiles) {
+ const files = globSync(pattern, { ignore: excludedTxt });
+ for (const file of files) {
+ assert.ok(
+ existsSync(new URL(file, expectedCwd)),
+ `Expected file ${pattern} to exist in build`,
+ );
+ }
+ }
+ for (const file of excludedTxt) {
+ assert.ok(
+ !existsSync(new URL(file, expectedCwd)),
+ `Expected file ${file} to not exist in build`,
+ );
+ }
+ });
+
+ after(async () => {
+ await fixture.clean();
+ });
+});
diff --git a/packages/integrations/netlify/test/functions/redirects.test.js b/packages/integrations/netlify/test/functions/redirects.test.js
deleted file mode 100644
index 2c55aecb9ec5..000000000000
--- a/packages/integrations/netlify/test/functions/redirects.test.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { createServer } from 'node:http';
-import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-
-describe(
- 'SSR - Redirects',
- () => {
- let fixture;
-
- before(async () => {
- fixture = await loadFixture({ root: new URL('./fixtures/redirects/', import.meta.url) });
- await fixture.build();
- });
-
- it('Creates a redirects file', async () => {
- const redirects = await fixture.readFile('./_redirects');
- const parts = redirects.split(/\s+/);
- // based on https://github.com/withastro/astro/issues/16030 for the default option `trailingSlash: 'ignore'` both variants should be generated
- assert.deepEqual(parts, ['', '/other/', '/', '301', '/other', '/', '301', '']);
- });
-
- it('Does not create .html files', async () => {
- let hasErrored = false;
- try {
- await fixture.readFile('/other/index.html');
- } catch {
- hasErrored = true;
- }
- assert.equal(hasErrored, true, 'this file should not exist');
- });
-
- it('renders static 404 page', async () => {
- const entryURL = new URL(
- './fixtures/redirects/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(new Request('http://example.com/nonexistant-page'), {});
- assert.equal(resp.status, 404);
- assert.equal(resp.headers.get('content-type'), 'text/html; charset=utf-8');
- const text = await resp.text();
- assert.equal(text.includes('This is my static 404 page'), true);
- });
-
- it('does not pass through 404 request', async () => {
- let testServerCalls = 0;
- const testServer = createServer((_req, res) => {
- testServerCalls++;
- res.writeHead(200);
- res.end();
- });
- testServer.listen(5678);
- const entryURL = new URL(
- './fixtures/redirects/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(new Request('http://localhost:5678/nonexistant-page'), {});
- assert.equal(resp.status, 404);
- assert.equal(testServerCalls, 0);
- testServer.close();
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/redirects.test.ts b/packages/integrations/netlify/test/functions/redirects.test.ts
new file mode 100644
index 000000000000..9f983ea5cabc
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/redirects.test.ts
@@ -0,0 +1,62 @@
+import * as assert from 'node:assert/strict';
+import { createServer } from 'node:http';
+import { before, describe, it } from 'node:test';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
+
+describe('SSR - Redirects', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ before(async () => {
+ fixture = await loadFixture({ root: new URL('./fixtures/redirects/', import.meta.url) });
+ await fixture.build({});
+ });
+
+ it('Creates a redirects file', async () => {
+ const redirects = await fixture.readFile('./_redirects');
+ const parts = redirects.split(/\s+/);
+ // based on https://github.com/withastro/astro/issues/16030 for the default option `trailingSlash: 'ignore'` both variants should be generated
+ assert.deepEqual(parts, ['', '/other/', '/', '301', '/other', '/', '301', '']);
+ });
+
+ it('Does not create .html files', async () => {
+ let hasErrored = false;
+ try {
+ await fixture.readFile('/other/index.html');
+ } catch {
+ hasErrored = true;
+ }
+ assert.equal(hasErrored, true, 'this file should not exist');
+ });
+
+ it('renders static 404 page', async () => {
+ const entryURL = new URL(
+ './fixtures/redirects/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(new Request('http://example.com/nonexistant-page'), {});
+ assert.equal(resp.status, 404);
+ assert.equal(resp.headers.get('content-type'), 'text/html; charset=utf-8');
+ const text = await resp.text();
+ assert.equal(text.includes('This is my static 404 page'), true);
+ });
+
+ it('does not pass through 404 request', async () => {
+ let testServerCalls = 0;
+ const testServer = createServer((_req, res) => {
+ testServerCalls++;
+ res.writeHead(200);
+ res.end();
+ });
+ testServer.listen(5678);
+ const entryURL = new URL(
+ './fixtures/redirects/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(new Request('http://localhost:5678/nonexistant-page'), {});
+ assert.equal(resp.status, 404);
+ assert.equal(testServerCalls, 0);
+ testServer.close();
+ });
+});
diff --git a/packages/integrations/netlify/test/functions/sessions.test.js b/packages/integrations/netlify/test/functions/sessions.test.ts
similarity index 90%
rename from packages/integrations/netlify/test/functions/sessions.test.js
rename to packages/integrations/netlify/test/functions/sessions.test.ts
index 7b41cb129648..89d4a1b8d432 100644
--- a/packages/integrations/netlify/test/functions/sessions.test.js
+++ b/packages/integrations/netlify/test/functions/sessions.test.ts
@@ -1,10 +1,9 @@
-// @ts-check
import assert from 'node:assert/strict';
import { mkdir, rm } from 'node:fs/promises';
import { after, before, describe, it } from 'node:test';
import { BlobsServer } from '@netlify/blobs/server';
import * as devalue from 'devalue';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
import netlify from '../../dist/index.js';
import { sessionDrivers } from 'astro/config';
@@ -14,11 +13,9 @@ const dataDir = '.netlify/sessions';
describe('Astro.session', () => {
describe('Production', () => {
- /** @type {import('../../../../astro/test/test-utils.js').Fixture} */
- let fixture;
+ let fixture: Fixture;
- /** @type {BlobsServer} */
- let blobServer;
+ let blobServer: BlobsServer;
before(async () => {
process.env.NETLIFY = '1';
await rm(dataDir, { recursive: true, force: true }).catch(() => {});
@@ -35,6 +32,7 @@ describe('Astro.session', () => {
output: 'server',
adapter: netlify(),
session: {
+ // @ts-ignore - session driver types are complex generics
driver: sessionDrivers.netlifyBlobs({
name: 'test',
uncachedEdgeURL: `http://localhost:8971`,
@@ -52,17 +50,12 @@ describe('Astro.session', () => {
const mod = await import(entryURL.href);
handler = mod.default;
});
- /** @type {(request: Request, options: {}) => Promise} */
- let handler;
+ let handler: (request: Request, options: Record) => Promise;
after(async () => {
await blobServer.stop();
delete process.env.NETLIFY;
});
- /**
- * @param {string} path
- * @param {RequestInit} requestInit
- */
- function fetchResponse(path, requestInit) {
+ function fetchResponse(path: string, requestInit: RequestInit) {
return handler(new Request(new URL(path, 'http://example.com'), requestInit), {});
}
diff --git a/packages/integrations/netlify/test/functions/skew-protection.test.js b/packages/integrations/netlify/test/functions/skew-protection.test.js
deleted file mode 100644
index ee5f8c840689..000000000000
--- a/packages/integrations/netlify/test/functions/skew-protection.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import * as assert from 'node:assert/strict';
-import { readFile } from 'node:fs/promises';
-import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
-
-describe(
- 'Skew Protection',
- () => {
- let fixture;
-
- before(async () => {
- // Set DEPLOY_ID env var for the test
- process.env.DEPLOY_ID = 'test-deploy-123';
-
- fixture = await loadFixture({
- root: new URL('./fixtures/skew-protection/', import.meta.url),
- });
- await fixture.build();
-
- // Clean up
- delete process.env.DEPLOY_ID;
- });
-
- it('Server islands inline adapter headers', async () => {
- // Render a page with server islands and check the HTML contains inline headers
- const entryURL = new URL(
- './fixtures/skew-protection/.netlify/v1/functions/ssr/ssr.mjs',
- import.meta.url,
- );
- const { default: handler } = await import(entryURL);
- const resp = await handler(new Request('http://example.com/server-island'), {});
- const html = await resp.text();
-
- // Check that the HTML contains the inline headers in the server island script
- // Should have something like: const headers = new Headers({"X-Netlify-Deploy-ID":"test-deploy-123"});
- assert.ok(
- html.includes('test-deploy-123'),
- 'Expected server island HTML to include deploy ID in inline script',
- );
- });
-
- it('Manifest contains internalFetchHeaders', async () => {
- // The manifest is embedded in the build output
- // Check the manifest file which contains the serialized manifest
- const manifestURL = new URL(
- './fixtures/skew-protection/.netlify/build/chunks/',
- import.meta.url,
- );
-
- // Find the manifest file (it has a hash in the name)
- const { readdir } = await import('node:fs/promises');
- const files = await readdir(manifestURL);
- let found = false;
- for (const file of files) {
- const contents = await readFile(new URL(file, manifestURL), 'utf-8');
- if (contents.includes('"internalFetchHeaders":{"X-Netlify-Deploy-ID":"test-deploy-123"}')) {
- found = true;
- break;
- }
- }
- assert.ok(
- found,
- 'Manifest should include internalFetchHeaders field with the correct deploy ID value',
- );
- });
- },
- {
- timeout: 120000,
- },
-);
diff --git a/packages/integrations/netlify/test/functions/skew-protection.test.ts b/packages/integrations/netlify/test/functions/skew-protection.test.ts
new file mode 100644
index 000000000000..e2dec88abfcf
--- /dev/null
+++ b/packages/integrations/netlify/test/functions/skew-protection.test.ts
@@ -0,0 +1,64 @@
+import * as assert from 'node:assert/strict';
+import { readFile } from 'node:fs/promises';
+import { before, describe, it } from 'node:test';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
+
+describe('Skew Protection', { timeout: 120000 }, () => {
+ let fixture: Fixture;
+
+ before(async () => {
+ // Set DEPLOY_ID env var for the test
+ process.env.DEPLOY_ID = 'test-deploy-123';
+
+ fixture = await loadFixture({
+ root: new URL('./fixtures/skew-protection/', import.meta.url),
+ });
+ await fixture.build({});
+
+ // Clean up
+ delete process.env.DEPLOY_ID;
+ });
+
+ it('Server islands inline adapter headers', async () => {
+ // Render a page with server islands and check the HTML contains inline headers
+ const entryURL = new URL(
+ './fixtures/skew-protection/.netlify/v1/functions/ssr/ssr.mjs',
+ import.meta.url,
+ );
+ const { default: handler } = await import(entryURL.href);
+ const resp = await handler(new Request('http://example.com/server-island'), {});
+ const html = await resp.text();
+
+ // Check that the HTML contains the inline headers in the server island script
+ // Should have something like: const headers = new Headers({"X-Netlify-Deploy-ID":"test-deploy-123"});
+ assert.ok(
+ html.includes('test-deploy-123'),
+ 'Expected server island HTML to include deploy ID in inline script',
+ );
+ });
+
+ it('Manifest contains internalFetchHeaders', async () => {
+ // The manifest is embedded in the build output
+ // Check the manifest file which contains the serialized manifest
+ const manifestURL = new URL(
+ './fixtures/skew-protection/.netlify/build/chunks/',
+ import.meta.url,
+ );
+
+ // Find the manifest file (it has a hash in the name)
+ const { readdir } = await import('node:fs/promises');
+ const files = await readdir(manifestURL);
+ let found = false;
+ for (const file of files) {
+ const contents = await readFile(new URL(file, manifestURL), 'utf-8');
+ if (contents.includes('"internalFetchHeaders":{"X-Netlify-Deploy-ID":"test-deploy-123"}')) {
+ found = true;
+ break;
+ }
+ }
+ assert.ok(
+ found,
+ 'Manifest should include internalFetchHeaders field with the correct deploy ID value',
+ );
+ });
+});
diff --git a/packages/integrations/netlify/test/hosted/hosted.test.js b/packages/integrations/netlify/test/hosted/hosted.test.ts
similarity index 94%
rename from packages/integrations/netlify/test/hosted/hosted.test.js
rename to packages/integrations/netlify/test/hosted/hosted.test.ts
index 3bc9349f960b..fb671afb4008 100644
--- a/packages/integrations/netlify/test/hosted/hosted.test.js
+++ b/packages/integrations/netlify/test/hosted/hosted.test.ts
@@ -24,6 +24,6 @@ describe('Hosted Netlify Tests', () => {
const responseTwo = await fetch(`${NETLIFY_TEST_URL}/time`).then((res) => res.text());
- assert.notEqual(responseOne.body, responseTwo.body);
+ assert.notEqual(responseOne, responseTwo);
});
});
diff --git a/packages/integrations/netlify/test/static/headers.test.js b/packages/integrations/netlify/test/static/headers.test.ts
similarity index 81%
rename from packages/integrations/netlify/test/static/headers.test.js
rename to packages/integrations/netlify/test/static/headers.test.ts
index 5c1400098b10..d777cbc824ae 100644
--- a/packages/integrations/netlify/test/static/headers.test.js
+++ b/packages/integrations/netlify/test/static/headers.test.ts
@@ -1,13 +1,13 @@
import * as assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
describe('SSG - headers', () => {
- let fixture;
+ let fixture: Fixture;
before(async () => {
fixture = await loadFixture({ root: new URL('./fixtures/redirects/', import.meta.url) });
- await fixture.build();
+ await fixture.build({});
});
it('Generates headers for static assets', async () => {
diff --git a/packages/integrations/netlify/test/static/image-missing-dimension.test.js b/packages/integrations/netlify/test/static/image-missing-dimension.test.ts
similarity index 92%
rename from packages/integrations/netlify/test/static/image-missing-dimension.test.js
rename to packages/integrations/netlify/test/static/image-missing-dimension.test.ts
index 932958ad399d..3519081e1160 100644
--- a/packages/integrations/netlify/test/static/image-missing-dimension.test.js
+++ b/packages/integrations/netlify/test/static/image-missing-dimension.test.ts
@@ -9,12 +9,12 @@ describe('Image validation when is not size specification in netlify.', () => {
});
try {
- await fixture.build();
+ await fixture.build({});
assert.fail();
} catch (e) {
// check the error image about missing image dimension
assert.match(
- e.name,
+ (e as Error).name,
/MissingImageDimension/,
`Build failed but not with the expected "MissingImageDimension"`,
);
diff --git a/packages/integrations/netlify/test/static/redirects.test.js b/packages/integrations/netlify/test/static/redirects.test.ts
similarity index 85%
rename from packages/integrations/netlify/test/static/redirects.test.js
rename to packages/integrations/netlify/test/static/redirects.test.ts
index 9e9d0c87298e..e541efa58117 100644
--- a/packages/integrations/netlify/test/static/redirects.test.js
+++ b/packages/integrations/netlify/test/static/redirects.test.ts
@@ -1,13 +1,13 @@
import * as assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
describe('SSG - Redirects', () => {
- let fixture;
+ let fixture: Fixture;
before(async () => {
fixture = await loadFixture({ root: new URL('./fixtures/redirects/', import.meta.url) });
- await fixture.build();
+ await fixture.build({});
});
it('Creates a redirects file', async () => {
diff --git a/packages/integrations/netlify/test/static/static-headers.test.js b/packages/integrations/netlify/test/static/static-headers.test.ts
similarity index 86%
rename from packages/integrations/netlify/test/static/static-headers.test.js
rename to packages/integrations/netlify/test/static/static-headers.test.ts
index a5b7014894b0..5a478eccfed7 100644
--- a/packages/integrations/netlify/test/static/static-headers.test.js
+++ b/packages/integrations/netlify/test/static/static-headers.test.ts
@@ -1,14 +1,14 @@
import * as assert from 'node:assert/strict';
import { existsSync, readdirSync } from 'node:fs';
import { before, describe, it } from 'node:test';
-import { loadFixture } from '../../../../astro/test/test-utils.js';
+import { type Fixture, loadFixture } from '../../../../astro/test/test-utils.js';
describe('Static headers', () => {
- let fixture;
+ let fixture: Fixture;
before(async () => {
fixture = await loadFixture({ root: new URL('./fixtures/static-headers/', import.meta.url) });
- await fixture.build();
+ await fixture.build({});
});
it('SSR function is generated when server islands are used with output: static', async () => {
@@ -23,7 +23,7 @@ describe('Static headers', () => {
it('CSP headers are added when CSP is enabled', async () => {
const config = await fixture.readFile('../.netlify/v1/config.json');
const headers = JSON.parse(config).headers;
- const index = headers.find((x) => x.for === '/');
+ const index = headers.find((x: { for: string }) => x.for === '/');
assert.notEqual(index, undefined, 'the index must have CSP headers');
assert.notEqual(
diff --git a/packages/integrations/netlify/tsconfig.test.json b/packages/integrations/netlify/tsconfig.test.json
new file mode 100644
index 000000000000..e8d5292cf781
--- /dev/null
+++ b/packages/integrations/netlify/tsconfig.test.json
@@ -0,0 +1,14 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "include": ["test/**/*.ts"],
+ "exclude": ["test/fixtures/**", "test/*/fixtures/**", "test/hosted/hosted-astro-project/**"],
+ "compilerOptions": {
+ "noEmit": true,
+ "allowJs": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "rewriteRelativeImportExtensions": true,
+ "rootDir": "."
+ },
+ "references": [{ "path": "../../astro/tsconfig.test.json" }]
+}