diff --git a/fixtures/browser/graphql-with-mjs/__snapshots__/index.test.js.snap b/fixtures/browser/graphql-with-mjs/__snapshots__/index.test.js.snap
deleted file mode 100644
index 5e56b8d6..00000000
--- a/fixtures/browser/graphql-with-mjs/__snapshots__/index.test.js.snap
+++ /dev/null
@@ -1,5 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`graphql with mjs entrypoint correctly bundles files in development 1`] = `"Pikachu"`;
-
-exports[`graphql with mjs entrypoint correctly bundles files in production 1`] = `"Pikachu"`;
diff --git a/fixtures/browser/graphql-with-mjs/index.test.js b/fixtures/browser/graphql-with-mjs/index.test.js
deleted file mode 100644
index 6149ed88..00000000
--- a/fixtures/browser/graphql-with-mjs/index.test.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const {
- bootstrap,
- startDevelopmentServer,
- startProductionServer,
-} = require('../../utils');
-const puppeteer = require('puppeteer');
-
-beforeEach(async () => {
- await bootstrap({ directory: global.testDirectory, template: __dirname });
- global.appDevPort = await startDevelopmentServer({
- directory: global.testDirectory,
- });
- global.appProdPort = await startProductionServer({
- directory: global.testDirectory,
- });
- // Wait for serve to boot up
- await new Promise(resolve => setTimeout(resolve, 1000));
-});
-
-// https://github.com/facebook/create-react-app/issues/5234
-// https://github.com/facebook/create-react-app/pull/5258
-describe('graphql with mjs entrypoint', () => {
- it('correctly bundles files in development', async () => {
- const browser = await puppeteer.launch({ headless: true });
- try {
- const page = await browser.newPage();
- await page.goto(`http://localhost:${global.appDevPort}/`);
- await page.waitForSelector('.Pokemon-Name-Data');
- const output = await page.evaluate(() => {
- return Array.from(
- document.getElementsByClassName('Pokemon-Name-Data')
- ).pop().innerHTML;
- });
- expect(output).toMatchSnapshot();
- } finally {
- browser.close();
- }
- });
-
- it('correctly bundles files in production', async () => {
- const browser = await puppeteer.launch({ headless: true });
- try {
- const page = await browser.newPage();
- await page.goto(`http://localhost:${global.appProdPort}/`);
- await page.waitForSelector('.Pokemon-Name-Data');
- const output = await page.evaluate(() => {
- return Array.from(
- document.getElementsByClassName('Pokemon-Name-Data')
- ).pop().innerHTML;
- });
- expect(output).toMatchSnapshot();
- } finally {
- browser.close();
- }
- });
-});
diff --git a/fixtures/browser/jest.config.js b/fixtures/browser/jest.config.js
deleted file mode 100644
index e3ab37e7..00000000
--- a/fixtures/browser/jest.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports = {
- testEnvironment: 'node',
- testMatch: ['**/*.test.js'],
- testPathIgnorePatterns: ['/src/', 'node_modules'],
- setupTestFrameworkScriptFile: './setupBrowserTests.js',
- forceExit: true,
-};
diff --git a/fixtures/browser/setupBrowserTests.js b/fixtures/browser/setupBrowserTests.js
deleted file mode 100644
index 9bbc3ffb..00000000
--- a/fixtures/browser/setupBrowserTests.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const fs = require('fs-extra');
-const tempy = require('tempy');
-beforeEach(() => {
- global.testDirectory = tempy.directory();
- jest.setTimeout(1000 * 60 * 5);
-});
-afterEach(() => {
- fs.removeSync(global.testDirectory);
-});
diff --git a/fixtures/output/jest.config.js b/fixtures/output/jest.config.js
deleted file mode 100644
index fa718fa3..00000000
--- a/fixtures/output/jest.config.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- testEnvironment: 'node',
- testMatch: ['**/*.test.js'],
- setupTestFrameworkScriptFile: './setupOutputTests.js',
-};
diff --git a/fixtures/output/setupOutputTests.js b/fixtures/output/setupOutputTests.js
deleted file mode 100644
index b7094069..00000000
--- a/fixtures/output/setupOutputTests.js
+++ /dev/null
@@ -1,6 +0,0 @@
-beforeAll(() => {
- jest.setTimeout(1000 * 60 * 5);
-});
-beforeEach(() => {
- jest.setTimeout(1000 * 60 * 5);
-});
diff --git a/fixtures/output/webpack-message-formatting/index.test.js b/fixtures/output/webpack-message-formatting/index.test.js
deleted file mode 100644
index 475fb108..00000000
--- a/fixtures/output/webpack-message-formatting/index.test.js
+++ /dev/null
@@ -1,157 +0,0 @@
-const {
- bootstrap,
- getOutputDevelopment,
- 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();
- });
-
- it('formats css syntax error', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppCss.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats unknown export', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppUnknownExport.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats aliased unknown export', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppAliasUnknownExport.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats no default export', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppNoDefault.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats missing package', async () => {
- 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();
- });
-
- it('helps when users tries to use sass', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppSass.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats file not found error', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppUnknownFile.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-
- it('formats case sensitive path error', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppIncorrectCase.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputDevelopment({ directory: testDirectory });
- if (process.platform === 'darwin') {
- expect(response.stderr).toMatch(
- `Cannot find file: 'export5.js' does not match the corresponding name on disk: './src/Export5.js'.`
- );
- } else {
- expect(response.stderr).not.toEqual(''); // TODO: figure out how we can test this on Linux/Windows
- // I believe getting this working requires we tap into enhanced-resolve
- // pipeline, which is debt we don't want to take on right now.
- }
- });
-
- it('formats out of scope error', async () => {
- fs.copySync(
- path.join(__dirname, 'src', 'AppOutOfScopeImport.js'),
- path.join(testDirectory, 'src', 'App.js')
- );
-
- const response = await getOutputProduction({ directory: testDirectory });
- expect(response).toMatchSnapshot();
- });
-});
diff --git a/fixtures/output/webpack-message-formatting/public/index.html b/fixtures/output/webpack-message-formatting/public/index.html
deleted file mode 100644
index 86010b24..00000000
--- a/fixtures/output/webpack-message-formatting/public/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- React App
-
-
-
-
-
diff --git a/fixtures/smoke/boostrap-sass/index.test.js b/fixtures/smoke/boostrap-sass/index.test.js
deleted file mode 100644
index 44f3a6c9..00000000
--- a/fixtures/smoke/boostrap-sass/index.test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-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 });
- });
-});
diff --git a/fixtures/smoke/boostrap-sass/public/index.html b/fixtures/smoke/boostrap-sass/public/index.html
deleted file mode 100644
index 86010b24..00000000
--- a/fixtures/smoke/boostrap-sass/public/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- React App
-
-
-
-
-
diff --git a/fixtures/smoke/builds-with-multiple-runtimes/index.test.js b/fixtures/smoke/builds-with-multiple-runtimes/index.test.js
deleted file mode 100644
index 990ea7b3..00000000
--- a/fixtures/smoke/builds-with-multiple-runtimes/index.test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-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 });
- });
-});
diff --git a/fixtures/smoke/builds-with-multiple-runtimes/public/index.html b/fixtures/smoke/builds-with-multiple-runtimes/public/index.html
deleted file mode 100644
index 86010b24..00000000
--- a/fixtures/smoke/builds-with-multiple-runtimes/public/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- React App
-
-
-
-
-
diff --git a/fixtures/smoke/issue-5176-flow-class-properties/index.test.js b/fixtures/smoke/issue-5176-flow-class-properties/index.test.js
deleted file mode 100644
index 72a7a3da..00000000
--- a/fixtures/smoke/issue-5176-flow-class-properties/index.test.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const { bootstrap, isSuccessfulTest } = require('../../utils');
-beforeEach(async () => {
- await bootstrap({ directory: global.testDirectory, template: __dirname });
-});
-
-describe('issue #5176 (flow class properties interaction)', () => {
- it('passes tests', async () => {
- await isSuccessfulTest({
- directory: global.testDirectory,
- jestEnvironment: 'node',
- });
- });
-});
diff --git a/fixtures/smoke/issue-5176-flow-class-properties/public/index.html b/fixtures/smoke/issue-5176-flow-class-properties/public/index.html
deleted file mode 100644
index 86010b24..00000000
--- a/fixtures/smoke/issue-5176-flow-class-properties/public/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- React App
-
-
-
-
-
diff --git a/fixtures/smoke/relative-paths/index.test.js b/fixtures/smoke/relative-paths/index.test.js
deleted file mode 100644
index 1f367f64..00000000
--- a/fixtures/smoke/relative-paths/index.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const fs = require('fs-extra');
-const globby = require('globby');
-const path = require('path');
-const {
- bootstrap,
- isSuccessfulDevelopment,
- isSuccessfulProduction,
-} = require('../../utils');
-beforeEach(async () => {
- await bootstrap({ directory: global.testDirectory, template: __dirname });
-});
-
-describe('relative paths', () => {
- // TODO: enable when development relative paths are supported
- xit('builds in development', async () => {
- await isSuccessfulDevelopment({ directory: global.testDirectory });
- });
- it('builds in production', async () => {
- await isSuccessfulProduction({ directory: global.testDirectory });
-
- const buildDir = path.join(global.testDirectory, 'build');
- const cssFile = path.join(
- buildDir,
- globby.sync('**/*.css', { cwd: buildDir }).pop()
- );
- const svgFile = path.join(
- buildDir,
- globby.sync('**/*.svg', { cwd: buildDir }).pop()
- );
- const desiredPath = /url\((.+?)\)/
- .exec(fs.readFileSync(cssFile, 'utf8'))
- .pop();
- expect(path.resolve(path.join(path.dirname(cssFile), desiredPath))).toBe(
- path.resolve(svgFile)
- );
- });
-});
diff --git a/fixtures/smoke/relative-paths/public/index.html b/fixtures/smoke/relative-paths/public/index.html
deleted file mode 100644
index 86010b24..00000000
--- a/fixtures/smoke/relative-paths/public/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- React App
-
-
-
-
-
diff --git a/fixtures/smoke/setupSmokeTests.js b/fixtures/smoke/setupSmokeTests.js
deleted file mode 100644
index 1d4038de..00000000
--- a/fixtures/smoke/setupSmokeTests.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const fs = require('fs-extra');
-const tempy = require('tempy');
-
-beforeEach(() => {
- global.testDirectory = tempy.directory();
- jest.setTimeout(1000 * 60 * 5);
-});
-afterEach(() => {
- fs.removeSync(global.testDirectory);
-});
diff --git a/fixtures/utils.js b/fixtures/utils.js
deleted file mode 100644
index 0c08a327..00000000
--- a/fixtures/utils.js
+++ /dev/null
@@ -1,177 +0,0 @@
-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 }) {
- const shouldInstallScripts = process.env.CI && process.env.CI !== 'false';
- await Promise.all(
- ['public/', 'src/', 'package.json'].map(async file =>
- fs.copy(path.join(template, file), path.join(directory, file))
- )
- );
- if (shouldInstallScripts) {
- const packageJson = fs.readJsonSync(path.join(directory, 'package.json'));
- packageJson.dependencies = Object.assign({}, packageJson.dependencies, {
- 'react-scripts': 'latest',
- });
- fs.writeJsonSync(path.join(directory, 'package.json'), packageJson);
- }
- await execa('yarnpkg', ['install', '--mutex', 'network'], { cwd: directory });
- if (!shouldInstallScripts) {
- fs.ensureSymlinkSync(
- path.resolve(
- path.join(
- __dirname,
- '..',
- 'packages',
- 'react-scripts',
- 'bin',
- 'react-scripts.js'
- )
- ),
- path.join(directory, 'node_modules', '.bin', 'react-scripts')
- );
- await execa('yarnpkg', ['link', 'react-scripts'], { 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 isSuccessfulTest({ directory, jestEnvironment = 'jsdom' }) {
- await execa(
- './node_modules/.bin/react-scripts',
- ['test', '--env', jestEnvironment, '--ci'],
- {
- cwd: directory,
- env: { CI: 'true' },
- }
- );
-}
-
-async function getOutputDevelopment({ directory, env = {} }) {
- try {
- const { stdout, stderr } = await execa(
- './node_modules/.bin/react-scripts',
- ['start', '--smoke-test'],
- {
- cwd: directory,
- env: Object.assign(
- {},
- {
- BROWSER: 'none',
- PORT: await getPort(),
- 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)
- ),
- };
- }
-}
-
-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)
- ),
- };
- }
-}
-
-async function startDevelopmentServer({ directory, env = {} }) {
- const port = await getPort();
- execa('./node_modules/.bin/react-scripts', ['start'], {
- cwd: directory,
- env: Object.assign(
- {},
- {
- BROWSER: 'none',
- PORT: port,
- CI: 'false',
- FORCE_COLOR: '0',
- },
- env
- ),
- });
- return port;
-}
-
-async function startProductionServer({ directory, env = {} }) {
- const port = await getPort();
- await execa('./node_modules/.bin/react-scripts', ['build'], {
- cwd: directory,
- env: Object.assign({}, { CI: 'false' }, env),
- });
- execa('./node_modules/.bin/serve', ['-s', 'build', '-p', port], {
- cwd: directory,
- });
- return port;
-}
-
-module.exports = {
- bootstrap,
- isSuccessfulDevelopment,
- isSuccessfulProduction,
- isSuccessfulTest,
- getOutputDevelopment,
- getOutputProduction,
- startDevelopmentServer,
- startProductionServer,
-};
diff --git a/package.json b/package.json
index ec66107f..71eaa2a6 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,6 @@
"compile:lockfile": "node tasks/compile-lockfile.js"
},
"devDependencies": {
- "async-sema": "^2.1.3",
"eslint": "5.6.0",
"execa": "1.0.0",
"fs-extra": "^7.0.0",
@@ -36,7 +35,8 @@
"puppeteer": "^1.8.0",
"strip-ansi": "^4.0.0",
"svg-term-cli": "^2.1.1",
- "tempy": "^0.2.1"
+ "tempy": "^0.2.1",
+ "wait-for-localhost": "2.0.1"
},
"husky": {
"hooks": {
diff --git a/tasks/e2e-behavior.sh b/tasks/e2e-behavior.sh
index f4ed7765..1ca2e012 100755
--- a/tasks/e2e-behavior.sh
+++ b/tasks/e2e-behavior.sh
@@ -95,14 +95,9 @@ git clean -df
# Now that we have published them, run all tests as if they were released.
# ******************************************************************************
-# Browser tests
-CI=true ./node_modules/.bin/jest --config fixtures/browser/jest.config.js
-
-# Smoke tests
-CI=true ./node_modules/.bin/jest --config fixtures/smoke/jest.config.js
-
-# Output tests
-CI=true ./node_modules/.bin/jest --config fixtures/output/jest.config.js
+# Run all tests
+cd test/
+CI=true ../node_modules/.bin/jest -w 2
# Cleanup
cleanup
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 00000000..f6340108
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,45 @@
+# Create React App End-to-End Tests
+
+## Usage
+
+These tests ensure various functionality contracts are upheld across dependency upgrades.
+
+To get started locally, run `cd packages/react-scripts/ && yarn link; cd ../../test/ && ../node_modules/.bin/jest --watchAll`.
+
+It's suggested that you filter down tests to avoid re-running everything. The most common tests will be the webpack messages.
+To only run the webpack messages, type `p` followed by `webpack-message` and press `[enter]`.
+
+## How do these work?
+
+### `fixtures/`
+
+Each `fixture/` gets spun up in a temporary directory and has its dependencies installed with Yarn PnP (for speed).
+To opt-out of PnP, create a `.disable-pnp` file in the specific fixture directory.
+
+A global (`testSetup`) is created which has a few interesting properties:
+
+- `testSetup.testDirectory`: the directory containing the test application
+- `testSetup.scripts`: an object allowing you to invoke `react-scripts` commands and friends
+
+All tests for each `fixture/` are then ran.
+
+#### `testSetup.scripts`
+
+##### `start`
+
+This will run the `start` command, it can be ran asynchronously or blocking if `{ smoke: true }` is used.
+If ran asynchronously, it will return the `port` and a `done` function to clean up the process.
+If ran blocking, it will return the `stdout` and `stderr` of the process.
+
+##### `build`
+
+This will run the `build` command and return the `stdout` and `stderr` of the process.
+
+##### `test`
+
+This will run the `test` command and return the `stdout` and `stderr` of the process.
+
+##### `serve`
+
+This will run serve the application.
+It will return the `port` and a `done` function to clean up the process.
diff --git a/fixtures/browser/graphql-with-mjs/public/index.html b/test/fixtures/__shared__/template/public/index.html
similarity index 100%
rename from fixtures/browser/graphql-with-mjs/public/index.html
rename to test/fixtures/__shared__/template/public/index.html
diff --git a/test/fixtures/__shared__/test-setup.js b/test/fixtures/__shared__/test-setup.js
new file mode 100644
index 00000000..30d1ac64
--- /dev/null
+++ b/test/fixtures/__shared__/test-setup.js
@@ -0,0 +1,21 @@
+const path = require('path');
+const fs = require('fs-extra');
+const TestSetup = require('./util/setup');
+
+const fixturePath = path.dirname(module.parent.filename);
+const fixtureName = path.basename(fixturePath);
+const disablePnp = fs.existsSync(path.resolve(fixturePath, '.disable-pnp'));
+const testSetup = new TestSetup(fixtureName, fixturePath, {
+ pnp: !disablePnp,
+});
+
+beforeAll(async () => {
+ await testSetup.setup();
+}, 1000 * 60 * 5);
+afterAll(async () => {
+ await testSetup.teardown();
+});
+
+beforeEach(() => jest.setTimeout(1000 * 60 * 5));
+
+module.exports = testSetup;
diff --git a/test/fixtures/__shared__/util/scripts.js b/test/fixtures/__shared__/util/scripts.js
new file mode 100644
index 00000000..0965c654
--- /dev/null
+++ b/test/fixtures/__shared__/util/scripts.js
@@ -0,0 +1,113 @@
+const execa = require('execa');
+const getPort = require('get-port');
+const os = require('os');
+const stripAnsi = require('strip-ansi');
+const waitForLocalhost = require('wait-for-localhost');
+
+function stripYarn(output) {
+ let lines = output.split('\n');
+
+ let runIndex = lines.findIndex(line => line.match(/^yarn run/));
+ if (runIndex !== -1) {
+ lines.splice(0, runIndex + 2);
+ lines = lines.filter(line => !line.match(/^info Visit.*yarnpkg/));
+ }
+
+ return lines.join('\n');
+}
+
+function execaSafe(...args) {
+ return execa(...args)
+ .then(({ stdout, stderr, ...rest }) => ({
+ fulfilled: true,
+ rejected: false,
+ stdout: stripYarn(stripAnsi(stdout)),
+ stderr: stripYarn(stripAnsi(stderr)),
+ ...rest,
+ }))
+ .catch(err => ({
+ fulfilled: false,
+ rejected: true,
+ reason: err,
+ stdout: '',
+ stderr: stripYarn(
+ stripAnsi(
+ err.message
+ .split(os.EOL)
+ .slice(2)
+ .join(os.EOL)
+ )
+ ),
+ }));
+}
+
+module.exports = class ReactScripts {
+ constructor(root) {
+ this.root = root;
+ }
+
+ async start({ smoke = false, env = {} } = {}) {
+ const port = await getPort();
+ const options = {
+ cwd: this.root,
+ env: Object.assign(
+ {},
+ {
+ CI: 'false',
+ FORCE_COLOR: '0',
+ BROWSER: 'none',
+ PORT: port,
+ },
+ env
+ ),
+ };
+
+ if (smoke) {
+ return await execaSafe('yarnpkg', ['start', '--smoke-test'], options);
+ }
+ const startProcess = execa('yarnpkg', ['start'], options);
+ await waitForLocalhost(port);
+ return {
+ port,
+ done() {
+ startProcess.kill('SIGKILL');
+ },
+ };
+ }
+
+ async build({ env = {} } = {}) {
+ return await execaSafe('yarnpkg', ['build'], {
+ cwd: this.root,
+ env: Object.assign({}, { CI: 'false', FORCE_COLOR: '0' }, env),
+ });
+ }
+
+ async serve() {
+ const port = await getPort();
+ const serveProcess = execa(
+ 'yarnpkg',
+ ['serve', '--', '-p', port, '-s', 'build/'],
+ {
+ cwd: this.root,
+ }
+ );
+ await waitForLocalhost(port);
+ return {
+ port,
+ done() {
+ serveProcess.kill('SIGKILL');
+ },
+ };
+ }
+
+ async test({ jestEnvironment = 'jsdom', env = {} } = {}) {
+ return await execaSafe(
+ 'yarnpkg',
+ ['test', '--env', jestEnvironment, '--ci'],
+ {
+ cwd: this.root,
+ env: Object.assign({}, { CI: 'true' }, env),
+ }
+ );
+ }
+};
diff --git a/test/fixtures/__shared__/util/setup.js b/test/fixtures/__shared__/util/setup.js
new file mode 100644
index 00000000..8dd7d2e3
--- /dev/null
+++ b/test/fixtures/__shared__/util/setup.js
@@ -0,0 +1,104 @@
+const execa = require('execa');
+const fs = require('fs-extra');
+const path = require('path');
+const tempy = require('tempy');
+const ReactScripts = require('./scripts');
+
+module.exports = class TestSetup {
+ constructor(fixtureName, templateDirectory, { pnp = true } = {}) {
+ this.fixtureName = fixtureName;
+
+ this.templateDirectory = templateDirectory;
+ this.testDirectory = null;
+ this._scripts = null;
+
+ this.setup = this.setup.bind(this);
+ this.teardown = this.teardown.bind(this);
+
+ this.isLocal = !(process.env.CI && process.env.CI !== 'false');
+ this.settings = { pnp: pnp && !this.isLocal };
+ }
+
+ async setup() {
+ await this.teardown();
+ this.testDirectory = tempy.directory();
+ await fs.copy(
+ path.resolve(__dirname, '..', 'template'),
+ this.testDirectory
+ );
+ await fs.copy(this.templateDirectory, this.testDirectory);
+ await fs.remove(path.resolve(this.testDirectory, 'test.partial.js'));
+ await fs.remove(path.resolve(this.testDirectory, '.disable-pnp'));
+
+ const packageJson = await fs.readJson(
+ path.resolve(this.testDirectory, 'package.json')
+ );
+
+ const shouldInstallScripts = !this.isLocal;
+ if (shouldInstallScripts) {
+ packageJson.dependencies = Object.assign({}, packageJson.dependencies, {
+ 'react-scripts': 'latest',
+ });
+ }
+ packageJson.scripts = Object.assign({}, packageJson.scripts, {
+ start: 'react-scripts start',
+ build: 'react-scripts build',
+ test: 'react-scripts test',
+ });
+ packageJson.license = packageJson.license || 'UNLICENSED';
+ await fs.writeJson(
+ path.resolve(this.testDirectory, 'package.json'),
+ packageJson
+ );
+
+ await execa(
+ 'yarnpkg',
+ [
+ 'install',
+ this.settings.pnp ? '--enable-pnp' : null,
+ '--mutex',
+ 'network',
+ ].filter(Boolean),
+ {
+ cwd: this.testDirectory,
+ }
+ );
+
+ if (!shouldInstallScripts) {
+ await fs.ensureSymlink(
+ path.resolve(
+ path.resolve(
+ __dirname,
+ '../../../..',
+ 'packages',
+ 'react-scripts',
+ 'bin',
+ 'react-scripts.js'
+ )
+ ),
+ path.join(this.testDirectory, 'node_modules', '.bin', 'react-scripts')
+ );
+ await execa('yarnpkg', ['link', 'react-scripts'], {
+ cwd: this.testDirectory,
+ });
+ }
+ }
+
+ get scripts() {
+ if (this.testDirectory == null) {
+ return null;
+ }
+ if (this._scripts == null) {
+ this._scripts = new ReactScripts(this.testDirectory);
+ }
+ return this._scripts;
+ }
+
+ async teardown() {
+ if (this.testDirectory != null) {
+ await fs.remove(this.testDirectory);
+ this.testDirectory = null;
+ this._scripts = null;
+ }
+ }
+};
diff --git a/test/fixtures/boostrap-sass/.disable-pnp b/test/fixtures/boostrap-sass/.disable-pnp
new file mode 100644
index 00000000..e69de29b
diff --git a/test/fixtures/boostrap-sass/index.test.js b/test/fixtures/boostrap-sass/index.test.js
new file mode 100644
index 00000000..4be53d03
--- /dev/null
+++ b/test/fixtures/boostrap-sass/index.test.js
@@ -0,0 +1,16 @@
+const testSetup = require('../__shared__/test-setup');
+
+if (testSetup.isLocal) {
+ // TODO: make this work locally
+ test('skipped locally', () => {});
+} else {
+ test('builds in development', async () => {
+ const { fulfilled } = await testSetup.scripts.start({ smoke: true });
+ expect(fulfilled).toBe(true);
+ });
+
+ test('builds in production', async () => {
+ const { fulfilled } = await testSetup.scripts.build();
+ expect(fulfilled).toBe(true);
+ });
+}
diff --git a/fixtures/smoke/boostrap-sass/package.json b/test/fixtures/boostrap-sass/package.json
similarity index 100%
rename from fixtures/smoke/boostrap-sass/package.json
rename to test/fixtures/boostrap-sass/package.json
diff --git a/fixtures/smoke/boostrap-sass/src/index.js b/test/fixtures/boostrap-sass/src/index.js
similarity index 100%
rename from fixtures/smoke/boostrap-sass/src/index.js
rename to test/fixtures/boostrap-sass/src/index.js
diff --git a/fixtures/smoke/boostrap-sass/src/index.sass b/test/fixtures/boostrap-sass/src/index.sass
similarity index 100%
rename from fixtures/smoke/boostrap-sass/src/index.sass
rename to test/fixtures/boostrap-sass/src/index.sass
diff --git a/test/fixtures/builds-with-multiple-runtimes/index.test.js b/test/fixtures/builds-with-multiple-runtimes/index.test.js
new file mode 100644
index 00000000..64d328ae
--- /dev/null
+++ b/test/fixtures/builds-with-multiple-runtimes/index.test.js
@@ -0,0 +1,10 @@
+const testSetup = require('../__shared__/test-setup');
+
+test('builds in development', async () => {
+ const { fulfilled } = await testSetup.scripts.start({ smoke: true });
+ expect(fulfilled).toBe(true);
+});
+test('builds in production', async () => {
+ const { fulfilled } = await testSetup.scripts.build();
+ expect(fulfilled).toBe(true);
+});
diff --git a/fixtures/smoke/builds-with-multiple-runtimes/package.json b/test/fixtures/builds-with-multiple-runtimes/package.json
similarity index 82%
rename from fixtures/smoke/builds-with-multiple-runtimes/package.json
rename to test/fixtures/builds-with-multiple-runtimes/package.json
index b2792516..b0652fe7 100644
--- a/fixtures/smoke/builds-with-multiple-runtimes/package.json
+++ b/test/fixtures/builds-with-multiple-runtimes/package.json
@@ -1,6 +1,7 @@
{
"dependencies": {
"dva": "2.4.0",
+ "history": "4.7.2",
"ky": "0.3.0",
"react": "latest",
"react-dom": "latest"
diff --git a/fixtures/smoke/builds-with-multiple-runtimes/src/index.js b/test/fixtures/builds-with-multiple-runtimes/src/index.js
similarity index 100%
rename from fixtures/smoke/builds-with-multiple-runtimes/src/index.js
rename to test/fixtures/builds-with-multiple-runtimes/src/index.js
diff --git a/test/fixtures/issue-5176-flow-class-properties/index.test.js b/test/fixtures/issue-5176-flow-class-properties/index.test.js
new file mode 100644
index 00000000..fa09a222
--- /dev/null
+++ b/test/fixtures/issue-5176-flow-class-properties/index.test.js
@@ -0,0 +1,8 @@
+const testSetup = require('../__shared__/test-setup');
+
+test('passes tests', async () => {
+ const { fulfilled } = await testSetup.scripts.test({
+ jestEnvironment: 'node',
+ });
+ expect(fulfilled).toBe(true);
+});
diff --git a/fixtures/smoke/issue-5176-flow-class-properties/package.json b/test/fixtures/issue-5176-flow-class-properties/package.json
similarity index 100%
rename from fixtures/smoke/issue-5176-flow-class-properties/package.json
rename to test/fixtures/issue-5176-flow-class-properties/package.json
diff --git a/fixtures/smoke/issue-5176-flow-class-properties/src/App.js b/test/fixtures/issue-5176-flow-class-properties/src/App.js
similarity index 100%
rename from fixtures/smoke/issue-5176-flow-class-properties/src/App.js
rename to test/fixtures/issue-5176-flow-class-properties/src/App.js
diff --git a/fixtures/smoke/issue-5176-flow-class-properties/src/App.test.js b/test/fixtures/issue-5176-flow-class-properties/src/App.test.js
similarity index 100%
rename from fixtures/smoke/issue-5176-flow-class-properties/src/App.test.js
rename to test/fixtures/issue-5176-flow-class-properties/src/App.test.js
diff --git a/test/fixtures/mjs-support/__snapshots__/index.test.js.snap b/test/fixtures/mjs-support/__snapshots__/index.test.js.snap
new file mode 100644
index 00000000..1fff9768
--- /dev/null
+++ b/test/fixtures/mjs-support/__snapshots__/index.test.js.snap
@@ -0,0 +1,5 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`can use mjs library in development 1`] = `"Pikachu"`;
+
+exports[`can use mjs library in production 1`] = `"Pikachu"`;
diff --git a/test/fixtures/mjs-support/index.test.js b/test/fixtures/mjs-support/index.test.js
new file mode 100644
index 00000000..767af17b
--- /dev/null
+++ b/test/fixtures/mjs-support/index.test.js
@@ -0,0 +1,43 @@
+const testSetup = require('../__shared__/test-setup');
+
+const puppeteer = require('puppeteer');
+
+test('can use mjs library in development', async () => {
+ const { port, done } = await testSetup.scripts.start();
+
+ const browser = await puppeteer.launch({ headless: true });
+ try {
+ const page = await browser.newPage();
+ await page.goto(`http://localhost:${port}/`);
+ await page.waitForSelector('.Pokemon-Name-Data', { timeout: 0 });
+ const output = await page.evaluate(() => {
+ return Array.from(
+ document.getElementsByClassName('Pokemon-Name-Data')
+ ).pop().innerHTML;
+ });
+ expect(output).toMatchSnapshot();
+ } finally {
+ browser.close();
+ done();
+ }
+});
+test('can use mjs library in production', async () => {
+ await testSetup.scripts.build();
+ const { port, done } = await testSetup.scripts.serve();
+
+ const browser = await puppeteer.launch({ headless: true });
+ try {
+ const page = await browser.newPage();
+ await page.goto(`http://localhost:${port}/`);
+ await page.waitForSelector('.Pokemon-Name-Data', { timeout: 0 });
+ const output = await page.evaluate(() => {
+ return Array.from(
+ document.getElementsByClassName('Pokemon-Name-Data')
+ ).pop().innerHTML;
+ });
+ expect(output).toMatchSnapshot();
+ } finally {
+ browser.close();
+ done();
+ }
+});
diff --git a/fixtures/browser/graphql-with-mjs/package.json b/test/fixtures/mjs-support/package.json
similarity index 85%
rename from fixtures/browser/graphql-with-mjs/package.json
rename to test/fixtures/mjs-support/package.json
index ad9cf3d8..47b6cf58 100644
--- a/fixtures/browser/graphql-with-mjs/package.json
+++ b/test/fixtures/mjs-support/package.json
@@ -3,6 +3,7 @@
"apollo-boost": "0.1.16",
"graphql": "14.0.2",
"react-apollo": "2.2.1",
+ "apollo-client": "2.4.2",
"react": "latest",
"react-dom": "latest",
"serve": "10.0.2"
diff --git a/fixtures/browser/graphql-with-mjs/src/App.js b/test/fixtures/mjs-support/src/App.js
similarity index 100%
rename from fixtures/browser/graphql-with-mjs/src/App.js
rename to test/fixtures/mjs-support/src/App.js
diff --git a/fixtures/browser/graphql-with-mjs/src/index.js b/test/fixtures/mjs-support/src/index.js
similarity index 100%
rename from fixtures/browser/graphql-with-mjs/src/index.js
rename to test/fixtures/mjs-support/src/index.js
diff --git a/test/fixtures/relative-paths/index.test.js b/test/fixtures/relative-paths/index.test.js
new file mode 100644
index 00000000..f29dc2b3
--- /dev/null
+++ b/test/fixtures/relative-paths/index.test.js
@@ -0,0 +1,25 @@
+const testSetup = require('../__shared__/test-setup');
+
+const fs = require('fs-extra');
+const globby = require('globby');
+const path = require('path');
+
+test('contains a relative path in production build', async () => {
+ await testSetup.scripts.build();
+
+ const buildDir = path.join(testSetup.testDirectory, 'build');
+ const cssFile = path.join(
+ buildDir,
+ globby.sync('**/*.css', { cwd: buildDir }).pop()
+ );
+ const svgFile = path.join(
+ buildDir,
+ globby.sync('**/*.svg', { cwd: buildDir }).pop()
+ );
+ const desiredPath = /url\((.+?)\)/
+ .exec(fs.readFileSync(cssFile, 'utf8'))
+ .pop();
+ expect(path.resolve(path.join(path.dirname(cssFile), desiredPath))).toBe(
+ path.resolve(svgFile)
+ );
+});
diff --git a/fixtures/smoke/relative-paths/package.json b/test/fixtures/relative-paths/package.json
similarity index 100%
rename from fixtures/smoke/relative-paths/package.json
rename to test/fixtures/relative-paths/package.json
diff --git a/fixtures/smoke/relative-paths/src/index.css b/test/fixtures/relative-paths/src/index.css
similarity index 100%
rename from fixtures/smoke/relative-paths/src/index.css
rename to test/fixtures/relative-paths/src/index.css
diff --git a/fixtures/smoke/relative-paths/src/index.js b/test/fixtures/relative-paths/src/index.js
similarity index 100%
rename from fixtures/smoke/relative-paths/src/index.js
rename to test/fixtures/relative-paths/src/index.js
diff --git a/fixtures/smoke/relative-paths/src/logo.svg b/test/fixtures/relative-paths/src/logo.svg
similarity index 100%
rename from fixtures/smoke/relative-paths/src/logo.svg
rename to test/fixtures/relative-paths/src/logo.svg
diff --git a/test/fixtures/webpack-message-formatting/.disable-pnp b/test/fixtures/webpack-message-formatting/.disable-pnp
new file mode 100644
index 00000000..e69de29b
diff --git a/fixtures/output/webpack-message-formatting/__snapshots__/index.test.js.snap b/test/fixtures/webpack-message-formatting/__snapshots__/index.test.js.snap
similarity index 78%
rename from fixtures/output/webpack-message-formatting/__snapshots__/index.test.js.snap
rename to test/fixtures/webpack-message-formatting/__snapshots__/index.test.js.snap
index 6a510ef7..a70b43ef 100644
--- a/fixtures/output/webpack-message-formatting/__snapshots__/index.test.js.snap
+++ b/test/fixtures/webpack-message-formatting/__snapshots__/index.test.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`webpack message formatting formats aliased unknown export 1`] = `
+exports[`formats aliased unknown export 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -14,7 +14,7 @@ Attempted import error: 'bar' is not exported from './AppUnknownExport' (importe
}
`;
-exports[`webpack message formatting formats babel syntax error 1`] = `
+exports[`formats babel syntax error 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -36,7 +36,7 @@ Syntax error: Unterminated JSX contents (8:13)
}
`;
-exports[`webpack message formatting formats css syntax error 1`] = `
+exports[`formats css syntax error 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -56,7 +56,7 @@ Syntax error: Unexpected } (3:2)
}
`;
-exports[`webpack message formatting formats eslint error 1`] = `
+exports[`formats eslint error 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -72,7 +72,7 @@ Search for the keywords to learn more about each error.
}
`;
-exports[`webpack message formatting formats eslint warning 1`] = `
+exports[`formats eslint warning 1`] = `
Object {
"stderr": "",
"stdout": "Creating an optimized production build...
@@ -88,7 +88,7 @@ To ignore, add // eslint-disable-next-line to the line before.
}
`;
-exports[`webpack message formatting formats file not found error 1`] = `
+exports[`formats file not found error 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -102,7 +102,7 @@ Cannot find file './ThisFileSouldNotExist' in './src'.
}
`;
-exports[`webpack message formatting formats missing package 1`] = `
+exports[`formats missing package 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -118,7 +118,7 @@ You can install this package by running: yarn add unknown-package.
}
`;
-exports[`webpack message formatting formats no default export 1`] = `
+exports[`formats no default export 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -132,7 +132,7 @@ Attempted import error: './ExportNoDefault' does not contain a default export (i
}
`;
-exports[`webpack message formatting formats out of scope error 1`] = `
+exports[`formats out of scope error 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -147,7 +147,7 @@ You can either move it inside src/, or add a symlink to it from project's node_m
}
`;
-exports[`webpack message formatting formats unknown export 1`] = `
+exports[`formats unknown export 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
@@ -161,7 +161,7 @@ Attempted import error: 'bar' is not exported from './AppUnknownExport'.
}
`;
-exports[`webpack message formatting helps when users tries to use sass 1`] = `
+exports[`helps when users tries to use sass 1`] = `
Object {
"stderr": "Creating an optimized production build...
Failed to compile.
diff --git a/test/fixtures/webpack-message-formatting/index.test.js b/test/fixtures/webpack-message-formatting/index.test.js
new file mode 100644
index 00000000..1aebc3a2
--- /dev/null
+++ b/test/fixtures/webpack-message-formatting/index.test.js
@@ -0,0 +1,136 @@
+const testSetup = require('../__shared__/test-setup');
+
+const fs = require('fs-extra');
+const path = require('path');
+
+test('formats babel syntax error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppBabel.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats css syntax error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppCss.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats unknown export', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppUnknownExport.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats aliased unknown export', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppAliasUnknownExport.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats no default export', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppNoDefault.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats missing package', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppMissingPackage.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats eslint warning', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppLintWarning.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ let { stdout, stderr } = await testSetup.scripts.build();
+ const sizeIndex = stdout.indexOf('File sizes after gzip');
+ if (sizeIndex !== -1) {
+ stdout = stdout.substring(0, sizeIndex);
+ }
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats eslint error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppLintError.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('helps when users tries to use sass', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppSass.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats file not found error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppUnknownFile.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
+
+test('formats case sensitive path error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppIncorrectCase.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.start({ smoke: true });
+ if (process.platform === 'darwin') {
+ expect(stderr).toMatch(
+ `Cannot find file: 'export5.js' does not match the corresponding name on disk: './src/Export5.js'.`
+ );
+ } else {
+ expect(stderr).not.toEqual(''); // TODO: figure out how we can test this on Linux/Windows
+ // I believe getting this working requires we tap into enhanced-resolve
+ // pipeline, which is debt we don't want to take on right now.
+ }
+});
+
+test('formats out of scope error', async () => {
+ fs.copySync(
+ path.join(__dirname, 'src', 'AppOutOfScopeImport.js'),
+ path.join(testSetup.testDirectory, 'src', 'App.js')
+ );
+
+ const { stdout, stderr } = await testSetup.scripts.build();
+ expect({ stdout, stderr }).toMatchSnapshot();
+});
diff --git a/fixtures/output/webpack-message-formatting/package.json b/test/fixtures/webpack-message-formatting/package.json
similarity index 100%
rename from fixtures/output/webpack-message-formatting/package.json
rename to test/fixtures/webpack-message-formatting/package.json
diff --git a/fixtures/output/webpack-message-formatting/src/AppAliasUnknownExport.js b/test/fixtures/webpack-message-formatting/src/AppAliasUnknownExport.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppAliasUnknownExport.js
rename to test/fixtures/webpack-message-formatting/src/AppAliasUnknownExport.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppBabel.js b/test/fixtures/webpack-message-formatting/src/AppBabel.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppBabel.js
rename to test/fixtures/webpack-message-formatting/src/AppBabel.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppCss.css b/test/fixtures/webpack-message-formatting/src/AppCss.css
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppCss.css
rename to test/fixtures/webpack-message-formatting/src/AppCss.css
diff --git a/fixtures/output/webpack-message-formatting/src/AppCss.js b/test/fixtures/webpack-message-formatting/src/AppCss.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppCss.js
rename to test/fixtures/webpack-message-formatting/src/AppCss.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppIncorrectCase.js b/test/fixtures/webpack-message-formatting/src/AppIncorrectCase.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppIncorrectCase.js
rename to test/fixtures/webpack-message-formatting/src/AppIncorrectCase.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppLintError.js b/test/fixtures/webpack-message-formatting/src/AppLintError.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppLintError.js
rename to test/fixtures/webpack-message-formatting/src/AppLintError.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppLintWarning.js b/test/fixtures/webpack-message-formatting/src/AppLintWarning.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppLintWarning.js
rename to test/fixtures/webpack-message-formatting/src/AppLintWarning.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppMissingPackage.js b/test/fixtures/webpack-message-formatting/src/AppMissingPackage.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppMissingPackage.js
rename to test/fixtures/webpack-message-formatting/src/AppMissingPackage.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppNoDefault.js b/test/fixtures/webpack-message-formatting/src/AppNoDefault.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppNoDefault.js
rename to test/fixtures/webpack-message-formatting/src/AppNoDefault.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppOutOfScopeImport.js b/test/fixtures/webpack-message-formatting/src/AppOutOfScopeImport.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppOutOfScopeImport.js
rename to test/fixtures/webpack-message-formatting/src/AppOutOfScopeImport.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppSass.js b/test/fixtures/webpack-message-formatting/src/AppSass.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppSass.js
rename to test/fixtures/webpack-message-formatting/src/AppSass.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppSass.scss b/test/fixtures/webpack-message-formatting/src/AppSass.scss
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppSass.scss
rename to test/fixtures/webpack-message-formatting/src/AppSass.scss
diff --git a/fixtures/output/webpack-message-formatting/src/AppUnknownExport.js b/test/fixtures/webpack-message-formatting/src/AppUnknownExport.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppUnknownExport.js
rename to test/fixtures/webpack-message-formatting/src/AppUnknownExport.js
diff --git a/fixtures/output/webpack-message-formatting/src/AppUnknownFile.js b/test/fixtures/webpack-message-formatting/src/AppUnknownFile.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/AppUnknownFile.js
rename to test/fixtures/webpack-message-formatting/src/AppUnknownFile.js
diff --git a/fixtures/output/webpack-message-formatting/src/Export5.js b/test/fixtures/webpack-message-formatting/src/Export5.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/Export5.js
rename to test/fixtures/webpack-message-formatting/src/Export5.js
diff --git a/fixtures/output/webpack-message-formatting/src/ExportNoDefault.js b/test/fixtures/webpack-message-formatting/src/ExportNoDefault.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/ExportNoDefault.js
rename to test/fixtures/webpack-message-formatting/src/ExportNoDefault.js
diff --git a/fixtures/output/webpack-message-formatting/src/FooExport.js b/test/fixtures/webpack-message-formatting/src/FooExport.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/FooExport.js
rename to test/fixtures/webpack-message-formatting/src/FooExport.js
diff --git a/fixtures/output/webpack-message-formatting/src/index.js b/test/fixtures/webpack-message-formatting/src/index.js
similarity index 100%
rename from fixtures/output/webpack-message-formatting/src/index.js
rename to test/fixtures/webpack-message-formatting/src/index.js
diff --git a/fixtures/smoke/jest.config.js b/test/jest.config.js
similarity index 53%
rename from fixtures/smoke/jest.config.js
rename to test/jest.config.js
index b2f8182e..2f70a94b 100644
--- a/fixtures/smoke/jest.config.js
+++ b/test/jest.config.js
@@ -1,6 +1,7 @@
+'use strict';
+
module.exports = {
testEnvironment: 'node',
- testMatch: ['**/*.test.js'],
+ testMatch: ['/**/*.test.js'],
testPathIgnorePatterns: ['/src/', 'node_modules'],
- setupTestFrameworkScriptFile: './setupSmokeTests.js',
};