Skip to content

Commit

Permalink
refactor: tests (#389)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Jul 29, 2019
1 parent 212525c commit dd32fad
Show file tree
Hide file tree
Showing 9 changed files with 681 additions and 203 deletions.
3 changes: 2 additions & 1 deletion src/runtime/addStyleUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function addAttrs(element, attrs) {
}

module.exports = function addStyleUrl(url, options) {
/* istanbul ignore if */
if (typeof DEBUG !== 'undefined' && DEBUG) {
if (typeof document !== 'object') {
throw new Error(
Expand All @@ -29,7 +30,7 @@ module.exports = function addStyleUrl(url, options) {

addAttrs(link, options.attrs);

const [head] = document.getElementsByTagName('head');
const head = document.getElementsByTagName('head')[0];

head.appendChild(link);

Expand Down
13 changes: 11 additions & 2 deletions src/runtime/addStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ var getElement = (function() {
// due to cross-origin restrictions
styleTarget = styleTarget.contentDocument.head;
} catch (e) {
// istanbul ignore next
styleTarget = null;
}
}
Expand All @@ -73,6 +74,7 @@ var singletonCounter = 0;
var stylesInsertedAtTop = [];

module.exports = function(list, options) {
/* istanbul ignore if */
if (typeof DEBUG !== 'undefined' && DEBUG) {
if (typeof document !== 'object') {
throw new Error(
Expand Down Expand Up @@ -112,8 +114,10 @@ module.exports = function(list, options) {
var item = styles[i];
var domStyle = stylesInDom[item.id];

domStyle.refs--;
mayRemove.push(domStyle);
if (domStyle) {
domStyle.refs--;
mayRemove.push(domStyle);
}
}

if (newList) {
Expand Down Expand Up @@ -323,6 +327,7 @@ function addStyle(obj, options) {
};
}

/* istanbul ignore next */
var replaceText = (function() {
var textStore = [];

Expand All @@ -336,6 +341,8 @@ var replaceText = (function() {
function applyToSingletonTag(style, index, remove, obj) {
var css = remove ? '' : obj.css;

// For old IE
/* istanbul ignore if */
if (style.styleSheet) {
style.styleSheet.cssText = replaceText(index, css);
} else {
Expand Down Expand Up @@ -374,6 +381,8 @@ function applyToTag(style, obj) {
' */';
}

// For old IE
/* istanbul ignore if */
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
Expand Down
176 changes: 176 additions & 0 deletions test/basic.test.js → test/loader.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* eslint-env browser */
const path = require('path');

const loaderUtils = require('loader-utils');

const url = require('../url');
const useable = require('../useable');

const utils = require('./utils');

describe('basic tests', () => {
Expand Down Expand Up @@ -619,3 +624,174 @@ describe('basic tests', () => {
});
});
});

describe('url tests', () => {
let getOptions;
let origGetOptions;

beforeEach(() => {
getOptions = jest.fn();

origGetOptions = loaderUtils.getOptions;
// Mock loaderUtils to override options
loaderUtils.getOptions = getOptions;
});

afterEach(() => {
loaderUtils.getOptions = origGetOptions;
});

it('should output HMR code by default', () => {
expect(/(module\.hot)/g.test(url.pitch())).toBe(true);
});

it('should NOT output HMR code when options.hmr is false', () => {
getOptions.mockReturnValue({ hmr: false });

expect(/(module\.hot)/g.test(url.pitch())).toBe(false);
});

it('should output HMR code when options.hmr is true', () => {
getOptions.mockReturnValue({ hmr: true });

expect(/(module\.hot)/g.test(url.pitch())).toBe(true);
});
});

describe('useable tests', () => {
describe('insert into', () => {
const { runCompilerTest } = utils;

let fs;

const requiredCss = '.required { color: blue }';
const requiredCssTwo = '.requiredTwo { color: cyan }';
const localScopedCss = ':local(.className) { background: red; }';
const localComposingCss = `
:local(.composingClass) {
composes: className from './localScoped.css';
color: blue;
}
`;
const requiredStyle = `<style type="text/css">${requiredCss}</style>`;
const existingStyle = `<style id="existing-style">.existing { color: yellow }</style>`;
const checkValue = '<div class="check">check</div>';
const rootDir = `${path.resolve(`${__dirname}/../`)}/`;
const jsdomHtml = [
'<html>',
"<head id='head'>",
existingStyle,
'</head>',
'<body>',
"<div class='target'>",
checkValue,
'</div>',
"<iframe class='iframeTarget'/>",
'</body>',
'</html>',
].join('\n');
const requiredJS = [
"var el = document.createElement('div');",
'el.id = "test-shadow";',
'document.body.appendChild(el)',
"var css = require('./style.css');",
'css.use();',
].join('\n');

const styleLoaderOptions = {};
const cssRule = {};

const defaultCssRule = {
test: /\.css?$/,
use: [
{
loader: 'style-loader/useable',
options: styleLoaderOptions,
},
'css-loader',
],
};

const webpackConfig = {
entry: './main.js',
output: {
filename: 'bundle.js',
},
module: {
rules: [cssRule],
},
};

const setupWebpackConfig = () => {
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(() => {
// Reset all style-loader options
for (const member in styleLoaderOptions) {
if (Object.prototype.hasOwnProperty.call(styleLoaderOptions, member)) {
delete styleLoaderOptions[member];
}
}

for (const member in defaultCssRule) {
if (Object.prototype.hasOwnProperty.call(defaultCssRule, member)) {
cssRule[member] = defaultCssRule[member];
}
}

setupWebpackConfig();
});

it('insert into iframe', (done) => {
const selector = 'iframe.iframeTarget';

styleLoaderOptions.insertInto = selector;

runCompilerTest(
requiredStyle,
done,
function test() {
return this.document.querySelector(selector).contentDocument.head
.innerHTML;
},
selector
);
});
});

describe('hmr', () => {
let getOptions;

beforeEach(() => {
getOptions = jest.fn();

// Mock loaderUtils to override options
loaderUtils.getOptions = getOptions;
});

it('should output HMR code by default', () => {
expect(/(module\.hot)/g.test(useable.pitch())).toBe(true);
});

it('should NOT output HMR code when options.hmr is false', () => {
getOptions.mockReturnValue({ hmr: false });

expect(/(module\.hot)/g.test(useable.pitch())).toBe(false);
});

it('should output HMR code when options.hmr is true', () => {
getOptions.mockReturnValue({ hmr: true });

expect(/(module\.hot)/g.test(useable.pitch())).toBe(true);
});
});
});
109 changes: 105 additions & 4 deletions test/runtime/__snapshots__/addStyle.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`addStyle should insert style tag in iframe 1`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><iframe class=\\"iframeTarget\\"></iframe></body>"`;
exports[`addStyle should insert style tag in iframe 2`] = `"<style type=\\"text/css\\">.foo { color: red }</style>"`;
exports[`addStyle should throw error with invalid "insertAt" option 1`] = `
"[Style Loader]
Invalid value for parameter 'insertAt' ('options.insertAt') found.
Must be 'top', 'bottom', or Object.
(https://github.com/webpack-contrib/style-loader#insertat)
"
`;
exports[`addStyle should throw error with invalid "insertInto" option 1`] = `"'#test><><><' is not a valid selector"`;
exports[`addStyle should throw error with invalid "insertInto" option 2`] = `"Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid."`;
exports[`addStyle should work "insertAt" option and with children 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work "insertAt" option and with children 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work #2 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
Expand All @@ -8,6 +29,8 @@ exports[`addStyle should work with "attrs" option #2 1`] = `"<head><title>Title<
exports[`addStyle should work with "attrs" option 1`] = `"<head><title>Title</title><style foo=\\"bar\\" type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "base" option 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "insertAt" option #2 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "insertAt" option #3 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.bar { color: blue }</style><script src=\\"https://example.com/script.js\\" id=\\"id\\"></script></head><body><h1>Hello world</h1></body>"`;
Expand All @@ -20,16 +43,94 @@ exports[`addStyle should work with "insertInto" option #3 1`] = `"<head><title>T
exports[`addStyle should work with "insertInto" option 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "singleton" option 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "singleton" option 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.bar { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "sourceMap" option 1`] = `
"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }
/*# sourceURL=style-1.css */
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTEuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQXFCLGVBQWUsRUFBRSIsImZpbGUiOiJzdHlsZS0xLmNzcyIsInNvdXJjZXNDb250ZW50IjpbIi5mb28geyBjb2xvcjogcmVkIH0iXX0= */</style></head><body><h1>Hello world</h1></body>"
`;
exports[`addStyle should work with "transform" option #2 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "transform" option #3 1`] = `"<head><title>Title</title></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "transform" option 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with media 1`] = `"<head><title>Title</title><style type=\\"text/css\\" media=\\"screen and (min-width:320px)\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with nonce 1`] = `"<head><title>Title</title><style type=\\"text/css\\" nonce=\\"none\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with same module id in list 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.foo { color: green }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with same module id in list 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: black }</style><style type=\\"text/css\\">.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #2 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #2 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: blue }</style><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #3 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #3 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #5 1`] = `"<head><title>Title</title><style type=\\"text/css\\" media=\\"screen and (min-width:320px\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #5 2`] = `"<head><title>Title</title><style type=\\"text/css\\" media=\\"screen and (min-width:320px\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #6 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #6 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: blue }.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #7 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #7 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: green }</style><style type=\\"text/css\\">.foo { color: black }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #8 1`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div id=\\"id\\"><style type=\\"text/css\\">.foo { color: red }</style></div></body>"`;
exports[`addStyle should work with updates #8 2`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div id=\\"id\\"></div></body>"`;
exports[`addStyle should work with updates #9 1`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div id=\\"id\\"><style type=\\"text/css\\">.foo { color: blue }</style><style type=\\"text/css\\">.foo { color: yellow }</style></div></body>"`;
exports[`addStyle should work with updates #9 2`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div id=\\"id\\"><style type=\\"text/css\\">.foo { color: black }</style></div></body>"`;
exports[`addStyle should work with updates #9 3`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div id=\\"id\\"></div></body>"`;
exports[`addStyle should work with updates #10 1`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div><div id=\\"custom\\"><style type=\\"text/css\\">.foo { color: red }</style></div></div></body>"`;
exports[`addStyle should work with updates #10 2`] = `"<head><title>Title</title></head><body><h1>Hello world</h1><div></div></body>"`;
exports[`addStyle should work with updates #11 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #11 2`] = `"<head><title>Title</title></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #12 1`] = `
"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }
/*# sourceURL=style-40.css */
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTQwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFxQixlQUFlLEVBQUUiLCJmaWxlIjoic3R5bGUtNDAuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvbyB7IGNvbG9yOiByZWQgfSJdfQ== */</style></head><body><h1>Hello world</h1></body>"
`;
exports[`addStyle should work with updates #12 2`] = `
"<head><title>Title</title><style type=\\"text/css\\">.foo { color: black }
/*# sourceURL=style-40.css */
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTQwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQkJCQixjQUFxQixlQUFlLEVBQUUiLCJmaWxlIjoic3R5bGUtNDAuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvbyB7IGNvbG9yOiBibGFjayB9Il19 */</style></head><body><h1>Hello world</h1></body>"
`;
exports[`addStyle should work with updates #13 1`] = `"<head><title>Title</title><style type=\\"text/css\\" media=\\"screen and (min-width:320px)\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #13 2`] = `"<head><title>Title</title><style type=\\"text/css\\" media=\\"screen and (min-width:640px)\\">.foo { color: black }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #14 1`] = `
"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }
/*# sourceURL=style-42.css */
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTQyLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFxQixlQUFlLEVBQUUiLCJmaWxlIjoic3R5bGUtNDIuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvbyB7IGNvbG9yOiByZWQgfSJdfQ== */</style><style type=\\"text/css\\">.bar { color: yellow }
/*# sourceURL=style-43.css */
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTQzLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFxQixlQUFlLEVBQUUiLCJmaWxlIjoic3R5bGUtNDMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvbyB7IGNvbG9yOiByZWQgfSJdfQ== */</style></head><body><h1>Hello world</h1></body>"
`;
exports[`addStyle should work with updates #14 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: black }</style><style type=\\"text/css\\">.bar { color: gray }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #15 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates #15 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: black }</style><style type=\\"text/css\\">.foo { color: red }</style><style type=\\"text/css\\">.foo { color: yellow }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates 1`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: red }</style></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with updates 2`] = `"<head><title>Title</title><style type=\\"text/css\\">.foo { color: blue }</style></head><body><h1>Hello world</h1></body>"`;
2 changes: 2 additions & 0 deletions test/runtime/__snapshots__/addStyleUrl.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`addStyle should work 1`] = `"<head><title>Title</title><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"./style-1.css\\"></head><body><h1>Hello world</h1></body>"`;
exports[`addStyle should work with "attrs" option 1`] = `"<head><title>Title</title><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"./style-1.css\\" foo=\\"bar\\"></head><body><h1>Hello world</h1></body>"`;
Loading

0 comments on commit dd32fad

Please sign in to comment.