From 4267337fb077ac5e6969578048b0bddf20c18362 Mon Sep 17 00:00:00 2001 From: Yangshun Tay Date: Tue, 10 Jul 2018 10:42:32 -0700 Subject: [PATCH] Fix CSS tests (#839) * Fix CSS tests * Revamp * - * fix failing test * add test for minifyCss with fixtures & snapshot * remove unintended addition * simplify the test.css --- .babelrc | 4 + lib/__tests__/build-files.test.js | 141 +++++++++--------- lib/server/__tests__/__fixtures__/test.css | 21 +++ lib/server/__tests__/__fixtures__/test.md | 26 ++++ .../__snapshots__/utils.test.js.snap | 5 + lib/server/__tests__/utils.test.js | 24 +++ lib/server/generate.js | 12 +- lib/server/utils.js | 14 +- package.json | 19 +-- 9 files changed, 178 insertions(+), 88 deletions(-) create mode 100644 lib/server/__tests__/__fixtures__/test.css create mode 100644 lib/server/__tests__/__fixtures__/test.md create mode 100644 lib/server/__tests__/__snapshots__/utils.test.js.snap create mode 100644 lib/server/__tests__/utils.test.js diff --git a/.babelrc b/.babelrc index 3490fcb3f7..bd74bcfccf 100644 --- a/.babelrc +++ b/.babelrc @@ -3,6 +3,10 @@ "test": { "presets": [ "env" + ], + "plugins": [ + "transform-class-properties", + "transform-object-rest-spread" ] } } diff --git a/lib/__tests__/build-files.test.js b/lib/__tests__/build-files.test.js index 7651848fe5..91f6067c42 100644 --- a/lib/__tests__/build-files.test.js +++ b/lib/__tests__/build-files.test.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -const cssnano = require('cssnano'); const filepath = require('filepath'); const fm = require('front-matter'); const fs = require('fs-extra'); @@ -15,6 +14,7 @@ const shell = require('shelljs'); const CWD = process.cwd(); +const utils = require('../server/utils'); const siteConfig = require(CWD + '/website/siteConfig.js'); const buildDir = CWD + '/website/build'; const docsDir = CWD + '/docs'; @@ -34,82 +34,85 @@ function clearBuildFolder() { return rimraf(buildDir); } -beforeEach(() => { - shell.cd(CWD); -}); - -beforeAll(() => { - generateSite(); - return Promise.all([ - glob(docsDir + '/**/*.md'), - glob(buildDir + '/' + siteConfig.projectName + '/docs/**/*.html'), - glob(docsDir + '/assets/*'), - glob(buildDir + '/' + siteConfig.projectName + '/img/*'), - ]).then(function(results) { - [ - inputMarkdownFiles, - outputHTMLFiles, - inputAssetsFiles, - outputAssetsFiles, - ] = results; +describe('Build files', () => { + beforeEach(() => { + shell.cd(CWD); }); -}); -afterAll(() => { - clearBuildFolder(); -}); - -test('Build folder exists', function() { - return fs.stat(buildDir).then(function(status) { - expect(status.isDirectory()).toBeTruthy(); + beforeAll(() => { + generateSite(); + return Promise.all([ + glob(docsDir + '/**/*.md'), + glob(buildDir + '/' + siteConfig.projectName + '/docs/**/*.html'), + glob(docsDir + '/assets/*'), + glob(buildDir + '/' + siteConfig.projectName + '/img/*'), + ]).then(function(results) { + [ + inputMarkdownFiles, + outputHTMLFiles, + inputAssetsFiles, + outputAssetsFiles, + ] = results; + }); }); -}); -test('Generated HTML for each Markdown resource', function() { - let metadata = []; - outputHTMLFiles.forEach(function(file) { - const path = filepath.create(file); - metadata.push(path.basename()); + afterAll(() => { + clearBuildFolder(); }); - inputMarkdownFiles.forEach(function(file) { - const data = fs.readFileSync(file, 'utf8'); - const frontmatter = fm(data); - expect(metadata).toContain(frontmatter.attributes.id + '.html'); - }); -}); -test('Generated table of contents', function() { - outputHTMLFiles.forEach(function(file) { - const fileContents = fs.readFileSync(file, 'utf8'); - expect(fileContents).not.toContain(''); + test('Build folder exists', function() { + return fs.stat(buildDir).then(function(status) { + expect(status.isDirectory()).toBeTruthy(); + }); }); -}); -test('Concatenated CSS files', function() { - return Promise.all([ - glob(staticCSSDir + '/*.css'), - fs.readFile( - buildDir + '/' + siteConfig.projectName + '/css/main.css', - 'utf8' - ), - ]).then(function(results) { - const [inputFiles, outputFile] = results; - inputFiles.forEach(async function(file) { - const contents = fs.readFileSync(file, 'utf8'); - const {css} = await cssnano.process(contents, {}, {preset: 'default'}); - expect(outputFile).toContain(css); + test('Generated HTML for each Markdown resource', function() { + let metadata = []; + outputHTMLFiles.forEach(function(file) { + const path = filepath.create(file); + metadata.push(path.basename()); + }); + inputMarkdownFiles.forEach(function(file) { + const data = fs.readFileSync(file, 'utf8'); + const frontmatter = fm(data); + expect(metadata).toContain(frontmatter.attributes.id + '.html'); + }); + }); + + test('Generated table of contents', function() { + outputHTMLFiles.forEach(function(file) { + const fileContents = fs.readFileSync(file, 'utf8'); + expect(fileContents).not.toContain(''); + }); + }); + + test('Concatenated CSS files', async function() { + const inputFiles = await glob(staticCSSDir + '/*.css'); + const combinedCSSFile = + buildDir + '/' + siteConfig.projectName + '/css/main.css'; + const fileContents = await Promise.all( + [combinedCSSFile, ...inputFiles].map(file => fs.readFile(file, 'utf8')) + ); + + const [outputFileContent, ...inputFileContents] = fileContents; + const minifiedCssFiles = await Promise.all( + inputFileContents.map(utils.minifyCss) + ); + + minifiedCssFiles.forEach(fileContent => { + expect(outputFileContent).toContain(fileContent); + }); + }); + + test('Copied assets from /docs/assets', function() { + let metadata = []; + outputAssetsFiles.forEach(function(file) { + const path = filepath.create(file); + metadata.push(path.basename()); + }); + inputAssetsFiles.forEach(function(file) { + const path = filepath.create(file); + expect(metadata).toContain(path.basename()); }); }); }); - -test('Copied assets from /docs/assets', function() { - let metadata = []; - outputAssetsFiles.forEach(function(file) { - const path = filepath.create(file); - metadata.push(path.basename()); - }); - inputAssetsFiles.forEach(function(file) { - const path = filepath.create(file); - expect(metadata).toContain(path.basename()); - }); -}); diff --git a/lib/server/__tests__/__fixtures__/test.css b/lib/server/__tests__/__fixtures__/test.css new file mode 100644 index 0000000000..b950ec790c --- /dev/null +++ b/lib/server/__tests__/__fixtures__/test.css @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +.hljs { + margin-left: -15px; + margin-right: -15px; + border: 1px solid #eee; + border-radius: 6px; + padding: 15px; + font-size: 15px; + max-width: 50rem; +} +.hljs.javascript { + background-color: rgba(247, 223, 30, 0.03); +} +.hljs .comment { + opacity: 0.7; +} \ No newline at end of file diff --git a/lib/server/__tests__/__fixtures__/test.md b/lib/server/__tests__/__fixtures__/test.md new file mode 100644 index 0000000000..ead5cf2cac --- /dev/null +++ b/lib/server/__tests__/__fixtures__/test.md @@ -0,0 +1,26 @@ +--- +title: This is not a css +--- + +This is a markdown, not a css + +.homeWrapperInner .homeCodeSnippet > div:nth-child(1) { + display: none; +} + +@media (max-width: 480px) { + .projectTitle { + font-size: 30px; + } + + .homeCodeSnippet .hljs { + font-size: 13px; + padding: 0; + } + .homeWrapperInner .homeCodeSnippet > div:nth-child(1) { + display: block; + } + .homeWrapperInner .homeCodeSnippet > div:nth-child(2) { + display: none; + } +} \ No newline at end of file diff --git a/lib/server/__tests__/__snapshots__/utils.test.js.snap b/lib/server/__tests__/__snapshots__/utils.test.js.snap new file mode 100644 index 0000000000..64cf15a187 --- /dev/null +++ b/lib/server/__tests__/__snapshots__/utils.test.js.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`server utils minify css 1`] = `".hljs{margin-left:-15px;margin-right:-15px;border:1px solid #eee;border-radius:6px;padding:15px;font-size:15px;max-width:50rem}.hljs.javascript{background-color:rgba(247,223,30,.03)}.hljs .comment{opacity:.7}"`; + +exports[`server utils minify css 2`] = `[Error: Unexpected "space" found.]`; diff --git a/lib/server/__tests__/utils.test.js b/lib/server/__tests__/utils.test.js new file mode 100644 index 0000000000..8459edcd40 --- /dev/null +++ b/lib/server/__tests__/utils.test.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +const path = require('path'); +const fs = require('fs'); +const utils = require('../utils'); + +describe('server utils', () => { + test('minify css', () => { + const testCss = fs.readFileSync( + path.join(__dirname, '__fixtures__', 'test.css'), + 'utf8' + ); + const notCss = fs.readFileSync( + path.join(__dirname, '__fixtures__', 'test.md'), + 'utf8' + ); + utils.minifyCss(testCss).then(css => expect(css).toMatchSnapshot()); + utils.minifyCss(notCss).catch(e => expect(e).toMatchSnapshot()); + }); +}); diff --git a/lib/server/generate.js b/lib/server/generate.js index d0c76139c7..0070d545e1 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -11,12 +11,12 @@ async function execute() { const metadataUtils = require('./metadataUtils'); const CWD = process.cwd(); - const cssnano = require('cssnano'); const fs = require('fs-extra'); const readMetadata = require('./readMetadata.js'); const path = require('path'); - const getTOC = require('../core/getTOC.js'); + const getTOC = require('../core/getTOC'); const utils = require('../core/utils.js'); + const serverUtils = require('./utils'); const React = require('react'); const mkdirp = require('mkdirp'); const glob = require('glob'); @@ -445,13 +445,7 @@ async function execute() { // Use cssnano to minify the final combined CSS. const mainCss = join(buildDir, 'css', 'main.css'); const cssContent = fs.readFileSync(mainCss, 'utf8'); - const {css} = await cssnano.process( - cssContent, - /* postcssOpts */ {}, - /* cssnanoOpts */ { - preset: 'default', - } - ); + const css = await serverUtils.minifyCss(cssContent); fs.writeFileSync(mainCss, css); // compile/copy pages from user diff --git a/lib/server/utils.js b/lib/server/utils.js index efb22ac451..dd90d8ee1b 100644 --- a/lib/server/utils.js +++ b/lib/server/utils.js @@ -4,9 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ + +const cssnano = require('cssnano'); const path = require('path'); const escapeStringRegexp = require('escape-string-regexp'); -const env = require('./env.js'); // Return the subdirectory path from a reference directory // Example: @@ -29,6 +30,7 @@ function getLanguage(file, refDir) { const match = regexSubFolder.exec(file); // Avoid misinterpreting subdirectory as language + const env = require('./env.js'); if (match && env.translation.enabled) { const enabledLanguages = env.translation .enabledLanguages() @@ -40,7 +42,17 @@ function getLanguage(file, refDir) { return null; } +function minifyCss(cssContent) { + return cssnano + .process(cssContent, { + preset: 'default', + zindex: false, + }) + .then(result => result.css); +} + module.exports = { getSubDir, getLanguage, + minifyCss, }; diff --git a/package.json b/package.json index 5d2f286f4e..4091577966 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,12 @@ "description": "Easy to Maintain Open Source Documentation Websites", "version": "1.3.2", "license": "MIT", - "keywords": ["documentation", "websites", "open source", "docusaurus"], + "keywords": [ + "documentation", + "websites", + "open source", + "docusaurus" + ], "repository": { "type": "git", "url": "https://github.com/facebook/Docusaurus.git" @@ -11,14 +16,10 @@ "scripts": { "ci-check": "yarn lint && yarn prettier:diff", "format:source": "prettier --config .prettierrc --write \"lib/**/*.js\"", - "format:examples": - "prettier --config .prettierrc --write \"examples/**/*.js\"", - "lint": - "eslint --cache \"lib/**/*.js\" \"examples/**/*.js\" \"website/**/*.js\"", - "nit:source": - "prettier --config .prettierrc --list-different \"lib/**/*.js\"", - "nit:examples": - "prettier --config .prettierrc --list-different \"examples/**/*.js\"", + "format:examples": "prettier --config .prettierrc --write \"examples/**/*.js\"", + "lint": "eslint --cache \"lib/**/*.js\" \"examples/**/*.js\" \"website/**/*.js\"", + "nit:source": "prettier --config .prettierrc --list-different \"lib/**/*.js\"", + "nit:examples": "prettier --config .prettierrc --list-different \"examples/**/*.js\"", "precommit": "lint-staged", "prettier": "yarn format:source && yarn format:examples", "prettier:diff": "yarn nit:source && yarn nit:examples",