From c37b40558a50ad6afd477439c588a3bb8ad3f83e Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 05:25:15 +0800 Subject: [PATCH 1/8] chore: use `import.meta.dirname` --- documentation/docs/30-add-ons/99-community.md | 4 ++-- packages/sv-utils/src/tests/css/index.ts | 5 ++--- packages/sv-utils/src/tests/html/index.ts | 5 ++--- packages/sv-utils/src/tests/js/index.ts | 5 ++--- packages/sv-utils/src/tests/svelte/svelte/index.ts | 5 ++--- packages/sv/src/addons/tests/drizzle/test.ts | 3 +-- .../cli/tests/snapshots/@my-org/sv/tests/setup/global.js | 4 ++-- packages/sv/src/core/fetch-packages.ts | 3 +-- packages/sv/src/create/scripts/build-templates.js | 3 +-- .../sv/src/create/templates/addon/tests/setup/global.js | 4 ++-- packages/sv/src/create/utils.ts | 7 ++----- packages/sv/src/migrate/migrations/tests.spec.ts | 5 ++--- scripts/generate-api-surface.js | 5 ++--- 13 files changed, 23 insertions(+), 35 deletions(-) diff --git a/documentation/docs/30-add-ons/99-community.md b/documentation/docs/30-add-ons/99-community.md index 4aa233141..a1f51fbe7 100644 --- a/documentation/docs/30-add-ons/99-community.md +++ b/documentation/docs/30-add-ons/99-community.md @@ -134,10 +134,10 @@ export default defineConfig({ And the global test setup script `tests/setup/global.js`: ```js -import { fileURLToPath } from 'node:url'; +import path from 'node:path'; import { setupGlobal } from 'sv/testing'; -const TEST_DIR = fileURLToPath(new URL('../../.test-output/', import.meta.url)); +const TEST_DIR = path.resolve(import.meta.dirname, '..', '..', '.test-output'); export default setupGlobal({ TEST_DIR }); ``` diff --git a/packages/sv-utils/src/tests/css/index.ts b/packages/sv-utils/src/tests/css/index.ts index 4a9032f55..b42f215ff 100644 --- a/packages/sv-utils/src/tests/css/index.ts +++ b/packages/sv-utils/src/tests/css/index.ts @@ -1,12 +1,11 @@ import fs from 'node:fs'; -import { join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; import { format } from 'oxfmt'; import { describe, expect, test } from 'vitest'; import oxfmtConfig from '../../../../../oxfmt.config.ts'; import { parseCss, serializeCss } from '../../tooling/index.ts'; -const baseDir = resolve(fileURLToPath(import.meta.url), '..'); +const baseDir = import.meta.dirname; const categoryDirectories = getDirectoryNames(baseDir); for (const categoryDirectory of categoryDirectories) { diff --git a/packages/sv-utils/src/tests/html/index.ts b/packages/sv-utils/src/tests/html/index.ts index cf94e27f8..8fb0b5646 100644 --- a/packages/sv-utils/src/tests/html/index.ts +++ b/packages/sv-utils/src/tests/html/index.ts @@ -1,12 +1,11 @@ import fs from 'node:fs'; -import { join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; import { format } from 'oxfmt'; import { describe, expect, test } from 'vitest'; import oxfmtConfig from '../../../../../oxfmt.config.ts'; import { parseHtml, serializeHtml } from '../../tooling/index.ts'; -const baseDir = resolve(fileURLToPath(import.meta.url), '..'); +const baseDir = import.meta.dirname; const categoryDirectories = getDirectoryNames(baseDir); for (const categoryDirectory of categoryDirectories) { diff --git a/packages/sv-utils/src/tests/js/index.ts b/packages/sv-utils/src/tests/js/index.ts index 191aaeac7..02c437e2d 100644 --- a/packages/sv-utils/src/tests/js/index.ts +++ b/packages/sv-utils/src/tests/js/index.ts @@ -1,10 +1,9 @@ import fs from 'node:fs'; -import { join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; import { describe, expect, test } from 'vitest'; import { parseScript, serializeScript } from '../../tooling/index.ts'; -const baseDir = resolve(fileURLToPath(import.meta.url), '..'); +const baseDir = import.meta.dirname; const categoryDirectories = getDirectoryNames(baseDir); for (const categoryDirectory of categoryDirectories) { diff --git a/packages/sv-utils/src/tests/svelte/svelte/index.ts b/packages/sv-utils/src/tests/svelte/svelte/index.ts index b207b6f43..933c7b0c5 100644 --- a/packages/sv-utils/src/tests/svelte/svelte/index.ts +++ b/packages/sv-utils/src/tests/svelte/svelte/index.ts @@ -1,10 +1,9 @@ import fs from 'node:fs'; -import { join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; import { describe, expect, test } from 'vitest'; import { parseSvelte, serializeSvelte } from '../../../../src/tooling/index.ts'; -const baseDir = resolve(fileURLToPath(import.meta.url), '..'); +const baseDir = import.meta.dirname; const categoryDirectories = getDirectoryNames(baseDir); for (const categoryDirectory of categoryDirectories) { diff --git a/packages/sv/src/addons/tests/drizzle/test.ts b/packages/sv/src/addons/tests/drizzle/test.ts index 911fc0226..e794e3759 100644 --- a/packages/sv/src/addons/tests/drizzle/test.ts +++ b/packages/sv/src/addons/tests/drizzle/test.ts @@ -1,7 +1,6 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; -import { fileURLToPath } from 'node:url'; import { execSync } from 'tinyexec'; import { beforeAll, expect } from 'vitest'; import drizzle from '../../drizzle.ts'; @@ -39,7 +38,7 @@ const { test, testCases, prepareServer } = setupTest( beforeAll(() => { if (!MUST_HAVE_DOCKER) return; - const cwd = path.dirname(fileURLToPath(import.meta.url)); + const cwd = import.meta.dirname; try { execSync('docker', ['--version'], { nodeOptions: { cwd }, throwOnError: true }); diff --git a/packages/sv/src/cli/tests/snapshots/@my-org/sv/tests/setup/global.js b/packages/sv/src/cli/tests/snapshots/@my-org/sv/tests/setup/global.js index 1f9a11ce1..e8100be3f 100644 --- a/packages/sv/src/cli/tests/snapshots/@my-org/sv/tests/setup/global.js +++ b/packages/sv/src/cli/tests/snapshots/@my-org/sv/tests/setup/global.js @@ -1,7 +1,7 @@ -import { fileURLToPath } from 'node:url'; +import path from 'node:path'; import { setupGlobal } from 'sv/testing'; -const TEST_DIR = fileURLToPath(new URL('../../.test-output/', import.meta.url)); +const TEST_DIR = path.resolve(import.meta.dirname, '..', '..', '.test-output'); export default setupGlobal({ TEST_DIR, diff --git a/packages/sv/src/core/fetch-packages.ts b/packages/sv/src/core/fetch-packages.ts index 013f4cd5f..24d0fc8c8 100644 --- a/packages/sv/src/core/fetch-packages.ts +++ b/packages/sv/src/core/fetch-packages.ts @@ -2,7 +2,6 @@ import fs from 'node:fs'; import { platform } from 'node:os'; import path from 'node:path'; import { pipeline } from 'node:stream/promises'; -import { fileURLToPath } from 'node:url'; import { createGunzip } from 'node:zlib'; import { color, coerceVersion, downloadJson, dedent } from '@sveltejs/sv-utils'; import { unpackTar } from 'modern-tar/fs'; @@ -11,7 +10,7 @@ import * as common from './common.ts'; import type { AddonDefinition, AddonReference } from './config.ts'; // path to the `node_modules` directory of `sv` -const NODE_MODULES = fileURLToPath(new URL('../../node_modules', import.meta.url)); +const NODE_MODULES = path.resolve(import.meta.dirname, '..', '..', 'node_modules'); function verifyPackage(addonPkg: Record, specifier: string): string | undefined { const peerDeps = { ...addonPkg.peerDependencies }; diff --git a/packages/sv/src/create/scripts/build-templates.js b/packages/sv/src/create/scripts/build-templates.js index 3ff6dd22b..d52ef5253 100644 --- a/packages/sv/src/create/scripts/build-templates.js +++ b/packages/sv/src/create/scripts/build-templates.js @@ -2,7 +2,6 @@ import fs from 'node:fs'; import { createRequire } from 'node:module'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import parser from 'gitignore-parser'; import { format } from 'oxfmt'; import { transform } from 'sucrase'; @@ -11,7 +10,7 @@ import oxfmtConfig from '../../../../../oxfmt.config.ts'; /** @import { File, LanguageType } from '../index.ts' */ -const pkgRoot = path.resolve(fileURLToPath(import.meta.url), '..', '..'); +const pkgRoot = path.resolve(import.meta.dirname, '..'); const require = createRequire(import.meta.url); const createVitePath = path.dirname(require.resolve('create-vite/package.json')); diff --git a/packages/sv/src/create/templates/addon/tests/setup/global.js b/packages/sv/src/create/templates/addon/tests/setup/global.js index 1f9a11ce1..e8100be3f 100644 --- a/packages/sv/src/create/templates/addon/tests/setup/global.js +++ b/packages/sv/src/create/templates/addon/tests/setup/global.js @@ -1,7 +1,7 @@ -import { fileURLToPath } from 'node:url'; +import path from 'node:path'; import { setupGlobal } from 'sv/testing'; -const TEST_DIR = fileURLToPath(new URL('../../.test-output/', import.meta.url)); +const TEST_DIR = path.resolve(import.meta.dirname, '..', '..', '.test-output'); export default setupGlobal({ TEST_DIR, diff --git a/packages/sv/src/create/utils.ts b/packages/sv/src/create/utils.ts index b666d86dd..78a5ab546 100644 --- a/packages/sv/src/create/utils.ts +++ b/packages/sv/src/create/utils.ts @@ -1,6 +1,5 @@ import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import type { Common } from './index.ts'; export function mkdirp(dir: string): void { @@ -58,14 +57,12 @@ export function copy( } } -export function dist(path: string): string { +export function dist(currentPath: string): string { // we need to make this check, because vitest is making the package root the cwd, // but executing the cli from the command line already makes the dist folder the cwd. const insideDistFolder = import.meta.url.includes('dist'); - return fileURLToPath( - new URL(`./${!insideDistFolder ? 'dist/' : ''}${path}`, import.meta.url).href - ); + return path.resolve(import.meta.dirname, insideDistFolder ? '' : 'dist', currentPath); } export function getSharedFiles(): Common['files'] { diff --git a/packages/sv/src/migrate/migrations/tests.spec.ts b/packages/sv/src/migrate/migrations/tests.spec.ts index b5bbca775..eb0ae9efb 100644 --- a/packages/sv/src/migrate/migrations/tests.spec.ts +++ b/packages/sv/src/migrate/migrations/tests.spec.ts @@ -1,11 +1,10 @@ import fs from 'node:fs'; -import path, { resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import path from 'node:path'; import { describe, expect, test } from 'vitest'; import { prepareSvApi } from '../../core/engine.ts'; import { createWorkspace } from '../../core/workspace.ts'; -const baseDir = resolve(fileURLToPath(import.meta.url), '..'); +const baseDir = import.meta.dirname; const migrationDirectories = getDirectoryNames(baseDir); const tasksDirectoryName = 'tasks'; const testsDirectoryName = 'tests'; diff --git a/scripts/generate-api-surface.js b/scripts/generate-api-surface.js index da4c7934e..2c2c503e1 100644 --- a/scripts/generate-api-surface.js +++ b/scripts/generate-api-surface.js @@ -12,11 +12,10 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; -import { fileURLToPath } from 'node:url'; import { format } from 'oxfmt'; import oxfmtConfig from '../oxfmt.config.ts'; -const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url))); +const ROOT = path.resolve(import.meta.dirname, '..'); const packages = [ { @@ -225,7 +224,7 @@ export async function generateApiSurface() { return generated; } -const isMain = process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]); +const isMain = process.argv[1] && import.meta.filename === path.resolve(process.argv[1]); if (isMain) { generateApiSurface().catch((err) => { From adb435791de2961d182a0ea5a41103a571c54b68 Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 06:15:13 +0800 Subject: [PATCH 2/8] test: use shared `.test-output` dir under `packages/sv` --- packages/sv/src/create/tests/check.ts | 5 ++--- packages/sv/src/create/tests/playground.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/sv/src/create/tests/check.ts b/packages/sv/src/create/tests/check.ts index 5f428a430..9a0ebe355 100644 --- a/packages/sv/src/create/tests/check.ts +++ b/packages/sv/src/create/tests/check.ts @@ -3,15 +3,14 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { exec, type Result } from 'tinyexec'; import { beforeAll, describe, expect, test } from 'vitest'; -import { add, officialAddons } from '../../../../sv/src/index.ts'; import { createProject } from '../../cli/create.ts'; +import { add, officialAddons } from '../../index.ts'; import { type LanguageType, type TemplateType, create } from '../index.ts'; // Resolve the given path relative to the current file const resolve_path = (path: string) => fileURLToPath(new URL(path, import.meta.url)); -// use a directory outside of packages to ensure it isn't added to the pnpm workspace -const test_workspace_dir = resolve_path('../../../../../.test-output/create/'); +const test_workspace_dir = resolve_path('../../../.test-output/create/'); // prepare test pnpm workspace fs.rmSync(test_workspace_dir, { recursive: true, force: true }); diff --git a/packages/sv/src/create/tests/playground.ts b/packages/sv/src/create/tests/playground.ts index 039dccc45..361bbc37f 100644 --- a/packages/sv/src/create/tests/playground.ts +++ b/packages/sv/src/create/tests/playground.ts @@ -12,7 +12,7 @@ import { } from '../playground.ts'; const resolvePath = (path: string) => fileURLToPath(new URL(path, import.meta.url)); -const testWorkspaceDir = resolvePath('../../../.test-output/create/'); +const testWorkspaceDir = resolvePath('../../../.test-output/playground/'); test.for([ { input: 'https://svelte.dev/playground/628f435d787a465f9c1f1854134d6f70/', valid: true }, From 829f9b43a02d5383691799b9e2c92fd0e952fc54 Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 06:15:16 +0800 Subject: [PATCH 3/8] test: clarify playground e2e test names and dirs --- packages/sv/src/create/tests/playground.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sv/src/create/tests/playground.ts b/packages/sv/src/create/tests/playground.ts index 361bbc37f..1ef0520ea 100644 --- a/packages/sv/src/create/tests/playground.ts +++ b/packages/sv/src/create/tests/playground.ts @@ -147,15 +147,15 @@ test('detect dependencies from playground files', () => { expect(Array.from(dependencies.keys()).length).toBe(3); }); -test('real world download and convert playground async', async () => { - const directory = path.join(testWorkspaceDir, 'real-world-playground'); +test('download and convert playground e2e (svelte async)', async () => { + const directory = path.join(testWorkspaceDir, 'playground-e2e-svelte-async'); if (fs.existsSync(directory)) { fs.rmSync(directory, { recursive: true }); } create({ cwd: directory, - name: 'real-world-playground', + name: 'playground-e2e-svelte-async', template: 'minimal', types: 'typescript' }); @@ -199,15 +199,15 @@ test('real world download and convert playground async', async () => { expect(viteConfigContent).toContain('experimental: { async: true }'); }); -test('real world download and convert playground without async', async () => { - const directory = path.join(testWorkspaceDir, 'real-world-playground-old'); +test('download and convert playground e2e (pre svelte async)', async () => { + const directory = path.join(testWorkspaceDir, 'playground-e2e-pre-svelte-async'); if (fs.existsSync(directory)) { fs.rmSync(directory, { recursive: true }); } create({ cwd: directory, - name: 'real-world-playground-old', + name: 'playground-e2e-pre-svelte-async', template: 'minimal', types: 'typescript' }); From bd8e8127ebaec623e56ea311e64399271b37ed9d Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 05:56:42 +0800 Subject: [PATCH 4/8] test: straighten out variable names --- packages/sv/src/cli/tests/cli.ts | 40 +++++++++++----------- packages/sv/src/create/tests/check.ts | 18 +++++----- packages/sv/src/create/tests/playground.ts | 6 ++-- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/sv/src/cli/tests/cli.ts b/packages/sv/src/cli/tests/cli.ts index 80d7b2316..e1930e8a0 100644 --- a/packages/sv/src/cli/tests/cli.ts +++ b/packages/sv/src/cli/tests/cli.ts @@ -8,13 +8,13 @@ import { beforeAll, describe, expect, it } from 'vitest'; /** Matches `sv@1.2.3`, `sv@0.0.0-next.0`, `sv@1.0.0-rc.1+build.5`. */ const SV_VERSION_REGEX = /sv@\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?/g; -const monoRepoPath = path.resolve(__dirname, '..', '..', '..', '..', '..'); -const svBinPath = path.resolve(monoRepoPath, 'packages', 'sv', 'dist', 'bin.mjs'); -const testOutputCliPath = path.resolve(monoRepoPath, 'packages', 'sv', '.test-output', 'cli'); +const ROOT = path.resolve(__dirname, '..', '..', '..', '..', '..'); +const SV_BIN_PATH = path.resolve(ROOT, 'packages', 'sv', 'dist', 'bin.mjs'); +const TEST_DIR = path.resolve(ROOT, 'packages', 'sv', '.test-output', 'cli'); beforeAll(() => { - if (fs.existsSync(testOutputCliPath)) { - fs.rmSync(testOutputCliPath, { force: true, recursive: true }); + if (fs.existsSync(TEST_DIR)) { + fs.rmSync(TEST_DIR, { force: true, recursive: true }); } }); @@ -72,15 +72,15 @@ describe('cli', () => { snapshot?: boolean; }; - const testOutputPath = path.relative( - monoRepoPath, - path.resolve(testOutputCliPath, projectName) + const projectPath = path.relative( + ROOT, + path.resolve(TEST_DIR, projectName) ); const allArgs = [ - svBinPath, + SV_BIN_PATH, 'create', - testOutputPath, + projectPath, '--template', template, ...(template === 'addon' ? [] : ['--types', 'ts']), @@ -89,12 +89,12 @@ describe('cli', () => { ]; /** - * Same as `exec`. but `cwd` defaults to `testOutputPath` + * Same as `exec`. but `cwd` defaults to `projectPath` */ const run = (...params: Parameters) => { const [command, args, options = {}] = params; options.nodeOptions ??= {}; - options.nodeOptions.cwd ??= testOutputPath; + options.nodeOptions.cwd ??= projectPath; return exec(command, args, options); }; @@ -108,15 +108,15 @@ describe('cli', () => { `Error with cli:\n cmd: node ${allArgs.join(' ')}\n stdout: ${result.stdout}\n stderr: ${result.stderr}` ).toBe(0); // test output path exists - expect(fs.existsSync(testOutputPath)).toBe(true); + expect(fs.existsSync(projectPath)).toBe(true); // package.json has a name - const packageJsonPath = path.resolve(testOutputPath, 'package.json'); + const packageJsonPath = path.resolve(projectPath, 'package.json'); const { data: packageJson } = parse.json(fs.readFileSync(packageJsonPath, 'utf-8')); expect(packageJson.name).toBe(projectName); const snapPath = path.resolve( - monoRepoPath, + ROOT, 'packages', 'sv', 'src', @@ -126,7 +126,7 @@ describe('cli', () => { projectName ); const relativeFiles = snapshot - ? (fs.readdirSync(testOutputPath, { recursive: true }) as string[]) + ? (fs.readdirSync(projectPath, { recursive: true }) as string[]) : []; // Files from ai-tools repo (skills, agents) change independently - @@ -135,7 +135,7 @@ describe('cli', () => { const aiToolsPattern = /[\\/](skills|agents)[\\/]/; for (const relativeFile of relativeFiles) { - if (!fs.statSync(path.resolve(testOutputPath, relativeFile)).isFile()) continue; + if (!fs.statSync(path.resolve(projectPath, relativeFile)).isFile()) continue; if (['.svg', '.env'].some((ext) => relativeFile.endsWith(ext))) continue; const normalized = relativeFile.replace(/\\/g, '/'); @@ -151,7 +151,7 @@ describe('cli', () => { continue; } - let generated = fs.readFileSync(path.resolve(testOutputPath, relativeFile), 'utf-8'); + let generated = fs.readFileSync(path.resolve(projectPath, relativeFile), 'utf-8'); if (relativeFile === 'package.json') { const { data: generatedPackageJson } = parse.json(generated); // remove @types/node from generated package.json as we test on different node versions @@ -220,7 +220,7 @@ describe('cli', () => { } if (projectName === 'create-experimental') { - const read = (p: string) => fs.readFileSync(path.resolve(testOutputPath, p), 'utf-8'); + const read = (p: string) => fs.readFileSync(path.resolve(projectPath, p), 'utf-8'); const envFile = read('src/env.ts'); expect(envFile).toContain('defineEnvVars'); expect(envFile).toContain('DATABASE_URL'); @@ -231,7 +231,7 @@ describe('cli', () => { if (template === 'addon') { // replace sv and sv-utils versions in package.json for tests - const packageJsonPath = path.resolve(testOutputPath, 'package.json'); + const packageJsonPath = path.resolve(projectPath, 'package.json'); const { data: packageJson } = parse.json(fs.readFileSync(packageJsonPath, 'utf-8')); packageJson.peerDependencies['sv'] = 'file:../../../..'; packageJson.devDependencies['sv'] = 'file:../../../..'; diff --git a/packages/sv/src/create/tests/check.ts b/packages/sv/src/create/tests/check.ts index 9a0ebe355..8bdca0719 100644 --- a/packages/sv/src/create/tests/check.ts +++ b/packages/sv/src/create/tests/check.ts @@ -8,23 +8,23 @@ import { add, officialAddons } from '../../index.ts'; import { type LanguageType, type TemplateType, create } from '../index.ts'; // Resolve the given path relative to the current file -const resolve_path = (path: string) => fileURLToPath(new URL(path, import.meta.url)); +const resolvePath = (path: string) => fileURLToPath(new URL(path, import.meta.url)); -const test_workspace_dir = resolve_path('../../../.test-output/create/'); +const TEST_DIR = resolvePath('../../../.test-output/create/'); // prepare test pnpm workspace -fs.rmSync(test_workspace_dir, { recursive: true, force: true }); -fs.mkdirSync(test_workspace_dir, { recursive: true }); +fs.rmSync(TEST_DIR, { recursive: true, force: true }); +fs.mkdirSync(TEST_DIR, { recursive: true }); -fs.writeFileSync(path.join(test_workspace_dir, 'pnpm-workspace.yaml'), 'packages:\n - ./*\n'); +fs.writeFileSync(path.join(TEST_DIR, 'pnpm-workspace.yaml'), 'packages:\n - ./*\n'); beforeAll(async () => { const install = await exec('pnpm', ['install', '--no-frozen-lockfile'], { - nodeOptions: { cwd: test_workspace_dir } + nodeOptions: { cwd: TEST_DIR } }); if (install.exitCode !== 0) { throw new Error( - `pnpm install failed in ${test_workspace_dir}\n stdout: ${install.stdout}\n stderr: ${install.stderr}` + `pnpm install failed in ${TEST_DIR}\n stdout: ${install.stdout}\n stderr: ${install.stderr}` ); } }, 60000); @@ -35,13 +35,13 @@ beforeAll(async () => { */ const script_test_map = new Map Result]>>(); -const templates = fs.readdirSync(resolve_path('../templates/')) as TemplateType[]; +const templates = fs.readdirSync(resolvePath('../templates/')) as TemplateType[]; for (const template of templates.filter((t) => t !== 'addon')) { if (template[0] === '.') continue; for (const types of ['checkjs', 'typescript', 'none'] as LanguageType[]) { - const cwd = path.join(test_workspace_dir, `${template}-${types}`); + const cwd = path.join(TEST_DIR, `${template}-${types}`); fs.rmSync(cwd, { recursive: true, force: true }); if (template === 'demo' && types === 'typescript') { diff --git a/packages/sv/src/create/tests/playground.ts b/packages/sv/src/create/tests/playground.ts index 1ef0520ea..221c50fac 100644 --- a/packages/sv/src/create/tests/playground.ts +++ b/packages/sv/src/create/tests/playground.ts @@ -12,7 +12,7 @@ import { } from '../playground.ts'; const resolvePath = (path: string) => fileURLToPath(new URL(path, import.meta.url)); -const testWorkspaceDir = resolvePath('../../../.test-output/playground/'); +const TEST_DIR = resolvePath('../../../.test-output/playground/'); test.for([ { input: 'https://svelte.dev/playground/628f435d787a465f9c1f1854134d6f70/', valid: true }, @@ -148,7 +148,7 @@ test('detect dependencies from playground files', () => { }); test('download and convert playground e2e (svelte async)', async () => { - const directory = path.join(testWorkspaceDir, 'playground-e2e-svelte-async'); + const directory = path.join(TEST_DIR, 'playground-e2e-svelte-async'); if (fs.existsSync(directory)) { fs.rmSync(directory, { recursive: true }); } @@ -200,7 +200,7 @@ test('download and convert playground e2e (svelte async)', async () => { }); test('download and convert playground e2e (pre svelte async)', async () => { - const directory = path.join(testWorkspaceDir, 'playground-e2e-pre-svelte-async'); + const directory = path.join(TEST_DIR, 'playground-e2e-pre-svelte-async'); if (fs.existsSync(directory)) { fs.rmSync(directory, { recursive: true }); } From 1db5198810cf04213c2e8d5cfb19c243c8f299fc Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 05:56:44 +0800 Subject: [PATCH 5/8] test: derive monorepo root with `empathic/find` --- packages/sv/src/addons/tests/_setup/global.ts | 7 +++++-- packages/sv/src/cli/tests/cli.ts | 8 +++----- packages/sv/src/create/tests/check.ts | 11 +++++------ packages/sv/src/create/tests/playground.ts | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/sv/src/addons/tests/_setup/global.ts b/packages/sv/src/addons/tests/_setup/global.ts index d5938b925..335ec458a 100644 --- a/packages/sv/src/addons/tests/_setup/global.ts +++ b/packages/sv/src/addons/tests/_setup/global.ts @@ -1,9 +1,12 @@ +import path from 'node:path'; import process from 'node:process'; -import { fileURLToPath } from 'node:url'; +import * as find from 'empathic/find'; import { setupGlobal } from 'sv/testing'; import { exec } from 'tinyexec'; -const TEST_DIR = fileURLToPath(new URL('../../../../.test-output/addons/', import.meta.url)); +const ROOT = path.dirname(find.up('pnpm-workspace.yaml', { cwd: import.meta.dirname })!); +const TEST_DIR = path.resolve(ROOT, 'packages', 'sv', '.test-output', 'addons'); + const CI = Boolean(process.env.CI); export default setupGlobal({ diff --git a/packages/sv/src/cli/tests/cli.ts b/packages/sv/src/cli/tests/cli.ts index e1930e8a0..dc84727e6 100644 --- a/packages/sv/src/cli/tests/cli.ts +++ b/packages/sv/src/cli/tests/cli.ts @@ -2,13 +2,14 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; import { parse } from '@sveltejs/sv-utils'; +import * as find from 'empathic/find'; import { exec } from 'tinyexec'; import { beforeAll, describe, expect, it } from 'vitest'; /** Matches `sv@1.2.3`, `sv@0.0.0-next.0`, `sv@1.0.0-rc.1+build.5`. */ const SV_VERSION_REGEX = /sv@\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?/g; -const ROOT = path.resolve(__dirname, '..', '..', '..', '..', '..'); +const ROOT = path.dirname(find.up('pnpm-workspace.yaml', { cwd: import.meta.dirname })!); const SV_BIN_PATH = path.resolve(ROOT, 'packages', 'sv', 'dist', 'bin.mjs'); const TEST_DIR = path.resolve(ROOT, 'packages', 'sv', '.test-output', 'cli'); @@ -72,10 +73,7 @@ describe('cli', () => { snapshot?: boolean; }; - const projectPath = path.relative( - ROOT, - path.resolve(TEST_DIR, projectName) - ); + const projectPath = path.relative(ROOT, path.resolve(TEST_DIR, projectName)); const allArgs = [ SV_BIN_PATH, diff --git a/packages/sv/src/create/tests/check.ts b/packages/sv/src/create/tests/check.ts index 8bdca0719..0b8db36b8 100644 --- a/packages/sv/src/create/tests/check.ts +++ b/packages/sv/src/create/tests/check.ts @@ -1,16 +1,15 @@ import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; +import * as find from 'empathic/find'; import { exec, type Result } from 'tinyexec'; import { beforeAll, describe, expect, test } from 'vitest'; import { createProject } from '../../cli/create.ts'; import { add, officialAddons } from '../../index.ts'; import { type LanguageType, type TemplateType, create } from '../index.ts'; -// Resolve the given path relative to the current file -const resolvePath = (path: string) => fileURLToPath(new URL(path, import.meta.url)); - -const TEST_DIR = resolvePath('../../../.test-output/create/'); +const ROOT = path.dirname(find.up('pnpm-workspace.yaml', { cwd: import.meta.dirname })!); +const TEMPLATES_DIR = path.resolve(ROOT, 'packages', 'sv', 'src', 'create', 'templates'); +const TEST_DIR = path.resolve(ROOT, 'packages', 'sv', '.test-output', 'create'); // prepare test pnpm workspace fs.rmSync(TEST_DIR, { recursive: true, force: true }); @@ -35,7 +34,7 @@ beforeAll(async () => { */ const script_test_map = new Map Result]>>(); -const templates = fs.readdirSync(resolvePath('../templates/')) as TemplateType[]; +const templates = fs.readdirSync(TEMPLATES_DIR) as TemplateType[]; for (const template of templates.filter((t) => t !== 'addon')) { if (template[0] === '.') continue; diff --git a/packages/sv/src/create/tests/playground.ts b/packages/sv/src/create/tests/playground.ts index 221c50fac..074aad9c0 100644 --- a/packages/sv/src/create/tests/playground.ts +++ b/packages/sv/src/create/tests/playground.ts @@ -1,6 +1,6 @@ import * as fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; +import * as find from 'empathic/find'; import { expect, test } from 'vitest'; import { create } from '../index.ts'; import { @@ -11,8 +11,8 @@ import { validatePlaygroundUrl } from '../playground.ts'; -const resolvePath = (path: string) => fileURLToPath(new URL(path, import.meta.url)); -const TEST_DIR = resolvePath('../../../.test-output/playground/'); +const ROOT = path.dirname(find.up('pnpm-workspace.yaml', { cwd: import.meta.dirname })!); +const TEST_DIR = path.resolve(ROOT, 'packages', 'sv', '.test-output', 'playground'); test.for([ { input: 'https://svelte.dev/playground/628f435d787a465f9c1f1854134d6f70/', valid: true }, From 9f5c3de6e41703152013a2cd92fa76ad64871a64 Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 05:59:17 +0800 Subject: [PATCH 6/8] rename file --- packages/sv/src/create/tests/{check.ts => create.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/sv/src/create/tests/{check.ts => create.ts} (100%) diff --git a/packages/sv/src/create/tests/check.ts b/packages/sv/src/create/tests/create.ts similarity index 100% rename from packages/sv/src/create/tests/check.ts rename to packages/sv/src/create/tests/create.ts From ce8d1db31d8610a8fa9c524d1bafb3df2260ac4f Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 06:27:49 +0800 Subject: [PATCH 7/8] comment --- documentation/docs/30-add-ons/99-community.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/30-add-ons/99-community.md b/documentation/docs/30-add-ons/99-community.md index a1f51fbe7..3d9b0e10c 100644 --- a/documentation/docs/30-add-ons/99-community.md +++ b/documentation/docs/30-add-ons/99-community.md @@ -136,7 +136,7 @@ And the global test setup script `tests/setup/global.js`: ```js import path from 'node:path'; import { setupGlobal } from 'sv/testing'; - +// test projects are scaffolded into `/.test-output` const TEST_DIR = path.resolve(import.meta.dirname, '..', '..', '.test-output'); export default setupGlobal({ TEST_DIR }); From fb6caf3bf809198d8336d546951442eea3daea0f Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Sat, 29 Aug 2026 06:32:36 +0800 Subject: [PATCH 8/8] fix --- packages/sv/src/create/tests/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sv/src/create/tests/create.ts b/packages/sv/src/create/tests/create.ts index 0b8db36b8..104d2689f 100644 --- a/packages/sv/src/create/tests/create.ts +++ b/packages/sv/src/create/tests/create.ts @@ -3,8 +3,8 @@ import path from 'node:path'; import * as find from 'empathic/find'; import { exec, type Result } from 'tinyexec'; import { beforeAll, describe, expect, test } from 'vitest'; +import { add, officialAddons } from '../../../../sv/src/index.ts'; import { createProject } from '../../cli/create.ts'; -import { add, officialAddons } from '../../index.ts'; import { type LanguageType, type TemplateType, create } from '../index.ts'; const ROOT = path.dirname(find.up('pnpm-workspace.yaml', { cwd: import.meta.dirname })!);