mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-05-19 05:03:23 +08:00
Run behavioral smoke tests with Jest, add output tests (#5150)
* Run smoke tests with Jest * Get a unique port for smoke test * Upgrade verdaccio across the board * Drop unneeded step * Try latest instead * Boot registry in home directory * Correct config path * Add mutex * Test webpack message formatting * Strip color * Add browserslist to default * Disable another broken feature
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "builds-with-multiple-runtimes",
|
||||
"description": "Tests that a build succeeds with multiple runtime versions",
|
||||
"dependencies": {
|
||||
"dva": "2.4.0",
|
||||
"ky": "0.3.0"
|
||||
}
|
||||
}
|
||||
5
fixtures/output/jest.config.js
Normal file
5
fixtures/output/jest.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.js'],
|
||||
setupTestFrameworkScriptFile: './setupOutputTests.js',
|
||||
};
|
||||
6
fixtures/output/setupOutputTests.js
Normal file
6
fixtures/output/setupOutputTests.js
Normal file
@@ -0,0 +1,6 @@
|
||||
beforeAll(() => {
|
||||
jest.setTimeout(1000 * 60 * 5);
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.setTimeout(1000 * 60 * 5);
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`webpack message formatting formats babel syntax error 1`] = `
|
||||
Object {
|
||||
"stderr": "Creating an optimized production build...
|
||||
Failed to compile.
|
||||
|
||||
./src/App.js
|
||||
Syntax error: Unterminated JSX contents (8:12)
|
||||
|
||||
6 | <div>
|
||||
7 | <span>
|
||||
> 8 | </div>
|
||||
| ^
|
||||
9 | );
|
||||
10 | }
|
||||
11 | }
|
||||
|
||||
|
||||
",
|
||||
"stdout": "",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`webpack message formatting formats css syntax error 1`] = `
|
||||
Object {
|
||||
"stderr": "Creating an optimized production build...
|
||||
[31mFailed to compile.
|
||||
[39m
|
||||
[7m./src/AppCss.css[27m
|
||||
Syntax Error: (3:2) Unexpected }
|
||||
|
||||
[90m 1 | [39m[33m.App[39m [33m{[39m
|
||||
[90m 2 | [39m color[33m:[39m red[33m;[39m
|
||||
[31m[1m>[22m[39m[90m 3 | [39m[33m}[39m[33m}[39m
|
||||
[90m | [39m [31m[1m^[22m[39m
|
||||
[90m 4 | [39m
|
||||
|
||||
|
||||
",
|
||||
"stdout": "",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`webpack message formatting formats eslint error 1`] = `
|
||||
Object {
|
||||
"stderr": "Creating an optimized production build...
|
||||
Failed to compile.
|
||||
|
||||
./src/App.js
|
||||
Line 4: 'b' is not defined no-undef
|
||||
|
||||
Search for the keywords to learn more about each error.
|
||||
|
||||
|
||||
",
|
||||
"stdout": "",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`webpack message formatting formats eslint warning 1`] = `
|
||||
Object {
|
||||
"stderr": "",
|
||||
"stdout": "Creating an optimized production build...
|
||||
Compiled with warnings.
|
||||
|
||||
./src/App.js
|
||||
Line 3: 'foo' is defined but never used no-unused-vars
|
||||
|
||||
Search for the keywords to learn more about each warning.
|
||||
To ignore, add // eslint-disable-next-line to the line before.
|
||||
|
||||
",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`webpack message formatting formats missing package 1`] = `
|
||||
Object {
|
||||
"stderr": "Creating an optimized production build...
|
||||
[31mFailed to compile.
|
||||
[39m
|
||||
Module not found: Error: Can't resolve 'unknown-package' in '/private/var/folders/c3/vytj6_h56b77f_g72smntm3m0000gn/T/bf26e1d3700ad14275f6eefb5e4417c1/src'
|
||||
|
||||
|
||||
",
|
||||
"stdout": "",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`webpack message formatting formats unknown export 1`] = `
|
||||
Object {
|
||||
"stderr": "Creating an optimized production build...
|
||||
Failed to compile.
|
||||
|
||||
./src/App.js
|
||||
1:1677-1680 './AppUnknownExport' does not contain an export named 'bar'.
|
||||
|
||||
|
||||
",
|
||||
"stdout": "",
|
||||
}
|
||||
`;
|
||||
88
fixtures/output/webpack-message-formatting/index.test.js
Normal file
88
fixtures/output/webpack-message-formatting/index.test.js
Normal file
@@ -0,0 +1,88 @@
|
||||
const { bootstrap, getOutputProduction } = require('../../utils');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const Semaphore = require('async-sema');
|
||||
const tempy = require('tempy');
|
||||
|
||||
describe('webpack message formatting', () => {
|
||||
const semaphore = new Semaphore(1, { capacity: Infinity });
|
||||
let testDirectory;
|
||||
beforeAll(async () => {
|
||||
testDirectory = tempy.directory();
|
||||
await bootstrap({ directory: testDirectory, template: __dirname });
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await semaphore.acquire();
|
||||
});
|
||||
afterEach(async () => {
|
||||
fs.removeSync(path.join(testDirectory, 'src', 'App.js'));
|
||||
semaphore.release();
|
||||
});
|
||||
|
||||
it('formats babel syntax error', async () => {
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppBabel.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit('formats css syntax error', async () => {
|
||||
// TODO: fix me!
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppCss.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit('formats unknown export', async () => {
|
||||
// TODO: fix me!
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppUnknownExport.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit('formats missing package', async () => {
|
||||
// TODO: fix me!
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppMissingPackage.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('formats eslint warning', async () => {
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppLintWarning.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
const sizeIndex = response.stdout.indexOf('File sizes after gzip');
|
||||
if (sizeIndex !== -1) {
|
||||
response.stdout = response.stdout.substring(0, sizeIndex);
|
||||
}
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('formats eslint error', async () => {
|
||||
fs.copySync(
|
||||
path.join(__dirname, 'src', 'AppLintError.js'),
|
||||
path.join(testDirectory, 'src', 'App.js')
|
||||
);
|
||||
|
||||
const response = await getOutputProduction({ directory: testDirectory });
|
||||
expect(response).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
11
fixtures/output/webpack-message-formatting/package.json
Normal file
11
fixtures/output/webpack-message-formatting/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"node-sass": "4.x",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"react-scripts": "latest"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
13
fixtures/output/webpack-message-formatting/src/AppBabel.js
Normal file
13
fixtures/output/webpack-message-formatting/src/AppBabel.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,3 @@
|
||||
.App {
|
||||
color: red;
|
||||
}}
|
||||
10
fixtures/output/webpack-message-formatting/src/AppCss.js
Normal file
10
fixtures/output/webpack-message-formatting/src/AppCss.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import './AppCss.css';
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return <div className="App" />;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
function foo() {
|
||||
const a = b;
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
function foo() {}
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
import { bar } from 'unknown-package';
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount() {
|
||||
bar();
|
||||
}
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
import { bar } from './AppUnknownExport';
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount() {
|
||||
bar();
|
||||
}
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,3 @@
|
||||
export function foo() {
|
||||
console.log('bar');
|
||||
}
|
||||
5
fixtures/output/webpack-message-formatting/src/index.js
Normal file
5
fixtures/output/webpack-message-formatting/src/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
17
fixtures/smoke/boostrap-sass/index.test.js
Normal file
17
fixtures/smoke/boostrap-sass/index.test.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const {
|
||||
bootstrap,
|
||||
isSuccessfulDevelopment,
|
||||
isSuccessfulProduction,
|
||||
} = require('../../utils');
|
||||
beforeEach(async () => {
|
||||
await bootstrap({ directory: global.testDirectory, template: __dirname });
|
||||
});
|
||||
|
||||
describe('bootstrap sass', () => {
|
||||
it('builds in development', async () => {
|
||||
await isSuccessfulDevelopment({ directory: global.testDirectory });
|
||||
});
|
||||
it('builds in production', async () => {
|
||||
await isSuccessfulProduction({ directory: global.testDirectory });
|
||||
});
|
||||
});
|
||||
9
fixtures/smoke/boostrap-sass/package.json
Normal file
9
fixtures/smoke/boostrap-sass/package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"bootstrap": "4.x",
|
||||
"node-sass": "4.x",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"react-scripts": "latest"
|
||||
}
|
||||
}
|
||||
9
fixtures/smoke/boostrap-sass/public/index.html
Normal file
9
fixtures/smoke/boostrap-sass/public/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
5
fixtures/smoke/boostrap-sass/src/index.js
Normal file
5
fixtures/smoke/boostrap-sass/src/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.sass';
|
||||
|
||||
ReactDOM.render(<div />, document.getElementById('root'));
|
||||
1
fixtures/smoke/boostrap-sass/src/index.sass
Normal file
1
fixtures/smoke/boostrap-sass/src/index.sass
Normal file
@@ -0,0 +1 @@
|
||||
@import "~bootstrap/scss/bootstrap.scss";
|
||||
17
fixtures/smoke/builds-with-multiple-runtimes/index.test.js
Normal file
17
fixtures/smoke/builds-with-multiple-runtimes/index.test.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const {
|
||||
bootstrap,
|
||||
isSuccessfulDevelopment,
|
||||
isSuccessfulProduction,
|
||||
} = require('../../utils');
|
||||
beforeEach(async () => {
|
||||
await bootstrap({ directory: global.testDirectory, template: __dirname });
|
||||
});
|
||||
|
||||
describe('builds-with-multiple-runtimes', () => {
|
||||
it('builds in development', async () => {
|
||||
await isSuccessfulDevelopment({ directory: global.testDirectory });
|
||||
});
|
||||
it('builds in production', async () => {
|
||||
await isSuccessfulProduction({ directory: global.testDirectory });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"dva": "2.4.0",
|
||||
"ky": "0.3.0",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"react-scripts": "latest"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
5
fixtures/smoke/jest.config.js
Normal file
5
fixtures/smoke/jest.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.js'],
|
||||
setupTestFrameworkScriptFile: './setupSmokeTests.js',
|
||||
};
|
||||
10
fixtures/smoke/setupSmokeTests.js
Normal file
10
fixtures/smoke/setupSmokeTests.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const fs = require('fs-extra');
|
||||
const tempy = require('tempy');
|
||||
|
||||
beforeEach(() => {
|
||||
global.testDirectory = tempy.directory();
|
||||
jest.setTimeout(1000 * 60 * 5);
|
||||
});
|
||||
afterEach(() => {
|
||||
fs.removeSync(global.testDirectory);
|
||||
});
|
||||
75
fixtures/utils.js
Normal file
75
fixtures/utils.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const execa = require('execa');
|
||||
const fs = require('fs-extra');
|
||||
const getPort = require('get-port');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const stripAnsi = require('strip-ansi');
|
||||
|
||||
async function bootstrap({ directory, template }) {
|
||||
await Promise.all(
|
||||
['public/', 'src/', 'package.json'].map(async file =>
|
||||
fs.copy(path.join(template, file), path.join(directory, file))
|
||||
)
|
||||
);
|
||||
await execa('yarnpkg', ['install', '--mutex', 'network'], { cwd: directory });
|
||||
}
|
||||
|
||||
async function isSuccessfulDevelopment({ directory }) {
|
||||
const { stdout, stderr } = await execa(
|
||||
'./node_modules/.bin/react-scripts',
|
||||
['start', '--smoke-test'],
|
||||
{
|
||||
cwd: directory,
|
||||
env: { BROWSER: 'none', PORT: await getPort() },
|
||||
}
|
||||
);
|
||||
|
||||
if (!/Compiled successfully/.test(stdout)) {
|
||||
throw new Error(`stdout: ${stdout}${os.EOL + os.EOL}stderr: ${stderr}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function isSuccessfulProduction({ directory }) {
|
||||
const { stdout, stderr } = await execa(
|
||||
'./node_modules/.bin/react-scripts',
|
||||
['build'],
|
||||
{
|
||||
cwd: directory,
|
||||
}
|
||||
);
|
||||
|
||||
if (!/Compiled successfully/.test(stdout)) {
|
||||
throw new Error(`stdout: ${stdout}${os.EOL + os.EOL}stderr: ${stderr}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function getOutputProduction({ directory, env = {} }) {
|
||||
try {
|
||||
const { stdout, stderr } = await execa(
|
||||
'./node_modules/.bin/react-scripts',
|
||||
['build'],
|
||||
{
|
||||
cwd: directory,
|
||||
env: Object.assign({}, { CI: 'false', FORCE_COLOR: '0' }, env),
|
||||
}
|
||||
);
|
||||
return { stdout: stripAnsi(stdout), stderr: stripAnsi(stderr) };
|
||||
} catch (err) {
|
||||
return {
|
||||
stdout: '',
|
||||
stderr: stripAnsi(
|
||||
err.message
|
||||
.split(os.EOL)
|
||||
.slice(2)
|
||||
.join(os.EOL)
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
bootstrap,
|
||||
isSuccessfulDevelopment,
|
||||
isSuccessfulProduction,
|
||||
getOutputProduction,
|
||||
};
|
||||
@@ -18,17 +18,20 @@
|
||||
"format": "prettier --trailing-comma es5 --single-quote --write 'packages/*/*.js' 'packages/*/!(node_modules)/**/*.js'"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-spawn": "^6.0.5",
|
||||
"async-sema": "^2.1.3",
|
||||
"eslint": "5.6.0",
|
||||
"execa": "1.0.0",
|
||||
"fs-extra": "^7.0.0",
|
||||
"get-port": "^4.0.0",
|
||||
"husky": "1.0.0-rc.15",
|
||||
"jest": "^23.6.0",
|
||||
"lerna": "2.9.1",
|
||||
"lerna-changelog": "^0.8.0",
|
||||
"lint-staged": "^7.0.5",
|
||||
"meow": "^5.0.0",
|
||||
"multimatch": "^2.1.0",
|
||||
"prettier": "1.14.3",
|
||||
"strip-ansi": "^4.0.0",
|
||||
"svg-term-cli": "^2.1.1",
|
||||
"tempy": "^0.2.1"
|
||||
},
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`formats various webpack errors correctly eslint errors 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
"[7m./template/src/App.js[27m
|
||||
[1mLine 8:[22m 'c' is not defined [31m[4mno-undef[24m[39m
|
||||
|
||||
Search for the [4m[31mkeywords[39m[24m to learn more about each error.",
|
||||
],
|
||||
"warnings": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`formats various webpack errors correctly eslint warning 1`] = `
|
||||
Object {
|
||||
"errors": Array [],
|
||||
"warnings": Array [
|
||||
"[7m./template/src/App.js[27m
|
||||
[1mLine 7:[22m 'unUsed' is defined but never used [33m[4mno-unused-vars[24m[39m",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`formats various webpack errors correctly export not found 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
"[7m./template/src/index.js 1:182-185[27m
|
||||
'./App' does not contain an export named 'App'.",
|
||||
],
|
||||
"warnings": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`formats various webpack errors correctly invalid css syntax 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
"[7m./template/src/App.css[27m
|
||||
Syntax error: (19:1) Unexpected }
|
||||
|
||||
17 | font-size: calc(10px + 2vmin);
|
||||
18 | color: white;
|
||||
> 19 | }
|
||||
| ^
|
||||
20 |
|
||||
21 | .App-link {",
|
||||
],
|
||||
"warnings": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`formats various webpack errors correctly invalid js syntax (babel) 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
"[7m./template/src/App.js[27m
|
||||
Syntax error: Expected corresponding JSX closing tag for <div> (10:27)
|
||||
|
||||
8 | render() {
|
||||
9 | return (
|
||||
> 10 | <div className=\\"App\\"></p>
|
||||
| ^
|
||||
11 | <header className=\\"App-header\\">
|
||||
12 | <img src={logo} className=\\"App-logo\\" alt=\\"logo\\" />
|
||||
13 | <p>",
|
||||
],
|
||||
"warnings": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`formats various webpack errors correctly module not found 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
"[7m./template/src/App.js[27m
|
||||
Module not found: Can't resolve 'blabla' in '/Users/joe/Documents/Development/OSS/create-react-app/packages/react-scripts/template/src'",
|
||||
],
|
||||
"warnings": Array [
|
||||
"[7m./template/src/App.js[27m
|
||||
[1mLine 5:[22m 'bla' is defined but never used [33m[4mno-unused-vars[24m[39m",
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const formatWebpackMessages = require('../formatWebpackMessages');
|
||||
|
||||
// TODO: test these messages by actually running a build so we can validate
|
||||
// webpack upgrades didn't break any of our massaging
|
||||
// https://github.com/facebook/create-react-app/pull/5137
|
||||
describe('formats various webpack errors correctly', () => {
|
||||
it('invalid js syntax (babel)', () => {
|
||||
const json = {
|
||||
errors: [
|
||||
'./template/src/App.js\nModule Error (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/thread-loader/dist/cjs.js):\n\n Line 10: Parsing error: Expected corresponding JSX closing tag for <div>\n\n 8 | render() {\n 9 | return (\n> 10 | <div className="App"></p>\n | ^\n 11 | <header className="App-header">\n 12 | <img src={logo} className="App-logo" alt="logo" />\n 13 | <p>\n\n\n @ ./template/src/index.js 1:77-100 1:182-185\n @ multi ./config/polyfills.js ./template/src/index.js',
|
||||
'./template/src/App.js\nModule build failed (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/thread-loader/dist/cjs.js):\nThread Loader (Worker 0)\n/Users/joe/Documents/Development/OSS/create-react-app/packages/react-scripts/template/src/App.js: Expected corresponding JSX closing tag for <div> (10:27)\n\n 8 | render() {\n 9 | return (\n> 10 | <div className="App"></p>\n | ^\n 11 | <header className="App-header">\n 12 | <img src={logo} className="App-logo" alt="logo" />\n 13 | <p>\n\n at _class.raise (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:779:15)\n at _class.jsxParseElementAt (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:8111:18)\n at _class.jsxParseElement (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:8137:19)\n at _class.parseExprAtom (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:8144:21)\n at _class.parseExprSubscripts (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:2758:21)\n at _class.parseMaybeUnary (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:2737:21)\n at _class.parseExprOps (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:2646:21)\n at _class.parseMaybeConditional (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:2618:21)\n at _class.parseMaybeAssign (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:2565:21)\n at _class.parseMaybeAssign (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/@babel/core/node_modules/babylon/lib/index.js:7270:57)\n @ ./template/src/index.js 1:77-100 1:182-185\n @ multi ./config/polyfills.js ./template/src/index.js',
|
||||
],
|
||||
warnings: [],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('invalid css syntax', () => {
|
||||
const json = {
|
||||
errors: [
|
||||
'./template/src/App.css\nModule build failed (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/mini-css-extract-plugin/dist/loader.js):\nModuleBuildError: Module build failed (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/postcss-loader/lib/index.js):\nSyntax Error \n\n(19:1) Unexpected }\n\n 17 | font-size: calc(10px + 2vmin);\n 18 | color: white;\n> 19 | }\n | ^\n 20 | \n 21 | .App-link {\n\n at runLoaders (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/webpack/lib/NormalModule.js:286:20)\n at /Users/joe/Documents/Development/OSS/create-react-app/node_modules/loader-runner/lib/LoaderRunner.js:364:11\n at /Users/joe/Documents/Development/OSS/create-react-app/node_modules/loader-runner/lib/LoaderRunner.js:230:18\n at context.callback (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/loader-runner/lib/LoaderRunner.js:111:13)\n at Promise.resolve.then.then.catch (/Users/joe/Documents/Development/OSS/create-react-app/node_modules/postcss-loader/lib/index.js:194:44)\n at <anonymous>\n @ ./template/src/App.js 1:1905-1923\n @ ./template/src/index.js\n @ multi ./config/polyfills.js ./template/src/index.js',
|
||||
],
|
||||
warnings: [],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('module not found', () => {
|
||||
const json = {
|
||||
errors: [
|
||||
"./template/src/App.js\nModule not found: Error: Can't resolve 'blabla' in '/Users/joe/Documents/Development/OSS/create-react-app/packages/react-scripts/template/src'\n @ ./template/src/App.js 5:0-25\n @ ./template/src/index.js\n @ multi ./config/polyfills.js ../react-dev-utils/webpackHotDevClient.js ./template/src/index.js",
|
||||
],
|
||||
warnings: [
|
||||
"./template/src/App.js\nModule Warning (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/thread-loader/dist/cjs.js):\n\n \u001b[1mLine 5:\u001b[22m 'bla' is defined but never used \u001b[33m\u001b[4mno-unused-vars\u001b[24m\u001b[39m\n\n\n @ ./template/src/index.js 5:0-24 7:36-39\n @ multi ./config/polyfills.js ../react-dev-utils/webpackHotDevClient.js ./template/src/index.js",
|
||||
],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('eslint errors', () => {
|
||||
const json = {
|
||||
errors: [
|
||||
"./template/src/App.js\nModule Error (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/thread-loader/dist/cjs.js):\n\n \u001b[1mLine 8:\u001b[22m 'c' is not defined \u001b[31m\u001b[4mno-undef\u001b[24m\u001b[39m\n\nSearch for the \u001b[4m\u001b[31mkeywords\u001b[39m\u001b[24m to learn more about each error.\n @ ./template/src/index.js 1:77-100 1:182-185\n @ multi ./config/polyfills.js ./template/src/index.js",
|
||||
],
|
||||
warnings: [],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('eslint warning', () => {
|
||||
const json = {
|
||||
errors: [],
|
||||
warnings: [
|
||||
"./template/src/App.js\nModule Warning (from /Users/joe/Documents/Development/OSS/create-react-app/node_modules/thread-loader/dist/cjs.js):\n\n \u001b[1mLine 7:\u001b[22m 'unUsed' is defined but never used \u001b[33m\u001b[4mno-unused-vars\u001b[24m\u001b[39m\n\n\n @ ./template/src/index.js 1:77-100 1:182-185\n @ multi ./config/polyfills.js ./template/src/index.js",
|
||||
],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('export not found', () => {
|
||||
const json = {
|
||||
errors: [
|
||||
"./template/src/index.js 1:182-185\n\"export 'App' was not found in './App'\n @ multi ./config/polyfills.js ./template/src/index.js",
|
||||
],
|
||||
warnings: [],
|
||||
};
|
||||
|
||||
expect(formatWebpackMessages(json)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -76,7 +76,7 @@ yarn
|
||||
|
||||
# Start local registry
|
||||
tmp_registry_log=`mktemp`
|
||||
nohup npx verdaccio@3.2.0 -c tasks/verdaccio.yaml &>$tmp_registry_log &
|
||||
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
|
||||
# Wait for `verdaccio` to boot
|
||||
grep -q 'http address' <(tail -f $tmp_registry_log)
|
||||
|
||||
@@ -92,22 +92,14 @@ git clean -df
|
||||
./tasks/publish.sh --yes --force-publish=* --skip-git --cd-version=prerelease --exact --npm-tag=latest
|
||||
|
||||
# ******************************************************************************
|
||||
# Now that we have published them, create a clean app folder and install them.
|
||||
# Now that we have published them, run all tests as if they were released.
|
||||
# ******************************************************************************
|
||||
|
||||
# Install the app in a temporary location
|
||||
cd $temp_app_path
|
||||
npx create-react-app test-behavior
|
||||
# Smoke tests
|
||||
./node_modules/.bin/jest --config fixtures/smoke/jest.config.js
|
||||
|
||||
# ******************************************************************************
|
||||
# Now that we used create-react-app to create an app depending on react-scripts,
|
||||
# let's run through all of our behavior tests.
|
||||
# ******************************************************************************
|
||||
|
||||
# Enter the app directory
|
||||
cd "$temp_app_path/test-behavior"
|
||||
|
||||
node "$root_path"/tasks/test-behavior.js "$temp_app_path/test-behavior"
|
||||
# Output tests
|
||||
./node_modules/.bin/jest --config fixtures/output/jest.config.js
|
||||
|
||||
# Cleanup
|
||||
cleanup
|
||||
|
||||
@@ -86,7 +86,7 @@ yarn
|
||||
|
||||
# Start local registry
|
||||
tmp_registry_log=`mktemp`
|
||||
nohup npx verdaccio@3.2.0 -c tasks/verdaccio.yaml &>$tmp_registry_log &
|
||||
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
|
||||
# Wait for `verdaccio` to boot
|
||||
grep -q 'http address' <(tail -f $tmp_registry_log)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ yarn
|
||||
|
||||
# Start local registry
|
||||
tmp_registry_log=`mktemp`
|
||||
nohup npx verdaccio@3.2.0 -c tasks/verdaccio.yaml &>$tmp_registry_log &
|
||||
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
|
||||
# Wait for `verdaccio` to boot
|
||||
grep -q 'http address' <(tail -f $tmp_registry_log)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ yarn
|
||||
|
||||
# Start local registry
|
||||
tmp_registry_log=`mktemp`
|
||||
nohup npx verdaccio@3.2.0 -c tasks/verdaccio.yaml &>$tmp_registry_log &
|
||||
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
|
||||
# Wait for `verdaccio` to boot
|
||||
grep -q 'http address' <(tail -f $tmp_registry_log)
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ yarn
|
||||
|
||||
# Start local registry
|
||||
tmp_registry_log=`mktemp`
|
||||
nohup npx verdaccio@3.2.0 -c tasks/verdaccio.yaml &>$tmp_registry_log &
|
||||
(cd && nohup npx verdaccio@3.8.2 -c "$root_path"/tasks/verdaccio.yaml &>$tmp_registry_log &)
|
||||
# Wait for `verdaccio` to boot
|
||||
grep -q 'http address' <(tail -f $tmp_registry_log)
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const spawn = require('cross-spawn');
|
||||
|
||||
const applicationPath = args.pop();
|
||||
const applicationPackageJson = path.resolve(applicationPath, 'package.json');
|
||||
const applicationSrc = path.resolve(applicationPath, 'src');
|
||||
const applicationModules = path.resolve(applicationPath, 'node_modules');
|
||||
|
||||
const fixturePath = path.resolve(__dirname, '..', 'fixtures', 'behavior');
|
||||
const fixtures = fs
|
||||
.readdirSync(fixturePath)
|
||||
.map(fixture => path.resolve(fixturePath, fixture))
|
||||
.filter(path => fs.lstatSync(path).isDirectory);
|
||||
|
||||
const packageContents = require(applicationPackageJson);
|
||||
|
||||
function install({ root }) {
|
||||
spawn.sync('yarnpkg', ['--cwd', root, 'install'], { cwd: root });
|
||||
}
|
||||
|
||||
function startApp({ root }) {
|
||||
const output = spawn
|
||||
.sync('yarnpkg', ['start', '--smoke-test'], { cwd: root })
|
||||
.output.join('');
|
||||
|
||||
if (!/Compiled successfully/.test(output)) {
|
||||
throw new Error(output);
|
||||
}
|
||||
|
||||
console.log('\t = application started: ', output);
|
||||
}
|
||||
|
||||
function buildApp({ root }) {
|
||||
const output = spawn
|
||||
.sync('yarnpkg', ['build'], { cwd: root })
|
||||
.output.join('');
|
||||
|
||||
if (!/Compiled successfully/.test(output)) {
|
||||
throw new Error(output);
|
||||
}
|
||||
|
||||
console.log('\t = application built: ', output);
|
||||
}
|
||||
|
||||
console.log(`=> checking ${fixtures.length} fixtures`);
|
||||
for (const fixture of fixtures) {
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
dependencies,
|
||||
devDependencies,
|
||||
} = require(path.resolve(fixture, 'package.json'));
|
||||
console.log(`\t * checking fixture ${name}`);
|
||||
console.log(`\t ... this fixture: ${description}`);
|
||||
|
||||
fs.emptyDirSync(applicationSrc);
|
||||
fs.emptyDirSync(applicationModules);
|
||||
fs.copySync(path.resolve(fixture, 'src'), applicationSrc);
|
||||
|
||||
try {
|
||||
fs.writeJsonSync(
|
||||
applicationPackageJson,
|
||||
Object.assign({}, packageContents, {
|
||||
dependencies: Object.assign(
|
||||
{},
|
||||
packageContents.dependencies,
|
||||
dependencies
|
||||
),
|
||||
devDependencies: Object.assign(
|
||||
{},
|
||||
packageContents.devDependencies,
|
||||
devDependencies
|
||||
),
|
||||
}),
|
||||
{
|
||||
spaces: 2,
|
||||
EOL: os.EOL,
|
||||
}
|
||||
);
|
||||
install({ root: applicationPath });
|
||||
startApp({ root: applicationPath });
|
||||
buildApp({ root: applicationPath });
|
||||
} catch (e) {
|
||||
console.error(`\t ! failed on ${name}:`);
|
||||
throw e;
|
||||
} finally {
|
||||
fs.writeJsonSync(applicationPackageJson, packageContents, {
|
||||
spaces: 2,
|
||||
EOL: os.EOL,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user