mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
Use real filesystem for unit testing (#12172)
This commit is contained in:
parent
5ab2d980aa
commit
64bb796c0f
38 changed files with 578 additions and 940 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -21,7 +21,8 @@ package-lock.json
|
|||
|
||||
packages/astro/src/**/*.prebuilt.ts
|
||||
packages/astro/src/**/*.prebuilt-dev.ts
|
||||
!packages/astro/vendor/vite/dist
|
||||
packages/astro/test/units/_temp-fixtures/*
|
||||
!packages/astro/test/units/_temp-fixtures/package.json
|
||||
packages/integrations/**/.netlify/
|
||||
|
||||
# exclude IntelliJ/WebStorm stuff
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"**/dist/**",
|
||||
"**/smoke/**",
|
||||
"**/fixtures/**",
|
||||
"**/_temp-fixtures/**",
|
||||
"**/vendor/**",
|
||||
"**/.vercel/**",
|
||||
],
|
||||
|
|
|
@ -87,6 +87,9 @@
|
|||
"allowAny": [
|
||||
"astro"
|
||||
]
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"fs-fixture@2.4.0": "patches/fs-fixture@2.4.0.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,14 +112,15 @@
|
|||
"build": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" --copy-wasm && tsc",
|
||||
"build:ci": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" --copy-wasm",
|
||||
"dev": "astro-scripts dev --copy-wasm --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.{ts,js}\"",
|
||||
"test": "pnpm run test:node && pnpm run test:types",
|
||||
"test:match": "pnpm run test:node --match",
|
||||
"test": "pnpm run test:unit && pnpm run test:integration && pnpm run test:types",
|
||||
"test:match": "astro-scripts test \"test/**/*.test.js\" --match",
|
||||
"test:e2e": "pnpm test:e2e:chrome && pnpm test:e2e:firefox",
|
||||
"test:e2e:match": "playwright test -g",
|
||||
"test:e2e:chrome": "playwright test",
|
||||
"test:e2e:firefox": "playwright test --config playwright.firefox.config.js",
|
||||
"test:types": "tsc --project tsconfig.tests.json",
|
||||
"test:node": "astro-scripts test \"test/**/*.test.js\""
|
||||
"test:unit": "astro-scripts test \"test/units/**/*.test.js\" --teardown ./test/units/teardown.js",
|
||||
"test:integration": "astro-scripts test \"test/*.test.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/compiler": "^2.10.3",
|
||||
|
@ -210,9 +211,9 @@
|
|||
"eol": "^0.10.0",
|
||||
"execa": "^8.0.1",
|
||||
"expect-type": "^1.1.0",
|
||||
"fs-fixture": "^2.4.0",
|
||||
"mdast-util-mdx": "^3.0.0",
|
||||
"mdast-util-mdx-jsx": "^3.1.3",
|
||||
"memfs": "^4.14.0",
|
||||
"node-mocks-http": "^1.16.1",
|
||||
"parse-srcset": "^1.0.2",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
|
|
|
@ -77,6 +77,9 @@ export default function createVitePluginAstroServer({
|
|||
}
|
||||
|
||||
process.on('unhandledRejection', handleUnhandledRejection);
|
||||
viteServer.httpServer?.on('close', () => {
|
||||
process.off('unhandledRejection', handleUnhandledRejection);
|
||||
});
|
||||
|
||||
return () => {
|
||||
// Push this middleware to the front of the stack so that it can intercept responses.
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({});
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"name": "@test/content-mixed-errors",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"name": "Placeholder"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
title: Placeholder post
|
||||
---
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
try {
|
||||
await getCollection('authors')
|
||||
} catch (e) {
|
||||
return e
|
||||
}
|
||||
---
|
||||
|
||||
<h1>Worked</h1>
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
await getCollection('blog')
|
||||
---
|
||||
|
||||
<h1>Worked</h1>
|
8
packages/astro/test/units/_temp-fixtures/package.json
Normal file
8
packages/astro/test/units/_temp-fixtures/package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "astro-temp-fixtures",
|
||||
"description": "This directory contains nested directories of dynamically created unit test fixtures. The deps here can be used by them",
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "workspace:*",
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
|
@ -1,25 +1,19 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createFs, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/tailwindcss-ts/', import.meta.url);
|
||||
import { createFixture, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('Astro config formats', () => {
|
||||
it('An mjs config can import TypeScript modules', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': ``,
|
||||
'/src/stuff.ts': `export default 'works';`,
|
||||
'/astro.config.mjs': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': ``,
|
||||
'/src/stuff.ts': `export default 'works';`,
|
||||
'/astro.config.mjs': `\
|
||||
import stuff from './src/stuff.ts';
|
||||
export default {}
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, () => {
|
||||
await runInContainer({ inlineConfig: { root: fixture.path } }, () => {
|
||||
assert.equal(
|
||||
true,
|
||||
true,
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
import nodeFS from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { attachContentServerListeners } from '../../../dist/content/index.js';
|
||||
import { createFs, runInContainer, triggerFSEvent } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
|
||||
function getTypesDts() {
|
||||
const typesdtsURL = new URL('../../../templates/content/types.d.ts', import.meta.url);
|
||||
const relpath = path
|
||||
.relative(fileURLToPath(root), fileURLToPath(typesdtsURL))
|
||||
.replace(/\\/g, '/');
|
||||
return {
|
||||
[relpath]: nodeFS.readFileSync(typesdtsURL, 'utf-8'),
|
||||
};
|
||||
}
|
||||
import { createFixture, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('frontmatter', () => {
|
||||
it('errors in content/ does not crash server', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
...getTypesDts(),
|
||||
'/src/content/posts/blog.md': `
|
||||
const fixture = await createFixture({
|
||||
'/src/content/posts/blog.md': `\
|
||||
---
|
||||
title: One
|
||||
---
|
||||
`,
|
||||
'/src/content/config.ts': `
|
||||
'/src/content/config.ts': `\
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const posts = defineCollection({
|
||||
|
@ -38,7 +21,7 @@ describe('frontmatter', () => {
|
|||
posts
|
||||
};
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
'/src/pages/index.astro': `\
|
||||
---
|
||||
---
|
||||
<html>
|
||||
|
@ -48,14 +31,12 @@ describe('frontmatter', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||
await runInContainer({ inlineConfig: { root: fixture.path } }, async (container) => {
|
||||
await attachContentServerListeners(container);
|
||||
|
||||
fs.writeFileFromRootSync(
|
||||
await fixture.writeFile(
|
||||
'/src/content/posts/blog.md',
|
||||
`
|
||||
---
|
||||
|
@ -64,7 +45,6 @@ describe('frontmatter', () => {
|
|||
---
|
||||
`,
|
||||
);
|
||||
triggerFSEvent(container, fs, '/src/content/posts/blog.md', 'change');
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
// Note, if we got here, it didn't crash
|
||||
});
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* correctPath.js <https://github.com/streamich/fs-monkey/blob/af36a890d8070b25b9eae7178824f653bad5621f/src/correctPath.js>
|
||||
* Taken from:
|
||||
* https://github.com/streamich/fs-monkeys
|
||||
*/
|
||||
|
||||
const isWin = process.platform === 'win32';
|
||||
|
||||
/*!
|
||||
* removeTrailingSeparator <https://github.com/darsain/remove-trailing-separator>
|
||||
*
|
||||
* Inlined from:
|
||||
* Copyright (c) darsain.
|
||||
* Released under the ISC License.
|
||||
*/
|
||||
function removeTrailingSeparator(str) {
|
||||
let i = str.length - 1;
|
||||
if (i < 2) {
|
||||
return str;
|
||||
}
|
||||
while (isSeparator(str, i)) {
|
||||
i--;
|
||||
}
|
||||
return str.substr(0, i + 1);
|
||||
}
|
||||
|
||||
function isSeparator(str, i) {
|
||||
let char = str[i];
|
||||
return i > 0 && (char === '/' || (isWin && char === '\\'));
|
||||
}
|
||||
|
||||
/*!
|
||||
* normalize-path <https://github.com/jonschlinkert/normalize-path>
|
||||
*
|
||||
* Inlined from:
|
||||
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
function normalizePath(str, stripTrailing) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError('expected a string');
|
||||
}
|
||||
str = str.replace(/[\\/]+/g, '/');
|
||||
if (stripTrailing !== false) {
|
||||
str = removeTrailingSeparator(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/*!
|
||||
* unixify <https://github.com/jonschlinkert/unixify>
|
||||
*
|
||||
* Inlined from:
|
||||
* Copyright (c) 2014, 2017, Jon Schlinkert.
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
export function unixify(filepath, stripTrailing = true) {
|
||||
if (isWin) {
|
||||
filepath = normalizePath(filepath, stripTrailing);
|
||||
return filepath.replace(/^([a-zA-Z]+:|\.\/)/, '');
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
|
||||
/*
|
||||
* Corrects a windows path to unix format (including \\?\c:...)
|
||||
*/
|
||||
export function correctPath(filepath) {
|
||||
return unixify(filepath.replace(/^\\\\\?\\.:\\/, '\\'));
|
||||
}
|
|
@ -1,26 +1,19 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('base configuration', () => {
|
||||
describe('with trailingSlash: "never"', () => {
|
||||
describe('index route', () => {
|
||||
it('Requests that include a trailing slash 404', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>testing</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>testing</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
|
@ -38,18 +31,15 @@ describe('base configuration', () => {
|
|||
});
|
||||
|
||||
it('Requests that exclude a trailing slash 200', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>testing</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>testing</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
|
@ -69,18 +59,14 @@ describe('base configuration', () => {
|
|||
|
||||
describe('sub route', () => {
|
||||
it('Requests that include a trailing slash 404', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/sub/index.astro': `<h1>testing</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/sub/index.astro': `<h1>testing</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
|
@ -98,18 +84,14 @@ describe('base configuration', () => {
|
|||
});
|
||||
|
||||
it('Requests that exclude a trailing slash 200', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/sub/index.astro': `<h1>testing</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/sub/index.astro': `<h1>testing</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
|
|
|
@ -1,129 +1,146 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import _sync from '../../../dist/core/sync/index.js';
|
||||
import { createFsWithFallback } from '../test-utils.js';
|
||||
import { createFixture } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/content-mixed-errors/', import.meta.url);
|
||||
|
||||
async function sync({ fs }) {
|
||||
async function sync(root) {
|
||||
try {
|
||||
await _sync(
|
||||
{
|
||||
root: fileURLToPath(root),
|
||||
logLevel: 'silent',
|
||||
},
|
||||
{
|
||||
fs,
|
||||
},
|
||||
);
|
||||
await _sync({
|
||||
root,
|
||||
logLevel: 'silent',
|
||||
});
|
||||
return 0;
|
||||
} catch (_) {
|
||||
} catch {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const baseFileTree = {
|
||||
'/src/content/authors/placeholder.json': `{ "name": "Placeholder" }`,
|
||||
'/src/content/blog/placeholder.md': `\
|
||||
---
|
||||
title: Placeholder post
|
||||
---
|
||||
`,
|
||||
'/src/pages/authors.astro': `\
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
try {
|
||||
await getCollection('authors')
|
||||
} catch (e) {
|
||||
return e
|
||||
}
|
||||
---
|
||||
|
||||
<h1>Worked</h1>
|
||||
`,
|
||||
'/src/pages/blog.astro': `\
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
await getCollection('blog')
|
||||
---
|
||||
|
||||
<h1>Worked</h1>`,
|
||||
};
|
||||
|
||||
describe('Content Collections - mixed content errors', () => {
|
||||
it('raises "mixed content" error when content in data collection', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/authors/ben.md': `---
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/authors/ben.md': `\
|
||||
---
|
||||
name: Ben
|
||||
---
|
||||
|
||||
# Ben`,
|
||||
'/src/content/authors/tony.json': `{ "name": "Tony" }`,
|
||||
'/src/content/config.ts': `
|
||||
# Ben
|
||||
`,
|
||||
'/src/content/authors/tony.json': `{ "name": "Tony" }`,
|
||||
'/src/content/config.ts': `\
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
const authors = defineCollection({
|
||||
type: 'data',
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
const authors = defineCollection({
|
||||
type: 'data',
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
}),
|
||||
});
|
||||
export const collections = { authors };
|
||||
`,
|
||||
});
|
||||
|
||||
export const collections = { authors };`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
|
||||
assert.equal(await sync({ fs }), 1);
|
||||
assert.equal(await sync(fixture.path), 1);
|
||||
});
|
||||
|
||||
it('raises "mixed content" error when data in content collection', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/blog/post.md': `---
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/blog/post.md': `\
|
||||
---
|
||||
title: Post
|
||||
---
|
||||
|
||||
# Post`,
|
||||
'/src/content/blog/post.yaml': `title: YAML Post`,
|
||||
'/src/content/config.ts': `
|
||||
# Post
|
||||
`,
|
||||
'/src/content/blog/post.yaml': `title: YAML Post`,
|
||||
'/src/content/config.ts': `\
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
const blog = defineCollection({
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
const blog = defineCollection({
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
});
|
||||
export const collections = { blog };
|
||||
`,
|
||||
});
|
||||
|
||||
export const collections = { blog };`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
|
||||
assert.equal(await sync({ fs }), 1);
|
||||
assert.equal(await sync(fixture.path), 1);
|
||||
});
|
||||
|
||||
it('raises error when data collection configured as content collection', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/banners/welcome.json': `{ "src": "/example", "alt": "Welcome" }`,
|
||||
'/src/content/config.ts': `
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/banners/welcome.json': `{ "src": "/example", "alt": "Welcome" }`,
|
||||
'/src/content/config.ts': `\
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
const banners = defineCollection({
|
||||
schema: z.object({
|
||||
src: z.string(),
|
||||
alt: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
const banners = defineCollection({
|
||||
schema: z.object({
|
||||
src: z.string(),
|
||||
alt: z.string(),
|
||||
}),
|
||||
});
|
||||
export const collections = { banners };
|
||||
`,
|
||||
});
|
||||
|
||||
export const collections = { banners };`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
|
||||
assert.equal(await sync({ fs }), 1);
|
||||
assert.equal(await sync(fixture.path), 1);
|
||||
});
|
||||
|
||||
it('does not raise error for empty collection with config', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
// Add placeholder to ensure directory exists
|
||||
'/src/content/i18n/_placeholder.txt': 'Need content here',
|
||||
'/src/content/config.ts': `
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
// Add placeholder to ensure directory exists
|
||||
'/src/content/i18n/_placeholder.txt': 'Need content here',
|
||||
'/src/content/config.ts': `\
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
const i18n = defineCollection({
|
||||
type: 'data',
|
||||
schema: z.object({
|
||||
greeting: z.string(),
|
||||
}),
|
||||
});
|
||||
const i18n = defineCollection({
|
||||
type: 'data',
|
||||
schema: z.object({
|
||||
greeting: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { i18n };`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
export const collections = { i18n };
|
||||
`,
|
||||
});
|
||||
|
||||
const res = await sync({ fs });
|
||||
assert.equal(res, 0);
|
||||
assert.equal(await sync(fixture.path), 0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,39 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
|
||||
import { attachContentServerListeners } from '../../../dist/content/server-listeners.js';
|
||||
import { createFsWithFallback, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/content/', import.meta.url);
|
||||
const baseFileTree = {
|
||||
'astro.config.mjs': `\
|
||||
import mdx from '@astrojs/mdx';
|
||||
export default {
|
||||
integrations: [mdx()]
|
||||
};
|
||||
`,
|
||||
'/src/content/blog/promo/_launch-week-styles.css': `\
|
||||
body {
|
||||
font-family: 'Comic Sans MS', sans-serif;
|
||||
}
|
||||
`,
|
||||
'/src/content/blog/promo/launch-week.mdx': `\
|
||||
---
|
||||
title: 'Launch week!'
|
||||
description: 'Join us for the exciting launch of SPACE BLOG'
|
||||
publishedDate: 'Sat May 21 2022 00:00:00 GMT-0400 (Eastern Daylight Time)'
|
||||
tags: ['announcement']
|
||||
---
|
||||
|
||||
import './_launch-week-styles.css';
|
||||
|
||||
Join us for the space blog launch!
|
||||
|
||||
- THIS THURSDAY
|
||||
- Houston, TX
|
||||
- Dress code: **interstellar casual** ✨
|
||||
`,
|
||||
};
|
||||
|
||||
/** @type {typeof runInContainer} */
|
||||
async function runInContainerWithContentListeners(params, callback) {
|
||||
|
@ -18,9 +45,9 @@ async function runInContainerWithContentListeners(params, callback) {
|
|||
|
||||
describe('Content Collections - render()', () => {
|
||||
it('can be called in a page component', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/config.ts': `
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/config.ts': `
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
const blog = defineCollection({
|
||||
|
@ -32,7 +59,7 @@ describe('Content Collections - render()', () => {
|
|||
|
||||
export const collections = { blog };
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
const blog = await getCollection('blog');
|
||||
|
@ -47,15 +74,12 @@ describe('Content Collections - render()', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainerWithContentListeners(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
@ -79,9 +103,9 @@ describe('Content Collections - render()', () => {
|
|||
});
|
||||
|
||||
it('can be used in a layout component', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/components/Layout.astro': `
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/components/Layout.astro': `
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
const blog = await getCollection('blog');
|
||||
|
@ -99,7 +123,7 @@ describe('Content Collections - render()', () => {
|
|||
</html>
|
||||
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
|
@ -107,15 +131,12 @@ describe('Content Collections - render()', () => {
|
|||
<h1 slot="title">Index page</h2>
|
||||
</Layout>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainerWithContentListeners(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
@ -139,9 +160,9 @@ describe('Content Collections - render()', () => {
|
|||
});
|
||||
|
||||
it('can be used in a slot', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/config.ts': `
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/config.ts': `
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
const blog = defineCollection({
|
||||
|
@ -153,7 +174,7 @@ describe('Content Collections - render()', () => {
|
|||
|
||||
export const collections = { blog };
|
||||
`,
|
||||
'/src/components/Layout.astro': `
|
||||
'/src/components/Layout.astro': `
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
|
@ -164,7 +185,7 @@ describe('Content Collections - render()', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
@ -177,15 +198,12 @@ describe('Content Collections - render()', () => {
|
|||
<Content slot="main" />
|
||||
</Layout>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainerWithContentListeners(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
@ -209,9 +227,9 @@ describe('Content Collections - render()', () => {
|
|||
});
|
||||
|
||||
it('can be called from any js/ts file', async () => {
|
||||
const fs = createFsWithFallback(
|
||||
{
|
||||
'/src/content/config.ts': `
|
||||
const fixture = await createFixture({
|
||||
...baseFileTree,
|
||||
'/src/content/config.ts': `
|
||||
import { z, defineCollection } from 'astro:content';
|
||||
|
||||
const blog = defineCollection({
|
||||
|
@ -223,7 +241,7 @@ describe('Content Collections - render()', () => {
|
|||
|
||||
export const collections = { blog };
|
||||
`,
|
||||
'/src/launch-week.ts': `
|
||||
'/src/launch-week.ts': `
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
export let Content;
|
||||
|
@ -234,7 +252,7 @@ describe('Content Collections - render()', () => {
|
|||
|
||||
Content = mod.Content;
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import { Content } from '../launch-week.ts';
|
||||
---
|
||||
|
@ -246,15 +264,12 @@ describe('Content Collections - render()', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainerWithContentListeners(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
import {
|
||||
createFs,
|
||||
createRequestAndResponse,
|
||||
runInContainer,
|
||||
triggerFSEvent,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('dev container', () => {
|
||||
it('can render requests', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
const name = 'Testing';
|
||||
---
|
||||
|
@ -26,11 +17,9 @@ describe('dev container', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||
await runInContainer({ inlineConfig: { root: fixture.path } }, async (container) => {
|
||||
const { req, res, text } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
|
@ -43,89 +32,16 @@ describe('dev container', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('HMR only short circuits on previously cached modules', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/components/Header.astro': `
|
||||
<h1>{Astro.props.title}</h1>
|
||||
`,
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import Header from '../components/Header.astro';
|
||||
const name = 'Testing';
|
||||
---
|
||||
<html>
|
||||
<head><title>{name}</title></head>
|
||||
<body class="one">
|
||||
<Header title={name} />
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
|
||||
await runInContainer({ fs, inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||
let r = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
});
|
||||
container.handle(r.req, r.res);
|
||||
let html = await r.text();
|
||||
let $ = cheerio.load(html);
|
||||
assert.equal($('body.one').length, 1);
|
||||
|
||||
fs.writeFileFromRootSync(
|
||||
'/src/components/Header.astro',
|
||||
`
|
||||
<h1>{Astro.props.title}</h1>
|
||||
`,
|
||||
);
|
||||
triggerFSEvent(container, fs, '/src/components/Header.astro', 'change');
|
||||
|
||||
fs.writeFileFromRootSync(
|
||||
'/src/pages/index.astro',
|
||||
`
|
||||
---
|
||||
import Header from '../components/Header.astro';
|
||||
const name = 'Testing';
|
||||
---
|
||||
<html>
|
||||
<head><title>{name}</title></head>
|
||||
<body class="two">
|
||||
<Header title={name} />
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
);
|
||||
triggerFSEvent(container, fs, '/src/pages/index.astro', 'change');
|
||||
|
||||
r = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
});
|
||||
container.handle(r.req, r.res);
|
||||
html = await r.text();
|
||||
$ = cheerio.load(html);
|
||||
assert.equal($('body.one').length, 0);
|
||||
assert.equal($('body.two').length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('Allows dynamic segments in injected routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/components/test.astro': `<h1>{Astro.params.slug}</h1>`,
|
||||
'/src/pages/test-[slug].astro': `<h1>{Astro.params.slug}</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/components/test.astro': `<h1>{Astro.params.slug}</h1>`,
|
||||
'/src/pages/test-[slug].astro': `<h1>{Astro.params.slug}</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
integrations: [
|
||||
{
|
||||
|
@ -164,19 +80,15 @@ describe('dev container', () => {
|
|||
});
|
||||
|
||||
it('Serves injected 404 route for any 404', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/components/404.astro': `<h1>Custom 404</h1>`,
|
||||
'/src/pages/page.astro': `<h1>Regular page</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/components/404.astro': `<h1>Custom 404</h1>`,
|
||||
'/src/pages/page.astro': `<h1>Regular page</h1>`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
integrations: [
|
||||
{
|
||||
|
@ -226,10 +138,14 @@ describe('dev container', () => {
|
|||
});
|
||||
|
||||
it('items in public/ are not available from root when using a base', async () => {
|
||||
const fixture = await createFixture({
|
||||
'/public/test.txt': `Test`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/sub/',
|
||||
},
|
||||
},
|
||||
|
@ -260,7 +176,11 @@ describe('dev container', () => {
|
|||
});
|
||||
|
||||
it('items in public/ are available from root when not using a base', async () => {
|
||||
await runInContainer({ inlineConfig: { root: fileURLToPath(root) } }, async (container) => {
|
||||
const fixture = await createFixture({
|
||||
'/public/test.txt': `Test`,
|
||||
});
|
||||
|
||||
await runInContainer({ inlineConfig: { root: fixture.path } }, async (container) => {
|
||||
// Try the root path
|
||||
let r = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
|
||||
describe('head injection', () => {
|
||||
it('Dynamic injection from component created in the page frontmatter', async () => {
|
||||
const fs = createFs(
|
||||
const fixture = await createFixture(
|
||||
{
|
||||
'/src/components/Other.astro': `
|
||||
<style>
|
||||
|
@ -64,9 +63,8 @@ describe('head injection', () => {
|
|||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
@ -87,7 +85,7 @@ describe('head injection', () => {
|
|||
});
|
||||
|
||||
it('Dynamic injection from a layout component', async () => {
|
||||
const fs = createFs(
|
||||
const fixture = await createFixture(
|
||||
{
|
||||
'/src/components/Other.astro': `
|
||||
<style>
|
||||
|
@ -164,9 +162,8 @@ describe('head injection', () => {
|
|||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
vite: { server: { middlewareMode: true } },
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('hydration', () => {
|
||||
it(
|
||||
'should not crash when reassigning a hydrated component',
|
||||
{ skip: true, todo: "It seems that `components/Client.svelte` isn't found" },
|
||||
async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import Svelte from '../components/Client.svelte';
|
||||
const Foo = Svelte;
|
||||
|
@ -26,15 +22,12 @@ describe('hydration', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
logLevel: 'silent',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
|
||||
import {
|
||||
createContainerWithAutomaticRestart,
|
||||
startContainer,
|
||||
} from '../../../dist/core/dev/index.js';
|
||||
import { createFs, createRequestAndResponse, triggerFSEvent } from '../test-utils.js';
|
||||
import { createFixture, createRequestAndResponse } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
/** @type {import('astro').AstroInlineConfig} */
|
||||
const defaultInlineConfig = {
|
||||
logLevel: 'silent',
|
||||
};
|
||||
|
||||
function isStarted(container) {
|
||||
return !!container.viteServer.httpServer?.listening;
|
||||
}
|
||||
|
||||
describe('dev container restarts', () => {
|
||||
// Checking for restarts may hang if no restarts happen, so set a 20s timeout for each test
|
||||
describe('dev container restarts', { timeout: 20000 }, () => {
|
||||
it('Surfaces config errors on restarts', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
<html>
|
||||
<head><title>Test</title></head>
|
||||
<body>
|
||||
|
@ -27,16 +29,14 @@ describe('dev container restarts', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
'/astro.config.mjs': `
|
||||
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
'/astro.config.mjs': ``,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
|
@ -52,40 +52,37 @@ describe('dev container restarts', () => {
|
|||
|
||||
// Create an error
|
||||
let restartComplete = restart.restarted();
|
||||
fs.writeFileFromRootSync('/astro.config.mjs', 'const foo = bar');
|
||||
|
||||
// Vite watches the real filesystem, so we have to mock this part. It's not so bad.
|
||||
await fixture.writeFile('/astro.config.mjs', 'const foo = bar');
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fs.getFullyResolvedPath('/astro.config.mjs'),
|
||||
fixture.getPath('/astro.config.mjs').replace(/\\/g, '/'),
|
||||
);
|
||||
|
||||
// Wait for the restart to finish
|
||||
let hmrError = await restartComplete;
|
||||
assert.notEqual(typeof hmrError, 'undefined');
|
||||
assert.ok(hmrError instanceof Error);
|
||||
|
||||
// Do it a second time to make sure we are still watching
|
||||
|
||||
restartComplete = restart.restarted();
|
||||
fs.writeFileFromRootSync('/astro.config.mjs', 'const foo = bar2');
|
||||
|
||||
// Vite watches the real filesystem, so we have to mock this part. It's not so bad.
|
||||
await fixture.writeFile('/astro.config.mjs', 'const foo = bar2');
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fs.getFullyResolvedPath('/astro.config.mjs'),
|
||||
fixture.getPath('/astro.config.mjs').replace(/\\/g, '/'),
|
||||
);
|
||||
|
||||
hmrError = await restartComplete;
|
||||
assert.notEqual(typeof hmrError, 'undefined');
|
||||
assert.ok(hmrError instanceof Error);
|
||||
} finally {
|
||||
await restart.container.close();
|
||||
}
|
||||
});
|
||||
|
||||
it('Restarts the container if previously started', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
<html>
|
||||
<head><title>Test</title></head>
|
||||
<body>
|
||||
|
@ -93,14 +90,14 @@ describe('dev container restarts', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
'/astro.config.mjs': ``,
|
||||
},
|
||||
root,
|
||||
);
|
||||
'/astro.config.mjs': ``,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
await startContainer(restart.container);
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
@ -108,7 +105,12 @@ describe('dev container restarts', () => {
|
|||
try {
|
||||
// Trigger a change
|
||||
let restartComplete = restart.restarted();
|
||||
triggerFSEvent(restart.container, fs, '/astro.config.mjs', 'change');
|
||||
await fixture.writeFile('/astro.config.mjs', '');
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fixture.getPath('/astro.config.mjs').replace(/\\/g, '/'),
|
||||
);
|
||||
await restartComplete;
|
||||
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
@ -118,18 +120,16 @@ describe('dev container restarts', () => {
|
|||
});
|
||||
|
||||
it('Is able to restart project using Tailwind + astro.config.ts', async () => {
|
||||
const troot = new URL('../../fixtures/tailwindcss-ts/', import.meta.url);
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': ``,
|
||||
'/astro.config.ts': ``,
|
||||
},
|
||||
troot,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': ``,
|
||||
'/astro.config.ts': ``,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
await startContainer(restart.container);
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
@ -137,7 +137,12 @@ describe('dev container restarts', () => {
|
|||
try {
|
||||
// Trigger a change
|
||||
let restartComplete = restart.restarted();
|
||||
triggerFSEvent(restart.container, fs, '/astro.config.ts', 'change');
|
||||
await fixture.writeFile('/astro.config.ts', '');
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fixture.getPath('/astro.config.mjs').replace(/\\/g, '/'),
|
||||
);
|
||||
await restartComplete;
|
||||
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
@ -147,24 +152,27 @@ describe('dev container restarts', () => {
|
|||
});
|
||||
|
||||
it('Is able to restart project on package.json changes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': ``,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': ``,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
await startContainer(restart.container);
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
||||
try {
|
||||
let restartComplete = restart.restarted();
|
||||
fs.writeFileSync('/package.json', `{}`);
|
||||
triggerFSEvent(restart.container, fs, '/package.json', 'change');
|
||||
await fixture.writeFile('/package.json', `{}`);
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fixture.getPath('/package.json').replace(/\\/g, '/'),
|
||||
);
|
||||
await restartComplete;
|
||||
} finally {
|
||||
await restart.container.close();
|
||||
|
@ -172,16 +180,15 @@ describe('dev container restarts', () => {
|
|||
});
|
||||
|
||||
it('Is able to restart on viteServer.restart API call', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': ``,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': ``,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
await startContainer(restart.container);
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
@ -196,26 +203,28 @@ describe('dev container restarts', () => {
|
|||
});
|
||||
|
||||
it('Is able to restart project on .astro/settings.json changes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': ``,
|
||||
'/.astro/settings.json': `{}`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': ``,
|
||||
'/.astro/settings.json': `{}`,
|
||||
});
|
||||
|
||||
const restart = await createContainerWithAutomaticRestart({
|
||||
fs,
|
||||
inlineConfig: { root: fileURLToPath(root), logLevel: 'silent' },
|
||||
inlineConfig: {
|
||||
...defaultInlineConfig,
|
||||
root: fixture.path,
|
||||
},
|
||||
});
|
||||
await startContainer(restart.container);
|
||||
assert.equal(isStarted(restart.container), true);
|
||||
|
||||
try {
|
||||
let restartComplete = restart.restarted();
|
||||
fs.mkdirSync('/.astro/', { recursive: true });
|
||||
fs.writeFileSync('/.astro/settings.json', `{ }`);
|
||||
triggerFSEvent(restart.container, fs, '/.astro/settings.json', 'change');
|
||||
await fixture.writeFile('/.astro/settings.json', `{ }`);
|
||||
// TODO: fix this hack
|
||||
restart.container.viteServer.watcher.emit(
|
||||
'change',
|
||||
fixture.getPath('/.astro/settings.json').replace(/\\/g, '/'),
|
||||
);
|
||||
await restartComplete;
|
||||
} finally {
|
||||
await restart.container.close();
|
||||
|
|
|
@ -1,30 +1,23 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('core/render chunk', () => {
|
||||
it('does not throw on user object with type', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `\
|
||||
---
|
||||
const value = { type: 'foobar' }
|
||||
---
|
||||
<div id="chunk">{value}</div>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
logLevel: 'silent',
|
||||
integrations: [],
|
||||
},
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { createFs, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createFixture, createRequestAndResponse, runInContainer } from '../test-utils.js';
|
||||
|
||||
describe('core/render components', () => {
|
||||
it('should sanitize dynamic tags', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
const TagA = 'p style=color:red;'
|
||||
const TagB = 'p><script id="pwnd">console.log("pwnd")</script>'
|
||||
|
@ -23,15 +19,12 @@ describe('core/render components', () => {
|
|||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
logLevel: 'silent',
|
||||
integrations: [],
|
||||
},
|
||||
|
@ -58,9 +51,8 @@ describe('core/render components', () => {
|
|||
});
|
||||
|
||||
it('should merge `class` and `class:list`', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `
|
||||
---
|
||||
import Class from '../components/Class.astro';
|
||||
import ClassList from '../components/ClassList.astro';
|
||||
|
@ -74,20 +66,17 @@ describe('core/render components', () => {
|
|||
<BothFlipped class:list={{ blue: true }} class="red" />
|
||||
<BothSpread class:list={{ blue: true }} { ...{ class: "red" }} />
|
||||
`,
|
||||
'/src/components/Class.astro': `<pre id="class" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/ClassList.astro': `<pre id="class-list" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothLiteral.astro': `<pre id="both-literal" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothFlipped.astro': `<pre id="both-flipped" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothSpread.astro': `<pre id="both-spread" set:html={JSON.stringify(Astro.props)} />`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
'/src/components/Class.astro': `<pre id="class" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/ClassList.astro': `<pre id="class-list" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothLiteral.astro': `<pre id="both-literal" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothFlipped.astro': `<pre id="both-flipped" set:html={JSON.stringify(Astro.props)} />`,
|
||||
'/src/components/BothSpread.astro': `<pre id="both-spread" set:html={JSON.stringify(Astro.props)} />`,
|
||||
});
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
inlineConfig: {
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
logLevel: 'silent',
|
||||
integrations: [],
|
||||
},
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/response-redirect.ts': `export const GET = ({ url }) => Response.redirect("https://example.com/destination", 307)`,
|
||||
'/src/pages/response.ts': `export const GET = ({ url }) => new Response(null, { headers: { Location: "https://example.com/destination" }, status: 307 })`,
|
||||
|
@ -23,9 +21,9 @@ describe('endpoints', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { Logger } from '../../../dist/core/logger/core.js';
|
||||
import { createRouteManifest } from '../../../dist/core/routing/manifest/create.js';
|
||||
import { createBasicSettings, createFs } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
import { createBasicSettings, createFixture } from '../test-utils.js';
|
||||
|
||||
function getManifestRoutes(manifest) {
|
||||
return manifest.routes.map((route) => ({
|
||||
|
@ -41,21 +38,17 @@ function assertRouteRelations(routes, relations) {
|
|||
|
||||
describe('routing - createRouteManifest', () => {
|
||||
it('using trailingSlash: "never" does not match the index route when it contains a trailing slash', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
});
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
const [{ pattern }] = manifest.routes;
|
||||
assert.equal(pattern.test(''), true);
|
||||
|
@ -63,15 +56,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('endpoint routes are sorted before page routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/[contact].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[contact].ts': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/[contact].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[contact].ts': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
experimental: {
|
||||
|
@ -91,9 +81,8 @@ describe('routing - createRouteManifest', () => {
|
|||
];
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
@ -117,18 +106,15 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('static routes are sorted before dynamic and rest routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/[dynamic].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest].astro': `<h1>test</h1>`,
|
||||
'/src/pages/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/static-[dynamic].astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/[dynamic].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest].astro': `<h1>test</h1>`,
|
||||
'/src/pages/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/static-[dynamic].astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
experimental: {
|
||||
|
@ -137,9 +123,8 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assertRouteRelations(getManifestRoutes(manifest), [
|
||||
|
@ -154,21 +139,18 @@ describe('routing - createRouteManifest', () => {
|
|||
|
||||
it('route sorting with multi-layer index page conflict', async () => {
|
||||
// Reproducing regression from https://github.com/withastro/astro/issues/10071
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/a/1.astro': `<h1>test</h1>`,
|
||||
'/src/pages/a/2.astro': `<h1>test</h1>`,
|
||||
'/src/pages/a/3.astro': `<h1>test</h1>`,
|
||||
'/src/pages/modules/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/modules/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/test/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/test/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/a/1.astro': `<h1>test</h1>`,
|
||||
'/src/pages/a/2.astro': `<h1>test</h1>`,
|
||||
'/src/pages/a/3.astro': `<h1>test</h1>`,
|
||||
'/src/pages/modules/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/modules/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/test/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/test/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
experimental: {
|
||||
|
@ -177,9 +159,8 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assertRouteRelations(getManifestRoutes(manifest), [
|
||||
|
@ -200,24 +181,21 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('route sorting respects the file tree', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/[dynamic_folder]/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_folder]/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_folder]/[...rest].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest]/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest]/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_file].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...other].astro': `<h1>test</h1>`,
|
||||
'/src/pages/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/[dynamic_folder]/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_folder]/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_folder]/[...rest].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest]/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...rest]/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[dynamic_file].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[...other].astro': `<h1>test</h1>`,
|
||||
'/src/pages/static.astro': `<h1>test</h1>`,
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
experimental: {
|
||||
|
@ -226,9 +204,8 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assertRouteRelations(getManifestRoutes(manifest), [
|
||||
|
@ -263,15 +240,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('injected routes are sorted in legacy mode above filesystem routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -289,9 +263,8 @@ describe('routing - createRouteManifest', () => {
|
|||
];
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
@ -315,15 +288,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('injected routes are sorted alongside filesystem routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/[...slug].astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -345,9 +315,8 @@ describe('routing - createRouteManifest', () => {
|
|||
];
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
@ -371,15 +340,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('redirects are sorted in legacy mode below the filesystem routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/contributing.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/contributing.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -392,9 +358,8 @@ describe('routing - createRouteManifest', () => {
|
|||
},
|
||||
});
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
@ -418,15 +383,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('redirects are sorted alongside the filesystem routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/contributing.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/index.astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/contributing.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -445,9 +407,8 @@ describe('routing - createRouteManifest', () => {
|
|||
},
|
||||
});
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
@ -471,14 +432,11 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('report colliding static routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/contributing.astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/contributing.astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -496,9 +454,8 @@ describe('routing - createRouteManifest', () => {
|
|||
];
|
||||
|
||||
const manifestOptions = {
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
};
|
||||
|
||||
const { logger, logs } = getLogger();
|
||||
|
@ -523,15 +480,12 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('report colliding SSR dynamic routes', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/[foo].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[bar].astro': `<h1>test</h1>`,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/[foo].astro': `<h1>test</h1>`,
|
||||
'/src/pages/[bar].astro': `<h1>test</h1>`,
|
||||
});
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -542,9 +496,8 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
const manifestOptions = {
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
};
|
||||
|
||||
const { logger, logs } = getLogger();
|
||||
|
@ -569,16 +522,13 @@ describe('routing - createRouteManifest', () => {
|
|||
});
|
||||
|
||||
it('should concatenate each part of the segment. issues#10122', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/a-[b].astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/a-[b].233.ts': ``,
|
||||
},
|
||||
root,
|
||||
);
|
||||
const fixture = await createFixture({
|
||||
'/src/pages/a-[b].astro': `<h1>test</h1>`,
|
||||
'/src/pages/blog/a-[b].233.ts': ``,
|
||||
});
|
||||
|
||||
const settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
base: '/search',
|
||||
trailingSlash: 'never',
|
||||
|
@ -599,9 +549,8 @@ describe('routing - createRouteManifest', () => {
|
|||
];
|
||||
|
||||
const manifest = createRouteManifest({
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
});
|
||||
|
||||
assert.deepEqual(getManifestRoutes(manifest), [
|
||||
|
|
|
@ -11,12 +11,11 @@ import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-serve
|
|||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/[serverDynamic].astro': `
|
||||
---
|
||||
|
@ -131,15 +130,14 @@ describe('Route matching', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
trailingSlash: 'never',
|
||||
output: 'hybrid',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
@ -149,9 +147,8 @@ describe('Route matching', () => {
|
|||
pipeline = DevPipeline.create(undefined, { loader, logger: defaultLogger, manifest, settings });
|
||||
manifestData = createRouteManifest(
|
||||
{
|
||||
cwd: fileURLToPath(root),
|
||||
cwd: fixture.path,
|
||||
settings,
|
||||
fsMod: fs,
|
||||
},
|
||||
defaultLogger,
|
||||
);
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/[...testSlashTrim].astro': `
|
||||
---
|
||||
|
@ -34,15 +32,14 @@ describe('Route sanitization', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
trailingSlash: 'never',
|
||||
output: 'hybrid',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/api.ts': `export const GET = () => Response.json({ success: true })`,
|
||||
};
|
||||
|
@ -20,15 +18,14 @@ describe('trailingSlash', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
trailingSlash: 'always',
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
@ -20,14 +19,13 @@ describe('endpoints', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem, root);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
|
19
packages/astro/test/units/teardown.js
Normal file
19
packages/astro/test/units/teardown.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import fs from 'node:fs';
|
||||
|
||||
export default function teardown(testPassed) {
|
||||
// Delete all directories within `_temp-fixtures` directory if all test passed
|
||||
if (testPassed) {
|
||||
try {
|
||||
const tempFixturesDir = new URL('./_temp-fixtures/', import.meta.url);
|
||||
const entries = fs.readdirSync(tempFixturesDir);
|
||||
for (const entry of entries) {
|
||||
if (entry === 'package.json' || entry === 'node_modules') continue;
|
||||
const dir = new URL(entry, tempFixturesDir);
|
||||
fs.rmSync(dir, { recursive: true });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to delete temp fixtures');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
import { EventEmitter } from 'node:events';
|
||||
import realFS from 'node:fs';
|
||||
import npath from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { Volume } from 'memfs';
|
||||
import { createFixture as _createFixture } from 'fs-fixture';
|
||||
import httpMocks from 'node-mocks-http';
|
||||
import { getDefaultClientDirectives } from '../../dist/core/client-directive/index.js';
|
||||
import { resolveConfig } from '../../dist/core/config/index.js';
|
||||
|
@ -13,7 +12,6 @@ import { nodeLogDestination } from '../../dist/core/logger/node.js';
|
|||
import { NOOP_MIDDLEWARE_FN } from '../../dist/core/middleware/noop-middleware.js';
|
||||
import { Pipeline } from '../../dist/core/render/index.js';
|
||||
import { RouteCache } from '../../dist/core/render/route-cache.js';
|
||||
import { unixify } from './correct-path.js';
|
||||
|
||||
/** @type {import('../../src/core/logger/core').Logger} */
|
||||
export const defaultLogger = new Logger({
|
||||
|
@ -27,102 +25,21 @@ export const silentLogging = {
|
|||
level: 'error',
|
||||
};
|
||||
|
||||
class VirtualVolume extends Volume {
|
||||
#root = '';
|
||||
constructor(root) {
|
||||
super();
|
||||
this.#root = root;
|
||||
}
|
||||
|
||||
#forcePath(p) {
|
||||
if (p instanceof URL) {
|
||||
p = unixify(fileURLToPath(p));
|
||||
} else {
|
||||
p = unixify(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
getFullyResolvedPath(pth) {
|
||||
return npath.posix.join(this.#root, pth);
|
||||
}
|
||||
|
||||
readFile(p, ...args) {
|
||||
return super.readFile(this.#forcePath(p), ...args);
|
||||
}
|
||||
|
||||
existsSync(p) {
|
||||
return super.existsSync(this.#forcePath(p));
|
||||
}
|
||||
|
||||
writeFileFromRootSync(pth, ...rest) {
|
||||
return super.writeFileSync(this.getFullyResolvedPath(pth), ...rest);
|
||||
}
|
||||
}
|
||||
|
||||
class VirtualVolumeWithFallback extends VirtualVolume {
|
||||
// Fallback to the real fs
|
||||
readFile(p, ...args) {
|
||||
const cb = args[args.length - 1];
|
||||
const argsMinusCallback = args.slice(0, args.length - 1);
|
||||
return super.readFile(p, ...argsMinusCallback, function (err, data) {
|
||||
if (err) {
|
||||
realFS.readFile(p, ...argsMinusCallback, function (err2, data2) {
|
||||
if (err2) {
|
||||
cb(err);
|
||||
} else {
|
||||
cb(null, data2);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cb(null, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readFileSync(p, ...args) {
|
||||
try {
|
||||
return super.readFileSync(p, ...args);
|
||||
} catch {
|
||||
return realFS.readFileSync(p, ...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createFs(json, root, VolumeImpl = VirtualVolume) {
|
||||
if (typeof root !== 'string') {
|
||||
root = unixify(fileURLToPath(root));
|
||||
}
|
||||
|
||||
const structure = {};
|
||||
for (const [key, value] of Object.entries(json)) {
|
||||
const fullpath = npath.posix.join(root, key);
|
||||
structure[fullpath] = value;
|
||||
}
|
||||
|
||||
const fs = new VolumeImpl(root);
|
||||
fs.fromJSON(structure);
|
||||
return fs;
|
||||
}
|
||||
|
||||
export function createFsWithFallback(json, root) {
|
||||
return createFs(json, root, VirtualVolumeWithFallback);
|
||||
}
|
||||
const tempFixturesDir = fileURLToPath(new URL('./_temp-fixtures/', import.meta.url));
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('../../src/core/dev/container').Container} container
|
||||
* @param {typeof import('node:fs')} fs
|
||||
* @param {string} shortPath
|
||||
* @param {'change'} eventType
|
||||
* @param {import('fs-fixture').FileTree} tree
|
||||
*/
|
||||
export function triggerFSEvent(container, fs, shortPath, eventType) {
|
||||
container.viteServer.watcher.emit(eventType, fs.getFullyResolvedPath(shortPath));
|
||||
|
||||
if (!fileURLToPath(container.settings.config.root).startsWith('/')) {
|
||||
const drive = fileURLToPath(container.settings.config.root).slice(0, 2);
|
||||
container.viteServer.watcher.emit(eventType, drive + fs.getFullyResolvedPath(shortPath));
|
||||
}
|
||||
export async function createFixture(tree) {
|
||||
return await _createFixture(
|
||||
{
|
||||
'package.json': '{}',
|
||||
...tree,
|
||||
},
|
||||
{
|
||||
tempDir: tempFixturesDir,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function createRequestAndResponse(reqOptions = {}) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
||||
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
||||
|
@ -12,13 +11,13 @@ import testAdapter from '../../test-adapter.js';
|
|||
import {
|
||||
createAstroModule,
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
async function createDevPipeline(overrides = {}) {
|
||||
const settings = overrides.settings ?? (await createBasicSettings({ root: '/' }));
|
||||
async function createDevPipeline(overrides = {}, root) {
|
||||
const settings = overrides.settings ?? (await createBasicSettings({ root }));
|
||||
const loader = overrides.loader ?? createLoader();
|
||||
const manifest = createDevelopmentManifest(settings);
|
||||
|
||||
|
@ -28,31 +27,31 @@ async function createDevPipeline(overrides = {}) {
|
|||
describe('vite-plugin-astro-server', () => {
|
||||
describe('request', () => {
|
||||
it('renders a request', async () => {
|
||||
const pipeline = await createDevPipeline({
|
||||
loader: createLoader({
|
||||
import(id) {
|
||||
if (id === '\0astro-internal:middleware') {
|
||||
return { onRequest: (_, next) => next() };
|
||||
}
|
||||
const Page = createComponent(() => {
|
||||
return render`<div id="test">testing</div>`;
|
||||
});
|
||||
return createAstroModule(Page);
|
||||
},
|
||||
}),
|
||||
const fixture = await createFixture({
|
||||
// Note that the content doesn't matter here because we are using a custom loader.
|
||||
'/src/pages/index.astro': '',
|
||||
});
|
||||
const pipeline = await createDevPipeline(
|
||||
{
|
||||
loader: createLoader({
|
||||
import(id) {
|
||||
if (id === '\0astro-internal:middleware') {
|
||||
return { onRequest: (_, next) => next() };
|
||||
}
|
||||
const Page = createComponent(() => {
|
||||
return render`<div id="test">testing</div>`;
|
||||
});
|
||||
return createAstroModule(Page);
|
||||
},
|
||||
}),
|
||||
},
|
||||
fixture.path,
|
||||
);
|
||||
const controller = createController({ loader: pipeline.loader });
|
||||
const { req, res, text } = createRequestAndResponse();
|
||||
const fs = createFs(
|
||||
{
|
||||
// Note that the content doesn't matter here because we are using a custom loader.
|
||||
'/src/pages/index.astro': '',
|
||||
},
|
||||
'/',
|
||||
);
|
||||
const manifestData = createRouteManifest(
|
||||
{
|
||||
fsMod: fs,
|
||||
cwd: fixture.path,
|
||||
settings: pipeline.settings,
|
||||
},
|
||||
defaultLogger,
|
||||
|
@ -82,7 +81,6 @@ describe('vite-plugin-astro-server', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/url.astro': `{Astro.request.url}`,
|
||||
'/src/pages/prerendered.astro': `---
|
||||
|
@ -90,14 +88,13 @@ describe('vite-plugin-astro-server', () => {
|
|||
---
|
||||
{Astro.request.url}`,
|
||||
};
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createFixture,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/index.js': `export const GET = () => {
|
||||
const headers = new Headers();
|
||||
|
@ -51,14 +49,13 @@ describe('endpoints', () => {
|
|||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
const fixture = await createFixture(fileSystem);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
root: fixture.path,
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
|
|
24
patches/fs-fixture@2.4.0.patch
Normal file
24
patches/fs-fixture@2.4.0.patch
Normal file
|
@ -0,0 +1,24 @@
|
|||
diff --git a/dist/index.d.mts b/dist/index.d.mts
|
||||
index be5b88e034211892ba079c3c5c5c6f5d5f767cd4..55dcc0e99c66719d5fa68d4713b02c1919deae19 100644
|
||||
--- a/dist/index.d.mts
|
||||
+++ b/dist/index.d.mts
|
||||
@@ -61,6 +61,10 @@ type Api = ApiBase & {
|
||||
type FileTree = {
|
||||
[path: string]: string | FileTree | ((api: Api) => string | Symlink);
|
||||
};
|
||||
-declare const createFixture: (source?: string | FileTree) => Promise<FsFixture>;
|
||||
+type CreateFixtureOptions = {
|
||||
+ // An absolute path to a different directory than `os.tmpdir()`
|
||||
+ tempDir?: string
|
||||
+}
|
||||
+declare const createFixture: (source?: string | FileTree, opts?: CreateFixtureOptions) => Promise<FsFixture>;
|
||||
|
||||
-export { type FileTree, FsFixture, createFixture };
|
||||
+export { type FileTree, FsFixture, CreateFixtureOptions, createFixture };
|
||||
diff --git a/dist/index.mjs b/dist/index.mjs
|
||||
index cd6cab3beebf3f38fe4f1e2a9c58aff2b87258f7..ad24d852a357fd582f9e83ac20cb73bfbcb9bfc0 100755
|
||||
--- a/dist/index.mjs
|
||||
+++ b/dist/index.mjs
|
||||
@@ -1 +1 @@
|
||||
-import s from"fs/promises";import o from"path";import y from"fs";import m from"os";typeof Symbol.asyncDispose!="symbol"&&Object.defineProperty(Symbol,"asyncDispose",{configurable:!1,enumerable:!1,writable:!1,value:Symbol.for("asyncDispose")});class w{path;constructor(t){this.path=t}getPath(...t){return o.join(this.path,...t)}exists(t=""){return s.access(this.getPath(t)).then(()=>!0,()=>!1)}rm(t=""){return s.rm(this.getPath(t),{recursive:!0,force:!0})}writeFile(t,r){return s.writeFile(this.getPath(t),r)}writeJson(t,r){return this.writeFile(t,JSON.stringify(r,null,2))}readFile(t,r){return s.readFile(this.getPath(t),r)}async[Symbol.asyncDispose](){await this.rm()}}const g=y.realpathSync(m.tmpdir()),b=`fs-fixture-${Date.now()}`;let l=0;const P=()=>(l+=1,l);class h{target;type;path;constructor(t,r){this.target=t,this.type=r}}const u=(i,t,r)=>{const e=[];for(const n in i){if(!Object.hasOwn(i,n))continue;const c=o.join(t,n);let a=i[n];if(typeof a=="function"){const f=Object.assign(Object.create(r),{filePath:c}),p=a(f);if(p instanceof h){p.path=c,e.push(p);continue}else a=p}typeof a=="string"?e.push({path:c,content:a}):e.push(...u(a,c,r))}return e},d=async i=>{const t=o.join(g,`${b}-${P()}/`);if(await s.mkdir(t,{recursive:!0}),i){if(typeof i=="string")await s.cp(i,t,{recursive:!0});else if(typeof i=="object"){const r={fixturePath:t,getPath:(...e)=>o.join(t,...e),symlink:(e,n)=>new h(e,n)};await Promise.all(u(i,t,r).map(async e=>{await s.mkdir(o.dirname(e.path),{recursive:!0}),e instanceof h?await s.symlink(e.target,e.path,e.type):await s.writeFile(e.path,e.content)}))}}return new w(t)};export{d as createFixture};
|
||||
+import s from"fs/promises";import o from"path";import y from"fs";import m from"os";typeof Symbol.asyncDispose!="symbol"&&Object.defineProperty(Symbol,"asyncDispose",{configurable:!1,enumerable:!1,writable:!1,value:Symbol.for("asyncDispose")});class w{path;constructor(t){this.path=t}getPath(...t){return o.join(this.path,...t)}exists(t=""){return s.access(this.getPath(t)).then(()=>!0,()=>!1)}rm(t=""){return s.rm(this.getPath(t),{recursive:!0,force:!0})}writeFile(t,r){return s.writeFile(this.getPath(t),r)}writeJson(t,r){return this.writeFile(t,JSON.stringify(r,null,2))}readFile(t,r){return s.readFile(this.getPath(t),r)}async[Symbol.asyncDispose](){await this.rm()}}const g=y.realpathSync(m.tmpdir()),b=`fs-fixture-${Date.now()}`;let l=0;const P=()=>(l+=1,l);class h{target;type;path;constructor(t,r){this.target=t,this.type=r}}const u=(i,t,r)=>{const e=[];for(const n in i){if(!Object.hasOwn(i,n))continue;const c=o.join(t,n);let a=i[n];if(typeof a=="function"){const f=Object.assign(Object.create(r),{filePath:c}),p=a(f);if(p instanceof h){p.path=c,e.push(p);continue}else a=p}typeof a=="string"?e.push({path:c,content:a}):e.push(...u(a,c,r))}return e},d=async (i, opts)=>{const t=o.join(opts?.tempDir ?? g,`${b}-${P()}/`);if(await s.mkdir(t,{recursive:!0}),i){if(typeof i=="string")await s.cp(i,t,{recursive:!0});else if(typeof i=="object"){const r={fixturePath:t,getPath:(...e)=>o.join(t,...e),symlink:(e,n)=>new h(e,n)};await Promise.all(u(i,t,r).map(async e=>{await s.mkdir(o.dirname(e.path),{recursive:!0}),e instanceof h?await s.symlink(e.target,e.path,e.type):await s.writeFile(e.path,e.content)}))}}return new w(t)};export{d as createFixture};
|
103
pnpm-lock.yaml
103
pnpm-lock.yaml
|
@ -4,6 +4,11 @@ settings:
|
|||
autoInstallPeers: false
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
fs-fixture@2.4.0:
|
||||
hash: hvkuaks2ic76pdflr3iifgi4ku
|
||||
path: patches/fs-fixture@2.4.0.patch
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
|
@ -703,15 +708,15 @@ importers:
|
|||
expect-type:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
fs-fixture:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0(patch_hash=hvkuaks2ic76pdflr3iifgi4ku)
|
||||
mdast-util-mdx:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
mdast-util-mdx-jsx:
|
||||
specifier: ^3.1.3
|
||||
version: 3.1.3
|
||||
memfs:
|
||||
specifier: ^4.14.0
|
||||
version: 4.14.0
|
||||
node-mocks-http:
|
||||
specifier: ^1.16.1
|
||||
version: 1.16.1(@types/node@18.19.50)
|
||||
|
@ -2665,12 +2670,6 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/content-mixed-errors:
|
||||
dependencies:
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/content-ssr-integration:
|
||||
dependencies:
|
||||
'@astrojs/mdx':
|
||||
|
@ -4172,6 +4171,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/units/_temp-fixtures:
|
||||
dependencies:
|
||||
'@astrojs/mdx':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../integrations/mdx
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/create-astro:
|
||||
dependencies:
|
||||
'@astrojs/cli-kit':
|
||||
|
@ -6528,24 +6536,6 @@ packages:
|
|||
resolution: {integrity: sha512-n5JEf16Wr4mdkRMZ8wMP/wN9/sHmTjRPbouXjJH371mZ2LEGDl72t8tEsMRNFerQN/QJtivOxqK1frdGa4QK5Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@jsonjoy.com/base64@1.1.2':
|
||||
resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==}
|
||||
engines: {node: '>=10.0'}
|
||||
peerDependencies:
|
||||
tslib: '2'
|
||||
|
||||
'@jsonjoy.com/json-pack@1.1.0':
|
||||
resolution: {integrity: sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==}
|
||||
engines: {node: '>=10.0'}
|
||||
peerDependencies:
|
||||
tslib: '2'
|
||||
|
||||
'@jsonjoy.com/util@1.3.0':
|
||||
resolution: {integrity: sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==}
|
||||
engines: {node: '>=10.0'}
|
||||
peerDependencies:
|
||||
tslib: '2'
|
||||
|
||||
'@libsql/client@0.14.0':
|
||||
resolution: {integrity: sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==}
|
||||
|
||||
|
@ -8274,6 +8264,10 @@ packages:
|
|||
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
|
||||
engines: {node: '>=6 <7 || >=8'}
|
||||
|
||||
fs-fixture@2.4.0:
|
||||
resolution: {integrity: sha512-aFoTWGj288IEOdXBeesdcbdMvRtExbqpOp1SCjE3nRdlT7vBBCD6bf76C9FCq8/6pIPSo56P7+HeT9zT/n8rMA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
fsevents@2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
|
@ -8475,10 +8469,6 @@ packages:
|
|||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
||||
hyperdyperid@1.2.0:
|
||||
resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==}
|
||||
engines: {node: '>=10.18'}
|
||||
|
||||
hyperid@3.3.0:
|
||||
resolution: {integrity: sha512-7qhCVT4MJIoEsNcbhglhdmBKb09QtcmJNiIQGq7js/Khf5FtQQ9bzcAuloeqBeee7XD7JqDeve9KNlQya5tSGQ==}
|
||||
|
||||
|
@ -8924,10 +8914,6 @@ packages:
|
|||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
memfs@4.14.0:
|
||||
resolution: {integrity: sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==}
|
||||
engines: {node: '>= 4.0.0'}
|
||||
|
||||
merge-anything@5.1.7:
|
||||
resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==}
|
||||
engines: {node: '>=12.13'}
|
||||
|
@ -10243,12 +10229,6 @@ packages:
|
|||
thenify@3.3.1:
|
||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||
|
||||
thingies@1.21.0:
|
||||
resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==}
|
||||
engines: {node: '>=10.18'}
|
||||
peerDependencies:
|
||||
tslib: ^2
|
||||
|
||||
timestring@6.0.0:
|
||||
resolution: {integrity: sha512-wMctrWD2HZZLuIlchlkE2dfXJh7J2KDI9Dwl+2abPYg0mswQHfOAyQW3jJg1pY5VfttSINZuKcXoB3FGypVklA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -10302,12 +10282,6 @@ packages:
|
|||
resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tree-dump@1.0.2:
|
||||
resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==}
|
||||
engines: {node: '>=10.0'}
|
||||
peerDependencies:
|
||||
tslib: '2'
|
||||
|
||||
trim-lines@3.0.1:
|
||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
||||
|
||||
|
@ -11997,22 +11971,6 @@ snapshots:
|
|||
|
||||
'@jsdevtools/rehype-toc@3.0.2': {}
|
||||
|
||||
'@jsonjoy.com/base64@1.1.2(tslib@2.7.0)':
|
||||
dependencies:
|
||||
tslib: 2.7.0
|
||||
|
||||
'@jsonjoy.com/json-pack@1.1.0(tslib@2.7.0)':
|
||||
dependencies:
|
||||
'@jsonjoy.com/base64': 1.1.2(tslib@2.7.0)
|
||||
'@jsonjoy.com/util': 1.3.0(tslib@2.7.0)
|
||||
hyperdyperid: 1.2.0
|
||||
thingies: 1.21.0(tslib@2.7.0)
|
||||
tslib: 2.7.0
|
||||
|
||||
'@jsonjoy.com/util@1.3.0(tslib@2.7.0)':
|
||||
dependencies:
|
||||
tslib: 2.7.0
|
||||
|
||||
'@libsql/client@0.14.0':
|
||||
dependencies:
|
||||
'@libsql/core': 0.14.0
|
||||
|
@ -13833,6 +13791,8 @@ snapshots:
|
|||
jsonfile: 4.0.0
|
||||
universalify: 0.1.2
|
||||
|
||||
fs-fixture@2.4.0(patch_hash=hvkuaks2ic76pdflr3iifgi4ku): {}
|
||||
|
||||
fsevents@2.3.2:
|
||||
optional: true
|
||||
|
||||
|
@ -14145,8 +14105,6 @@ snapshots:
|
|||
|
||||
human-signals@5.0.0: {}
|
||||
|
||||
hyperdyperid@1.2.0: {}
|
||||
|
||||
hyperid@3.3.0:
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
|
@ -14709,13 +14667,6 @@ snapshots:
|
|||
|
||||
media-typer@0.3.0: {}
|
||||
|
||||
memfs@4.14.0:
|
||||
dependencies:
|
||||
'@jsonjoy.com/json-pack': 1.1.0(tslib@2.7.0)
|
||||
'@jsonjoy.com/util': 1.3.0(tslib@2.7.0)
|
||||
tree-dump: 1.0.2(tslib@2.7.0)
|
||||
tslib: 2.7.0
|
||||
|
||||
merge-anything@5.1.7:
|
||||
dependencies:
|
||||
is-what: 4.1.16
|
||||
|
@ -16344,10 +16295,6 @@ snapshots:
|
|||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
|
||||
thingies@1.21.0(tslib@2.7.0):
|
||||
dependencies:
|
||||
tslib: 2.7.0
|
||||
|
||||
timestring@6.0.0: {}
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
|
@ -16387,10 +16334,6 @@ snapshots:
|
|||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
tree-dump@1.0.2(tslib@2.7.0):
|
||||
dependencies:
|
||||
tslib: 2.7.0
|
||||
|
||||
trim-lines@3.0.1: {}
|
||||
|
||||
trough@2.2.0: {}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
packages:
|
||||
- 'packages/**/*'
|
||||
- 'packages/astro/test/units/_temp-fixtures'
|
||||
- 'examples/**/*'
|
||||
- 'smoke/**/*'
|
||||
- 'scripts'
|
||||
- 'benchmark'
|
||||
- 'benchmark/packages/*'
|
||||
# Below excludes are only for Turbo because it doesn't respect gitignore like pnpm does
|
||||
- '!packages/astro/test/units/_temp-fixtures/*'
|
||||
- '!**/.vercel/**'
|
||||
|
|
|
@ -25,6 +25,8 @@ export default async function test() {
|
|||
timeout: { type: 'string', alias: 't' },
|
||||
// Test setup file
|
||||
setup: { type: 'string', alias: 's' },
|
||||
// Test teardown file
|
||||
teardown: { type: 'string' },
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -59,6 +61,10 @@ export default async function test() {
|
|||
files.push(tempTestFile);
|
||||
}
|
||||
|
||||
const teardownModule = args.values.teardown
|
||||
? await import(pathToFileURL(path.resolve(args.values.teardown)).toString())
|
||||
: undefined;
|
||||
|
||||
// https://nodejs.org/api/test.html#runoptions
|
||||
run({
|
||||
files,
|
||||
|
@ -74,6 +80,10 @@ export default async function test() {
|
|||
// so we set it here manually
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.on('end', () => {
|
||||
const testPassed = process.exitCode === 0 || process.exitCode === undefined;
|
||||
teardownModule?.default(testPassed);
|
||||
})
|
||||
.pipe(new spec())
|
||||
.pipe(process.stdout);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue