fuse-box
Version:
Fuse-Box a bundler that does it right
157 lines (143 loc) • 4.19 kB
text/typescript
import {createEnv} from "../stubs/TestEnvironment";
import {should} from "fuse-test-runner";
import {CSSPlugin} from "../../plugins/stylesheet/CSSplugin";
import {PostCSS} from "../../plugins/stylesheet/PostCSSPlugin";
const postcss = require("postcss");
const changeDisplayPlugin = postcss.plugin("ChangeDisplayPlugin", function (options) {
return function (css) {
css.walkRules(function (rule) {
rule.walkDecls(function (decl, i) {
if (decl.prop === "display") {
decl.value = "block";
}
});
});
};
});
// This is essentially how the url plugin works
// It requires the global postcss options to be passed through ("from", "to")
const urlPlugin = postcss.plugin("UrlPlugin", function (options) {
return function (css, result) {
let opts = result.opts;
css.walkRules(function (rule) {
rule.walkDecls(function (decl) {
let pattern = /(url\(\s*['"]?)([^"')]+)(["']?\s*\))/g;
if (pattern.test(decl.value)) {
decl.value = decl.value
.replace(pattern, (matched, before, url, after) => {
const newUrl = opts.from + "/" + url;
return `${before}${newUrl}${after}`;
});
}
});
});
};
});
const idToClassPlugin = postcss.plugin("IdToClass", function (options) {
return function (css) {
css.walkRules(function (rule) {
if (rule.selector && rule.selector[0] === "#") {
rule.selector = "." + rule.selector.slice(1);
}
});
};
});
export class PostcssPluginTest {
"Should be unmodified with no plugins"() {
return setup({
plugins: [
[PostCSS(), CSSPlugin({})]
]
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`display: grid;`);
});
}
"Should execute single plugin"() {
return setup({
plugins: [
[PostCSS([changeDisplayPlugin]), CSSPlugin({})]
]
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`display: block`);
});
}
"Should execute several plugins"() {
return setup({
plugins: [
[PostCSS([changeDisplayPlugin, idToClassPlugin]), CSSPlugin({})]
]
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`display: block`);
should(out).notFindString(`#moon`);
should(out).findString(`.moon`);
});
}
"Should execute several plugins (legacy option)"() {
return setup({
plugins: [
[PostCSS([changeDisplayPlugin], {plugins: [idToClassPlugin]}), CSSPlugin({})]
]
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`display: block`);
should(out).notFindString(`#moon`);
should(out).findString(`.moon`);
});
}
"Should execute several plugins (legacy option 2)"() {
return setup({
plugins: [
[PostCSS({plugins: [changeDisplayPlugin, idToClassPlugin]}), CSSPlugin({})]
]
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`display: block`);
should(out).notFindString(`#moon`);
should(out).findString(`.moon`);
});
}
"Should be able to pass options to postcss"() {
return setup({
plugins: [
[PostCSS([urlPlugin], {from: "./somedir"}), CSSPlugin({})]
],
styleContent: `
body {
background-image: url("paper.gif");
}
`
})
.then((result) => {
const out = result.projectContents.toString();
should(out).findString(`background-image: url(\\"./somedir/paper.gif\\")`);
});
}
}
const style = `
.grid {
display: grid;
}
#moon {
color: #555;
}
`;
function setup({plugins, styleContent = style}) {
return createEnv({
project: {
files: {
"index.ts": `exports.style = require("./style.css")`,
"style.css": styleContent
},
plugins: plugins,
instructions: "index.ts",
},
})
}