0
0
mirror of https://github.com/sveltejs/svelte.git synced 2024-11-30 08:56:14 +01:00
svelte/test/helpers.js

245 lines
5.5 KiB
JavaScript
Raw Normal View History

import jsdom from 'jsdom';
import assert from 'assert';
2018-04-30 02:25:12 +02:00
import glob from 'tiny-glob/sync.js';
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
// for coverage purposes, we need to test source files,
// but for sanity purposes, we need to test dist files
2017-06-03 04:04:36 +02:00
export function loadSvelte(test) {
2017-11-23 14:45:22 +01:00
process.env.TEST = test ? 'true' : '';
2017-11-23 14:45:22 +01:00
const resolved = require.resolve('../compiler/svelte.js');
2017-06-03 04:04:36 +02:00
delete require.cache[resolved];
return require(resolved);
}
export const svelte = loadSvelte();
2017-06-03 04:04:36 +02:00
export function exists(path) {
try {
2017-06-03 04:04:36 +02:00
fs.statSync(path);
return true;
2017-06-03 04:04:36 +02:00
} catch (err) {
return false;
}
}
2017-06-03 04:04:36 +02:00
export function tryToLoadJson(file) {
try {
2017-06-03 04:04:36 +02:00
return JSON.parse(fs.readFileSync(file));
} catch (err) {
if (err.code !== 'ENOENT') throw err;
return null;
}
}
2017-06-03 04:04:36 +02:00
export function tryToReadFile(file) {
try {
return fs.readFileSync(file, 'utf-8');
2017-06-03 04:04:36 +02:00
} catch (err) {
if (err.code !== 'ENOENT') throw err;
return null;
}
}
export const virtualConsole = new jsdom.VirtualConsole();
2018-08-04 02:03:15 +02:00
const { window } = new jsdom.JSDOM('<main></main>', {virtualConsole});
2017-07-30 05:55:56 +02:00
global.document = window.document;
2017-06-03 04:04:36 +02:00
export function env() {
2017-07-30 05:55:56 +02:00
window._svelteTransitionManager = null;
window.document.body.innerHTML = '<main></main>';
2017-07-30 04:26:22 +02:00
return window;
}
2017-06-03 04:04:36 +02:00
function cleanChildren(node) {
let previous = null;
2017-07-02 05:27:02 +02:00
// sort attributes
const attributes = Array.from(node.attributes).sort((a, b) => {
return a.name < b.name ? -1 : 1;
});
attributes.forEach(attr => {
node.removeAttribute(attr.name);
});
attributes.forEach(attr => {
node.setAttribute(attr.name, attr.value);
});
// recurse
2017-06-03 04:04:36 +02:00
[...node.childNodes].forEach(child => {
if (child.nodeType === 3) {
2017-08-26 21:50:19 +02:00
// text
2017-06-03 04:04:36 +02:00
if (
node.namespaceURI === 'http://www.w3.org/2000/svg' &&
node.tagName !== 'text' &&
node.tagName !== 'tspan'
2017-06-03 04:04:36 +02:00
) {
node.removeChild(child);
2017-01-24 23:03:14 +01:00
}
2017-08-26 21:50:19 +02:00
child.data = child.data.replace(/\s{2,}/g, '\n');
2017-06-03 04:04:36 +02:00
if (previous && previous.nodeType === 3) {
previous.data += child.data;
2017-08-26 21:50:19 +02:00
previous.data = previous.data.replace(/\s{2,}/g, '\n');
2017-06-03 04:04:36 +02:00
node.removeChild(child);
2017-05-05 18:10:37 +02:00
child = previous;
}
2017-06-03 04:04:36 +02:00
} else {
cleanChildren(child);
}
previous = child;
});
// collapse whitespace
2017-06-03 04:04:36 +02:00
if (node.firstChild && node.firstChild.nodeType === 3) {
node.firstChild.data = node.firstChild.data.replace(/^\s+/, '');
2017-06-03 04:04:36 +02:00
if (!node.firstChild.data) node.removeChild(node.firstChild);
}
2017-06-03 04:04:36 +02:00
if (node.lastChild && node.lastChild.nodeType === 3) {
node.lastChild.data = node.lastChild.data.replace(/\s+$/, '');
2017-06-03 04:04:36 +02:00
if (!node.lastChild.data) node.removeChild(node.lastChild);
}
}
2017-07-02 05:27:02 +02:00
export function normalizeHtml(window, html) {
try {
const node = window.document.createElement('div');
node.innerHTML = html
.replace(/<!--.*?-->/g, '')
.replace(/>[\s\r\n]+</g, '><')
.trim();
cleanChildren(node, '');
return node.innerHTML.replace(/<\/?noscript\/?>/g, '');
} catch (err) {
throw new Error(`Failed to normalize HTML:\n${html}`);
}
2017-07-02 05:27:02 +02:00
}
2017-06-03 04:04:36 +02:00
export function setupHtmlEqual() {
2017-07-30 04:26:22 +02:00
const window = env();
assert.htmlEqual = (actual, expected, message) => {
assert.deepEqual(
normalizeHtml(window, actual),
normalizeHtml(window, expected),
message
);
};
}
2017-06-03 04:04:36 +02:00
export function loadConfig(file) {
try {
2017-06-03 04:04:36 +02:00
const resolved = require.resolve(file);
delete require.cache[resolved];
2017-07-30 07:04:23 +02:00
const config = require(resolved);
return config.default || config;
2017-06-03 04:04:36 +02:00
} catch (err) {
2017-07-22 02:37:45 +02:00
if (err.code === 'MODULE_NOT_FOUND') {
return {};
}
throw err;
}
}
2017-06-03 04:04:36 +02:00
export function addLineNumbers(code) {
return code
.split('\n')
2017-06-03 04:04:36 +02:00
.map((line, i) => {
i = String(i + 1);
while (i.length < 3) i = ` ${i}`;
return (
chalk.grey(` ${i}: `) +
line.replace(/^\t+/, match => match.split('\t').join(' '))
);
2017-06-03 04:04:36 +02:00
})
.join('\n');
}
2017-06-25 20:15:06 +02:00
function capitalise(str) {
return str[0].toUpperCase() + str.slice(1);
}
export function showOutput(cwd, options = {}, compile = svelte.compile) {
2018-04-30 02:25:12 +02:00
glob('**/*.html', { cwd }).forEach(file => {
2017-06-13 23:54:59 +02:00
if (file[0] === '_') return;
const name = path.basename(file)
.slice(0, -path.extname(file).length)
.replace(/^\d/, '_$&')
.replace(/[^a-zA-Z0-9_$]/g, '');
2018-04-16 02:07:08 +02:00
const { js } = compile(
fs.readFileSync(`${cwd}/${file}`, 'utf-8'),
Object.assign(options, {
2017-06-25 20:15:06 +02:00
filename: file,
2018-04-16 06:05:51 +02:00
name: capitalise(name)
})
);
2017-06-11 20:00:24 +02:00
console.log( // eslint-disable-line no-console
2018-04-16 02:07:08 +02:00
`\n>> ${chalk.cyan.bold(file)}\n${addLineNumbers(js.code)}\n<< ${chalk.cyan.bold(file)}`
);
});
}
const start = /\n(\t+)/;
export function deindent(strings, ...values) {
const indentation = start.exec(strings[0])[1];
const pattern = new RegExp(`^${indentation}`, 'gm');
let result = strings[0].replace(start, '').replace(pattern, '');
let trailingIndentation = getTrailingIndentation(result);
for (let i = 1; i < strings.length; i += 1) {
let expression = values[i - 1];
const string = strings[i].replace(pattern, '');
if (Array.isArray(expression)) {
expression = expression.length ? expression.join('\n') : null;
}
if (expression || expression === '') {
const value = String(expression).replace(
/\n/g,
`\n${trailingIndentation}`
);
result += value + string;
} else {
let c = result.length;
while (/\s/.test(result[c - 1])) c -= 1;
result = result.slice(0, c) + string;
}
trailingIndentation = getTrailingIndentation(result);
}
return result.trim().replace(/\t+$/gm, '');
}
function getTrailingIndentation(str) {
let i = str.length;
while (str[i - 1] === ' ' || str[i - 1] === '\t') i -= 1;
return str.slice(i, str.length);
}
export function spaces(i) {
let result = '';
while (i--) result += ' ';
return result;
}