Skip to content

Commit

Permalink
Add nunjucks compiler for helping with tests when requiring nunjucks …
Browse files Browse the repository at this point in the history
…views
  • Loading branch information
ediblecode committed May 24, 2017
1 parent 2dd9682 commit 7f831e1
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 14 deletions.
23 changes: 11 additions & 12 deletions test/_setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
* Setup dependencies for Mocha tests
*/

import sinon from "sinon";
import chai from "chai";
import chaiAsPromised from "chai-as-promised";
import sinonChai from "sinon-chai";
import jsdom from "jsdom";
require("./nunjucks-compiler.js");

var sinon = require("sinon");
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
var sinonChai = require("sinon-chai");

var testHelpers = require("./test-helpers");

// Setup chai, see https://github.com/domenic/sinon-chai/blob/master/test/common.js
global.chai = chai;
Expand All @@ -22,11 +25,7 @@ chai.use(chaiAsPromised);
global.sinon = sinon;
global.chai.use(sinonChai);

// Setup jsdom for faking dom and jquery
global.document = jsdom.jsdom("<html><head></head><body></body></html>");
global.window = document.defaultView;

// Loading jQuery doesn't work with ES6 import
global.jQuery = global.$ = require("jquery");

global.PRODUCTION = false;

// Setup a fake docm
testHelpers.setupDOM();
55 changes: 55 additions & 0 deletions test/nunjucks-compiler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Compiler for nunjucks templates when using Mocha, based on
// http://www.hammerlab.org/2015/02/14/testing-react-web-apps-with-mocha/
// and
// https://github.com/at0g/nunjucks-loader/blob/master/index.js.
// Similar to https://github.com/rotundasoftware/nunjucksify
//
// The reason is that templates are loaded with webpack via nunjucks-loader.
// By default Mocha would try and load the template as JS.
// This compiler intercepts the call to require the njk template and does the following:
// - Loads the nunjucks template
// - Precompiles it
// - Compiles a module for the template
//
// This then stops Mocha breaking and code can continue to require templates as normal e.g.:
//
// import template from "./some-template.njk";
// var str = template.render({ some: "data" });

var fs = require("fs"),
nunjucks = require("nunjucks"),
orig = require.extensions[".njk"];

require.extensions[".njk"] = function njk(module, filename) {

// optimization: external code never needs compilation.
if (filename.indexOf("node_modules/") >= 0) {
return (orig || require.extensions[".njk"])(module, filename);
}
var content = fs.readFileSync(filename, "utf8");

var env = new nunjucks.Environment();

var name = "test";

var nunjucksCompiledStr = nunjucks.precompileString(content, {
name: name,
env: env
});

nunjucksCompiledStr = nunjucksCompiledStr.replace(/window\.nunjucksPrecompiled/g, "nunjucks.nunjucksPrecompiled");

var compiledTemplate = "";
compiledTemplate += "var nunjucks = require(\"nunjucks\");\n";
compiledTemplate += "var env;\n";
compiledTemplate += "if (!nunjucks.currentEnv){\n";
compiledTemplate += "\tenv = nunjucks.currentEnv = new nunjucks.Environment([], { autoescape: true });\n";
compiledTemplate += "} else {\n";
compiledTemplate += "\tenv = nunjucks.currentEnv;\n";
compiledTemplate += "}\n";
compiledTemplate += nunjucksCompiledStr + ";\n";
compiledTemplate += "var src = { obj: nunjucks.nunjucksPrecompiled[\"" + name + "\"], type: \"code\" };\n\n";
compiledTemplate += "module.exports = new nunjucks.Template(src, env)";

return module._compile(compiledTemplate, filename);
};
42 changes: 40 additions & 2 deletions test/test-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

const fs = require("fs"),
path = require("path"),
nunjucks = require("nunjucks");
nunjucks = require("nunjucks"),
jsdom = require("jsdom");

/**
* Loads and renders a component template from the given name, with the given data.
Expand All @@ -21,6 +22,43 @@ function renderComponent(name, data) {
return nunjucks.renderString(`${ template}{{ ${ name }(content) }}"`, { content: data });
}

/**
* Constructs a fake DOM.
* return {Object} The setup values
*/
function setupDOM() {
const setupValues = {};

// Setup jsdom for faking dom and jquery
setupValues.document = jsdom.jsdom("<!doctype html><html><head><title>Test</title></head><body><div id='main'></div></body></html>");
setupValues.window = setupValues.document.defaultView;

// Loading jQuery doesn't work with ES6 import
// jQuery works with the window object from above
setupValues.jQuery = setupValues.$ = require("jquery")(setupValues.window);

// Copy HTML elements to global scope, for use in flow type annotations
setupValues.HTMLElement = setupValues.window.HTMLElement;
setupValues.HTMLHeadingElement = setupValues.window.HTMLHeadingElement;

// 'Fake matchMedia for use in jsdom
setupValues.window.matchMedia = setupValues.window.matchMedia || function() {
return {
matches: false,
addListener: () => {},
removeListener: () => {}
};
};

// Copy values to the global scope, e.g. $ etc
for (var key in setupValues) {
global[key] = setupValues[key];
}

return setupValues;
}

module.exports = {
renderComponent: renderComponent
renderComponent: renderComponent,
setupDOM: setupDOM
};

0 comments on commit 7f831e1

Please sign in to comment.