diff --git a/mocha.coverage.opts b/mocha.coverage.opts
index 44c841b78e..5ad6a0e7a4 100644
--- a/mocha.coverage.opts
+++ b/mocha.coverage.opts
@@ -2,4 +2,4 @@
--require reify
--recursive
./**/__test__.js
-test/test.js
+test/*.js
diff --git a/mocha.opts b/mocha.opts
index 5b1cf3bcb3..d10eaa31b3 100644
--- a/mocha.opts
+++ b/mocha.opts
@@ -1,4 +1,4 @@
--require reify
--recursive
./**/__test__.js
-test/test.js
+test/*.js
diff --git a/package.json b/package.json
index 0cfa078cb0..41de5e2370 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"coverage": "nyc report --reporter=text-lcov > coverage.lcov",
"codecov": "codecov",
"precodecov": "npm run coverage",
- "lint": "eslint src",
+ "lint": "eslint src test/*.js",
"build": "npm run build:main && npm run build:ssr",
"build:main": "rollup -c rollup.config.main.js",
"build:ssr": "rollup -c rollup.config.ssr.js",
@@ -66,10 +66,10 @@
},
"nyc": {
"include": [
- "compiler/**/*.js"
+ "src/**/*.js"
],
"exclude": [
- "compiler/**/__test__.js"
+ "src/**/__test__.js"
]
},
"babel": {
diff --git a/rollup.config.ssr.js b/rollup.config.ssr.js
index dd15e6592f..912aaecc3f 100644
--- a/rollup.config.ssr.js
+++ b/rollup.config.ssr.js
@@ -1,3 +1,4 @@
+import * as path from 'path';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
@@ -11,9 +12,9 @@ export default {
nodeResolve({ jsnext: true, module: true }),
commonjs()
],
- external: [ 'svelte', 'magic-string' ],
+ external: [ path.resolve( 'src/index.js' ), 'magic-string' ],
paths: {
- svelte: '../compiler/svelte.js'
+ [ path.resolve( 'src/index.js' ) ]: '../compiler/svelte.js'
},
sourceMap: true
};
diff --git a/src/server-side-rendering/compile.js b/src/server-side-rendering/compile.js
index 346e40ce75..38fdab5502 100644
--- a/src/server-side-rendering/compile.js
+++ b/src/server-side-rendering/compile.js
@@ -1,4 +1,4 @@
-import { parse, validate } from 'svelte';
+import { parse, validate } from '../index.js';
import { walk } from 'estree-walker';
import deindent from '../utils/deindent.js';
import isReference from '../utils/isReference.js';
diff --git a/test/formats.js b/test/formats.js
new file mode 100644
index 0000000000..a712c4b7a4
--- /dev/null
+++ b/test/formats.js
@@ -0,0 +1,178 @@
+import deindent from '../src/utils/deindent.js';
+import assert from 'assert';
+import { svelte, env, setupHtmlEqual } from './helpers.js';
+
+function testAmd ( code, expectedId, dependencies, html ) {
+ const fn = new Function( 'define', code );
+
+ return env().then( window => {
+ function define ( id, deps, factory ) {
+ assert.equal( id, expectedId );
+ assert.deepEqual( deps, Object.keys( dependencies ) );
+
+ const SvelteComponent = factory( ...Object.keys( dependencies ).map( key => dependencies[ key ] ) );
+
+ const main = window.document.body.querySelector( 'main' );
+ const component = new SvelteComponent({ target: main });
+
+ assert.htmlEqual( main.innerHTML, html );
+
+ component.teardown();
+ }
+
+ define.amd = true;
+
+ fn( define );
+ });
+}
+
+function testCjs ( code, dependencyById, html ) {
+ const fn = new Function( 'module', 'exports', 'require', code );
+
+ return env().then( window => {
+ const module = { exports: {} };
+ const require = id => {
+ return dependencyById[ id ];
+ };
+
+ fn( module, module.exports, require );
+
+ const SvelteComponent = module.exports;
+
+ const main = window.document.body.querySelector( 'main' );
+ const component = new SvelteComponent({ target: main });
+
+ assert.htmlEqual( main.innerHTML, html );
+
+ component.teardown();
+ });
+}
+
+function testIife ( code, name, globals, html ) {
+ const fn = new Function( Object.keys( globals ), `${code}\n\nreturn ${name};` );
+
+ return env().then( window => {
+ const SvelteComponent = fn( ...Object.keys( globals ).map( key => globals[ key ] ) );
+
+ const main = window.document.body.querySelector( 'main' );
+ const component = new SvelteComponent({ target: main });
+
+ assert.htmlEqual( main.innerHTML, html );
+
+ component.teardown();
+ });
+}
+
+describe( 'formats', () => {
+ before( setupHtmlEqual );
+
+ describe( 'amd', () => {
+ it( 'generates an AMD module', () => {
+ const source = deindent`
+
{{answer}}
+
+
+ `;
+
+ const { code } = svelte.compile( source, {
+ format: 'amd',
+ amd: { id: 'foo' }
+ });
+
+ return testAmd( code, 'foo', { answer: 42 }, `42
` );
+ });
+ });
+
+ describe( 'cjs', () => {
+ it( 'generates a CommonJS module', () => {
+ const source = deindent`
+ {{answer}}
+
+
+ `;
+
+ const { code } = svelte.compile( source, {
+ format: 'cjs'
+ });
+
+ return testCjs( code, { answer: 42 }, `42
` );
+ });
+ });
+
+ describe( 'iife', () => {
+ it( 'generates a self-executing script', () => {
+ const source = deindent`
+ {{answer}}
+
+
+ `;
+
+ const { code } = svelte.compile( source, {
+ format: 'iife',
+ name: 'Foo',
+ globals: {
+ answer: 'answer'
+ }
+ });
+
+ return testIife( code, 'Foo', { answer: 42 }, `42
` );
+ });
+ });
+
+ describe( 'umd', () => {
+ it( 'generates a UMD build', () => {
+ const source = deindent`
+ {{answer}}
+
+
+ `;
+
+ const { code } = svelte.compile( source, {
+ format: 'umd',
+ name: 'Foo',
+ globals: {
+ answer: 'answer'
+ },
+ amd: {
+ id: 'foo'
+ }
+ });
+
+ return testAmd( code, 'foo', { answer: 42 }, `42
` )
+ .then( () => testCjs( code, { answer: 42 }, `42
` ) )
+ .then( () => testIife( code, 'Foo', { answer: 42 }, `42
` ) );
+ });
+ });
+});
diff --git a/test/generate.js b/test/generate.js
new file mode 100644
index 0000000000..2c996fd1ca
--- /dev/null
+++ b/test/generate.js
@@ -0,0 +1,121 @@
+import spaces from '../src/utils/spaces.js';
+import assert from 'assert';
+import * as path from 'path';
+import * as fs from 'fs';
+import * as acorn from 'acorn';
+
+import { svelte, env, setupHtmlEqual } from './helpers.js';
+
+const cache = {};
+
+let showCompiledCode = false;
+let compileOptions = null;
+
+require.extensions[ '.html' ] = function ( module, filename ) {
+ const options = Object.assign({ filename }, compileOptions );
+ const code = cache[ filename ] || ( cache[ filename ] = svelte.compile( fs.readFileSync( filename, 'utf-8' ), options ).code );
+ if ( showCompiledCode ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
+
+ return module._compile( code, filename );
+};
+
+function addLineNumbers ( code ) {
+ return code.split( '\n' ).map( ( line, i ) => {
+ i = String( i + 1 );
+ while ( i.length < 3 ) i = ` ${i}`;
+
+ return `${i}: ${line.replace( /^\t+/, match => match.split( '\t' ).join( ' ' ) )}`;
+ }).join( '\n' );
+}
+
+function loadConfig ( dir ) {
+ try {
+ return require( `./generator/${dir}/_config.js` ).default;
+ } catch ( err ) {
+ if ( err.code === 'E_NOT_FOUND' ) {
+ return {};
+ }
+
+ throw err;
+ }
+}
+
+describe( 'generate', () => {
+ before( setupHtmlEqual );
+
+ fs.readdirSync( 'test/generator' ).forEach( dir => {
+ if ( dir[0] === '.' ) return;
+
+ const config = loadConfig( dir );
+
+ ( config.skip ? it.skip : config.solo ? it.only : it )( dir, () => {
+ let compiled;
+
+ showCompiledCode = config.show;
+ compileOptions = config.compileOptions || {};
+
+ try {
+ const source = fs.readFileSync( `test/generator/${dir}/main.html`, 'utf-8' );
+ compiled = svelte.compile( source );
+ } catch ( err ) {
+ if ( config.compileError ) {
+ config.compileError( err );
+ return;
+ } else {
+ throw err;
+ }
+ }
+
+ const { code } = compiled;
+
+ // check that no ES2015+ syntax slipped in
+ try {
+ const startIndex = code.indexOf( 'function renderMainFragment' ); // may change!
+ const es5 = spaces( startIndex ) + code.slice( startIndex ).replace( /export default .+/, '' );
+ acorn.parse( es5, { ecmaVersion: 5 });
+ } catch ( err ) {
+ if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
+ throw err;
+ }
+
+ cache[ path.resolve( `test/generator/${dir}/main.html` ) ] = code;
+
+ let SvelteComponent;
+
+ try {
+ SvelteComponent = require( `./generator/${dir}/main.html` ).default;
+ } catch ( err ) {
+ if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
+ throw err;
+ }
+
+ return env()
+ .then( window => {
+ // Put the constructor on window for testing
+ window.SvelteComponent = SvelteComponent;
+
+ const target = window.document.querySelector( 'main' );
+
+ const component = new SvelteComponent({
+ target,
+ data: config.data
+ });
+
+ if ( config.html ) {
+ assert.htmlEqual( target.innerHTML, config.html );
+ }
+
+ if ( config.test ) {
+ config.test( assert, component, target, window );
+ } else {
+ component.teardown();
+ assert.equal( target.innerHTML, '' );
+ }
+ })
+ .catch( err => {
+ if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
+ throw err;
+ });
+ });
+ });
+});
diff --git a/test/helpers.js b/test/helpers.js
new file mode 100644
index 0000000000..d1f0539a6c
--- /dev/null
+++ b/test/helpers.js
@@ -0,0 +1,112 @@
+import jsdom from 'jsdom';
+import assert from 'assert';
+import * as fs from 'fs';
+
+import * as consoleGroup from 'console-group';
+consoleGroup.install();
+
+import * as sourceMapSupport from 'source-map-support';
+sourceMapSupport.install();
+
+// for coverage purposes, we need to test source files,
+// but for sanity purposes, we need to test dist files
+export const svelte = process.env.COVERAGE ?
+ require( '../src/index.js' ) :
+ require( '../compiler/svelte.js' );
+
+export function exists ( path ) {
+ try {
+ fs.statSync( path );
+ return true;
+ } catch ( err ) {
+ return false;
+ }
+}
+
+export function tryToLoadJson ( file ) {
+ try {
+ return JSON.parse( fs.readFileSync( file ) );
+ } catch ( err ) {
+ if ( err.code !== 'ENOENT' ) throw err;
+ return null;
+ }
+}
+
+export function tryToReadFile ( file ) {
+ try {
+ return fs.readFileSync( file, 'utf-8' );
+ } catch ( err ) {
+ if ( err.code !== 'ENOENT' ) throw err;
+ return null;
+ }
+}
+
+export function env () {
+ return new Promise( ( fulfil, reject ) => {
+ jsdom.env( '', ( err, window ) => {
+ if ( err ) {
+ reject( err );
+ } else {
+ global.document = window.document;
+ fulfil( window );
+ }
+ });
+ });
+}
+
+function cleanChildren ( node ) {
+ let previous = null;
+
+ [ ...node.childNodes ].forEach( child => {
+ if ( child.nodeType === 8 ) {
+ // comment
+ node.removeChild( child );
+ return;
+ }
+
+ if ( child.nodeType === 3 ) {
+ child.data = child.data.replace( /\s{2,}/, '\n' );
+
+ // text
+ if ( previous && previous.nodeType === 3 ) {
+ previous.data += child.data;
+ previous.data = previous.data.replace( /\s{2,}/, '\n' );
+
+ node.removeChild( child );
+ }
+ }
+
+ else {
+ cleanChildren( child );
+ }
+
+ previous = child;
+ });
+
+ // collapse whitespace
+ if ( node.firstChild && node.firstChild.nodeType === 3 ) {
+ node.firstChild.data = node.firstChild.data.replace( /^\s+/, '' );
+ if ( !node.firstChild.data ) node.removeChild( node.firstChild );
+ }
+
+ if ( node.lastChild && node.lastChild.nodeType === 3 ) {
+ node.lastChild.data = node.lastChild.data.replace( /\s+$/, '' );
+ if ( !node.lastChild.data ) node.removeChild( node.lastChild );
+ }
+}
+
+export function setupHtmlEqual () {
+ return env().then( window => {
+ assert.htmlEqual = ( actual, expected, message ) => {
+ window.document.body.innerHTML = actual.trim();
+ cleanChildren( window.document.body, '' );
+ actual = window.document.body.innerHTML;
+
+ window.document.body.innerHTML = expected.trim();
+ cleanChildren( window.document.body, '' );
+ expected = window.document.body.innerHTML;
+
+ assert.deepEqual( actual, expected, message );
+ };
+ });
+}
diff --git a/test/parse.js b/test/parse.js
new file mode 100644
index 0000000000..0be35e08f9
--- /dev/null
+++ b/test/parse.js
@@ -0,0 +1,36 @@
+import assert from 'assert';
+import * as fs from 'fs';
+import { svelte, exists } from './helpers.js';
+
+describe( 'parse', () => {
+ fs.readdirSync( 'test/parser' ).forEach( dir => {
+ if ( dir[0] === '.' ) return;
+
+ const solo = exists( `test/parser/${dir}/solo` );
+
+ ( solo ? it.only : it )( dir, () => {
+ const input = fs.readFileSync( `test/parser/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
+
+ try {
+ const actual = svelte.parse( input );
+ const expected = require( `./parser/${dir}/output.json` );
+
+ assert.deepEqual( actual.html, expected.html );
+ assert.deepEqual( actual.css, expected.css );
+ assert.deepEqual( actual.js, expected.js );
+ } catch ( err ) {
+ if ( err.name !== 'ParseError' ) throw err;
+
+ try {
+ const expected = require( `./parser/${dir}/error.json` );
+
+ assert.equal( err.message, expected.message );
+ assert.deepEqual( err.loc, expected.loc );
+ assert.equal( err.pos, expected.pos );
+ } catch ( err2 ) {
+ throw err2.code === 'MODULE_NOT_FOUND' ? err : err2;
+ }
+ }
+ });
+ });
+});
diff --git a/test/sourcemaps.js b/test/sourcemaps.js
new file mode 100644
index 0000000000..3417681629
--- /dev/null
+++ b/test/sourcemaps.js
@@ -0,0 +1,30 @@
+import * as fs from 'fs';
+import assert from 'assert';
+import { svelte, exists } from './helpers.js';
+import { SourceMapConsumer } from 'source-map';
+import { getLocator } from 'locate-character';
+
+describe( 'sourcemaps', () => {
+ fs.readdirSync( 'test/sourcemaps' ).forEach( dir => {
+ if ( dir[0] === '.' ) return;
+
+ const solo = exists( `test/sourcemaps/${dir}/solo` );
+
+ ( solo ? it.only : it )( dir, () => {
+ const input = fs.readFileSync( `test/sourcemaps/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
+ const { code, map } = svelte.compile( input );
+
+ fs.writeFileSync( `test/sourcemaps/${dir}/output.js`, `${code}\n//# sourceMappingURL=output.js.map` );
+ fs.writeFileSync( `test/sourcemaps/${dir}/output.js.map`, JSON.stringify( map, null, ' ' ) );
+
+ const { test } = require( `./sourcemaps/${dir}/test.js` );
+
+ const smc = new SourceMapConsumer( map );
+
+ const locateInSource = getLocator( input );
+ const locateInGenerated = getLocator( code );
+
+ test({ assert, code, map, smc, locateInSource, locateInGenerated });
+ });
+ });
+});
diff --git a/test/ssr.js b/test/ssr.js
new file mode 100644
index 0000000000..b985625922
--- /dev/null
+++ b/test/ssr.js
@@ -0,0 +1,44 @@
+import assert from 'assert';
+import * as fs from 'fs';
+
+import { exists, tryToLoadJson } from './helpers.js';
+
+function tryToReadFile ( file ) {
+ try {
+ return fs.readFileSync( file, 'utf-8' );
+ } catch ( err ) {
+ if ( err.code !== 'ENOENT' ) throw err;
+ return null;
+ }
+}
+
+describe( 'ssr', () => {
+ before( () => {
+ require( process.env.COVERAGE ?
+ '../src/server-side-rendering/register.js' :
+ '../ssr/register' );
+ });
+
+ fs.readdirSync( 'test/server-side-rendering' ).forEach( dir => {
+ if ( dir[0] === '.' ) return;
+
+ const solo = exists( `test/server-side-rendering/${dir}/solo` );
+
+ ( solo ? it.only : it )( dir, () => {
+ const component = require( `./server-side-rendering/${dir}/main.html` );
+
+ const expectedHtml = tryToReadFile( `test/server-side-rendering/${dir}/_expected.html` );
+ const expectedCss = tryToReadFile( `test/server-side-rendering/${dir}/_expected.css` ) || '';
+
+ const data = tryToLoadJson( `test/server-side-rendering/${dir}/data.json` );
+ const html = component.render( data );
+ const { css } = component.renderCss();
+
+ fs.writeFileSync( `test/server-side-rendering/${dir}/_actual.html`, html );
+ if ( css ) fs.writeFileSync( `test/server-side-rendering/${dir}/_actual.css`, css );
+
+ assert.htmlEqual( html, expectedHtml );
+ assert.equal( css.replace( /^\s+/gm, '' ), expectedCss.replace( /^\s+/gm, '' ) );
+ });
+ });
+});
diff --git a/test/test.js b/test/test.js
deleted file mode 100644
index b441265a32..0000000000
--- a/test/test.js
+++ /dev/null
@@ -1,549 +0,0 @@
-import deindent from '../src/utils/deindent.js';
-import spaces from '../src/utils/spaces.js';
-import assert from 'assert';
-import * as path from 'path';
-import * as fs from 'fs';
-import jsdom from 'jsdom';
-import * as acorn from 'acorn';
-import { SourceMapConsumer } from 'source-map';
-import { getLocator } from 'locate-character';
-
-import * as consoleGroup from 'console-group';
-consoleGroup.install();
-
-import * as sourceMapSupport from 'source-map-support';
-sourceMapSupport.install();
-
-// for coverage purposes, we need to test source files,
-// but for sanity purposes, we need to test dist files
-const svelte = process.env.COVERAGE ?
- require( '../src/index.js' ) :
- require( '../compiler/svelte.js' );
-
-const cache = {};
-
-let showCompiledCode = false;
-let compileOptions = null;
-
-require.extensions[ '.html' ] = function ( module, filename ) {
- const options = Object.assign({ filename }, compileOptions );
- const code = cache[ filename ] || ( cache[ filename ] = svelte.compile( fs.readFileSync( filename, 'utf-8' ), options ).code );
- if ( showCompiledCode ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
-
- return module._compile( code, filename );
-};
-
-function exists ( path ) {
- try {
- fs.statSync( path );
- return true;
- } catch ( err ) {
- return false;
- }
-}
-
-function env () {
- return new Promise( ( fulfil, reject ) => {
- jsdom.env( '', ( err, window ) => {
- if ( err ) {
- reject( err );
- } else {
- global.document = window.document;
- fulfil( window );
- }
- });
- });
-}
-
-function addLineNumbers ( code ) {
- return code.split( '\n' ).map( ( line, i ) => {
- i = String( i + 1 );
- while ( i.length < 3 ) i = ` ${i}`;
-
- return `${i}: ${line.replace( /^\t+/, match => match.split( '\t' ).join( ' ' ) )}`;
- }).join( '\n' );
-}
-
-function tryToLoadJson ( file ) {
- try {
- return JSON.parse( fs.readFileSync( file ) );
- } catch ( err ) {
- if ( err.code !== 'ENOENT' ) throw err;
- return null;
- }
-}
-
-function tryToReadFile ( file ) {
- try {
- return fs.readFileSync( file, 'utf-8' );
- } catch ( err ) {
- if ( err.code !== 'ENOENT' ) throw err;
- return null;
- }
-}
-
-describe( 'svelte', () => {
- before( () => {
- function cleanChildren ( node ) {
- let previous = null;
-
- [ ...node.childNodes ].forEach( child => {
- if ( child.nodeType === 8 ) {
- // comment
- node.removeChild( child );
- return;
- }
-
- if ( child.nodeType === 3 ) {
- child.data = child.data.replace( /\s{2,}/, '\n' );
-
- // text
- if ( previous && previous.nodeType === 3 ) {
- previous.data += child.data;
- previous.data = previous.data.replace( /\s{2,}/, '\n' );
-
- node.removeChild( child );
- }
- }
-
- else {
- cleanChildren( child );
- }
-
- previous = child;
- });
-
- // collapse whitespace
- if ( node.firstChild && node.firstChild.nodeType === 3 ) {
- node.firstChild.data = node.firstChild.data.replace( /^\s+/, '' );
- if ( !node.firstChild.data ) node.removeChild( node.firstChild );
- }
-
- if ( node.lastChild && node.lastChild.nodeType === 3 ) {
- node.lastChild.data = node.lastChild.data.replace( /\s+$/, '' );
- if ( !node.lastChild.data ) node.removeChild( node.lastChild );
- }
- }
-
- return env().then( window => {
- assert.htmlEqual = ( actual, expected, message ) => {
- window.document.body.innerHTML = actual.trim();
- cleanChildren( window.document.body, '' );
- actual = window.document.body.innerHTML;
-
- window.document.body.innerHTML = expected.trim();
- cleanChildren( window.document.body, '' );
- expected = window.document.body.innerHTML;
-
- assert.deepEqual( actual, expected, message );
- };
- });
- });
-
- describe( 'parse', () => {
- fs.readdirSync( 'test/parser' ).forEach( dir => {
- if ( dir[0] === '.' ) return;
-
- const solo = exists( `test/parser/${dir}/solo` );
-
- ( solo ? it.only : it )( dir, () => {
- const input = fs.readFileSync( `test/parser/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
-
- try {
- const actual = svelte.parse( input );
- const expected = require( `./parser/${dir}/output.json` );
-
- assert.deepEqual( actual.html, expected.html );
- assert.deepEqual( actual.css, expected.css );
- assert.deepEqual( actual.js, expected.js );
- } catch ( err ) {
- if ( err.name !== 'ParseError' ) throw err;
-
- try {
- const expected = require( `./parser/${dir}/error.json` );
-
- assert.equal( err.message, expected.message );
- assert.deepEqual( err.loc, expected.loc );
- assert.equal( err.pos, expected.pos );
- } catch ( err2 ) {
- throw err2.code === 'MODULE_NOT_FOUND' ? err : err2;
- }
- }
- });
- });
- });
-
- describe( 'validate', () => {
- fs.readdirSync( 'test/validator' ).forEach( dir => {
- if ( dir[0] === '.' ) return;
-
- const solo = exists( `test/validator/${dir}/solo` );
-
- ( solo ? it.only : it )( dir, () => {
- const input = fs.readFileSync( `test/validator/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
-
- try {
- const parsed = svelte.parse( input );
-
- const errors = [];
- const warnings = [];
-
- const { names } = svelte.validate( parsed, input, {
- onerror ( error ) {
- errors.push({
- message: error.message,
- pos: error.pos,
- loc: error.loc
- });
- },
-
- onwarn ( warning ) {
- warnings.push({
- message: warning.message,
- pos: warning.pos,
- loc: warning.loc
- });
- }
- });
-
- const expectedErrors = tryToLoadJson( `test/validator/${dir}/errors.json` ) || [];
- const expectedWarnings = tryToLoadJson( `test/validator/${dir}/warnings.json` ) || [];
- const expectedNames = tryToLoadJson( `test/validator/${dir}/names.json` ) || [];
-
- assert.deepEqual( errors, expectedErrors );
- assert.deepEqual( warnings, expectedWarnings );
- assert.deepEqual( names, expectedNames );
- } catch ( err ) {
- if ( err.name !== 'ParseError' ) throw err;
-
- try {
- const expected = require( `./validator/${dir}/error.json` );
-
- assert.equal( err.shortMessage, expected.message );
- assert.deepEqual( err.loc, expected.loc );
- assert.equal( err.pos, expected.pos );
- } catch ( err2 ) {
- throw err2.code === 'MODULE_NOT_FOUND' ? err : err2;
- }
- }
- });
- });
- });
-
- describe( 'generate', () => {
- function loadConfig ( dir ) {
- try {
- return require( `./generator/${dir}/_config.js` ).default;
- } catch ( err ) {
- if ( err.code === 'E_NOT_FOUND' ) {
- return {};
- }
-
- throw err;
- }
- }
-
- fs.readdirSync( 'test/generator' ).forEach( dir => {
- if ( dir[0] === '.' ) return;
-
- const config = loadConfig( dir );
-
- ( config.skip ? it.skip : config.solo ? it.only : it )( dir, () => {
- let compiled;
-
- showCompiledCode = config.show;
- compileOptions = config.compileOptions || {};
-
- try {
- const source = fs.readFileSync( `test/generator/${dir}/main.html`, 'utf-8' );
- compiled = svelte.compile( source );
- } catch ( err ) {
- if ( config.compileError ) {
- config.compileError( err );
- return;
- } else {
- throw err;
- }
- }
-
- const { code } = compiled;
-
- // check that no ES2015+ syntax slipped in
- try {
- const startIndex = code.indexOf( 'function renderMainFragment' ); // may change!
- const es5 = spaces( startIndex ) + code.slice( startIndex ).replace( /export default .+/, '' );
- acorn.parse( es5, { ecmaVersion: 5 });
- } catch ( err ) {
- if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
- throw err;
- }
-
- cache[ path.resolve( `test/generator/${dir}/main.html` ) ] = code;
-
- let SvelteComponent;
-
- try {
- SvelteComponent = require( `./generator/${dir}/main.html` ).default;
- } catch ( err ) {
- if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
- throw err;
- }
-
- return env()
- .then( window => {
- // Put the constructor on window for testing
- window.SvelteComponent = SvelteComponent;
-
- const target = window.document.querySelector( 'main' );
-
- const component = new SvelteComponent({
- target,
- data: config.data
- });
-
- if ( config.html ) {
- assert.htmlEqual( target.innerHTML, config.html );
- }
-
- if ( config.test ) {
- config.test( assert, component, target, window );
- } else {
- component.teardown();
- assert.equal( target.innerHTML, '' );
- }
- })
- .catch( err => {
- if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
- throw err;
- });
- });
- });
- });
-
- describe( 'formats', () => {
- function testAmd ( code, expectedId, dependencies, html ) {
- const fn = new Function( 'define', code );
-
- return env().then( window => {
- function define ( id, deps, factory ) {
- assert.equal( id, expectedId );
- assert.deepEqual( deps, Object.keys( dependencies ) );
-
- const SvelteComponent = factory( ...Object.keys( dependencies ).map( key => dependencies[ key ] ) );
-
- const main = window.document.body.querySelector( 'main' );
- const component = new SvelteComponent({ target: main });
-
- assert.htmlEqual( main.innerHTML, html );
-
- component.teardown();
- }
-
- define.amd = true;
-
- fn( define );
- });
- }
-
- function testCjs ( code, dependencyById, html ) {
- const fn = new Function( 'module', 'exports', 'require', code );
-
- return env().then( window => {
- const module = { exports: {} };
- const require = id => {
- return dependencyById[ id ];
- };
-
- fn( module, module.exports, require );
-
- const SvelteComponent = module.exports;
-
- const main = window.document.body.querySelector( 'main' );
- const component = new SvelteComponent({ target: main });
-
- assert.htmlEqual( main.innerHTML, html );
-
- component.teardown();
- });
- }
-
- function testIife ( code, name, globals, html ) {
- const fn = new Function( Object.keys( globals ), `${code}\n\nreturn ${name};` );
-
- return env().then( window => {
- const SvelteComponent = fn( ...Object.keys( globals ).map( key => globals[ key ] ) );
-
- const main = window.document.body.querySelector( 'main' );
- const component = new SvelteComponent({ target: main });
-
- assert.htmlEqual( main.innerHTML, html );
-
- component.teardown();
- });
- }
-
- describe( 'amd', () => {
- it( 'generates an AMD module', () => {
- const source = deindent`
- {{answer}}
-
-
- `;
-
- const { code } = svelte.compile( source, {
- format: 'amd',
- amd: { id: 'foo' }
- });
-
- return testAmd( code, 'foo', { answer: 42 }, `42
` );
- });
- });
-
- describe( 'cjs', () => {
- it( 'generates a CommonJS module', () => {
- const source = deindent`
- {{answer}}
-
-
- `;
-
- const { code } = svelte.compile( source, {
- format: 'cjs'
- });
-
- return testCjs( code, { answer: 42 }, `42
` );
- });
- });
-
- describe( 'iife', () => {
- it( 'generates a self-executing script', () => {
- const source = deindent`
- {{answer}}
-
-
- `;
-
- const { code } = svelte.compile( source, {
- format: 'iife',
- name: 'Foo',
- globals: {
- answer: 'answer'
- }
- });
-
- return testIife( code, 'Foo', { answer: 42 }, `42
` );
- });
- });
-
- describe( 'umd', () => {
- it( 'generates a UMD build', () => {
- const source = deindent`
- {{answer}}
-
-
- `;
-
- const { code } = svelte.compile( source, {
- format: 'umd',
- name: 'Foo',
- globals: {
- answer: 'answer'
- },
- amd: {
- id: 'foo'
- }
- });
-
- return testAmd( code, 'foo', { answer: 42 }, `42
` )
- .then( () => testCjs( code, { answer: 42 }, `42
` ) )
- .then( () => testIife( code, 'Foo', { answer: 42 }, `42
` ) );
- });
- });
- });
-
- describe( 'sourcemaps', () => {
- fs.readdirSync( 'test/sourcemaps' ).forEach( dir => {
- if ( dir[0] === '.' ) return;
-
- const solo = exists( `test/sourcemaps/${dir}/solo` );
-
- ( solo ? it.only : it )( dir, () => {
- const input = fs.readFileSync( `test/sourcemaps/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
- const { code, map } = svelte.compile( input );
-
- fs.writeFileSync( `test/sourcemaps/${dir}/output.js`, `${code}\n//# sourceMappingURL=output.js.map` );
- fs.writeFileSync( `test/sourcemaps/${dir}/output.js.map`, JSON.stringify( map, null, ' ' ) );
-
- const { test } = require( `./sourcemaps/${dir}/test.js` );
-
- const smc = new SourceMapConsumer( map );
-
- const locateInSource = getLocator( input );
- const locateInGenerated = getLocator( code );
-
- test({ assert, code, map, smc, locateInSource, locateInGenerated });
- });
- });
- });
-
- describe( 'ssr', () => {
- before( () => {
- require( '../ssr/register' );
- });
-
- fs.readdirSync( 'test/server-side-rendering' ).forEach( dir => {
- if ( dir[0] === '.' ) return;
-
- const solo = exists( `test/server-side-rendering/${dir}/solo` );
-
- ( solo ? it.only : it )( dir, () => {
- const component = require( `./server-side-rendering/${dir}/main.html` );
-
- const expectedHtml = tryToReadFile( `test/server-side-rendering/${dir}/_expected.html` );
- const expectedCss = tryToReadFile( `test/server-side-rendering/${dir}/_expected.css` ) || '';
-
- const data = tryToLoadJson( `test/server-side-rendering/${dir}/data.json` );
- const html = component.render( data );
- const { css } = component.renderCss();
-
- fs.writeFileSync( `test/server-side-rendering/${dir}/_actual.html`, html );
- if ( css ) fs.writeFileSync( `test/server-side-rendering/${dir}/_actual.css`, css );
-
- assert.htmlEqual( html, expectedHtml );
- assert.equal( css.replace( /^\s+/gm, '' ), expectedCss.replace( /^\s+/gm, '' ) );
- });
- });
- });
-});
diff --git a/test/validate.js b/test/validate.js
new file mode 100644
index 0000000000..597c9d7526
--- /dev/null
+++ b/test/validate.js
@@ -0,0 +1,60 @@
+import * as fs from 'fs';
+import assert from 'assert';
+import { svelte, exists, tryToLoadJson } from './helpers.js';
+
+describe( 'validate', () => {
+ fs.readdirSync( 'test/validator' ).forEach( dir => {
+ if ( dir[0] === '.' ) return;
+
+ const solo = exists( `test/validator/${dir}/solo` );
+
+ ( solo ? it.only : it )( dir, () => {
+ const input = fs.readFileSync( `test/validator/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
+
+ try {
+ const parsed = svelte.parse( input );
+
+ const errors = [];
+ const warnings = [];
+
+ const { names } = svelte.validate( parsed, input, {
+ onerror ( error ) {
+ errors.push({
+ message: error.message,
+ pos: error.pos,
+ loc: error.loc
+ });
+ },
+
+ onwarn ( warning ) {
+ warnings.push({
+ message: warning.message,
+ pos: warning.pos,
+ loc: warning.loc
+ });
+ }
+ });
+
+ const expectedErrors = tryToLoadJson( `test/validator/${dir}/errors.json` ) || [];
+ const expectedWarnings = tryToLoadJson( `test/validator/${dir}/warnings.json` ) || [];
+ const expectedNames = tryToLoadJson( `test/validator/${dir}/names.json` ) || [];
+
+ assert.deepEqual( errors, expectedErrors );
+ assert.deepEqual( warnings, expectedWarnings );
+ assert.deepEqual( names, expectedNames );
+ } catch ( err ) {
+ if ( err.name !== 'ParseError' ) throw err;
+
+ try {
+ const expected = require( `./validator/${dir}/error.json` );
+
+ assert.equal( err.shortMessage, expected.message );
+ assert.deepEqual( err.loc, expected.loc );
+ assert.equal( err.pos, expected.pos );
+ } catch ( err2 ) {
+ throw err2.code === 'MODULE_NOT_FOUND' ? err : err2;
+ }
+ }
+ });
+ });
+});