mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
272 lines
7.5 KiB
JavaScript
272 lines
7.5 KiB
JavaScript
"use strict";
|
|
|
|
require("../__util__/test-init");
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const marko = require("marko");
|
|
const autotest = require("../autotest");
|
|
const domToString = require("../__util__/domToString");
|
|
const createBrowserWithMarko = require("../__util__/create-marko-jsdom-module");
|
|
const expect = require("chai").expect;
|
|
const toDiffableHtml = require("diffable-html");
|
|
const browser = createBrowserWithMarko(__dirname, "<html><body></body></html>");
|
|
|
|
autotest("fixtures", {
|
|
html: testRunner,
|
|
vdom: testRunner,
|
|
"html ≅ vdom": compareNormalized
|
|
});
|
|
|
|
autotest("fixtures-deprecated", {
|
|
html: testRunner,
|
|
vdom: testRunner,
|
|
"html ≅ vdom": compareNormalized
|
|
});
|
|
|
|
autotest("fixtures-async-callback", {
|
|
html: testRunner
|
|
});
|
|
|
|
autotest("fixtures-async-deprecated", {
|
|
html: testRunner
|
|
});
|
|
|
|
function testRunner(fixture) {
|
|
fixture.test(() => runRenderTest(fixture));
|
|
}
|
|
|
|
function compareNormalized({ test, context }) {
|
|
test(function() {
|
|
if (
|
|
!context.hasOwnProperty("html") ||
|
|
!context.hasOwnProperty("vdom")
|
|
) {
|
|
this.skip();
|
|
} else {
|
|
expect(context.html).to.equal(context.vdom);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function runRenderTest(fixture) {
|
|
let dir = fixture.dir;
|
|
let output = fixture.mode || "html";
|
|
let snapshot = fixture.snapshot;
|
|
let isVDOM = output === "vdom";
|
|
|
|
let templatePath = path.join(dir, "template.marko");
|
|
let mainPath = path.join(dir, "test.js");
|
|
let main = !fs.existsSync(mainPath)
|
|
? {}
|
|
: isVDOM
|
|
? browser.require(mainPath)
|
|
: require(mainPath);
|
|
let loadOptions = main && main.loadOptions;
|
|
|
|
try {
|
|
var compilerOptions = {
|
|
output: output,
|
|
writeToDisk: main.writeToDisk !== false,
|
|
preserveWhitespace: main.preserveWhitespaceGlobal === true,
|
|
ignoreUnrecognizedTags: main.ignoreUnrecognizedTags === true
|
|
};
|
|
|
|
require("marko/compiler").configure(compilerOptions);
|
|
|
|
if (main.checkError) {
|
|
let e;
|
|
|
|
try {
|
|
isVDOM
|
|
? browser.require(templatePath)
|
|
: marko.load(templatePath, loadOptions);
|
|
} catch (_e) {
|
|
e = _e;
|
|
let errorFile = path.join(dir, "error.txt");
|
|
fs.writeFileSync(errorFile, e.stack.toString(), {
|
|
encoding: "utf8"
|
|
});
|
|
}
|
|
|
|
if (!e) {
|
|
throw new Error("Error expected");
|
|
}
|
|
|
|
main.checkError(e);
|
|
return;
|
|
} else {
|
|
let template = isVDOM
|
|
? browser.require(templatePath)
|
|
: marko.load(templatePath, loadOptions);
|
|
let templateData = Object.assign({}, main.templateData || {});
|
|
|
|
if (template.default) {
|
|
template = template.default;
|
|
}
|
|
|
|
let out = template.createOut();
|
|
let asyncEventsVerifier = createAsyncVerifier(
|
|
main,
|
|
snapshot,
|
|
out,
|
|
main.noFlushComment,
|
|
isVDOM
|
|
);
|
|
|
|
template.render(templateData, out).end();
|
|
|
|
if (isVDOM) {
|
|
let document = browser.window.document;
|
|
let actualNode = document.createDocumentFragment();
|
|
if (out.___state.___finished) {
|
|
out.___getResult().replaceChildrenOf(actualNode);
|
|
} else {
|
|
(await out).replaceChildrenOf(actualNode);
|
|
}
|
|
|
|
actualNode.normalize();
|
|
let vdomString = domToString(actualNode, {
|
|
childrenOnly: true
|
|
});
|
|
|
|
snapshot(vdomString, {
|
|
name: "vdom",
|
|
ext: ".html"
|
|
});
|
|
|
|
fixture.context.vdom = normalizeHtml(actualNode);
|
|
} else {
|
|
let html = (await out).getOutput();
|
|
|
|
if (main.checkHtml) {
|
|
fs.writeFileSync(path.join(dir, "actual.html"), html, {
|
|
encoding: "utf8"
|
|
});
|
|
main.checkHtml(html);
|
|
} else {
|
|
snapshot(html, {
|
|
ext: ".html",
|
|
format: toDiffableHtml
|
|
});
|
|
}
|
|
|
|
fixture.context.html = normalizeHtml(html);
|
|
}
|
|
|
|
asyncEventsVerifier.verify();
|
|
}
|
|
} finally {
|
|
require("marko/compiler").configure();
|
|
}
|
|
}
|
|
|
|
function normalizeHtml(htmlOrNode) {
|
|
let document = browser.window.document;
|
|
|
|
if (typeof htmlOrNode === "string") {
|
|
document.open();
|
|
document.write(htmlOrNode);
|
|
document.close();
|
|
} else {
|
|
document.documentElement.innerHTML = "";
|
|
document.body.appendChild(htmlOrNode);
|
|
}
|
|
|
|
const treeWalker = document.createTreeWalker(document.body);
|
|
const nodesToRemove = [];
|
|
|
|
while (treeWalker.nextNode()) {
|
|
const node = treeWalker.currentNode;
|
|
if (
|
|
node.nodeType === 8 ||
|
|
isIgnoredTag(node) ||
|
|
isClientReorderFragment(node)
|
|
) {
|
|
nodesToRemove.push(node);
|
|
} else if (node.tagName === "TEXTAREA") {
|
|
node.textContent = node.value;
|
|
}
|
|
}
|
|
|
|
nodesToRemove.forEach(n => n.remove());
|
|
document.body.innerHTML = document.body.innerHTML;
|
|
document.body.normalize();
|
|
|
|
return document.body.innerHTML.trim();
|
|
}
|
|
|
|
function isIgnoredTag(node) {
|
|
switch (node.tagName) {
|
|
case "LINK":
|
|
case "TITLE":
|
|
case "STYLE":
|
|
case "SCRIPT":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function isClientReorderFragment(node) {
|
|
return /^af\d+$/.test(node.id);
|
|
}
|
|
|
|
function createAsyncVerifier(main, snapshot, out, noFlushComment, isVDOM) {
|
|
var events = [];
|
|
var eventsByAwaitInstance = {};
|
|
|
|
var addEventListener = function(event) {
|
|
out.on(event, function(arg) {
|
|
var name = arg.name;
|
|
|
|
if (!eventsByAwaitInstance[name]) {
|
|
eventsByAwaitInstance[name] = [];
|
|
}
|
|
|
|
eventsByAwaitInstance[name].push(event);
|
|
|
|
events.push({
|
|
event: event,
|
|
arg: Object.assign({}, arg)
|
|
});
|
|
});
|
|
};
|
|
|
|
addEventListener("await:begin");
|
|
addEventListener("await:beforeRender");
|
|
addEventListener("await:finish");
|
|
|
|
if (!isVDOM && !noFlushComment) {
|
|
var _flush = out.flush;
|
|
out.flush = function() {
|
|
try {
|
|
out.comment("FLUSH");
|
|
} catch (e) {
|
|
// we may try to flush after the out has ended
|
|
// if this is the case, trying to add a comment
|
|
// will throw an error. we can safely ignore this
|
|
}
|
|
_flush && _flush.apply(out, arguments);
|
|
};
|
|
}
|
|
|
|
return {
|
|
verify() {
|
|
if (main.checkEvents && !isVDOM) {
|
|
main.checkEvents(events, snapshot, out);
|
|
}
|
|
|
|
// Make sure all of the await instances were correctly ended
|
|
Object.keys(eventsByAwaitInstance).forEach(function(name) {
|
|
var events = eventsByAwaitInstance[name];
|
|
expect(events).to.deep.equal([
|
|
"await:begin",
|
|
"await:beforeRender",
|
|
"await:finish"
|
|
]);
|
|
});
|
|
}
|
|
};
|
|
}
|