diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f00ebc07b9..9c2cb51034 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,6 +96,17 @@ Test samples are kept in `/test/xxx/samples` folder. 1. To run test, run `npm run test` 1. To run test for a specific feature, you can use the `-g` (aka `--grep`) option. For example, to only run test involving transitions, run `npm run test -- -g transition`. +##### Running solo test + +1. To run only one test, rename the test sample folder to end with `.solo`. For example, to run the `test/js/samples/action` only, rename it to `test/js/samples/action.solo`. +1. To run only one test suite, rename the test suite folder to end with `.solo`. For example, to run the `test/js` test suite only, rename it to `test/js.solo`. +1. Remember to rename the test folder back. The CI will fail if there's a solo test. + +##### Updating `.expected` files + +1. Tests suites like `css`, `js`, `server-side-rendering` asserts that the generated output has to match the content in the `.expected` file. For example, in the `js` test suites, the generated js code is compared against the content in `expected.js`. +1. To update the content of the `.expected` file, run the test with `--update` flag. (`npm run test --update`) + #### Breaking changes When adding a new breaking change, follow this template in your pull request: diff --git a/test/css/index.js b/test/css/index.js index 1f90d243be..dc17314597 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -1,6 +1,6 @@ import * as assert from 'assert'; import * as fs from 'fs'; -import { env, normalizeHtml, svelte } from '../helpers.js'; +import { env, svelte, setupHtmlEqual, shouldUpdateExpected } from '../helpers.js'; function try_require(file) { try { @@ -37,6 +37,10 @@ function create(code) { } describe('css', () => { + before(() => { + setupHtmlEqual(); + }); + fs.readdirSync(`${__dirname}/samples`).forEach(dir => { if (dir[0] === '.') return; @@ -80,7 +84,17 @@ describe('css', () => { css: read(`${__dirname}/samples/${dir}/expected.css`) }; - assert.equal(dom.css.code.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz'), expected.css); + const actual_css = dom.css.code.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz'); + try { + assert.equal(actual_css, expected.css); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${__dirname}/samples/${dir}/expected.css`, actual_css); + console.log(`Updated ${dir}/expected.css.`); + } else { + throw error; + } + } let ClientComponent; let ServerComponent; @@ -114,10 +128,8 @@ describe('css', () => { fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.html`, html); - assert.equal( - normalizeHtml(window, html.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz')), - normalizeHtml(window, expected.html) - ); + const actual_html = html.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz'); + assert.htmlEqual(actual_html, expected.html); window.document.head.innerHTML = ''; // remove added styles } catch (err) { @@ -127,13 +139,8 @@ describe('css', () => { // ssr try { - assert.equal( - normalizeHtml( - window, - ServerComponent.render(config.props).html.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz') - ), - normalizeHtml(window, expected.html) - ); + const actual_ssr = ServerComponent.render(config.props).html.replace(/svelte(-ref)?-[a-z0-9]+/g, (m, $1) => $1 ? m : 'svelte-xyz'); + assert.htmlEqual(actual_ssr, expected.html); } catch (err) { console.log(ssr.js.code); throw err; diff --git a/test/helpers.js b/test/helpers.js index d4f507fc87..ff40ac5f79 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -206,6 +206,10 @@ export function showOutput(cwd, options = {}, compile = svelte.compile) { }); } +export function shouldUpdateExpected() { + return process.argv.includes('--update'); +} + export function spaces(i) { let result = ''; while (i--) result += ' '; diff --git a/test/hydration/index.js b/test/hydration/index.js index 85e2ccc4a0..a0bfd6de4b 100644 --- a/test/hydration/index.js +++ b/test/hydration/index.js @@ -7,7 +7,8 @@ import { loadConfig, loadSvelte, env, - setupHtmlEqual + setupHtmlEqual, + shouldUpdateExpected } from '../helpers.js'; let compileOptions = null; @@ -76,7 +77,16 @@ describe('hydration', () => { props: config.props }); - assert.htmlEqual(target.innerHTML, fs.readFileSync(`${cwd}/_after.html`, 'utf-8')); + try { + assert.htmlEqual(target.innerHTML, fs.readFileSync(`${cwd}/_after.html`, 'utf-8')); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${cwd}/_after.html`, target.innerHTML); + console.log(`Updated ${cwd}/_after.html.`); + } else { + throw error; + } + } if (config.test) { config.test(assert, target, snapshot, component, window); diff --git a/test/js/index.js b/test/js/index.js index 5fd632d606..b16c25fe50 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -1,7 +1,8 @@ import * as assert from "assert"; import * as fs from "fs"; import * as path from "path"; -import { loadConfig, svelte } from "../helpers.js"; +import * as kleur from "kleur"; +import { loadConfig, svelte, shouldUpdateExpected } from "../helpers.js"; describe("js", () => { fs.readdirSync(`${__dirname}/samples`).forEach(dir => { @@ -14,8 +15,14 @@ describe("js", () => { throw new Error("Forgot to remove `solo: true` from test"); } + dir = path.resolve(`${__dirname}/samples`, dir); + + if (!fs.existsSync(`${dir}/input.svelte`)) { + console.log(colors.red().bold(`Missing file ${dir}/input.svelte. If you recently switched branches you may need to delete this directory`)); + return; + } + (solo ? it.only : it)(dir, () => { - dir = path.resolve(`${__dirname}/samples`, dir); const config = loadConfig(`${dir}/_config.js`); const input = fs.readFileSync(`${dir}/input.svelte`, "utf-8").replace(/\s+$/, ""); @@ -34,12 +41,32 @@ describe("js", () => { const output = `${dir}/_actual.js`; fs.writeFileSync(output, actual); - const expected = fs.readFileSync(`${dir}/expected.js`, "utf-8"); + const expectedPath = `${dir}/expected.js`; + + let expected = ''; + try { + expected = fs.readFileSync(expectedPath, "utf-8"); + } catch (error) { + console.log(error); + if (error.code === 'ENOENT') { + // missing expected.js + fs.writeFileSync(expectedPath, actual); + } + } - assert.equal( - actual.trim().replace(/^[ \t]+$/gm, ""), - expected.trim().replace(/^[ \t]+$/gm, "") - ); + try { + assert.equal( + actual.trim().replace(/^[ \t]+$/gm, ""), + expected.trim().replace(/^[ \t]+$/gm, "") + ); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(expectedPath, actual); + console.log(`Updated ${expectedPath}.`); + } else { + throw error; + } + } }); }); }); diff --git a/test/parser/index.js b/test/parser/index.js index 0188fac431..27c5ec1563 100644 --- a/test/parser/index.js +++ b/test/parser/index.js @@ -1,6 +1,6 @@ import * as assert from 'assert'; import * as fs from 'fs'; -import { svelte, tryToLoadJson } from '../helpers.js'; +import { svelte, tryToLoadJson, shouldUpdateExpected } from '../helpers.js'; describe('parse', () => { fs.readdirSync(`${__dirname}/samples`).forEach(dir => { @@ -15,7 +15,9 @@ describe('parse', () => { ); } - (solo ? it.only : it)(dir, () => { + const skip = !fs.existsSync(`${__dirname}/samples/${dir}/input.svelte`); + + (skip ? it.skip : solo ? it.only : it)(dir, () => { const options = tryToLoadJson(`${__dirname}/samples/${dir}/options.json`) || {}; const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, 'utf-8').replace(/\s+$/, ''); diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index 73b286044f..768917e833 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -6,7 +6,8 @@ import { showOutput, loadConfig, setupHtmlEqual, - tryToLoadJson + tryToLoadJson, + shouldUpdateExpected } from "../helpers.js"; function tryToReadFile(file) { @@ -58,18 +59,47 @@ describe("ssr", () => { fs.writeFileSync(`${dir}/_actual.html`, html); if (css.code) fs.writeFileSync(`${dir}/_actual.css`, css.code); - assert.htmlEqual(html, expectedHtml); - assert.equal( - css.code.replace(/^\s+/gm, ""), - expectedCss.replace(/^\s+/gm, "") - ); + try { + assert.htmlEqual(html, expectedHtml); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${dir}/_expected.html`, html); + console.log(`Updated ${dir}/_expected.html.`); + } else { + throw error; + } + } + + try { + assert.equal( + css.code.replace(/^\s+/gm, ""), + expectedCss.replace(/^\s+/gm, "") + ); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${dir}/_expected.css`, css.code); + console.log(`Updated ${dir}/_expected.css.`); + } else { + throw error; + } + } if (fs.existsSync(`${dir}/_expected-head.html`)) { fs.writeFileSync(`${dir}/_actual-head.html`, head); - assert.htmlEqual( - head, - fs.readFileSync(`${dir}/_expected-head.html`, 'utf-8') - ); + + try { + assert.htmlEqual( + head, + fs.readFileSync(`${dir}/_expected-head.html`, 'utf-8') + ); + } catch (error) { + if (shouldUpdateExpected()) { + fs.writeFileSync(`${dir}/_expected-head.html`, head); + console.log(`Updated ${dir}/_expected-head.html.`); + } else { + throw error; + } + } } if (show) showOutput(dir, { generate: 'ssr', format: 'cjs' });