remove test duplication

pull/15538/head
Rich Harris 4 months ago
parent 07aed41b7b
commit 4039f9ef24

@ -58,17 +58,15 @@ export function create_deferred() {
* @param {Partial<CompileOptions>} compileOptions
* @param {boolean} [output_map]
* @param {any} [preprocessor]
* @param {import('./suite').TemplatingMode} [templating_mode]
*/
export async function compile_directory(
cwd,
generate,
compileOptions = {},
output_map = false,
preprocessor,
templating_mode
preprocessor
) {
const output_dir = `${cwd}/_output/${generate}${templating_mode === 'functional' ? `-functional` : ''}`;
const output_dir = `${cwd}/_output/${generate}`;
fs.rmSync(output_dir, { recursive: true, force: true });
@ -79,8 +77,7 @@ export async function compile_directory(
let opts = {
filename: path.join(cwd, file),
...compileOptions,
generate,
templatingMode: templating_mode
generate
};
if (file.endsWith('.js')) {
@ -193,3 +190,6 @@ if (typeof window !== 'undefined') {
};
});
}
export const templatingMode =
/** @type {'string' | 'functional'} */ (process.env.TEMPLATING_MODE) ?? 'string';

@ -4,6 +4,7 @@ import * as fs from 'node:fs';
import { assert } from 'vitest';
import { compile_directory } from '../helpers.js';
import { assert_html_equal } from '../html_equal.js';
import { templatingMode } from '../helpers.js';
import { assert_ok, suite, type BaseTest } from '../suite.js';
import { createClassComponent } from 'svelte/legacy';
import { render } from 'svelte/server';
@ -41,24 +42,15 @@ function read(path: string): string | void {
return fs.existsSync(path) ? fs.readFileSync(path, 'utf-8') : undefined;
}
const { test, run } = suite<HydrationTest>(async (config, cwd, templating_mode) => {
const { test, run } = suite<HydrationTest>(async (config, cwd) => {
if (!config.load_compiled) {
await compile_directory(
cwd,
'client',
{ accessors: true, ...config.compileOptions },
undefined,
undefined,
templating_mode
);
await compile_directory(
cwd,
'server',
config.compileOptions,
undefined,
undefined,
templating_mode
);
await compile_directory(cwd, 'client', {
accessors: true,
templatingMode,
...config.compileOptions
});
await compile_directory(cwd, 'server', config.compileOptions, undefined, undefined);
}
const target = window.document.body;
@ -116,11 +108,7 @@ const { test, run } = suite<HydrationTest>(async (config, cwd, templating_mode)
};
const component = createClassComponent({
component: (
await import(
`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/main.svelte.js`
)
).default,
component: (await import(`${cwd}/_output/client/main.svelte.js`)).default,
target,
hydrate: true,
props: config.props,
@ -187,5 +175,4 @@ const { test, run } = suite<HydrationTest>(async (config, cwd, templating_mode)
});
export { test, assert_ok };
await run(__dirname, 'string');
await run(__dirname, 'functional');
await run(__dirname);

@ -4,8 +4,8 @@ import * as fs from 'node:fs';
import * as path from 'node:path';
import { compile } from 'svelte/compiler';
import { afterAll, assert, beforeAll, describe } from 'vitest';
import { suite, suite_with_variants, type TemplatingMode } from '../suite';
import { write } from '../helpers';
import { suite, suite_with_variants } from '../suite';
import { write, templatingMode } from '../helpers';
import type { Warning } from '#compiler';
const assert_file = path.resolve(__dirname, 'assert.js');
@ -35,41 +35,34 @@ const { run: run_browser_tests } = suite_with_variants<
return false;
},
() => {},
async (config, test_dir, variant, _, templating_mode) => {
await run_test(test_dir, config, variant === 'hydrate', templating_mode);
async (config, test_dir, variant) => {
await run_test(test_dir, config, variant === 'hydrate');
}
);
describe.concurrent(
'runtime-browser',
() => run_browser_tests(__dirname, 'string'),
// Browser tests are brittle and slow on CI
{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
);
describe.concurrent(
'runtime-browser-functional',
() => run_browser_tests(__dirname, 'functional'),
() => run_browser_tests(__dirname),
// Browser tests are brittle and slow on CI
{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
);
const { run: run_ce_tests } = suite<ReturnType<typeof import('./assert').test>>(
async (config, test_dir, templating_mode) => {
await run_test(test_dir, config, false, templating_mode);
async (config, test_dir) => {
await run_test(test_dir, config, false);
}
);
describe.concurrent(
'custom-elements',
() => run_ce_tests(__dirname, 'string', 'custom-elements-samples'),
() => run_ce_tests(__dirname, 'custom-elements-samples'),
// Browser tests are brittle and slow on CI
{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
);
describe.concurrent(
'custom-elements',
() => run_ce_tests(__dirname, 'functional', 'custom-elements-samples'),
() => run_ce_tests(__dirname, 'custom-elements-samples'),
// Browser tests are brittle and slow on CI
{ timeout: 20000, retry: process.env.CI ? 1 : 0 }
);
@ -77,8 +70,7 @@ describe.concurrent(
async function run_test(
test_dir: string,
config: ReturnType<typeof import('./assert').test>,
hydrate: boolean,
templating_mode: TemplatingMode
hydrate: boolean
) {
const warnings: any[] = [];
@ -102,17 +94,14 @@ async function run_test(
build.onLoad({ filter: /\.svelte$/ }, (args) => {
const compiled = compile(fs.readFileSync(args.path, 'utf-8').replace(/\r/g, ''), {
generate: 'client',
templatingMode,
...config.compileOptions,
immutable: config.immutable,
customElement: test_dir.includes('custom-elements-samples'),
accessors: 'accessors' in config ? config.accessors : true,
templatingMode: templating_mode
accessors: 'accessors' in config ? config.accessors : true
});
write(
`${test_dir}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/${path.basename(args.path)}.js`,
compiled.js.code
);
write(`${test_dir}/_output/client/${path.basename(args.path)}.js`, compiled.js.code);
compiled.warnings.forEach((warning) => {
if (warning.code === 'options_deprecated_accessors') return;
@ -121,10 +110,7 @@ async function run_test(
if (compiled.css !== null) {
compiled.js.code += `document.head.innerHTML += \`<style>${compiled.css.code}</style>\``;
write(
`${test_dir}/_output/${templating_mode === 'functional' ? '-functional' : ''}/${path.basename(args.path)}.css`,
compiled.css.code
);
write(`${test_dir}/_output/${path.basename(args.path)}.css`, compiled.css.code);
}
return {
@ -170,8 +156,7 @@ async function run_test(
...config.compileOptions,
immutable: config.immutable,
customElement: test_dir.includes('custom-elements-samples'),
accessors: 'accessors' in config ? config.accessors : true,
templatingMode: templating_mode
accessors: 'accessors' in config ? config.accessors : true
});
return {

@ -6,11 +6,11 @@ import { proxy } from 'svelte/internal/client';
import { flushSync, hydrate, mount, unmount } from 'svelte';
import { render } from 'svelte/server';
import { afterAll, assert, beforeAll } from 'vitest';
import { compile_directory } from '../helpers.js';
import { compile_directory, templatingMode } from '../helpers.js';
import { setup_html_equal } from '../html_equal.js';
import { raf } from '../animation-helpers.js';
import type { CompileOptions } from '#compiler';
import { suite_with_variants, type BaseTest, type TemplatingMode } from '../suite.js';
import { suite_with_variants, type BaseTest } from '../suite.js';
import { seen } from '../../src/internal/server/dev.js';
type Assert = typeof import('vitest').assert & {
@ -142,21 +142,16 @@ export function runtime_suite(runes: boolean) {
return false;
},
(config, cwd, templating_mode) => {
return common_setup(cwd, runes, config, templating_mode);
(config, cwd) => {
return common_setup(cwd, runes, config);
},
async (config, cwd, variant, common, templating_mode) => {
await run_test_variant(cwd, config, variant, common, runes, templating_mode);
async (config, cwd, variant, common) => {
await run_test_variant(cwd, config, variant, common, runes);
}
);
}
async function common_setup(
cwd: string,
runes: boolean | undefined,
config: RuntimeTest,
templating_mode: TemplatingMode
) {
async function common_setup(cwd: string, runes: boolean | undefined, config: RuntimeTest) {
const force_hmr = process.env.HMR && config.compileOptions?.dev !== false && !config.error;
const compileOptions: CompileOptions = {
@ -164,17 +159,17 @@ async function common_setup(
rootDir: cwd,
dev: force_hmr ? true : undefined,
hmr: force_hmr ? true : undefined,
templatingMode,
...config.compileOptions,
immutable: config.immutable,
accessors: 'accessors' in config ? config.accessors : true,
runes,
templatingMode: templating_mode
runes
};
// load_compiled can be used for debugging a test. It means the compiler will not run on the input
// so you can manipulate the output manually to see what fixes it, adding console.logs etc.
if (!config.load_compiled) {
await compile_directory(cwd, 'client', compileOptions, undefined, undefined, templating_mode);
await compile_directory(cwd, 'client', compileOptions, undefined, undefined);
await compile_directory(cwd, 'server', compileOptions);
}
@ -186,8 +181,7 @@ async function run_test_variant(
config: RuntimeTest,
variant: 'dom' | 'hydrate' | 'ssr',
compileOptions: CompileOptions,
runes: boolean,
templating_mode: TemplatingMode
runes: boolean
) {
let unintended_error = false;
@ -266,14 +260,9 @@ async function run_test_variant(
// Put things we need on window for testing
const styles = globSync('**/*.css', {
cwd: `${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}`
cwd: `${cwd}/_output/client`
})
.map((file) =>
fs.readFileSync(
`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/${file}`,
'utf-8'
)
)
.map((file) => fs.readFileSync(`${cwd}/_output/client/${file}`, 'utf-8'))
.join('\n')
.replace(/\/\*<\/?style>\*\//g, '');
@ -289,9 +278,7 @@ async function run_test_variant(
globalThis.requestAnimationFrame = globalThis.setTimeout;
let mod = await import(
`${cwd}/_output/client${templating_mode === 'functional' ? '-functional' : ''}/main.svelte.js`
);
let mod = await import(`${cwd}/_output/client/main.svelte.js`);
const target = window.document.querySelector('main') as HTMLElement;

@ -11,5 +11,4 @@ const { test, run } = runtime_suite(false);
export { test, ok };
await run(__dirname, 'string');
await run(__dirname, 'functional');
await run(__dirname);

@ -5,5 +5,4 @@ const { test, run } = runtime_suite(true);
export { test, ok };
await run(__dirname, 'string');
await run(__dirname, 'functional');
await run(__dirname);

@ -9,15 +9,8 @@ interface SnapshotTest extends BaseTest {
compileOptions?: Partial<import('#compiler').CompileOptions>;
}
const { test, run } = suite<SnapshotTest>(async (config, cwd, templating_mode) => {
await compile_directory(
cwd,
'client',
config.compileOptions,
undefined,
undefined,
templating_mode
);
const { test, run } = suite<SnapshotTest>(async (config, cwd) => {
await compile_directory(cwd, 'client', config.compileOptions);
await compile_directory(cwd, 'server', config.compileOptions);
// run `UPDATE_SNAPSHOTS=true pnpm test snapshot` to update snapshot tests
@ -25,18 +18,8 @@ const { test, run } = suite<SnapshotTest>(async (config, cwd, templating_mode) =
fs.rmSync(`${cwd}/_expected`, { recursive: true, force: true });
fs.cpSync(`${cwd}/_output`, `${cwd}/_expected`, { recursive: true, force: true });
} else {
const actual = globSync('**', { cwd: `${cwd}/_output`, onlyFiles: true }).filter(
// filters out files that might not yet be compiled (functional is executed after string)
(expected) =>
expected.startsWith('server/') ||
expected.startsWith(`client${templating_mode === 'functional' ? '-functional' : ''}/`)
);
const expected = globSync('**', { cwd: `${cwd}/_expected`, onlyFiles: true }).filter(
// filters out files that might not yet be compiled (functional is executed after string)
(expected) =>
expected.startsWith('server/') ||
expected.startsWith(`client${templating_mode === 'functional' ? '-functional' : ''}/`)
);
const actual = globSync('**', { cwd: `${cwd}/_output`, onlyFiles: true });
const expected = globSync('**', { cwd: `${cwd}/_expected`, onlyFiles: true });
assert.deepEqual(actual, expected);
@ -58,5 +41,4 @@ const { test, run } = suite<SnapshotTest>(async (config, cwd, templating_mode) =
export { test };
await run(__dirname, 'string');
await run(__dirname, 'functional');
await run(__dirname);

@ -6,8 +6,6 @@ export interface BaseTest {
solo?: boolean;
}
export type TemplatingMode = 'string' | 'functional';
/**
* To filter tests, run one of these:
*
@ -22,22 +20,14 @@ const filter = process.env.FILTER
)
: /./;
export function suite<Test extends BaseTest>(
fn: (config: Test, test_dir: string, templating_mode: TemplatingMode) => void
) {
export function suite<Test extends BaseTest>(fn: (config: Test, test_dir: string) => void) {
return {
test: (config: Test) => config,
run: async (
cwd: string,
templating_mode: TemplatingMode = 'string',
samples_dir = 'samples'
) => {
run: async (cwd: string, samples_dir = 'samples') => {
await for_each_dir<Test>(cwd, samples_dir, (config, dir) => {
let it_fn = config.skip ? it.skip : config.solo ? it.only : it;
it_fn(`${dir} (${templating_mode})`, () =>
fn(config, `${cwd}/${samples_dir}/${dir}`, templating_mode)
);
it_fn(dir, () => fn(config, `${cwd}/${samples_dir}/${dir}`));
});
}
};
@ -46,26 +36,12 @@ export function suite<Test extends BaseTest>(
export function suite_with_variants<Test extends BaseTest, Variants extends string, Common>(
variants: Variants[],
should_skip_variant: (variant: Variants, config: Test) => boolean | 'no-test',
common_setup: (
config: Test,
test_dir: string,
templating_mode: TemplatingMode
) => Promise<Common> | Common,
fn: (
config: Test,
test_dir: string,
variant: Variants,
common: Common,
templating_mode: TemplatingMode
) => void
common_setup: (config: Test, test_dir: string) => Promise<Common> | Common,
fn: (config: Test, test_dir: string, variant: Variants, common: Common) => void
) {
return {
test: (config: Test) => config,
run: async (
cwd: string,
templating_mode: TemplatingMode = 'string',
samples_dir = 'samples'
) => {
run: async (cwd: string, samples_dir = 'samples') => {
await for_each_dir<Test>(cwd, samples_dir, (config, dir) => {
let called_common = false;
let common: any = undefined;
@ -78,12 +54,12 @@ export function suite_with_variants<Test extends BaseTest, Variants extends stri
const solo = config.solo;
let it_fn = skip ? it.skip : solo ? it.only : it;
it_fn(`${dir} (${templating_mode}-${variant})`, async () => {
it_fn(dir, async () => {
if (!called_common) {
called_common = true;
common = await common_setup(config, `${cwd}/${samples_dir}/${dir}`, templating_mode);
common = await common_setup(config, `${cwd}/${samples_dir}/${dir}`);
}
return fn(config, `${cwd}/${samples_dir}/${dir}`, variant, common, templating_mode);
return fn(config, `${cwd}/${samples_dir}/${dir}`, variant, common);
});
}
});

Loading…
Cancel
Save