diff --git a/test/useable.test.js b/test/useable.test.js
index 981da074..0e1a945d 100644
--- a/test/useable.test.js
+++ b/test/useable.test.js
@@ -8,30 +8,136 @@ var loaderUtils = require('loader-utils');
var useable = require("../useable");
describe("useable tests", function () {
- var sandbox = sinon.sandbox.create();
- var getOptions;
+ describe('hmr', function () {
+ var sandbox = sinon.sandbox.create();
+ var getOptions;
- beforeEach(() => {
- // Mock loaderUtils to override options
- getOptions = sandbox.stub(loaderUtils, 'getOptions');
- });
+ beforeEach(() => {
+ // Mock loaderUtils to override options
+ getOptions = sandbox.stub(loaderUtils, 'getOptions');
+ });
- afterEach(() => {
- sandbox.restore();
- });
+ afterEach(() => {
+ sandbox.restore();
+ });
- it("should output HMR code by default", function () {
- assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
- });
+ it("should output HMR code by default", function () {
+ assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
+ });
- it("should NOT output HMR code when options.hmr is false", function () {
- getOptions.returns({hmr: false});
- assert.equal(/(module\.hot)/g.test(useable.pitch()), false);
+ it("should NOT output HMR code when options.hmr is false", function () {
+ getOptions.returns({hmr: false});
+ assert.equal(/(module\.hot)/g.test(useable.pitch()), false);
+ });
+
+ it("should output HMR code when options.hmr is true", function () {
+ getOptions.returns({hmr: true});
+ assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
+ });
});
- it("should output HMR code when options.hmr is true", function () {
- getOptions.returns({hmr: true});
- assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
+ describe('insert into', function () {
+ var path = require("path");
+
+ var utils = require("./utils"),
+ runCompilerTest = utils.runCompilerTest;
+
+ var fs;
+
+ var requiredCss = ".required { color: blue }",
+ requiredCssTwo = ".requiredTwo { color: cyan }",
+ localScopedCss = ":local(.className) { background: red; }",
+ localComposingCss = `
+ :local(.composingClass) {
+ composes: className from './localScoped.css';
+ color: blue;
+ }
+ `,
+ requiredStyle = ``,
+ existingStyle = ``,
+ checkValue = '
check
',
+ rootDir = path.resolve(__dirname + "/../") + "/",
+ jsdomHtml = [
+ "",
+ "",
+ existingStyle,
+ "",
+ "",
+ "",
+ checkValue,
+ "
",
+ "",
+ "",
+ ""
+ ].join("\n"),
+ requiredJS = [
+ "var el = document.createElement('div');",
+ "el.id = \"test-shadow\";",
+ "document.body.appendChild(el)",
+ "var css = require('./style.css');",
+ "css.use();",
+ ].join("\n");
+
+ var styleLoaderOptions = {};
+ var cssRule = {};
+
+ var defaultCssRule = {
+ test: /\.css?$/,
+ use: [
+ {
+ loader: "style-loader/useable",
+ options: styleLoaderOptions
+ },
+ "css-loader"
+ ]
+ };
+
+ var webpackConfig = {
+ entry: "./main.js",
+ output: {
+ filename: "bundle.js"
+ },
+ module: {
+ rules: [cssRule]
+ }
+ };
+
+ var setupWebpackConfig = function() {
+ fs = utils.setup(webpackConfig, jsdomHtml);
+
+ // Create a tiny file system. rootDir is used because loaders are referring to absolute paths.
+ fs.mkdirpSync(rootDir);
+ fs.writeFileSync(rootDir + "main.js", requiredJS);
+ fs.writeFileSync(rootDir + "style.css", requiredCss);
+ fs.writeFileSync(rootDir + "styleTwo.css", requiredCssTwo);
+ fs.writeFileSync(rootDir + "localScoped.css", localScopedCss);
+ fs.writeFileSync(rootDir + "localComposing.css", localComposingCss);
+ };
+
+ beforeEach(function() {
+ // Reset all style-loader options
+ for (var member in styleLoaderOptions) {
+ delete styleLoaderOptions[member];
+ }
+
+ for (var member in defaultCssRule) {
+ cssRule[member] = defaultCssRule[member];
+ }
+
+ setupWebpackConfig();
+ }); // before each
+
+ it("insert into iframe", function(done) {
+ let selector = "iframe.iframeTarget";
+ styleLoaderOptions.insertInto = selector;
+
+ let expected = requiredStyle;
+
+ runCompilerTest(expected, done, function() {
+ return this.document.querySelector(selector).contentDocument.head.innerHTML;
+ }, selector);
+ }); // it insert into
+
});
});
diff --git a/useable.js b/useable.js
index 01320053..8fabe263 100644
--- a/useable.js
+++ b/useable.js
@@ -18,6 +18,21 @@ module.exports.pitch = function (request) {
options.hmr = typeof options.hmr === 'undefined' ? true : options.hmr;
+ // The variable is needed, because the function should be inlined.
+ // If is just stored it in options, JSON.stringify will quote
+ // the function and it would be just a string at runtime
+ var insertInto;
+
+ if (typeof options.insertInto === "function") {
+ insertInto = options.insertInto.toString();
+ }
+
+ // We need to check if it a string, or variable will be "undefined"
+ // and the loader crashes
+ if (typeof options.insertInto === "string") {
+ insertInto = '"' + options.insertInto + '"';
+ }
+
var hmr = [
// Hot Module Replacement
"if(module.hot) {",
@@ -48,6 +63,8 @@ module.exports.pitch = function (request) {
"var refs = 0;",
"var dispose;",
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
+ "var options = " + JSON.stringify(options) + ";",
+ "options.insertInto = " + insertInto + ";",
"",
"if(typeof content === 'string') content = [[module.id, content, '']];",
// Export CSS Modules
@@ -55,7 +72,7 @@ module.exports.pitch = function (request) {
"",
"exports.use = exports.ref = function() {",
" if(!(refs++)) {",
- " dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, " + JSON.stringify(options) + ");",
+ " dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, options);",
" }",
"",
" return exports;",