From b3bea39892c68cd1ec052da7b17f6fe3b3a7fc06 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 16 Jul 2019 22:19:42 -0400 Subject: [PATCH] feat(react): updates libraries for React to newest versions (#1584) --- e2e/utils.ts | 2 +- package.json | 6 +- packages/react/migrations.json | 8 +- .../update-8-3-0/update-8-3-0.spec.ts | 102 +++++++++++++ .../migrations/update-8-3-0/update-8-3-0.ts | 140 ++++++++++++++++++ .../app/src/app/__fileName__.spec.tsx__tmpl__ | 2 +- .../__name__/__fileName__.spec.tsx__tmpl__ | 2 +- .../src/schematics/ng-add/ng-add.spec.ts | 2 +- .../react/src/schematics/ng-add/ng-add.ts | 2 +- packages/react/src/utils/styled.ts | 8 +- packages/react/src/utils/versions.ts | 16 +- packages/workspace/index.ts | 3 +- packages/workspace/src/utils/ast-utils.ts | 22 +++ yarn.lock | 57 +++---- 14 files changed, 322 insertions(+), 50 deletions(-) create mode 100644 packages/react/src/migrations/update-8-3-0/update-8-3-0.spec.ts create mode 100644 packages/react/src/migrations/update-8-3-0/update-8-3-0.ts diff --git a/e2e/utils.ts b/e2e/utils.ts index f1bfeff90158a..9626f18b92a4a 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -145,7 +145,7 @@ export function copyMissingPackages(): void { 'react-dom', '@types/react', '@types/react-dom', - 'react-testing-library', + '@testing-library', 'document-register-element' ]; diff --git a/package.json b/package.json index 2abb17e8ee65d..86250ba24fc94 100644 --- a/package.json +++ b/package.json @@ -98,9 +98,9 @@ "opn": "^5.3.0", "precise-commits": "1.0.2", "prettier": "1.16.4", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-testing-library": "6.0.0", + "react": "16.8.6", + "react-dom": "16.8.6", + "@testing-library/react": "8.0.5", "release-it": "^7.4.0", "rxjs": "~6.4.0", "semver": "5.4.1", diff --git a/packages/react/migrations.json b/packages/react/migrations.json index 63001b4458891..2e42d93da592c 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -1,3 +1,9 @@ { - "schematics": {} + "schematics": { + "update-8.3.0": { + "version": "8.3.0-beta.1", + "description": "Update React libraries", + "factory": "./src/migrations/update-8-3-0/update-8-3-0" + } + } } diff --git a/packages/react/src/migrations/update-8-3-0/update-8-3-0.spec.ts b/packages/react/src/migrations/update-8-3-0/update-8-3-0.spec.ts new file mode 100644 index 0000000000000..7b60b9f694439 --- /dev/null +++ b/packages/react/src/migrations/update-8-3-0/update-8-3-0.spec.ts @@ -0,0 +1,102 @@ +import { Tree } from '@angular-devkit/schematics'; +import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; +import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace'; + +import * as path from 'path'; +import { stripIndents } from '@angular-devkit/core/src/utils/literals'; + +describe('Update 8-0-0', () => { + let tree: Tree; + let schematicRunner: SchematicTestRunner; + + beforeEach(async () => { + tree = Tree.empty(); + schematicRunner = new SchematicTestRunner( + '@nrwl/react', + path.join(__dirname, '../../../migrations.json') + ); + tree = await schematicRunner + .callRule( + updateJsonInTree('package.json', () => ({ + dependencies: { + react: '16.8.1', + 'react-dom': '16.8.1', + 'react-router-dom': '5.0.0', + 'styled-components': '4.0.0' + }, + devDependencies: { + '@types/styled-components': '4.0.0', + 'react-testing-library': '5.0.0', + '@types/react': '16.8.0', + '@types/react-dom': '16.8.0' + } + })), + tree + ) + .toPromise(); + }); + + describe('imports', () => { + it(`should be migrate 'react-testing-library' to '@testing-library/react`, async () => { + tree.create( + 'Hello.spec.tsx', + ` + import Hello from './Hello'; + import React from 'react'; + import { render } from 'react-testing-library'; + ` + ); + + tree.create( + 'foo.spec.ts', + ` + import { render } from 'react-testing-library'; + ` + ); + + tree = await schematicRunner + .runSchematicAsync('update-8.3.0', {}, tree) + .toPromise(); + + expect(tree.read('Hello.spec.tsx').toString('utf-8')) + .toContain(stripIndents` + import Hello from './Hello'; + import React from 'react'; + import { render } from '@testing-library/react'; + `); + + expect(tree.read('foo.spec.ts').toString('utf-8')).toContain(stripIndents` + import { render } from '@testing-library/react'; + `); + }); + }); + + describe('dependencies', () => { + it('should update dependencies', async () => { + tree = await schematicRunner + .runSchematicAsync('update-8.3.0', {}, tree) + .toPromise(); + + const result = readJsonInTree(tree, 'package.json'); + + expect(result).toEqual( + expect.objectContaining({ + dependencies: { + react: '16.8.6', + 'react-dom': '16.8.6', + 'react-router-dom': '5.0.1', + 'styled-components': '4.3.2' + }, + devDependencies: { + '@testing-library/react': '8.0.5', + '@types/react': '16.8.23', + '@types/react-dom': '16.8.23', + '@types/styled-components': '4.1.18' + } + }) + ); + + expect(result.devDependencies['react-testing-library']).not.toBeDefined(); + }); + }); +}); diff --git a/packages/react/src/migrations/update-8-3-0/update-8-3-0.ts b/packages/react/src/migrations/update-8-3-0/update-8-3-0.ts new file mode 100644 index 0000000000000..a58b4c3863de0 --- /dev/null +++ b/packages/react/src/migrations/update-8-3-0/update-8-3-0.ts @@ -0,0 +1,140 @@ +import { + chain, + Rule, + SchematicContext, + Tree +} from '@angular-devkit/schematics'; +import { stripIndents } from '@angular-devkit/core/src/utils/literals'; +import { + formatFiles, + insert, + readJsonInTree, + updateJsonInTree, + updatePackageJsonDependencies +} from '@nrwl/workspace'; +import { + createSourceFile, + isImportDeclaration, + isStringLiteral, + ScriptTarget +} from 'typescript'; +import { ReplaceChange } from '@nrwl/workspace/src/utils/ast-utils'; +import { relative } from 'path'; +import { testingLibraryVersion } from '../../utils/versions'; + +const ignore = require('ignore'); + +export default function update(): Rule { + return chain([ + displayInformation, + updateDependencies, + updateImports, + formatFiles() + ]); +} + +function displayInformation(host: Tree, context: SchematicContext) { + context.logger.info(stripIndents` + React Testing Library has been repackaged as \`@testing-library/react\` as of version 8. + + We are replacing your \`react-testing-library\` imports with \`@testing-library/react\`. + + See: https://github.com/testing-library/react-testing-library/releases/tag/v8.0.0 + `); +} + +function updateDependencies(tree: Tree) { + const removeOld = updateJsonInTree( + 'package.json', + (json, context: SchematicContext) => { + json.dependencies = json.dependencies || {}; + json.devDependencies = json.devDependencies || {}; + // Just in case user installed it to dependencies instead of devDependencies. + delete json.dependencies['react-testing-library']; + delete json.devDependencies['react-testing-library']; + context.logger.info(`Removing \`react-testing-library\` as a dependency`); + return json; + } + ); + + const packageJson = readJsonInTree(tree, '/package.json'); + + const candidates = { + react: '16.8.6', + 'react-dom': '16.8.6', + 'react-router-dom': '5.0.1', + '@types/react': '16.8.23', + '@types/react-dom': '16.8.23', + 'styled-components': '4.3.2', + '@types/styled-components': '4.1.18', + '@emotion/styled': '10.0.14' + }; + + const updated = Object.entries(candidates).reduce( + (acc, [m, v]) => { + if (packageJson.dependencies[m]) { + acc.dependencies[m] = v; + } else if (packageJson.devDependencies[m]) { + acc.devDependencies[m] = v; + } + return acc; + }, + { + dependencies: {}, + devDependencies: { + '@testing-library/react': testingLibraryVersion + } + } + ); + + const addNew = updatePackageJsonDependencies( + updated.dependencies, + updated.devDependencies + ); + + return chain([removeOld, addNew]); +} + +function updateImports(host: Tree) { + let ig = ignore().add(['*', '!*.ts', '!*.tsx']); // include only .tsx? files + + if (host.exists('.gitignore')) { + ig = ig.add(host.read('.gitignore').toString()); + } + + host.visit(path => { + if (ig.ignores(relative('/', path))) { + return; + } + + const sourceFile = createSourceFile( + path, + host.read(path).toString(), + ScriptTarget.Latest, + true + ); + const changes = []; + sourceFile.statements.forEach(statement => { + if ( + isImportDeclaration(statement) && + isStringLiteral(statement.moduleSpecifier) + ) { + const nodeText = statement.moduleSpecifier.getText(sourceFile); + const modulePath = statement.moduleSpecifier + .getText(sourceFile) + .substr(1, nodeText.length - 2); + if (modulePath === 'react-testing-library') { + changes.push( + new ReplaceChange( + path, + statement.moduleSpecifier.getStart(sourceFile), + nodeText, + `'@testing-library/react'` + ) + ); + } + } + }); + insert(host, path, changes); + }); +} diff --git a/packages/react/src/schematics/application/files/app/src/app/__fileName__.spec.tsx__tmpl__ b/packages/react/src/schematics/application/files/app/src/app/__fileName__.spec.tsx__tmpl__ index ca2ec879994fa..544d5ffa8e73d 100644 --- a/packages/react/src/schematics/application/files/app/src/app/__fileName__.spec.tsx__tmpl__ +++ b/packages/react/src/schematics/application/files/app/src/app/__fileName__.spec.tsx__tmpl__ @@ -1,5 +1,5 @@ import React from 'react'; -import { render, cleanup } from 'react-testing-library'; +import { render, cleanup } from '@testing-library/react'; import App from './app'; diff --git a/packages/react/src/schematics/component/files/__name__/__fileName__.spec.tsx__tmpl__ b/packages/react/src/schematics/component/files/__name__/__fileName__.spec.tsx__tmpl__ index 8afedc72dd37c..292630f824045 100644 --- a/packages/react/src/schematics/component/files/__name__/__fileName__.spec.tsx__tmpl__ +++ b/packages/react/src/schematics/component/files/__name__/__fileName__.spec.tsx__tmpl__ @@ -1,5 +1,5 @@ import React from 'react'; -import { render, cleanup } from 'react-testing-library'; +import { render, cleanup } from '@testing-library/react'; import <%= className %> from './<%= fileName %>'; diff --git a/packages/react/src/schematics/ng-add/ng-add.spec.ts b/packages/react/src/schematics/ng-add/ng-add.spec.ts index 6d9155d5ee01b..33d4c0a8b18e8 100644 --- a/packages/react/src/schematics/ng-add/ng-add.spec.ts +++ b/packages/react/src/schematics/ng-add/ng-add.spec.ts @@ -21,7 +21,7 @@ describe('ng-add', () => { expect(packageJson.devDependencies['@nrwl/react']).toBeDefined(); expect(packageJson.devDependencies['@types/react']).toBeDefined(); expect(packageJson.devDependencies['@types/react-dom']).toBeDefined(); - expect(packageJson.devDependencies['react-testing-library']).toBeDefined(); + expect(packageJson.devDependencies['@testing-library/react']).toBeDefined(); }); describe('defaultCollection', () => { diff --git a/packages/react/src/schematics/ng-add/ng-add.ts b/packages/react/src/schematics/ng-add/ng-add.ts index 41c3cdcb92f1e..0d4c900a7c315 100644 --- a/packages/react/src/schematics/ng-add/ng-add.ts +++ b/packages/react/src/schematics/ng-add/ng-add.ts @@ -25,7 +25,7 @@ export function addDependencies(): Rule { '@nrwl/react': nxVersion, '@types/react': typesVersion, '@types/react-dom': domTypesVersion, - 'react-testing-library': testingLibraryVersion + '@testing-library/react': testingLibraryVersion } ); } diff --git a/packages/react/src/utils/styled.ts b/packages/react/src/utils/styled.ts index 17b28c9c357c3..5445cbd4ba583 100644 --- a/packages/react/src/utils/styled.ts +++ b/packages/react/src/utils/styled.ts @@ -1,7 +1,7 @@ import { emotionVersion, - styledComponentVersion, - styledComponentTypesVersion + styledComponentsVersion, + styledComponentsTypesVersion } from './versions'; import { PackageDependencies } from './dependencies'; @@ -10,10 +10,10 @@ export const CSS_IN_JS_DEPENDENCIES: { } = { 'styled-components': { dependencies: { - 'styled-components': styledComponentVersion + 'styled-components': styledComponentsVersion }, devDependencies: { - '@types/styled-components': styledComponentTypesVersion + '@types/styled-components': styledComponentsTypesVersion } }, '@emotion/styled': { diff --git a/packages/react/src/utils/versions.ts b/packages/react/src/utils/versions.ts index 54a6ec46a5c16..016da0eba0fbc 100644 --- a/packages/react/src/utils/versions.ts +++ b/packages/react/src/utils/versions.ts @@ -1,9 +1,9 @@ export const nxVersion = '*'; -export const frameworkVersion = '16.8.3'; -export const typesVersion = '16.8.4'; -export const styledComponentVersion = '4.2.0'; -export const styledComponentTypesVersion = '4.1.15'; -export const emotionVersion = '10.0.10'; -export const domTypesVersion = '16.8.2'; -export const reactRouterVersion = '5.0.0'; -export const testingLibraryVersion = '6.0.0'; +export const frameworkVersion = '16.8.6'; +export const typesVersion = '16.8.23'; +export const styledComponentsVersion = '4.3.2'; +export const styledComponentsTypesVersion = '4.1.18'; +export const emotionVersion = '10.0.14'; +export const domTypesVersion = '16.8.23'; +export const reactRouterVersion = '5.0.1'; +export const testingLibraryVersion = '8.0.5'; diff --git a/packages/workspace/index.ts b/packages/workspace/index.ts index e816c0ef9eed9..776ec2ef536cc 100644 --- a/packages/workspace/index.ts +++ b/packages/workspace/index.ts @@ -36,7 +36,8 @@ export { getProjectConfig, addParameterToConstructor, createOrUpdate, - findNodes + findNodes, + updatePackageJsonDependencies } from './src/utils/ast-utils'; export { diff --git a/packages/workspace/src/utils/ast-utils.ts b/packages/workspace/src/utils/ast-utils.ts index 78f8b090de729..b6365d7297666 100644 --- a/packages/workspace/src/utils/ast-utils.ts +++ b/packages/workspace/src/utils/ast-utils.ts @@ -417,6 +417,28 @@ export function addDepsToPackageJson( }); } +export function updatePackageJsonDependencies( + deps: any, + devDeps: any, + addInstall = true +): Rule { + return updateJsonInTree('package.json', (json, context: SchematicContext) => { + json.dependencies = { + ...(json.dependencies || {}), + ...deps + }; + json.devDependencies = { + ...(json.devDependencies || {}), + ...devDeps + }; + if (addInstall && !installAdded) { + context.addTask(new NodePackageInstallTask()); + installAdded = true; + } + return json; + }); +} + export function getProjectConfig(host: Tree, name: string): any { const angularJson = readJsonInTree(host, '/angular.json'); const projectConfig = angularJson.projects[name]; diff --git a/yarn.lock b/yarn.lock index 13af354ea986a..4e1c04eda9c24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -847,10 +847,10 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.3": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d" - integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg== +"@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== dependencies: regenerator-runtime "^0.13.2" @@ -1260,6 +1260,25 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== +"@testing-library/dom@^5.5.4": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-5.6.0.tgz#18a7c162a6a79964e731ad7b810022a28218047c" + integrity sha512-nAsRvQLr/b6TGNjuHMEbWXCNPLrQYnzqa/KKQZL7wBOtfptUxsa4Ah9aqkHW0ZmCSFmUDj4nFUxWPVTeMu0iCw== + dependencies: + "@babel/runtime" "^7.4.5" + "@sheerun/mutationobserver-shim" "^0.3.2" + aria-query "3.0.0" + pretty-format "^24.8.0" + wait-for-expect "^1.2.0" + +"@testing-library/react@6.0.0": + 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== + dependencies: + "@babel/runtime" "^7.5.4" + "@testing-library/dom" "^5.5.4" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -1928,7 +1947,7 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -aria-query@^3.0.0: +aria-query@3.0.0, aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= @@ -4931,16 +4950,6 @@ dom-serializer@0: domelementtype "^1.3.0" entities "^1.1.1" -dom-testing-library@^3.13.1: - version "3.19.4" - resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-3.19.4.tgz#f5b737f59ee9749a4568fa353f1f59be97c888c3" - integrity sha512-GJOx8CLpnkvM3takILOsld/itUUc9+7Qh6caN1Spj6+9jIgNPY36fsvoH7sEgYokC0lBRdttO7G7fIFYCXlmcA== - dependencies: - "@babel/runtime" "^7.4.3" - "@sheerun/mutationobserver-shim" "^0.3.2" - pretty-format "^24.7.0" - wait-for-expect "^1.1.1" - domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -10414,7 +10423,7 @@ pretty-error@^2.0.2: renderkid "^2.0.1" utila "~0.4" -pretty-format@^24.7.0, pretty-format@^24.8.0: +pretty-format@^24.8.0: version "24.8.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2" integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw== @@ -10716,14 +10725,6 @@ react-is@^16.8.1, react-is@^16.8.4: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== -react-testing-library@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/react-testing-library/-/react-testing-library-6.0.0.tgz#81edfcfae8a795525f48685be9bf561df45bb35d" - integrity sha512-h0h+YLe4KWptK6HxOMnoNN4ngu3W8isrwDmHjPC5gxc+nOZOCurOvbKVYCvvuAw91jdO7VZSm/5KR7TxKnz0qA== - dependencies: - "@babel/runtime" "^7.3.1" - dom-testing-library "^3.13.1" - react@^16.8.3: version "16.8.6" resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" @@ -13148,10 +13149,10 @@ w3c-xmlserializer@^1.0.1: webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" -wait-for-expect@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.1.1.tgz#9cd10e07d52810af9e0aaf509872e38f3c3d81ae" - integrity sha512-vd9JOqqEcBbCDhARWhW85ecjaEcfBLuXgVBqatfS3iw6oU4kzAcs+sCNjF+TC9YHPImCW7ypsuQc+htscIAQCw== +wait-for-expect@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.2.0.tgz#fdab6a26e87d2039101db88bff3d8158e5c3e13f" + integrity sha512-EJhKpA+5UHixduMBEGhTFuLuVgQBKWxkFbefOdj2bbk2/OpA5Opsc4aUTGmF+qJ+v3kTGxDRNYwKaT4j6g5n8Q== walker@^1.0.7, walker@~1.0.5: version "1.0.7"