Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP test/jest #36

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
{
"presets": ["es2015"],
"plugins": ["transform-flow-strip-types", "transform-object-rest-spread"]
"presets": [
["env", {
"targets": {
"node": "6"
}
}]
],
"plugins": [
["transform-runtime", {
"polyfill": false,
"regenerator": true
}],
"transform-flow-strip-types",
"transform-object-rest-spread"
]
}
2 changes: 2 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ignore]
.*/node_modules/.*
1 change: 0 additions & 1 deletion critical.css

This file was deleted.

1 change: 0 additions & 1 deletion default.critical.expected.css

This file was deleted.

9 changes: 0 additions & 9 deletions default.css

This file was deleted.

7 changes: 0 additions & 7 deletions default.non-critical.actual.css

This file was deleted.

7 changes: 0 additions & 7 deletions default.non-critical.expected.css

This file was deleted.

18 changes: 9 additions & 9 deletions lib/getChildRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
* @return {array} Array of child rules.
*/
function getChildRules(css, parent) {
var result = [];
var selectorRegExp = new RegExp(parent.selector);
const result = [];
const selectorRegExp = new RegExp(parent.selector);

// Walk all rules to mach child selectors
css.walkRules(selectorRegExp, function (rule) {
var childRule = (0, _matchChild.matchChild)(parent, rule);
css.walkRules(selectorRegExp, rule => {
const childRule = (0, _matchChild.matchChild)(parent, rule);
if (childRule) {
result.push(rule);
}
});

// Walk all at-rules to match nested child selectors
css.walkAtRules(function (atRule) {
atRule.walkRules(selectorRegExp, function (rule) {
var childRule = (0, _matchChild.matchChild)(parent, rule);
css.walkAtRules(atRule => {
atRule.walkRules(selectorRegExp, rule => {
const childRule = (0, _matchChild.matchChild)(parent, rule);
// Create new at-rule to append only necessary selector to critical
var criticalAtRule = _postcss2.default.atRule({
const criticalAtRule = _postcss2.default.atRule({
name: atRule.name,
params: atRule.params
});
Expand All @@ -46,7 +46,7 @@ function getChildRules(css, parent) {
* aren't identical.
*/
if ((rule.selector === parent.selector || childRule) && _postcss2.default.parse(rule).toString() !== _postcss2.default.parse(parent).toString()) {
var clone = rule.clone();
const clone = rule.clone();
criticalAtRule.append(clone);
result.push(criticalAtRule);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/getCriticalDestination.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ exports.getCriticalDestination = getCriticalDestination;
* @return {string} String corresponding to output destination.
*/
function getCriticalDestination(rule, dest) {
rule.walkDecls('critical-filename', function (decl) {
rule.walkDecls('critical-filename', decl => {
dest = decl.value.replace(/['"]*/g, '');
decl.remove();
});
Expand Down
40 changes: 19 additions & 21 deletions lib/getCriticalRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
* @param {string} test Declaration string. Default `critical-selector`
* @return {Object} clone Cloned, cleaned root node.
*/
function clean(root) {
var test = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'critical-selector';

var clone = root.clone();
function clean(root, test = 'critical-selector') {
const clone = root.clone();
if (clone.type === 'decl') {
clone.remove();
} else {
clone.walkDecls(test, function (decl) {
clone.walkDecls(test, decl => {
decl.remove();
});
}
Expand All @@ -45,12 +43,12 @@ function clean(root) {
* @return {Object} sortedRoot Root with nodes sorted by source order.
*/
function correctSourceOrder(root) {
var sortedRoot = _postcss2.default.root();
var clone = root.clone();
clone.walkRules(function (rule) {
var start = rule.source.start.line;
const sortedRoot = _postcss2.default.root();
const clone = root.clone();
clone.walkRules(rule => {
let start = rule.source.start.line;
if (rule.parent.type === 'atrule') {
var child = rule;
const child = rule;
rule = _postcss2.default.atRule({
name: rule.parent.name,
params: rule.parent.params
Expand Down Expand Up @@ -91,11 +89,11 @@ function establishContainer(node) {
* @return {Object} clonedRoot Root object.
*/
function updateCritical(root, update) {
var clonedRoot = root.clone();
const clonedRoot = root.clone();
if (update.type === 'rule') {
clonedRoot.append(clean(update.clone()));
} else {
update.clone().each(function (rule) {
update.clone().each(rule => {
clonedRoot.append(clean(rule.root()));
});
}
Expand All @@ -111,21 +109,21 @@ function updateCritical(root, update) {
* @return {object} Object containing critical rules, organized by output destination
*/
function getCriticalRules(css, defaultDest) {
var critical = (0, _atRule.getCriticalFromAtRule)({ css: css, defaultDest: defaultDest });
css.walkDecls('critical-selector', function (decl) {
var parent = decl.parent,
value = decl.value;

var dest = (0, _getCriticalDestination.getCriticalDestination)(parent, defaultDest);
var container = establishContainer(parent);
var childRules = value === 'scope' ? (0, _getChildRules.getChildRules)(css, parent) : [];
const critical = (0, _atRule.getCriticalFromAtRule)({ css, defaultDest });
css.walkDecls('critical-selector', decl => {
const parent = decl.parent,
value = decl.value;

const dest = (0, _getCriticalDestination.getCriticalDestination)(parent, defaultDest);
const container = establishContainer(parent);
const childRules = value === 'scope' ? (0, _getChildRules.getChildRules)(css, parent) : [];
// Sanity check, make sure we've got a root node
critical[dest] = critical[dest] || _postcss2.default.root();

switch (value) {
case 'scope':
// Add all child rules
var criticalRoot = childRules.reduce(function (acc, rule) {
const criticalRoot = childRules.reduce((acc, rule) => {
return acc.append(rule.clone());
}, critical[dest].append(container));

Expand Down
2 changes: 1 addition & 1 deletion lib/matchChild.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ exports.matchChild = matchChild;
* @return {object} Parent rule for which children should be included
*/
function matchChild(parent, rule) {
var childRegExp = new RegExp("(, )?(" + parent.selector + " [^,s]*),?.*"); // eslint-disable-line no-useless-escape
const childRegExp = new RegExp(`(, )?(${parent.selector} [^,\s]*),?.*`); // eslint-disable-line no-useless-escape
return rule.selector !== parent.selector && rule.selector.match(childRegExp) !== null;
}
14 changes: 9 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "postcss-critical-css",
"version": "3.0.2",
"version": "3.0.1",
"description": "Generate critical CSS using PostCSS",
"main": "index.js",
"repository": {
Expand All @@ -23,7 +23,10 @@
"babel-eslint": "^7.2.3",
"babel-plugin-transform-flow-strip-types": "^6.8.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.13.2",
"babel-runtime": "^6.26.0",
"eslint": "^3.3.1",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-flowtype": "^2.41.0",
Expand All @@ -32,6 +35,7 @@
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"flow-bin": "^0.48.0",
"jest": "^23.1.0",
"minimist": "^1.2.0",
"tape": "^4.8.0"
},
Expand All @@ -41,8 +45,7 @@
"flow": "flow; test $? -eq 0 -o $? -eq 2",
"eslint": "eslint test/**/*.js && eslint src/**",
"start": "eslint src/** && npm run flow && babel src --out-dir lib --watch",
"pretest": "./node_modules/.bin/babel-node test/preTest.js",
"test": "npm run build && npm run test-default && npm run test-no-preserve && npm run test-output-path && npm run test-output-dest && npm run test-no-args && npm run test-no-minify",
"test": "jest --verbose",
"test-no-args": "npm run pretest -- --noArgs && tape test --noArgs --test=default",
"test-no-minify": "npm run pretest -- --minify=false --fixtures-dir=fixtures-no-minify && tape test --fixtures-dir=fixtures-no-minify --test=default,this",
"test-output-dest": "npm run pretest -- --outputDest='custom.css' --fixtures-dir=fixtures-output-dest && tape test --outputDest='custom.css' --fixtures-dir=fixtures-output-dest --test=default",
Expand All @@ -52,7 +55,8 @@
},
"dependencies": {
"chalk": "^1.1.3",
"cssnano": "^4.0.0",
"postcss": "^7.0.0"
"cssnano": "^3.7.4",
"fs-extra": "^6.0.1",
"postcss": "^6.0.16"
}
}
29 changes: 29 additions & 0 deletions test/atRule.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const compareCritical = require('./compareCritical');
const { fsTimeout, normalizeOpts } = require('./utils');
const preTest = require('./preTest');

const opts = normalizeOpts();
beforeAll(async () => {
preTest('atRule', opts);
await fsTimeout();
});

describe('tests for @critical rule', () => {
it('should move all selectors in a file to critical css if @critical at-rule is used without wrapping anything', () => {
compareCritical(opts, 'standalone')
})

it('should remove @critical at-rule from non-critical css', () => {
compareCritical(opts, 'standalone', true)
})
})

describe('tests for @critical at-rule wrapping specific selectors', () => {
it('should move all selectors in a file to critical css if @critical rule is used without wrapping anything', () => {
compareCritical(opts, 'wrapping')
})

it('should remove @critical at-rule from non-critical css', () => {
compareCritical(opts, 'wrapping', true)
})
})
25 changes: 25 additions & 0 deletions test/compareCritical.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const fs = require('fs-extra');

module.exports = function compareCritical(opts, name, testNonCritical) {
let basePath = opts.outputPath || `${process.cwd()}/test/fixtures`
let actual = opts.outputDest || 'critical.css'

if (opts.noArgs) {
basePath = process.cwd()
}

const expected = testNonCritical
? `${name}.non-critical.expected.css`
: `${name}.critical.expected.css`
if (
(name !== 'default' || testNonCritical) &&
! opts.outputDest
) {
actual = testNonCritical
? `${name}.non-critical.actual.css`
: `${name}.critical.actual.css`
}

expect(fs.readFileSync(`${basePath}/${actual}`, 'utf8').trim())
.toEqual(fs.readFileSync(`${basePath}/${expected}`, 'utf8').trim())
}
71 changes: 71 additions & 0 deletions test/default.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const compareCritical = require('./compareCritical');
const { fsTimeout, normalizeOpts } = require('./utils');
const preTest = require('./preTest');

describe('default tests', () => {
const opts = normalizeOpts();
beforeAll(async () => {
preTest('default', opts);
await fsTimeout();
});

it('should move styles into critical stylesheet if @critical at-rule is used', () => {
compareCritical(opts, 'default')
})

it('should not modify non-critical stylesheet', () => {
compareCritical(opts, 'default', true)
})
})

describe('tests for `minify` option', () => {
const opts = normalizeOpts({ minify: false });
beforeAll(async () => {
preTest('options', opts);
await fsTimeout();
});

it('should not minify critical CSS styles if `minify` option is set to `false`', () => {
compareCritical(opts, 'minify-false')
})
})

describe('tests for `preserve` option', () => {
const opts = normalizeOpts({ preserve: false });
beforeAll(async () => {
preTest('options', opts);
await fsTimeout();
});

it('should move selectors specified with `@critical` or `critical-selector` to critical css file', () => {
compareCritical(opts, 'preserve')
})

it('should remove selectors specified with `@critical` or `critical-selector` from non-critical stylesheet', () => {
compareCritical(opts, 'preserve', true)
})
})

describe('tests for `outputDest` option', () => {
const opts = normalizeOpts({ outputDest: 'test-output-dest.critical.actual.css' });
beforeAll(async () => {
preTest('options', opts);
await fsTimeout();
});

it('should output critical css to filename configured in `outputDest` option', () => {
compareCritical(opts, 'output-dest')
})
})

describe('tests for `outputPath` option', () => {
const opts = normalizeOpts({ outputPath: `${process.cwd()}/test/fixtures/options/outputPath` });
beforeAll(async () => {
preTest('options', opts);
await fsTimeout();
});

it('should output critical css to filename configured in `outputDest` option', () => {
compareCritical(opts, 'output-path')
})
})
8 changes: 0 additions & 8 deletions test/fixtures-no-minify/critical.css

This file was deleted.

8 changes: 0 additions & 8 deletions test/fixtures-no-minify/default.critical.expected.css

This file was deleted.

6 changes: 0 additions & 6 deletions test/fixtures-no-minify/this.critical.actual.css

This file was deleted.

Loading