Skip to content

Commit

Permalink
refactor(postcss-reduce-initial): refactor and add tests for acquire …
Browse files Browse the repository at this point in the history
…script (#1169)

* refactor(postcss-reduce-initial): make acquire script testable and easier to maintain

- Separate main concerns into different files
- Replace comments with more readable code
- Refactor with testability in mind
- Replace dependencies with more up-to-date and lightweight alternatives

* test(postcss-reduce-initial): add tests for acquire script

* fixup! refactor(postcss-reduce-initial): make acquire script testable and easier to maintain

* fixup! test(postcss-reduce-initial): add tests for acquire script

Co-authored-by: Ludovico Fischer <43557+ludofischer@users.noreply.github.com>
  • Loading branch information
sigveio and ludofischer committed Jul 20, 2021
1 parent 506a823 commit ca5246d
Show file tree
Hide file tree
Showing 11 changed files with 505 additions and 381 deletions.
8 changes: 6 additions & 2 deletions jest.config.js
Expand Up @@ -2,8 +2,8 @@ module.exports = {
testEnvironment: 'node',
collectCoverageFrom: [
'packages/*/src/**/*.js',
'!packages/postcss-colormin/src/generate.js',
'!packages/postcss-reduce-initial/src/acquire.js',
'packages/postcss-reduce-initial/src/script/lib/io.mjs',
'packages/postcss-reduce-initial/src/script/lib/mdnCssProps.mjs',
'!packages/cssnano/src/__tests__/_processCss.js',
'!packages/cssnano/src/__tests__/_webpack.config.js',
],
Expand All @@ -14,4 +14,8 @@ module.exports = {
'_webpack.config.js',
],
testTimeout: 30000,
transform: {
'\\.[jt]sx?$': 'babel-jest',
'\\.mjs$': 'babel-jest',
},
};
7 changes: 3 additions & 4 deletions package.json
Expand Up @@ -42,12 +42,12 @@
"eslint-plugin-react": "^7.23.2",
"fs-extra": "^9.1.0",
"glob": "^7.1.4",
"got": "^11.8.1",
"html2plaintext": "^2.1.2",
"html-to-text": "^8.0.0",
"jest": "^27.0.1",
"jest-junit": "^12.1.0",
"lerna": "4.0.0",
"mdast-util-heading-range": "^2.1.2",
"node-fetch": "^2.6.1",
"pleeease-filters": "^4.0.0",
"postcss": "^8.3.0",
"postcss-devtools": "^1.1.1",
Expand All @@ -69,8 +69,7 @@
"toml": "^3.0.0",
"tomlify-j0.4": "^3.0.0",
"unist-builder": "^2.0.3",
"unist-util-remove": "^2.1.0",
"write-file": "^1.0.0"
"unist-util-remove": "^2.1.0"
},
"browserslist": {
"chrome58": [
Expand Down
2 changes: 1 addition & 1 deletion packages/postcss-reduce-initial/package.json
Expand Up @@ -9,7 +9,7 @@
"LICENSE-MIT"
],
"scripts": {
"acquire": "node ./src/acquire.mjs",
"acquire": "node ./src/script/acquire.mjs",
"prebuild": "rimraf dist",
"build": "cross-env BABEL_ENV=publish babel src --config-file ../../babel.config.json --out-dir dist --ignore '**/__tests__/,src/acquire.mjs'",
"prepare": "yarn build"
Expand Down
65 changes: 0 additions & 65 deletions packages/postcss-reduce-initial/src/acquire.mjs

This file was deleted.

58 changes: 58 additions & 0 deletions packages/postcss-reduce-initial/src/script/__tests__/io.js
@@ -0,0 +1,58 @@
import fetch from 'node-fetch';
import { handleError, toJSONString, write, generate } from '../lib/io.mjs';
import testData from './sampleProperties.json';

jest.mock('node-fetch');

// Selectively bypass mocking to use a real Response obj
const { Response } = jest.requireActual('node-fetch');

describe('toJSONString', () => {
const rawData = {
foo: 'bar',
'baz-qux': 'quux',
quuz: 'corge',
garply: 'waldo',
'fred-plugh': 'xyzzy-thud',
};

test('should produce parsable JSON', () => {
expect(JSON.parse(toJSONString(rawData))).toEqual(rawData);
});
});

describe('Smoke tests', () => {
const data = {
fromInitial: { foo: 'bar', baz: 'qux' },
toInitial: { qux: 'baz', bar: 'foo' },
};
const paths = { fromInitial: '/foo.json', toInitial: '/bar.json' };

test.each([
['fromInitial', paths.fromInitial, data.fromInitial],
['toInitial', paths.toInitial, data.toInitial],
])('should write JSON file based on key (%p)', (key, path, expected) => {
const err = expect.any(Function);
const fileFunc = jest.fn();

write(fileFunc, paths, data, key);

expect(fileFunc).toHaveBeenCalledWith(path, toJSONString(expected), err);
});

test('should handle file operation errors', () => {
expect(handleError).not.toThrowError();
expect(() => handleError(new Error('something went wrong'))).toThrowError();
});

test('should make it through promise chain with sample data and write 2 files', async () => {
const fileFunc = jest.fn();
fetch.mockReturnValue(
Promise.resolve(new Response(JSON.stringify(testData)))
);

await generate(fileFunc, paths, 'https://example.com/properties.json');

expect(fileFunc).toHaveBeenCalledTimes(2);
});
});
122 changes: 122 additions & 0 deletions packages/postcss-reduce-initial/src/script/__tests__/mdnCssProps.js
@@ -0,0 +1,122 @@
import {
isUserAgentDependent,
isComplexSyntax,
isUnpredictable,
toPlainText,
reduceInitial,
validate,
} from '../lib/mdnCssProps.mjs';

import testData from './sampleProperties.json';

describe('should recognise user agent dependent flags', () => {
test.each([
['dependsOnUserAgent', true],
['noPracticalInitialValue', true],
['noneButOverriddenInUserAgentCSS', true],
['variesFromBrowserToBrowser', true],
['invertOrCurrentColor', true],
['startOrNamelessValueIfLTRRightIfRTL', true],
['autoForSmartphoneBrowsersSupportingInflation', true],
['experimental', false],
['normal', false],
])('isUserAgentDependent(%p) expected: %p', (flag, expected) => {
expect(isUserAgentDependent(flag)).toBe(expected);
});
});

describe('should recognise properties with complex syntax', () => {
test.each([
[['foo', 'bar'], 'text-align', true],
[['foo', 'bar'], '--*', true],
['normal', '--*', true],
['normal', 'word-wrap', false],
['100%', 'text-align', false],
])('isComplexSyntax(%p, %p) expected: %p', (initial, key, expected) => {
expect(isComplexSyntax(initial, key)).toBe(expected);
});
});

describe('should recognise properties with unpredictable behavior', () => {
test.each([
['nonstandard', 'align-items', true],
['nonstandard', 'display', true],
['standard', 'display', true],
['standard', 'align-items', false],
['experimental', 'aspect-ratio', false],
])('isUnpredictable(%p, %p) expected: %p', (status, key, expected) => {
expect(isUnpredictable(status, key)).toBe(expected);
});
});

describe('should strip HTML, but leave relevant chars and separating spaces', () => {
test.each([
['<script>foo</script>', ''],
['<script type="text/javascript">bar<script>', ''],
['<script src="myscripts.js">baz</script>', ''],
['Hello &amp; Goodbye', 'Hello & Goodbye'],
['Eye<br>glasses', 'Eyeglasses'],
['Hand<p>writing</p>', 'Handwriting'],
['No space at end ', 'No space at end'],
['padding-box', 'padding-box'],
['50% 50% 0', '50% 50% 0'],
['0% 0%', '0% 0%'],
['100%', '100%'],
['auto', 'auto'],
])('toPlainText(%p) expected: %p', (string, expected) => {
expect(toPlainText(string)).toBe(expected);
});
});

describe('Reduce and validate sample data', () => {
let processedData = '';

beforeAll(() => {
processedData = reduceInitial(testData);
});

test('should reduce to expected object structure', () => {
expect(processedData).toEqual(
expect.objectContaining({
fromInitial: expect.any(Object),
toInitial: expect.any(Object),
})
);
});

test('should reduce to expected number of fromInitial items', () => {
expect(Object.keys(processedData.fromInitial)).toHaveLength(5);
});

test('should reduce to expected number of toInitial items', () => {
expect(Object.keys(processedData.toInitial)).toHaveLength(3);
});

test('should validate and return sample data as resolved promise', async () => {
expect.assertions(1);
await expect(validate(processedData)).resolves.toEqual(processedData);
});

test('should fail validation on missing data', async () => {
expect.assertions(1);
await expect(validate(undefined)).rejects.toThrow(Error);
});

test('should fail validation on missing fromInitial', async () => {
const partialData = JSON.parse(JSON.stringify(processedData));

delete partialData.fromInitial;

expect.assertions(1);
await expect(validate(partialData)).rejects.toThrow(Error);
});

test('should fail validation on missing toInitial', async () => {
const partialData = JSON.parse(JSON.stringify(processedData));

delete partialData.toInitial;

expect.assertions(1);
await expect(validate(partialData)).rejects.toThrow(Error);
});
});

0 comments on commit ca5246d

Please sign in to comment.