diff --git a/packages/create-svelte/templates/default/package.template.json b/packages/create-svelte/templates/default/package.template.json index 62d948a709f3..1c6cc11e7349 100644 --- a/packages/create-svelte/templates/default/package.template.json +++ b/packages/create-svelte/templates/default/package.template.json @@ -4,10 +4,13 @@ "scripts": { "dev": "svelte-kit dev", "build": "svelte-kit build", - "preview": "svelte-kit preview" + "preview": "svelte-kit preview", + "test": "wtr \"src/**/*.test.js\"" }, "devDependencies": { "@sveltejs/kit": "workspace:*", + "@web/test-runner": "^0.13.5", + "assert": "^2.0.0", "svelte": "^3.34.0" }, "type": "module", diff --git a/packages/create-svelte/templates/default/src/test/Counter.test.js b/packages/create-svelte/templates/default/src/test/Counter.test.js new file mode 100644 index 000000000000..52fff80d89e9 --- /dev/null +++ b/packages/create-svelte/templates/default/src/test/Counter.test.js @@ -0,0 +1,16 @@ +import { strict as assert } from 'assert'; +import Counter from '$lib/Counter/index.svelte'; + +describe('Counter', () => { + it('should increment when plus button is clicked', async () => { + const target = document.getElementById('svelte'); + new Counter({ target }); + const plusButton = target.getElementsByTagName('button')[1]; + const counter = target.querySelectorAll('.counter-digits strong')[1]; + assert.equal(counter.innerText, '0'); + plusButton.click(); + // you probably want to use fake timers in your real tests! + await new Promise((resolve) => setTimeout(resolve, 500)); + assert.equal(counter.innerText, '1'); + }); +}); diff --git a/packages/create-svelte/templates/default/src/test/HomePage.test.js b/packages/create-svelte/templates/default/src/test/HomePage.test.js new file mode 100644 index 000000000000..6a57fc24d1e8 --- /dev/null +++ b/packages/create-svelte/templates/default/src/test/HomePage.test.js @@ -0,0 +1,10 @@ +import { strict as assert } from 'assert'; +import HomePage from '../routes/index.svelte'; + +describe('HomePage', () => { + it('should render', () => { + const target = document.getElementById('svelte'); + new HomePage({ target }); + assert(/try editing src\/routes\/index.svelte/.test(target.innerText)); + }); +}); diff --git a/packages/create-svelte/templates/default/web-test-runner.config.js b/packages/create-svelte/templates/default/web-test-runner.config.js new file mode 100644 index 000000000000..dced7dae8d56 --- /dev/null +++ b/packages/create-svelte/templates/default/web-test-runner.config.js @@ -0,0 +1,79 @@ +import { spawn } from 'child_process'; + +/* + * Implementing plugin inline as a POC. This would be extracted to a separate + * npm module following a pattern similar to @snowpack/web-test-runner-plugin: + * https://github.com/snowpackjs/snowpack/tree/main/plugins/web-test-runner-plugin + * or vite-web-test-runner-plugin: + * https://github.com/betaboon/vite-web-test-runner-plugin + */ +const svelteKitPlugin = function () { + let server; + + // quick hack; use more resilient approach in real plugin + function randomPort(min = 49152, max = 65535) { + return Math.floor(Math.random() * (max - min) + min); + } + + // Currently, svelte-kit does not expose a method to the outside world to + // start a dev server in JS-land. Work-around for POC: spawn a child process + // that shells-out to svelte-kit cli. For real plugin, extract and export a + // method from svelte-kit to start a dev server. + function startTestServer(port) { + const testServer = spawn('npx', ['svelte-kit', 'dev', `--port=${port}`]); + + testServer.stderr.on('data', (data) => { + console.error(data.toString()); + }); + + testServer.stdout.on('data', (data) => { + console.log(data.toString()); + }); + + return new Promise((resolve, reject) => { + testServer.stdout.on('data', (data) => { + if (/http:\/\/localhost:\d+/.test(data)) { + resolve(testServer); + } + }); + + testServer.on('close', reject); + }); + } + + return { + name: 'svelte-kit-plugin', + + async serverStart({ app }) { + const port = randomPort(); + server = await startTestServer(port); + app.use((ctx, next) => { + ctx.redirect(`http://localhost:${port}${ctx.originalUrl}`); + }); + }, + + async serverStop() { + return server.kill(); + } + }; +}; + +process.env.NODE_ENV = 'test'; + +export default { + plugins: [svelteKitPlugin()], + testRunnerHtml: (testFramework) => ` + + + + + + +
+ + + ` +};