diff --git a/e2e/react.test.ts b/e2e/react.test.ts
index b4b2fc588b..af693d3ab3 100644
--- a/e2e/react.test.ts
+++ b/e2e/react.test.ts
@@ -29,42 +29,19 @@ describe('React Applications', () => {
);
updateFile(mainPath, `import '@proj/${libName}';\n` + readFile(mainPath));
- const lintResults = runCLI(`lint ${appName}`);
- expect(lintResults).toContain('All files pass linting.');
- runCLI(`build ${appName}`);
- checkFilesExist(
- `dist/apps/${appName}/index.html`,
- `dist/apps/${appName}/polyfills-es2015.js`,
- `dist/apps/${appName}/runtime-es2015.js`,
- `dist/apps/${appName}/vendor-es2015.js`,
- `dist/apps/${appName}/main-es2015.js`,
- `dist/apps/${appName}/styles-es2015.js`,
- `dist/apps/${appName}/polyfills-es5.js`,
- `dist/apps/${appName}/runtime-es5.js`,
- `dist/apps/${appName}/vendor-es5.js`,
- `dist/apps/${appName}/main-es5.js`,
- `dist/apps/${appName}/styles-es5.js`
- );
- runCLI(`build ${appName} --prod --output-hashing none`);
- checkFilesExist(
- `dist/apps/${appName}/index.html`,
- `dist/apps/${appName}/polyfills-es2015.js`,
- `dist/apps/${appName}/runtime-es2015.js`,
- `dist/apps/${appName}/main-es2015.js`,
- `dist/apps/${appName}/polyfills-es5.js`,
- `dist/apps/${appName}/runtime-es5.js`,
- `dist/apps/${appName}/main-es5.js`,
- `dist/apps/${appName}/styles.css`
- );
- const testResults = await runCLIAsync(`test ${appName}`);
- expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
- const lintE2eResults = runCLI(`lint ${appName}-e2e`);
- expect(lintE2eResults).toContain('All files pass linting.');
- const e2eResults = runCLI(`e2e ${appName}-e2e`);
- expect(e2eResults).toContain('All specs passed!');
-
const libTestResults = await runCLIAsync(`test ${libName}`);
expect(libTestResults.stderr).toContain('Test Suites: 1 passed, 1 total');
+
+ await testGeneratedApp(appName);
+ }, 120000);
+
+ it('should generate app with routing', async () => {
+ ensureProject();
+ const appName = uniq('app');
+
+ runCLI(`generate @nrwl/react:app ${appName} --routing --no-interactive`);
+
+ await testGeneratedApp(appName);
}, 120000);
it('should be able to use JSX', async () => {
@@ -101,8 +78,13 @@ describe('React Applications', () => {
const mainPath = `apps/${appName}/src/main.jsx`;
updateFile(mainPath, `import '@proj/${libName}';\n` + readFile(mainPath));
+ await testGeneratedApp(appName);
+ }, 30000);
+
+ async function testGeneratedApp(appName) {
const lintResults = runCLI(`lint ${appName}`);
expect(lintResults).toContain('All files pass linting.');
+
runCLI(`build ${appName}`);
checkFilesExist(
`dist/apps/${appName}/index.html`,
@@ -134,5 +116,5 @@ describe('React Applications', () => {
expect(lintE2eResults).toContain('All files pass linting.');
const e2eResults = runCLI(`e2e ${appName}-e2e`);
expect(e2eResults).toContain('All specs passed!');
- }, 30000);
+ }
});
diff --git a/e2e/utils.ts b/e2e/utils.ts
index 9626f18b92..ef187f2e17 100644
--- a/e2e/utils.ts
+++ b/e2e/utils.ts
@@ -143,6 +143,7 @@ export function copyMissingPackages(): void {
'react',
'react-dom',
+ 'react-router-dom',
'@types/react',
'@types/react-dom',
'@testing-library',
diff --git a/package.json b/package.json
index 86250ba24f..edf0c5f246 100644
--- a/package.json
+++ b/package.json
@@ -101,6 +101,7 @@
"react": "16.8.6",
"react-dom": "16.8.6",
"@testing-library/react": "8.0.5",
+ "react-router-dom": "5.0.1",
"release-it": "^7.4.0",
"rxjs": "~6.4.0",
"semver": "5.4.1",
diff --git a/packages/react/src/schematics/application/application.spec.ts b/packages/react/src/schematics/application/application.spec.ts
index d9c7013f76..46adda06b6 100644
--- a/packages/react/src/schematics/application/application.spec.ts
+++ b/packages/react/src/schematics/application/application.spec.ts
@@ -452,13 +452,15 @@ describe('app', () => {
appTree
);
+ const mainSource = tree.read('apps/my-app/src/main.tsx').toString();
+
const componentSource = tree
.read('apps/my-app/src/app/app.tsx')
.toString();
- expect(componentSource).toContain('react-router-dom');
- expect(componentSource).toContain('');
- expect(componentSource).toContain('');
+ expect(mainSource).toContain('react-router-dom');
+ expect(mainSource).toContain('');
+ expect(mainSource).toContain('');
expect(componentSource).toMatch(/
+import { BrowserRouter } from 'react-router-dom';
+<% } %>
import App from './app';
@@ -7,12 +10,20 @@ describe('App', () => {
afterEach(cleanup);
it('should render successfully', () => {
+ <% if (routing) { %>
+ const { baseElement } = render();
+ <% } else { %>
const { baseElement } = render();
+ <% } %>
expect(baseElement).toBeTruthy();
});
it('should have a greeting as the title', () => {
+ <% if (routing) { %>
+ const { getByText } = render();
+ <% } else { %>
const { getByText } = render();
+ <% } %>
expect(getByText('Welcome to <%= projectName %>!')).toBeTruthy();
});
});
diff --git a/packages/react/src/schematics/application/files/app/src/main.tsx__tmpl__ b/packages/react/src/schematics/application/files/app/src/main.tsx__tmpl__
index 76f479848c..32224f52bc 100644
--- a/packages/react/src/schematics/application/files/app/src/main.tsx__tmpl__
+++ b/packages/react/src/schematics/application/files/app/src/main.tsx__tmpl__
@@ -1,6 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
+<% if (routing) { %>
+import { BrowserRouter } from 'react-router-dom';
+<% } %>
import App from './app/app';
+<% if (routing) { %>
+ReactDOM.render(, document.getElementById('root'));
+<% } else { %>
ReactDOM.render(, document.getElementById('root'));
+<% } %>
diff --git a/packages/react/src/utils/ast-utils.ts b/packages/react/src/utils/ast-utils.ts
index 2e96a25804..9057fb5fc6 100644
--- a/packages/react/src/utils/ast-utils.ts
+++ b/packages/react/src/utils/ast-utils.ts
@@ -13,18 +13,6 @@ export function addRouter(sourcePath: string, source: ts.SourceFile): Change[] {
const outerMostJsxOpening = jsxOpening[0];
const outerMostJsxClosing = jsxClosing[jsxClosing.length - 1];
- const insertOpening = new InsertChange(
- sourcePath,
- outerMostJsxOpening.getStart(),
- ''
- );
-
- const insertClosing = new InsertChange(
- sourcePath,
- outerMostJsxClosing.getEnd(),
- ''
- );
-
const insertRoute = new InsertChange(
sourcePath,
outerMostJsxClosing.getStart(),
@@ -51,8 +39,6 @@ export function addRouter(sourcePath: string, source: ts.SourceFile): Change[] {
sourcePath,
`import { BrowserRouter as Router, Route, Link} from 'react-router-dom';`
),
- insertOpening,
- insertClosing,
insertRoute,
insertLink
];
diff --git a/yarn.lock b/yarn.lock
index 4e1c04eda9..950f6a3575 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -847,7 +847,7 @@
js-levenshtein "^1.1.3"
semver "^5.5.0"
-"@babel/runtime@^7.4.5", "@babel/runtime@^7.5.4":
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.4":
version "7.5.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b"
integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==
@@ -1271,7 +1271,7 @@
pretty-format "^24.8.0"
wait-for-expect "^1.2.0"
-"@testing-library/react@6.0.0":
+"@testing-library/react@8.0.5":
version "8.0.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-8.0.5.tgz#2301011a8c5567eba59691860df19a3cfc9d7425"
integrity sha512-2EzVi7HjUUF8gKzB4s+oCJ1+F4VOrphO+DlUO6Ptgtcz1ko4J2zqnr0t7g+T7uedXXjJ0wdq70zQMhJXP3w37A==
@@ -6429,6 +6429,11 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
+gud@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
+ integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
+
handle-thing@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
@@ -6568,6 +6573,18 @@ he@1.2.x:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+history@^4.9.0:
+ version "4.9.0"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca"
+ integrity sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ loose-envify "^1.2.0"
+ resolve-pathname "^2.2.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+ value-equal "^0.4.0"
+
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -6577,6 +6594,13 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
+hoist-non-react-statics@^3.1.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
+ integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
+ dependencies:
+ react-is "^16.7.0"
+
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@@ -8691,7 +8715,7 @@ longest@^1.0.1:
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -9058,6 +9082,15 @@ mimic-response@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+mini-create-react-context@^0.3.0:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189"
+ integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==
+ dependencies:
+ "@babel/runtime" "^7.4.0"
+ gud "^1.0.0"
+ tiny-warning "^1.0.2"
+
mini-css-extract-plugin@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz#a3f13372d6fcde912f3ee4cd039665704801e3b9"
@@ -10199,6 +10232,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+path-to-regexp@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
+ integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
+ dependencies:
+ isarray "0.0.1"
+
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@@ -10710,7 +10750,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-dom@^16.8.3:
+react-dom@16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
@@ -10720,12 +10760,41 @@ react-dom@^16.8.3:
prop-types "^15.6.2"
scheduler "^0.13.6"
-react-is@^16.8.1, react-is@^16.8.4:
+react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
-react@^16.8.3:
+react-router-dom@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be"
+ integrity sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.6.2"
+ react-router "5.0.1"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-router@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.1.tgz#04ee77df1d1ab6cb8939f9f01ad5702dbadb8b0f"
+ integrity sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ hoist-non-react-statics "^3.1.0"
+ loose-envify "^1.3.1"
+ mini-create-react-context "^0.3.0"
+ path-to-regexp "^1.7.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react@16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
@@ -11209,6 +11278,11 @@ resolve-from@^3.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
integrity sha1-six699nWiBvItuZTM17rywoYh0g=
+resolve-pathname@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
+ integrity sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -12530,6 +12604,16 @@ timers-ext@^0.1.5:
es5-ext "~0.10.46"
next-tick "1"
+tiny-invariant@^1.0.2:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
+ integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
+
+tiny-warning@^1.0.0, tiny-warning@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
tmp-promise@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-1.0.5.tgz#3208d7fa44758f86a2a4c4060f3c33fea30e8038"
@@ -13102,6 +13186,11 @@ validate-npm-package-name@^3.0.0:
dependencies:
builtins "^1.0.3"
+value-equal@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
+ integrity sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==
+
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"