diff options
Diffstat (limited to 'packages/integrations/netlify/test')
50 files changed, 749 insertions, 0 deletions
diff --git a/packages/integrations/netlify/test/functions/cookies.test.js b/packages/integrations/netlify/test/functions/cookies.test.js new file mode 100644 index 000000000..9d2565d91 --- /dev/null +++ b/packages/integrations/netlify/test/functions/cookies.test.js @@ -0,0 +1,53 @@ +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('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/edge-middleware.test.js b/packages/integrations/netlify/test/functions/edge-middleware.test.js new file mode 100644 index 000000000..683ec3b01 --- /dev/null +++ b/packages/integrations/netlify/test/functions/edge-middleware.test.js @@ -0,0 +1,66 @@ +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('edgeMiddleware: false', () => { + 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('<title>Middleware</title>'), true); + }); + + after(async () => { + process.env.EDGE_MIDDLEWARE = undefined; + await fixture.clean(); + }); + }); + + describe('edgeMiddleware: true', () => { + 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('<title></title>'), true); + }); + + after(async () => { + process.env.EDGE_MIDDLEWARE = undefined; + await fixture.clean(); + }); + }); + }, + { + timeout: 120000, + } +); diff --git a/packages/integrations/netlify/test/functions/fixtures/.gitignore b/packages/integrations/netlify/test/functions/fixtures/.gitignore new file mode 100644 index 000000000..916f60644 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/.gitignore @@ -0,0 +1 @@ +**/netlify diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/.astro/types.d.ts b/packages/integrations/netlify/test/functions/fixtures/cookies/.astro/types.d.ts new file mode 100644 index 000000000..03d7cc43f --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// <reference types="astro/client" /> +/// <reference path="content.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/astro.config.mjs b/packages/integrations/netlify/test/functions/fixtures/cookies/astro.config.mjs new file mode 100644 index 000000000..033024c1a --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/astro.config.mjs @@ -0,0 +1,11 @@ +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'server', + adapter: netlify(), + site: `http://example.com`, + security: { + checkOrigin: false + } +});
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/package.json b/packages/integrations/netlify/test/functions/fixtures/cookies/package.json new file mode 100644 index 000000000..14257a558 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/netlify-cookies", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/netlify": "workspace:" + } +} diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/src/env.d.ts b/packages/integrations/netlify/test/functions/fixtures/cookies/src/env.d.ts new file mode 100644 index 000000000..9bc5cb41c --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/src/env.d.ts @@ -0,0 +1 @@ +/// <reference path="../.astro/types.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/404.astro b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/404.astro new file mode 100644 index 000000000..9049fa0fb --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/404.astro @@ -0,0 +1,7 @@ +--- +export const prerender = false +const header = Astro.request.headers.get("x-test") +--- + +<p>This is my custom 404 page</p> +<p>x-test: {header}</p>
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/index.astro b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/index.astro new file mode 100644 index 000000000..53e029f04 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/index.astro @@ -0,0 +1,6 @@ +<html> +<head><title>Testing</title></head> +<body> + <h1>Testing</h1> +</body> +</html> diff --git a/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/login.js b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/login.js new file mode 100644 index 000000000..3f1fe17b5 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/cookies/src/pages/login.js @@ -0,0 +1,12 @@ + +export function POST() { + const headers = new Headers(); + headers.append('Set-Cookie', `foo=foo; HttpOnly`); + headers.append('Set-Cookie', `bar=bar; HttpOnly`); + headers.append('Location', '/'); + + return new Response('', { + status: 301, + headers, + }); +} diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/.astro/types.d.ts b/packages/integrations/netlify/test/functions/fixtures/middleware/.astro/types.d.ts new file mode 100644 index 000000000..03d7cc43f --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// <reference types="astro/client" /> +/// <reference path="content.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/astro.config.mjs b/packages/integrations/netlify/test/functions/fixtures/middleware/astro.config.mjs new file mode 100644 index 000000000..0da6bf580 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/astro.config.mjs @@ -0,0 +1,19 @@ +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'server', + adapter: netlify({ + edgeMiddleware: process.env.EDGE_MIDDLEWARE === 'true', + imageCDN: process.env.DISABLE_IMAGE_CDN ? false : undefined, + }), + image: { + remotePatterns: [{ + protocol: 'https', + hostname: '*.example.org', + pathname: '/images/*', + }], + domains: ['example.net', 'secret.example.edu'], + }, + site: `http://example.com`, +});
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/package.json b/packages/integrations/netlify/test/functions/fixtures/middleware/package.json new file mode 100644 index 000000000..ddc811223 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/netlify-middleware-without-handler-file", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/netlify": "workspace:", + "sharp": "^0.33.5" + } +} diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/astronaut.jpg b/packages/integrations/netlify/test/functions/fixtures/middleware/src/astronaut.jpg Binary files differnew file mode 100644 index 000000000..d3326bcc7 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/astronaut.jpg diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/env.d.ts b/packages/integrations/netlify/test/functions/fixtures/middleware/src/env.d.ts new file mode 100644 index 000000000..9bc5cb41c --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/env.d.ts @@ -0,0 +1 @@ +/// <reference path="../.astro/types.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/middleware.ts b/packages/integrations/netlify/test/functions/fixtures/middleware/src/middleware.ts new file mode 100644 index 000000000..9790b8755 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/middleware.ts @@ -0,0 +1,8 @@ +import https from 'node:https'; + +export const onRequest = (context, next) => { + context.locals.title = 'Middleware'; + context.locals.nodePrefixedImportExists = !!https; + + return next(); +}; diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/astronaut.astro b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/astronaut.astro new file mode 100644 index 000000000..b3da724c3 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/astronaut.astro @@ -0,0 +1,9 @@ +--- +import { Image } from 'astro:assets'; +import astronautImage from "../astronaut.jpg" + +export const prerender = true; +--- + +<Image src={astronautImage} alt="an astronaut floating in space" /> + diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/index.astro b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/index.astro new file mode 100644 index 000000000..d97f70698 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/index.astro @@ -0,0 +1,12 @@ +--- +const title = Astro.locals.title; +--- + +<html> +<head> + <title>{title}</title> +</head> +<body> +<h1>{title}</h1> +</body> +</html> diff --git a/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/prerender.astro b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/prerender.astro new file mode 100644 index 000000000..f0314c053 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/middleware/src/pages/prerender.astro @@ -0,0 +1,13 @@ +--- +export const prerender = true; +const title = Astro.locals.title; +--- + +<html> +<head> + <title>{title}</title> +</head> +<body> +<h1>{title}</h1> +</body> +</html> diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/.astro/types.d.ts b/packages/integrations/netlify/test/functions/fixtures/redirects/.astro/types.d.ts new file mode 100644 index 000000000..03d7cc43f --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// <reference types="astro/client" /> +/// <reference path="content.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/astro.config.mjs b/packages/integrations/netlify/test/functions/fixtures/redirects/astro.config.mjs new file mode 100644 index 000000000..55613bd91 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/astro.config.mjs @@ -0,0 +1,11 @@ +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'static', + adapter: netlify(), + site: `http://example.com`, + redirects: { + '/other': '/', + }, +}); diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/package.json b/packages/integrations/netlify/test/functions/fixtures/redirects/package.json new file mode 100644 index 000000000..9970a81de --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/netlify-redirects", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/netlify": "workspace:" + } +} diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/src/env.d.ts b/packages/integrations/netlify/test/functions/fixtures/redirects/src/env.d.ts new file mode 100644 index 000000000..9bc5cb41c --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/src/env.d.ts @@ -0,0 +1 @@ +/// <reference path="../.astro/types.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/404.astro b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/404.astro new file mode 100644 index 000000000..b9e3eda13 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/404.astro @@ -0,0 +1,5 @@ +--- +export const prerender = true +--- + +<p>This is my static 404 page</p>
\ No newline at end of file diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/index.astro b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/index.astro new file mode 100644 index 000000000..41f740c4c --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/index.astro @@ -0,0 +1,9 @@ +--- +export const prerender = false; +--- +<html> +<head><title>Testing</title></head> +<body> + <h1>Testing</h1> +</body> +</html> diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/nope.astro b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/nope.astro new file mode 100644 index 000000000..f48d767ee --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/nope.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/team/articles/[...slug].astro b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/team/articles/[...slug].astro new file mode 100644 index 000000000..996cd989e --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/redirects/src/pages/team/articles/[...slug].astro @@ -0,0 +1,27 @@ +--- +export const prerender = false; + +export const getStaticPaths = (async () => { + const posts = [ + { slug: 'one', data: {draft: false, title: 'One'} }, + { slug: 'two', data: {draft: false, title: 'Two'} } + ]; + return posts.map((post) => { + return { + params: { slug: post.slug }, + props: { draft: post.data.draft, title: post.data.title }, + }; + }); +}) + +const { slug } = Astro.params; +const { title } = Astro.props; +--- +<html> + <head> + <title>{ title }</title> + </head> + <body> + <h1>{ title }</h1> + </body> +</html> diff --git a/packages/integrations/netlify/test/functions/image-cdn.test.js b/packages/integrations/netlify/test/functions/image-cdn.test.js new file mode 100644 index 000000000..45b41e4de --- /dev/null +++ b/packages/integrations/netlify/test/functions/image-cdn.test.js @@ -0,0 +1,139 @@ +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'; + +describe( + 'Image CDN', + () => { + const root = new URL('./fixtures/middleware/', import.meta.url); + + describe('when running outside of netlify', () => { + it('does not enable Image CDN', async () => { + 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('when running inside of netlify', () => { + after(() => { + process.env.NETLIFY = undefined; + process.env.DISABLE_IMAGE_CDN = undefined; + }); + + it('enables Netlify Image CDN', async () => { + process.env.NETLIFY = 'true'; + 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.NETLIFY = 'true'; + 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.' + ); + }); + }); + }, + { + timeout: 120000, + } +); diff --git a/packages/integrations/netlify/test/functions/redirects.test.js b/packages/integrations/netlify/test/functions/redirects.test.js new file mode 100644 index 000000000..ac77056c4 --- /dev/null +++ b/packages/integrations/netlify/test/functions/redirects.test.js @@ -0,0 +1,69 @@ +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+/); + assert.deepEqual(parts, ['', '/other', '/', '301', '']); + // Snapshots are not supported in Node.js test yet (https://github.com/nodejs/node/issues/48260) + assert.equal(redirects, '\n/other / 301\n'); + }); + + 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/hosted/README.md b/packages/integrations/netlify/test/hosted/README.md new file mode 100644 index 000000000..8c1814844 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/README.md @@ -0,0 +1,3 @@ +The tests in this folder are done directly on a deployed Netlify website (hosted at https://curious-boba-495d6d.netlify.app) and are not run by the test suite. They instead run every week through a GitHub action. + +The purpose of those tests is to make sure that everything works as expected while deployed. In a way, they're as E2E as it gets. diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/astro.config.mjs b/packages/integrations/netlify/test/hosted/hosted-astro-project/astro.config.mjs new file mode 100644 index 000000000..94cc00f7b --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/astro.config.mjs @@ -0,0 +1,19 @@ +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + output: 'server', + adapter: netlify({ + edgeMiddleware: true, + }), + image: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'images.unsplash.com', + pathname: '/photo-1567674867291-b2595ac53ab4', + }, + ], + }, +}); diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/netlify.toml b/packages/integrations/netlify/test/hosted/hosted-astro-project/netlify.toml new file mode 100644 index 000000000..55c8404ee --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "pnpm run --filter @test/netlify-hosted-astro-project... build" +publish = "/packages/netlify/test/hosted/hosted-astro-project/dist" diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json b/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json new file mode 100644 index 000000000..69914a8db --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json @@ -0,0 +1,12 @@ +{ + "name": "@test/netlify-hosted-astro-project", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "astro build" + }, + "dependencies": { + "@astrojs/netlify": "workspace:*", + "astro": "^5.1.6" + } +} diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/assets/penguin.png b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/assets/penguin.png Binary files differnew file mode 100644 index 000000000..218acde5b --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/assets/penguin.png diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/env.d.ts b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/env.d.ts new file mode 100644 index 000000000..f7cbe9c1d --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/env.d.ts @@ -0,0 +1 @@ +/// <reference types="astro/client-image" /> diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/middleware.ts b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/middleware.ts new file mode 100644 index 000000000..1112a3566 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/middleware.ts @@ -0,0 +1,11 @@ +import https from 'node:https'; + +export const onRequest = (context, next) => { + console.info(context.netlify); + context.locals.middleware = context?.locals?.netlify?.context?.geo?.country?.code ?? null; + context.locals.runtime = 'Deno' in globalThis ? 'Deno' : 'Node'; + context.locals.title = 'Middleware'; + context.locals.nodePrefixedImportExists = !!https; + + return next(); +}; diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/country.astro b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/country.astro new file mode 100644 index 000000000..cad7116d6 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/country.astro @@ -0,0 +1,7 @@ +--- +const country = Astro.locals.middleware; +--- + +<h1>{country}</h1> +<h3>{country ? 'has context' : 'no context'}</h3> +<h2>{Astro.locals.runtime}</h2> diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/index.astro b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/index.astro new file mode 100644 index 000000000..7d2cfcdc3 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/index.astro @@ -0,0 +1,13 @@ +--- +import { Image } from 'astro:assets'; +import penguin from '../assets/penguin.png'; +--- + +<Image src={penguin} width={300} alt="" /> + +<Image + src="https://images.unsplash.com/photo-1567674867291-b2595ac53ab4" + width={300} + height={400} + alt="Astro" +/> diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro new file mode 100644 index 000000000..873b5c720 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro @@ -0,0 +1,5 @@ +--- +const currentTime = new Date().getTime(); +--- + +{currentTime} diff --git a/packages/integrations/netlify/test/hosted/hosted.test.js b/packages/integrations/netlify/test/hosted/hosted.test.js new file mode 100644 index 000000000..b8562ce82 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted.test.js @@ -0,0 +1,29 @@ +import * as assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; + +const NETLIFY_TEST_URL = 'https://curious-boba-495d6d.netlify.app'; + +describe('Hosted Netlify Tests', () => { + it('Image endpoint works', async () => { + const image = await fetch( + `${NETLIFY_TEST_URL}/_image?href=%2F_astro%2Fpenguin.e9c64733.png&w=300&f=webp` + ); + + assert.equal(image.status, 200); + }); + + it('passes context from edge middleware', async () => { + const response = await fetch(`${NETLIFY_TEST_URL}/country`); + const body = await response.text(); + assert.match(body, /has context/); + assert.match(body, /Deno/); + }); + + it('Server returns fresh content', async () => { + const responseOne = await fetch(`${NETLIFY_TEST_URL}/time`).then((res) => res.text()); + + const responseTwo = await fetch(`${NETLIFY_TEST_URL}/time`).then((res) => res.text()); + + assert.notEqual(responseOne.body, responseTwo.body); + }); +}); diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/.astro/types.d.ts b/packages/integrations/netlify/test/static/fixtures/redirects/.astro/types.d.ts new file mode 100644 index 000000000..03d7cc43f --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/.astro/types.d.ts @@ -0,0 +1,2 @@ +/// <reference types="astro/client" /> +/// <reference path="content.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/astro.config.mjs b/packages/integrations/netlify/test/static/fixtures/redirects/astro.config.mjs new file mode 100644 index 000000000..ce441d8b1 --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/astro.config.mjs @@ -0,0 +1,16 @@ +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'static', + adapter: netlify(), + site: "http://example.com", + redirects: { + '/other': '/', + '/two': { + status: 302, + destination: '/', + }, + '/blog/[...slug]': '/team/articles/[...slug]', + }, +}); diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/package.json b/packages/integrations/netlify/test/static/fixtures/redirects/package.json new file mode 100644 index 000000000..3e543bf35 --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/netlify-static-redirects", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/netlify": "workspace:" + } +} diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/src/env.d.ts b/packages/integrations/netlify/test/static/fixtures/redirects/src/env.d.ts new file mode 100644 index 000000000..9bc5cb41c --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/src/env.d.ts @@ -0,0 +1 @@ +/// <reference path="../.astro/types.d.ts" />
\ No newline at end of file diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/index.astro b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/index.astro new file mode 100644 index 000000000..53e029f04 --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/index.astro @@ -0,0 +1,6 @@ +<html> +<head><title>Testing</title></head> +<body> + <h1>Testing</h1> +</body> +</html> diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/nope.astro b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/nope.astro new file mode 100644 index 000000000..f48d767ee --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/nope.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect('/'); +--- diff --git a/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/team/articles/[...slug].astro b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/team/articles/[...slug].astro new file mode 100644 index 000000000..716d3bd5d --- /dev/null +++ b/packages/integrations/netlify/test/static/fixtures/redirects/src/pages/team/articles/[...slug].astro @@ -0,0 +1,25 @@ +--- +export const getStaticPaths = (async () => { + const posts = [ + { slug: 'one', data: {draft: false, title: 'One'} }, + { slug: 'two', data: {draft: false, title: 'Two'} } + ]; + return posts.map((post) => { + return { + params: { slug: post.slug }, + props: { draft: post.data.draft, title: post.data.title }, + }; + }); +}) + +const { slug } = Astro.params; +const { title } = Astro.props; +--- +<html> + <head> + <title>{ title }</title> + </head> + <body> + <h1>{ title }</h1> + </body> +</html> diff --git a/packages/integrations/netlify/test/static/headers.test.js b/packages/integrations/netlify/test/static/headers.test.js new file mode 100644 index 000000000..5c1400098 --- /dev/null +++ b/packages/integrations/netlify/test/static/headers.test.js @@ -0,0 +1,25 @@ +import * as assert from 'node:assert/strict'; +import { before, describe, it } from 'node:test'; +import { loadFixture } from '../../../../astro/test/test-utils.js'; + +describe('SSG - headers', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ root: new URL('./fixtures/redirects/', import.meta.url) }); + await fixture.build(); + }); + + it('Generates headers for static assets', async () => { + const config = await fixture.readFile('../.netlify/v1/config.json'); + const headers = JSON.parse(config).headers; + assert.deepEqual(headers, [ + { + for: '/_astro/*', + values: { + 'Cache-Control': 'public, max-age=31536000, immutable', + }, + }, + ]); + }); +}); diff --git a/packages/integrations/netlify/test/static/redirects.test.js b/packages/integrations/netlify/test/static/redirects.test.js new file mode 100644 index 000000000..cab954831 --- /dev/null +++ b/packages/integrations/netlify/test/static/redirects.test.js @@ -0,0 +1,34 @@ +import * as assert from 'node:assert/strict'; +import { before, describe, it } from 'node:test'; +import { loadFixture } from '../../../../astro/test/test-utils.js'; + +describe('SSG - 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+/); + assert.deepEqual(parts, [ + '', + + '/two', + '/', + '302', + + '/other', + '/', + '301', + + '/blog/*', + '/team/articles/*/index.html', + '301', + + '', + ]); + }); +}); diff --git a/packages/integrations/netlify/test/test-utils.js b/packages/integrations/netlify/test/test-utils.js new file mode 100644 index 000000000..7c012e86a --- /dev/null +++ b/packages/integrations/netlify/test/test-utils.js @@ -0,0 +1,12 @@ +import { execa } from 'execa'; + +/** Returns a process running the Astro CLI. */ +export function cli(/** @type {string[]} */ ...args) { + const spawned = execa('npx', ['astro', ...args], { + env: { ASTRO_TELEMETRY_DISABLED: true }, + }); + + spawned.stdout.setEncoding('utf8'); + + return spawned; +} |