From 20c24eb275156f2a313a7c671f0667b88b8ab1f8 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Wed, 2 Oct 2019 14:00:26 -0700 Subject: [PATCH 1/9] WIP upgrade react & react-router --- awx/ui_next/package-lock.json | 105 +- awx/ui_next/package.json | 6 +- .../LaunchButton/LaunchButton.test.jsx | 17 +- .../NotificationList.test.jsx | 4 +- .../NotificationListItem.test.jsx.snap | 42 +- .../OrganizationAccess.test.jsx | 2 +- .../OrganizationAccess.test.jsx.snap | 2294 ----------------- .../OrganizationAccessItem.test.jsx.snap | 36 +- .../JobTemplateDetail.test.jsx | 12 +- .../JobTemplateDetail.test.jsx.snap | 194 -- .../__snapshots__/enzymeHelpers.test.jsx.snap | 15 +- awx/ui_next/testUtils/enzymeHelpers.jsx | 55 +- 12 files changed, 183 insertions(+), 2599 deletions(-) delete mode 100644 awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccess.test.jsx.snap delete mode 100644 awx/ui_next/src/screens/Template/JobTemplateDetail/__snapshots__/JobTemplateDetail.test.jsx.snap diff --git a/awx/ui_next/package-lock.json b/awx/ui_next/package-lock.json index b1c6ee520c..5ec2c0cd7c 100644 --- a/awx/ui_next/package-lock.json +++ b/awx/ui_next/package-lock.json @@ -11596,6 +11596,16 @@ "dom-walk": "^0.1.0" } }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -13346,25 +13356,13 @@ } }, "react": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", - "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "version": "16.10.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.10.1.tgz", + "integrity": "sha512-2bisHwMhxQ3XQz4LiJJwG3360pY965pTl/MRrZYxIBKVj4fOHoDs5aZAkYXGxDRO1Li+SyjTAilQEbOmtQJHzA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" - }, - "dependencies": { - "scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - } + "prop-types": "^15.6.2" } }, "react-codemirror2": { @@ -13373,20 +13371,20 @@ "integrity": "sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag==" }, "react-dom": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", - "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", + "version": "16.10.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.10.1.tgz", + "integrity": "sha512-SmM4ZW0uug0rn95U8uqr52I7UdNf6wdGLeXDmNLfg3y5q5H9eAbdjF5ubQc3bjDyRrvdAB2IKG7X0GzSpnn5Mg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.13.6" + "scheduler": "^0.16.1" }, "dependencies": { "scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-MIuie7SgsqMYOdCXVFZa8SKoNorJZUWHW8dPgto7uEHn1lX3fg2Gu0TzgK8USj76uxV7vB5eRMnZs/cdEHg+cg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -13424,30 +13422,51 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-router": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", - "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz", + "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", "requires": { - "history": "^4.7.2", - "hoist-non-react-statics": "^2.5.0", - "invariant": "^2.2.4", + "@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.1", - "warning": "^4.0.1" + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.10.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.1.tgz", + "integrity": "sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==" + } + } + } } }, "react-router-dom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", - "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.1.2.tgz", + "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==", "requires": { - "history": "^4.7.2", - "invariant": "^2.2.4", + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", "loose-envify": "^1.3.1", - "prop-types": "^15.6.1", - "react-router": "^4.3.1", - "warning": "^4.0.1" + "prop-types": "^15.6.2", + "react-router": "5.1.2", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" } }, "react-test-renderer": { @@ -16299,14 +16318,6 @@ "makeerror": "1.0.x" } }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/awx/ui_next/package.json b/awx/ui_next/package.json index 44f3e2926d..a18d850791 100644 --- a/awx/ui_next/package.json +++ b/awx/ui_next/package.json @@ -69,10 +69,10 @@ "html-entities": "^1.2.1", "js-yaml": "^3.13.1", "prop-types": "^15.6.2", - "react": "^16.8.6", + "react": "^16.10.1", "react-codemirror2": "^6.0.0", - "react-dom": "^16.8.6", - "react-router-dom": "^4.3.1", + "react-dom": "^16.10.1", + "react-router-dom": "^5.1.2", "react-virtualized": "^9.21.1", "styled-components": "^4.2.0" } diff --git a/awx/ui_next/src/components/LaunchButton/LaunchButton.test.jsx b/awx/ui_next/src/components/LaunchButton/LaunchButton.test.jsx index d8aa67783c..676758e12a 100644 --- a/awx/ui_next/src/components/LaunchButton/LaunchButton.test.jsx +++ b/awx/ui_next/src/components/LaunchButton/LaunchButton.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { createMemoryHistory } from 'history'; import { mountWithContexts } from '@testUtils/enzymeHelpers'; import { sleep } from '@testUtils/testUtils'; @@ -29,10 +30,11 @@ describe('LaunchButton', () => { ); expect(wrapper).toHaveLength(1); }); - test('redirects to job after successful launch', async done => { - const history = { - push: jest.fn(), - }; + + test('should redirect to job after successful launch', async () => { + const history = createMemoryHistory({ + initialEntries: ['/jobs/9000'], + }); JobTemplatesAPI.launch.mockResolvedValue({ data: { id: 9000, @@ -51,10 +53,10 @@ describe('LaunchButton', () => { expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1); await sleep(0); expect(JobTemplatesAPI.launch).toHaveBeenCalledWith(1); - expect(history.push).toHaveBeenCalledWith('/jobs/9000'); - done(); + expect(history.location.pathname).toEqual('/jobs/9000'); }); - test('displays error modal after unsuccessful launch', async done => { + + test('displays error modal after unsuccessful launch', async () => { JobTemplatesAPI.launch.mockRejectedValue( new Error({ response: { @@ -79,6 +81,5 @@ describe('LaunchButton', () => { await sleep(0); wrapper.update(); expect(wrapper.find('Modal').length).toBe(0); - done(); }); }); diff --git a/awx/ui_next/src/components/NotificationList/NotificationList.test.jsx b/awx/ui_next/src/components/NotificationList/NotificationList.test.jsx index 08fd6f161e..3f42d47c04 100644 --- a/awx/ui_next/src/components/NotificationList/NotificationList.test.jsx +++ b/awx/ui_next/src/components/NotificationList/NotificationList.test.jsx @@ -81,7 +81,9 @@ describe('', () => { ); await sleep(0); wrapper.update(); - expect(wrapper).toMatchSnapshot(); + const dataList = wrapper.find('PaginatedDataList'); + expect(dataList).toHaveLength(1); + expect(dataList.prop('items')).toEqual(data.results); }); test('should render list fetched of items', async () => { diff --git a/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationListItem.test.jsx.snap b/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationListItem.test.jsx.snap index e87fffe7ae..ee9f735fec 100644 --- a/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationListItem.test.jsx.snap +++ b/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationListItem.test.jsx.snap @@ -159,9 +159,27 @@ exports[` initially renders succe }, "displayName": "Styled(Link)", "foldedComponentIds": Array [], + "propTypes": Object { + "innerRef": [Function], + "onClick": [Function], + "replace": [Function], + "target": [Function], + "to": [Function], + }, "render": [Function], "styledComponentId": "sc-bdVaJa", - "target": [Function], + "target": Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "propTypes": Object { + "innerRef": [Function], + "onClick": [Function], + "replace": [Function], + "target": [Function], + "to": [Function], + }, + "render": [Function], + }, "toString": [Function], "warnTooManyClasses": [Function], "withComponent": [Function], @@ -176,23 +194,29 @@ exports[` initially renders succe > - - - Foo - - + + Foo + + + diff --git a/awx/ui_next/src/screens/Organization/OrganizationAccess/OrganizationAccess.test.jsx b/awx/ui_next/src/screens/Organization/OrganizationAccess/OrganizationAccess.test.jsx index b0d0b1bb33..eb0c1b8564 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationAccess/OrganizationAccess.test.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationAccess/OrganizationAccess.test.jsx @@ -85,7 +85,7 @@ describe('', () => { const wrapper = mountWithContexts( ); - expect(wrapper.find('OrganizationAccess')).toMatchSnapshot(); + expect(wrapper.find('PaginatedDataList')).toHaveLength(1); }); test('should fetch and display access records on mount', async done => { diff --git a/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccess.test.jsx.snap b/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccess.test.jsx.snap deleted file mode 100644 index 16a90aad59..0000000000 --- a/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccess.test.jsx.snap +++ /dev/null @@ -1,2294 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` initially renders succesfully 1`] = ` - - - - - - - - - - , - ] - } - columns={ - Array [ - Object { - "isSearchable": true, - "isSortable": true, - "key": "first_name", - "name": "First Name", - }, - Object { - "isSearchable": true, - "isSortable": true, - "key": "username", - "name": "Username", - }, - Object { - "isSearchable": true, - "isSortable": true, - "key": "last_name", - "name": "Last Name", - }, - ] - } - onSearch={[Function]} - onSort={[Function]} - qsConfig={ - Object { - "dateFields": Array [ - "modified", - "created", - ], - "defaultParams": Object { - "order_by": "first_name", - "page": 1, - "page_size": 5, - }, - "integerFields": Array [ - "page", - "page_size", - ], - "namespace": "access", - } - } - sortOrder="ascending" - sortedColumnKey="first_name" - > - - , - ] - } - columns={ - Array [ - Object { - "isSearchable": true, - "isSortable": true, - "key": "first_name", - "name": "First Name", - }, - Object { - "isSearchable": true, - "isSortable": true, - "key": "username", - "name": "Username", - }, - Object { - "isSearchable": true, - "isSortable": true, - "key": "last_name", - "name": "Last Name", - }, - ] - } - fillWidth={false} - i18n={"/i18n/"} - isAllSelected={false} - isCompact={false} - onCompact={null} - onExpand={null} - onSearch={[Function]} - onSelectAll={null} - onSort={[Function]} - qsConfig={ - Object { - "dateFields": Array [ - "modified", - "created", - ], - "defaultParams": Object { - "order_by": "first_name", - "page": 1, - "page_size": 5, - }, - "integerFields": Array [ - "page", - "page_size", - ], - "namespace": "access", - } - } - showSelectAll={false} - sortOrder="ascending" - sortedColumnKey="first_name" - > - - -
- - - -
- - -
- - - -
- - - -
- -
- - Search key dropdown - - } - > -
- - - Username - , - - Last Name - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - forwardedComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": ComponentStyle { - "componentId": "Search__Dropdown-sc-1dwuww3-2", - "isStatic": true, - "lastClassName": "eQMakY", - "rules": Array [ - "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;::before{border-color:var(--pf-global--BorderColor--200);border-top-left-radius:3px;border-bottom-left-radius:3px;}> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", - ], - }, - "displayName": "Search__Dropdown", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "Search__Dropdown-sc-1dwuww3-2", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - isGrouped={false} - isOpen={false} - isPlain={false} - onSelect={[Function]} - onToggle={[Function]} - position="left" - toggle={ - - First Name - - } - > -
- - -
, - } - } - > - - -
, - } - } - > - - - -
- - - - -
- - - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - suppressClassNameWarning={true} - > - - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - suppressClassNameWarning={true} - > - - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - > -
- - - - - - - - -
-
-
-
- - - - - - -
- - - - - -
- -
- - -
- - - - - -
-
-
-
- - - -
- -
- - - - - - - Sort By - - - - - Username - , - - Last Name - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - forwardedComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": ComponentStyle { - "componentId": "Sort__Dropdown-sc-21g5aw-0", - "isStatic": true, - "lastClassName": "kdSQuN", - "rules": Array [ - "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", - ], - }, - "displayName": "Sort__Dropdown", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "Sort__Dropdown-sc-21g5aw-0", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - First Name - - } - > - - Username - , - - Last Name - , - ] - } - isGrouped={false} - isOpen={false} - isPlain={false} - onSelect={[Function]} - onToggle={[Function]} - position="left" - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - First Name - - } - > -
- - -
, - } - } - > - - -
, - } - } - > - - - -
- - -
- - - Reverse Sort Order - - } - distance={15} - enableFlip={true} - entryDelay={500} - exitDelay={500} - flipBehavior={ - Array [ - "top", - "right", - "bottom", - "left", - "top", - "right", - "bottom", - ] - } - isAppLauncher={false} - maxWidth="18.75rem" - position="top" - trigger="mouseenter focus" - zIndex={9999} - > - - -
- Reverse Sort Order -
-
- - } - delay={ - Array [ - 500, - 500, - ] - } - distance={15} - flip={true} - flipBehavior={ - Array [ - "top", - "right", - "bottom", - "left", - "top", - "right", - "bottom", - ] - } - lazy={true} - maxWidth="18.75rem" - onCreate={[Function]} - performance={true} - placement="top" - popperOptions={ - Object { - "modifiers": Object { - "hide": Object { - "enabled": true, - }, - "preventOverflow": Object { - "enabled": true, - }, - }, - } - } - theme="pf-tooltip" - trigger="mouseenter focus" - zIndex={9999} - > - - - - - - - -
-
-
- Reverse Sort Order -
-
-
- - } - > -
- -
-
- Reverse Sort Order -
-
-
-
-
-
-
- -
-
- - - - :not(:first-child){margin-left:20px;}", - ], - }, - "displayName": "DataListToolbar__AdditionalControlsWrapper", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "DataListToolbar__AdditionalControlsWrapper-ajzso8-5", - "target": "div", - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - > -
- - - - - - - - - - - - -
-
-
- - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - -
- -
- Loading... -
-
-
-
-
-
-
- - - - - - <_default - isOpen={false} - onClose={[Function]} - title="Error!" - variant="danger" - > - - } - > - - - - -
-`; diff --git a/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccessItem.test.jsx.snap b/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccessItem.test.jsx.snap index d83714dcbb..beb4d775df 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccessItem.test.jsx.snap +++ b/awx/ui_next/src/screens/Organization/OrganizationAccess/__snapshots__/OrganizationAccessItem.test.jsx.snap @@ -273,9 +273,27 @@ exports[` initially renders succesfully 1`] = ` }, "displayName": "Styled(Link)", "foldedComponentIds": Array [], + "propTypes": Object { + "innerRef": [Function], + "onClick": [Function], + "replace": [Function], + "target": [Function], + "to": [Function], + }, "render": [Function], "styledComponentId": "sc-bdVaJa", - "target": [Function], + "target": Object { + "$$typeof": Symbol(react.forward_ref), + "displayName": "Link", + "propTypes": Object { + "innerRef": [Function], + "onClick": [Function], + "replace": [Function], + "target": [Function], + "to": [Function], + }, + "render": [Function], + }, "toString": [Function], "warnTooManyClasses": [Function], "withComponent": [Function], @@ -290,19 +308,25 @@ exports[` initially renders succesfully 1`] = ` > - - jane - + + jane + + diff --git a/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx index 19ae913eaf..3c9a6f3e33 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx @@ -50,14 +50,7 @@ describe('', () => { jest.clearAllMocks(); }); - test('initially renders succesfully', () => { - const wrapper = mountWithContexts( - - ); - expect(wrapper).toMatchSnapshot(); - }); - - test('Can load with missing summary fields', async done => { + test('Can load with missing summary fields', async () => { const mockTemplate = { ...template }; mockTemplate.summary_fields = { user_capabilities: {} }; @@ -69,8 +62,8 @@ describe('', () => { 'Detail[label="Description"]', el => el.length === 1 ); - done(); }); + test('When component mounts API is called to get instance groups', async done => { const wrapper = mountWithContexts( @@ -89,6 +82,7 @@ describe('', () => { expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalledTimes(1); done(); }); + test('Edit button is absent when user does not have edit privilege', async done => { const regularUser = { forks: 1, diff --git a/awx/ui_next/src/screens/Template/JobTemplateDetail/__snapshots__/JobTemplateDetail.test.jsx.snap b/awx/ui_next/src/screens/Template/JobTemplateDetail/__snapshots__/JobTemplateDetail.test.jsx.snap deleted file mode 100644 index 420d631c76..0000000000 --- a/awx/ui_next/src/screens/Template/JobTemplateDetail/__snapshots__/JobTemplateDetail.test.jsx.snap +++ /dev/null @@ -1,194 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` initially renders succesfully 1`] = ` - - - - - - - - - - -
- -
- Loading... -
-
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/awx/ui_next/testUtils/__snapshots__/enzymeHelpers.test.jsx.snap b/awx/ui_next/testUtils/__snapshots__/enzymeHelpers.test.jsx.snap index 6e8daa0552..c23aff5a8c 100644 --- a/awx/ui_next/testUtils/__snapshots__/enzymeHelpers.test.jsx.snap +++ b/awx/ui_next/testUtils/__snapshots__/enzymeHelpers.test.jsx.snap @@ -45,14 +45,19 @@ exports[`mountWithContexts injected I18nProvider should mount and render deeply exports[`mountWithContexts injected Router should mount and render 1`] = ` `; diff --git a/awx/ui_next/testUtils/enzymeHelpers.jsx b/awx/ui_next/testUtils/enzymeHelpers.jsx index 1ba808266d..37d5ee1a5a 100644 --- a/awx/ui_next/testUtils/enzymeHelpers.jsx +++ b/awx/ui_next/testUtils/enzymeHelpers.jsx @@ -5,6 +5,7 @@ import React from 'react'; import { shape, object, string, arrayOf } from 'prop-types'; import { mount, shallow } from 'enzyme'; +import { MemoryRouter, Router } from 'react-router-dom'; import { I18nProvider } from '@lingui/react'; import { ConfigProvider } from '../src/contexts/Config'; @@ -13,13 +14,13 @@ const intlProvider = new I18nProvider( { language, catalogs: { - [language]: {} - } + [language]: {}, + }, }, {} ); const { - linguiPublisher: { i18n: originalI18n } + linguiPublisher: { i18n: originalI18n }, } = intlProvider.getChildContext(); const defaultContexts = { @@ -34,13 +35,14 @@ const defaultContexts = { ansible_version: null, custom_virtualenvs: [], version: null, - toJSON: () => '/config/' + toJSON: () => '/config/', }, router: { - history: { + history_: { push: () => {}, replace: () => {}, createHref: () => {}, + listen: () => {}, location: { hash: '', pathname: '', @@ -61,33 +63,38 @@ const defaultContexts = { isExact: false, path: '', url: '', - } + }, }, toJSON: () => '/router/', }, }; -function wrapContexts (node, context) { - const { config } = context; +function wrapContexts(node, context) { + const { config, router } = context; class Wrap extends React.Component { - render () { + render() { // eslint-disable-next-line react/no-this-in-sfc const { children, ...props } = this.props; const component = React.cloneElement(children, props); + if (router.history) { + return ( + + {component} + + ); + } return ( - {component} + {component} ); } } - return ( - {node} - ); + return {node}; } -function applyDefaultContexts (context) { +function applyDefaultContexts(context) { if (!context) { return defaultContexts; } @@ -101,16 +108,16 @@ function applyDefaultContexts (context) { return newContext; } -export function shallowWithContexts (node, options = {}) { +export function shallowWithContexts(node, options = {}) { const context = applyDefaultContexts(options.context); return shallow(wrapContexts(node, context)); } -export function mountWithContexts (node, options = {}) { +export function mountWithContexts(node, options = {}) { const context = applyDefaultContexts(options.context); const childContextTypes = { linguiPublisher: shape({ - i18n: object.isRequired + i18n: object.isRequired, }).isRequired, config: shape({ ansible_version: string, @@ -122,9 +129,9 @@ export function mountWithContexts (node, options = {}) { location: shape({}), match: shape({}), }).isRequired, - history: shape({}).isRequired, + history: shape({}), }), - ...options.childContextTypes + ...options.childContextTypes, }; return mount(wrapContexts(node, context), { context, childContextTypes }); } @@ -136,11 +143,15 @@ export function mountWithContexts (node, options = {}) { * @param[selector] - The selector of the element(s) to wait for. * @param[callback] - Callback to poll - by default this checks for a node count of 1. */ -export function waitForElement (wrapper, selector, callback = el => el.length === 1) { +export function waitForElement( + wrapper, + selector, + callback = el => el.length === 1 +) { const interval = 100; return new Promise((resolve, reject) => { let attempts = 30; - (function pollElement () { + (function pollElement() { wrapper.update(); const el = wrapper.find(selector); if (callback(el)) { @@ -151,6 +162,6 @@ export function waitForElement (wrapper, selector, callback = el => el.length == return reject(new Error(message)); } return setTimeout(pollElement, interval); - }()); + })(); }); } From baf5bbc53a116557be188794787caeea2f7b166d Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 8 Oct 2019 15:26:44 -0700 Subject: [PATCH 2/9] finish updating tests for upgraded react-router --- .../OrganizationAdd/OrganizationAdd.test.jsx | 29 ++++------- .../OrganizationEdit.test.jsx | 10 ++-- .../JobTemplateAdd/JobTemplateAdd.test.jsx | 13 ++--- .../JobTemplateEdit/JobTemplateEdit.test.jsx | 12 ++--- awx/ui_next/testUtils/enzymeHelpers.test.jsx | 48 +++++++++---------- 5 files changed, 44 insertions(+), 68 deletions(-) diff --git a/awx/ui_next/src/screens/Organization/OrganizationAdd/OrganizationAdd.test.jsx b/awx/ui_next/src/screens/Organization/OrganizationAdd/OrganizationAdd.test.jsx index 72bffd067d..2a6ffb2b28 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationAdd/OrganizationAdd.test.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationAdd/OrganizationAdd.test.jsx @@ -1,10 +1,9 @@ import React from 'react'; - +import { createMemoryHistory } from 'history'; import { mountWithContexts, waitForElement, } from '../../../../testUtils/enzymeHelpers'; - import OrganizationAdd from './OrganizationAdd'; import { OrganizationsAPI } from '../../../api'; @@ -27,33 +26,25 @@ describe('', () => { }); test('should navigate to organizations list when cancel is clicked', () => { - const history = { - push: jest.fn(), - }; + const history = createMemoryHistory({}); const wrapper = mountWithContexts(, { context: { router: { history } }, }); - expect(history.push).not.toHaveBeenCalled(); wrapper.find('button[aria-label="Cancel"]').prop('onClick')(); - expect(history.push).toHaveBeenCalledWith('/organizations'); + expect(history.location.pathname).toEqual('/organizations'); }); test('should navigate to organizations list when close (x) is clicked', () => { - const history = { - push: jest.fn(), - }; + const history = createMemoryHistory({}); const wrapper = mountWithContexts(, { context: { router: { history } }, }); - expect(history.push).not.toHaveBeenCalled(); wrapper.find('button[aria-label="Close"]').prop('onClick')(); - expect(history.push).toHaveBeenCalledWith('/organizations'); + expect(history.location.pathname).toEqual('/organizations'); }); - test('successful form submission should trigger redirect', async done => { - const history = { - push: jest.fn(), - }; + test('successful form submission should trigger redirect', async () => { + const history = createMemoryHistory({}); const orgData = { name: 'new name', description: 'new description', @@ -77,11 +68,10 @@ describe('', () => { [3], [] ); - expect(history.push).toHaveBeenCalledWith('/organizations/5'); - done(); + expect(history.location.pathname).toEqual('/organizations/5'); }); - test('handleSubmit should post instance groups', async done => { + test('handleSubmit should post instance groups', async () => { const orgData = { name: 'new name', description: 'new description', @@ -104,7 +94,6 @@ describe('', () => { [] ); expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(5, 3); - done(); }); test('AnsibleSelect component renders if there are virtual environments', () => { diff --git a/awx/ui_next/src/screens/Organization/OrganizationEdit/OrganizationEdit.test.jsx b/awx/ui_next/src/screens/Organization/OrganizationEdit/OrganizationEdit.test.jsx index 102b49392f..0a9a4f9e82 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationEdit/OrganizationEdit.test.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationEdit/OrganizationEdit.test.jsx @@ -1,8 +1,7 @@ import React from 'react'; - +import { createMemoryHistory } from 'history'; import { OrganizationsAPI } from '@api'; import { mountWithContexts } from '@testUtils/enzymeHelpers'; - import OrganizationEdit from './OrganizationEdit'; jest.mock('@api'); @@ -65,17 +64,14 @@ describe('', () => { }); test('should navigate to organization detail when cancel is clicked', () => { - const history = { - push: jest.fn(), - }; + const history = createMemoryHistory({}); const wrapper = mountWithContexts( , { context: { router: { history } } } ); - expect(history.push).not.toHaveBeenCalled(); wrapper.find('button[aria-label="Cancel"]').prop('onClick')(); - expect(history.push).toHaveBeenCalledWith('/organizations/1/details'); + expect(history.location.pathname).toEqual('/organizations/1/details'); }); }); diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx index 41032535bf..1cb52e4e5d 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { createMemoryHistory } from 'history'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; import { sleep } from '@testUtils/testUtils'; import JobTemplateAdd from './JobTemplateAdd'; @@ -110,9 +111,7 @@ describe('', () => { }); test('should navigate to job template detail after form submission', async () => { - const history = { - push: jest.fn(), - }; + const history = createMemoryHistory({}); JobTemplatesAPI.create.mockResolvedValueOnce({ data: { id: 1, @@ -128,20 +127,18 @@ describe('', () => { jobTemplateData ); await sleep(0); - expect(history.push).toHaveBeenCalledWith( + expect(history.location.pathname).toEqual( '/templates/job_template/1/details' ); }); test('should navigate to templates list when cancel is clicked', async () => { - const history = { - push: jest.fn(), - }; + const history = createMemoryHistory({}); const wrapper = mountWithContexts(, { context: { router: { history } }, }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); wrapper.find('button[aria-label="Cancel"]').invoke('onClick')(); - expect(history.push).toHaveBeenCalledWith('/templates'); + expect(history.location.pathname).toEqual('/templates'); }); }); diff --git a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx index 363c1ca920..0ae8ea0c01 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { createMemoryHistory } from 'history'; import { sleep } from '@testUtils/testUtils'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; import { JobTemplatesAPI, LabelsAPI, ProjectsAPI } from '@api'; @@ -163,7 +164,7 @@ describe('', () => { await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); }); - test('handleSubmit should call api update', async done => { + test('handleSubmit should call api update', async () => { const wrapper = mountWithContexts( ); @@ -206,11 +207,10 @@ describe('', () => { expect(JobTemplatesAPI.disassociateLabel).toHaveBeenCalledTimes(2); expect(JobTemplatesAPI.associateLabel).toHaveBeenCalledTimes(2); expect(JobTemplatesAPI.generateLabel).toHaveBeenCalledTimes(2); - done(); }); - test('should navigate to job template detail when cancel is clicked', async done => { - const history = { push: jest.fn() }; + test('should navigate to job template detail when cancel is clicked', async () => { + const history = createMemoryHistory({}); const wrapper = mountWithContexts( , { context: { router: { history } } } @@ -220,11 +220,9 @@ describe('', () => { 'button[aria-label="Cancel"]', e => e.length === 1 ); - expect(history.push).not.toHaveBeenCalled(); cancelButton.prop('onClick')(); - expect(history.push).toHaveBeenCalledWith( + expect(history.location.pathname).toEqual( '/templates/job_template/1/details' ); - done(); }); }); diff --git a/awx/ui_next/testUtils/enzymeHelpers.test.jsx b/awx/ui_next/testUtils/enzymeHelpers.test.jsx index 0b830e8634..f5caaf5f75 100644 --- a/awx/ui_next/testUtils/enzymeHelpers.test.jsx +++ b/awx/ui_next/testUtils/enzymeHelpers.test.jsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { createMemoryHistory } from 'history'; import { Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; @@ -21,7 +22,7 @@ describe('mountWithContexts', () => { const Child = withI18n()(({ i18n }) => (
{i18n._(t`Text content`)}
)); - const Parent = () => (); + const Parent = () => ; const wrapper = mountWithContexts(); expect(wrapper.find('Parent')).toMatchSnapshot(); }); @@ -41,23 +42,17 @@ describe('mountWithContexts', () => { it('should mount and render with stubbed context', () => { const context = { router: { - history: { - push: jest.fn(), - replace: jest.fn(), - createHref: jest.fn(), - }, + history: createMemoryHistory({}), route: { location: {}, - match: {} - } - } + match: {}, + }, + }, }; const wrapper = mountWithContexts( - ( -
- home -
- ), +
+ home +
, { context } ); @@ -66,7 +61,7 @@ describe('mountWithContexts', () => { link.simulate('click', { button: 0 }); wrapper.update(); - expect(context.router.history.push).toHaveBeenCalledWith('/'); + expect(context.router.history.location.pathname).toEqual('/'); }); }); @@ -101,10 +96,7 @@ describe('mountWithContexts', () => { )} ); - const wrapper = mountWithContexts( - , - { context: { config } } - ); + const wrapper = mountWithContexts(, { context: { config } }); expect(wrapper.find('Foo')).toMatchSnapshot(); }); }); @@ -115,26 +107,26 @@ describe('mountWithContexts', () => { * after a short amount of time. */ class TestAsyncComponent extends Component { - constructor (props) { + constructor(props) { super(props); this.state = { displayElement: false }; } - componentDidMount () { + componentDidMount() { setTimeout(() => this.setState({ displayElement: true }), 500); } - render () { + render() { const { displayElement } = this.state; if (displayElement) { - return (
); + return
; } return null; } } describe('waitForElement', () => { - it('waits for the element and returns it', async (done) => { + it('waits for the element and returns it', async done => { const selector = '#test-async-component'; const wrapper = mountWithContexts(); expect(wrapper.exists(selector)).toEqual(false); @@ -145,7 +137,7 @@ describe('waitForElement', () => { done(); }); - it('eventually throws an error for elements that don\'t exist', async (done) => { + it("eventually throws an error for elements that don't exist", async done => { const wrapper = mountWithContexts(
); let error; @@ -154,7 +146,11 @@ describe('waitForElement', () => { } catch (err) { error = err; } finally { - expect(error).toEqual(new Error('Expected condition for <#does-not-exist> not met: el => el.length === 1')); + expect(error).toEqual( + new Error( + 'Expected condition for <#does-not-exist> not met: el => el.length === 1' + ) + ); done(); } }); From 9e44fea7b53160041bc450b05ea2d629128e7777 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 8 Oct 2019 15:29:56 -0700 Subject: [PATCH 3/9] bump react to lastest patch version --- awx/ui_next/package-lock.json | 26 +++++++++++++------------- awx/ui_next/package.json | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/awx/ui_next/package-lock.json b/awx/ui_next/package-lock.json index 5ec2c0cd7c..608292bfa2 100644 --- a/awx/ui_next/package-lock.json +++ b/awx/ui_next/package-lock.json @@ -13356,9 +13356,9 @@ } }, "react": { - "version": "16.10.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.10.1.tgz", - "integrity": "sha512-2bisHwMhxQ3XQz4LiJJwG3360pY965pTl/MRrZYxIBKVj4fOHoDs5aZAkYXGxDRO1Li+SyjTAilQEbOmtQJHzA==", + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.10.2.tgz", + "integrity": "sha512-MFVIq0DpIhrHFyqLU0S3+4dIcBhhOvBE8bJ/5kHPVOVaGdo0KuiQzpcjCPsf585WvhypqtrMILyoE2th6dT+Lw==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -13371,20 +13371,20 @@ "integrity": "sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag==" }, "react-dom": { - "version": "16.10.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.10.1.tgz", - "integrity": "sha512-SmM4ZW0uug0rn95U8uqr52I7UdNf6wdGLeXDmNLfg3y5q5H9eAbdjF5ubQc3bjDyRrvdAB2IKG7X0GzSpnn5Mg==", + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.10.2.tgz", + "integrity": "sha512-kWGDcH3ItJK4+6Pl9DZB16BXYAZyrYQItU4OMy0jAkv5aNqc+mAKb4TpFtAteI6TJZu+9ZlNhaeNQSVQDHJzkw==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.16.1" + "scheduler": "^0.16.2" }, "dependencies": { "scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-MIuie7SgsqMYOdCXVFZa8SKoNorJZUWHW8dPgto7uEHn1lX3fg2Gu0TzgK8USj76uxV7vB5eRMnZs/cdEHg+cg==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-BqYVWqwz6s1wZMhjFvLfVR5WXP7ZY32M/wYPo04CcuPM7XZEbV2TBNW7Z0UkguPTl0dWMA59VbNXxK6q+pHItg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -13447,9 +13447,9 @@ }, "dependencies": { "react-is": { - "version": "16.10.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.1.tgz", - "integrity": "sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==" + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz", + "integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==" } } } diff --git a/awx/ui_next/package.json b/awx/ui_next/package.json index a18d850791..ef6c934f4d 100644 --- a/awx/ui_next/package.json +++ b/awx/ui_next/package.json @@ -69,9 +69,9 @@ "html-entities": "^1.2.1", "js-yaml": "^3.13.1", "prop-types": "^15.6.2", - "react": "^16.10.1", + "react": "^16.10.2", "react-codemirror2": "^6.0.0", - "react-dom": "^16.10.1", + "react-dom": "^16.10.2", "react-router-dom": "^5.1.2", "react-virtualized": "^9.21.1", "styled-components": "^4.2.0" From 7ad2c03480efc35f260fefb1f845ce563014ebde Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Wed, 9 Oct 2019 14:51:38 -0700 Subject: [PATCH 4/9] clean up 'act()' warnings in tests --- .../NotificationList.test.jsx.snap | 5321 ----------------- ...est.jsx => NotificationTemplates.test.jsx} | 0 .../JobTemplateAdd/JobTemplateAdd.test.jsx | 60 +- .../JobTemplateEdit/JobTemplateEdit.test.jsx | 48 +- .../Template/shared/JobTemplateForm.test.jsx | 83 +- .../Template/shared/LabelSelect.test.jsx | 14 +- .../Template/shared/PlaybookSelect.test.jsx | 28 +- 7 files changed, 153 insertions(+), 5401 deletions(-) delete mode 100644 awx/ui_next/src/components/NotificationList/__snapshots__/NotificationList.test.jsx.snap rename awx/ui_next/src/screens/NotificationTemplate/{NotifcationTemplates.test.jsx => NotificationTemplates.test.jsx} (100%) diff --git a/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationList.test.jsx.snap b/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationList.test.jsx.snap deleted file mode 100644 index 6e1ad5ede3..0000000000 --- a/awx/ui_next/src/components/NotificationList/__snapshots__/NotificationList.test.jsx.snap +++ /dev/null @@ -1,5321 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` initially renders succesfully 1`] = ` - - - - - - - - - - - - - - - - - - - -
- - - -
- - -
- - - -
- - - -
- -
- - -
- Name -
-
-
- - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - suppressClassNameWarning={true} - > - - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - suppressClassNameWarning={true} - > - - Search value text input - - } - style={ - Object { - "width": "100%", - } - } - > -
- - - - - - - - -
-
-
-
- - - - - - -
-
- -
-
-
-
-
-
-
- -
- - - - - -
-
-
-
-
- - -
- -
- - - - - - - Sort By - - - - - Modified - , - - Created - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - Name - - } - > - - Modified - , - - Created - , - ] - } - forwardedComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": ComponentStyle { - "componentId": "Sort__Dropdown-sc-21g5aw-0", - "isStatic": true, - "lastClassName": "kdSQuN", - "rules": Array [ - "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", - ], - }, - "displayName": "Sort__Dropdown", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "Sort__Dropdown-sc-21g5aw-0", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - Name - - } - > - - Modified - , - - Created - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - Name - - } - > - - Modified - , - - Created - , - ] - } - isGrouped={false} - isOpen={false} - isPlain={false} - onSelect={[Function]} - onToggle={[Function]} - position="left" - style={ - Object { - "marginRight": "10px", - } - } - toggle={ - - Name - - } - > -
- - -
, - } - } - > - - -
, - } - } - > - - - -
- - -
- - - Reverse Sort Order -
- } - distance={15} - enableFlip={true} - entryDelay={500} - exitDelay={500} - flipBehavior={ - Array [ - "top", - "right", - "bottom", - "left", - "top", - "right", - "bottom", - ] - } - isAppLauncher={false} - maxWidth="18.75rem" - position="top" - trigger="mouseenter focus" - zIndex={9999} - > - - -
- Reverse Sort Order -
-
-
- } - delay={ - Array [ - 500, - 500, - ] - } - distance={15} - flip={true} - flipBehavior={ - Array [ - "top", - "right", - "bottom", - "left", - "top", - "right", - "bottom", - ] - } - lazy={true} - maxWidth="18.75rem" - onCreate={[Function]} - performance={true} - placement="top" - popperOptions={ - Object { - "modifiers": Object { - "hide": Object { - "enabled": true, - }, - "preventOverflow": Object { - "enabled": true, - }, - }, - } - } - theme="pf-tooltip" - trigger="mouseenter focus" - zIndex={9999} - > - - - - - - - -
-
-
- Reverse Sort Order -
-
-
-
- } - > -
- -
-
- Reverse Sort Order -
-
-
-
- - - - - - -
- - - :not(:first-child){margin-left:20px;}", - ], - }, - "displayName": "DataListToolbar__AdditionalControlsWrapper", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "DataListToolbar__AdditionalControlsWrapper-ajzso8-5", - "target": "div", - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - > -
- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - -
    - - - - -
  • - -
    - - - - Notification one - - - , - - Email - , - - - - - , - ] - } - key=".0" - rowid="items-list-item-1" - > -
    - - - - - - - - - - -
    - Email -
    -
    -
    -
    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
    -
  • -
    -
    -
    -
    - - - - -
  • - -
    - - - - Notification two - - - , - - Email - , - - - - - , - ] - } - key=".0" - rowid="items-list-item-2" - > -
    - - - - - - - - - - -
    - Email -
    -
    -
    -
    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
    -
  • -
    -
    -
    -
    - - - - -
  • - -
    - - - - Notification three - - - , - - Email - , - - - - - , - ] - } - key=".0" - rowid="items-list-item-3" - > -
    - - - - - - - - - - -
    - Email -
    -
    -
    -
    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    -
    -
    -
    -
    -
  • -
    -
    -
    -
    -
-
- <_default - itemCount={2} - onPerPageSelect={[Function]} - onSetPage={[Function]} - page={1} - perPage={5} - perPageOptions={ - Array [ - Object { - "title": "5", - "value": 5, - }, - Object { - "title": "10", - "value": 10, - }, - Object { - "title": "20", - "value": 20, - }, - Object { - "title": "50", - "value": 50, - }, - ] - } - variant="bottom" - > - - - - -
- -
- - - 5 - - per page - - - - - , - - 10 - - per page - - , - - 20 - - per page - - , - - 50 - - per page - - , - ] - } - isOpen={false} - isPlain={true} - onSelect={[Function]} - toggle={ - - -
-
- -
-
-
- } - showToggle={true} - toggleTemplate={[Function]} - widgetId="pagination-options-menu" - /> - } - > - - 5 - - per page - - - - - , - - 10 - - per page - - , - - 20 - - per page - - , - - 50 - - per page - - , - ] - } - isGrouped={false} - isOpen={false} - isPlain={true} - onSelect={[Function]} - position="left" - toggle={ - - -
-
- -
-
-
- } - showToggle={true} - toggleTemplate={[Function]} - widgetId="pagination-options-menu" - /> - } - > -
- -
- -
-
, - } - } - showToggle={true} - toggleTemplate={[Function]} - widgetId="pagination-options-menu" - > -
- -
- -
-
, - } - } - > - -
- -
- , - } - } - > - -
- - - - - - - - - - - - -
-
-
-
- - - - - - - <_default - isOpen={false} - onClose={[Function]} - title="Error!" - variant="danger" - > - - } - > - - - - -
- - - - - -`; diff --git a/awx/ui_next/src/screens/NotificationTemplate/NotifcationTemplates.test.jsx b/awx/ui_next/src/screens/NotificationTemplate/NotificationTemplates.test.jsx similarity index 100% rename from awx/ui_next/src/screens/NotificationTemplate/NotifcationTemplates.test.jsx rename to awx/ui_next/src/screens/NotificationTemplate/NotificationTemplates.test.jsx diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx index 1cb52e4e5d..0539c657fe 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { createMemoryHistory } from 'history'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; import { sleep } from '@testUtils/testUtils'; @@ -28,8 +29,6 @@ const jobTemplateData = { host_config_key: '', }; -// TODO: Needs React/React-router upgrade to remove `act()` warnings -// See https://github.com/ansible/awx/issues/4817 describe('', () => { const defaultProps = { description: '', @@ -53,13 +52,19 @@ describe('', () => { jest.clearAllMocks(); }); - test('should render Job Template Form', () => { - const wrapper = mountWithContexts(); + test('should render Job Template Form', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); expect(wrapper.find('JobTemplateForm').length).toBe(1); }); test('should render Job Template Form with default values', async () => { - const wrapper = mountWithContexts(); + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); expect(wrapper.find('input#template-description').text()).toBe( defaultProps.description @@ -90,7 +95,10 @@ describe('', () => { ...jobTemplateData, }, }); - const wrapper = mountWithContexts(); + let wrapper; + await act(async () => { + wrapper = mountWithContexts(); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); const formik = wrapper.find('Formik').instance(); const changeState = new Promise(resolve => { @@ -99,6 +107,7 @@ describe('', () => { values: { ...jobTemplateData, labels: [], + instanceGroups: [], }, }, () => resolve() @@ -119,10 +128,38 @@ describe('', () => { ...jobTemplateData, }, }); - const wrapper = mountWithContexts(, { - context: { router: { history } }, + let wrapper; + await act(async () => { + wrapper = mountWithContexts(, { + context: { router: { history } }, + }); }); + const updatedTemplateData = { + name: 'new name', + description: 'new description', + job_type: 'check', + }; + const labels = [ + { id: 3, name: 'Foo', isNew: true }, + { id: 4, name: 'Bar', isNew: true }, + { id: 5, name: 'Maple' }, + { id: 6, name: 'Tree' }, + ]; + JobTemplatesAPI.update.mockResolvedValue({ + data: { ...updatedTemplateData }, + }); + const formik = wrapper.find('Formik').instance(); + const changeState = new Promise(resolve => { + const values = { + ...jobTemplateData, + ...updatedTemplateData, + labels, + instanceGroups: [], + }; + formik.setState({ values }, () => resolve()); + }); + await changeState; await wrapper.find('JobTemplateForm').invoke('handleSubmit')( jobTemplateData ); @@ -134,8 +171,11 @@ describe('', () => { test('should navigate to templates list when cancel is clicked', async () => { const history = createMemoryHistory({}); - const wrapper = mountWithContexts(, { - context: { router: { history } }, + let wrapper; + await act(async () => { + wrapper = mountWithContexts(, { + context: { router: { history } }, + }); }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); wrapper.find('button[aria-label="Cancel"]').invoke('onClick')(); diff --git a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx index 0ae8ea0c01..6d6c1e4083 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { createMemoryHistory } from 'history'; import { sleep } from '@testUtils/testUtils'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; @@ -36,6 +37,7 @@ const mockJobTemplate = { results: [{ name: 'Sushi', id: 1 }, { name: 'Major', id: 2 }], }, inventory: { + id: 2, organization_id: 1, }, }, @@ -158,16 +160,22 @@ describe('', () => { }); test('initially renders successfully', async () => { - const wrapper = mountWithContexts( - - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); }); test('handleSubmit should call api update', async () => { - const wrapper = mountWithContexts( - - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); await waitForElement(wrapper, 'JobTemplateForm', e => e.length === 1); const updatedTemplateData = { name: 'new name', @@ -185,16 +193,13 @@ describe('', () => { }); const formik = wrapper.find('Formik').instance(); const changeState = new Promise(resolve => { - formik.setState( - { - values: { - ...mockJobTemplate, - ...updatedTemplateData, - labels, - }, - }, - () => resolve() - ); + const values = { + ...mockJobTemplate, + ...updatedTemplateData, + labels, + instanceGroups: [], + }; + formik.setState({ values }, () => resolve()); }); await changeState; wrapper.find('button[aria-label="Save"]').simulate('click'); @@ -211,10 +216,13 @@ describe('', () => { test('should navigate to job template detail when cancel is clicked', async () => { const history = createMemoryHistory({}); - const wrapper = mountWithContexts( - , - { context: { router: { history } } } - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + , + { context: { router: { history } } } + ); + }); const cancelButton = await waitForElement( wrapper, 'button[aria-label="Cancel"]', diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx index cf2da14304..efd57650e5 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; import { sleep } from '@testUtils/testUtils'; import JobTemplateForm from './JobTemplateForm'; @@ -71,14 +72,17 @@ describe('', () => { }); test('should render LabelsSelect', async () => { - const wrapper = mountWithContexts( - - ); - await waitForElement(wrapper, 'Form', el => el.length === 0); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + // await waitForElement(wrapper, 'Form', el => el.length === 0); expect(LabelsAPI.read).toHaveBeenCalled(); expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalled(); wrapper.update(); @@ -90,13 +94,16 @@ describe('', () => { }); test('should update form values on input changes', async () => { - const wrapper = mountWithContexts( - - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); const form = wrapper.find('Formik'); @@ -112,14 +119,16 @@ describe('', () => { target: { value: 'new job type', name: 'job_type' }, }); expect(form.state('values').job_type).toEqual('new job type'); - wrapper.find('InventoryLookup').prop('onChange')({ + wrapper.find('InventoryLookup').invoke('onChange')({ id: 3, name: 'inventory', }); expect(form.state('values').inventory).toEqual(3); - wrapper.find('ProjectLookup').prop('onChange')({ - id: 4, - name: 'project', + await act(async () => { + wrapper.find('ProjectLookup').invoke('onChange')({ + id: 4, + name: 'project', + }); }); expect(form.state('values').project).toEqual(4); wrapper.find('AnsibleSelect[name="playbook"]').simulate('change', { @@ -130,13 +139,16 @@ describe('', () => { test('should call handleSubmit when Submit button is clicked', async () => { const handleSubmit = jest.fn(); - const wrapper = mountWithContexts( - - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); expect(handleSubmit).not.toHaveBeenCalled(); wrapper.find('button[aria-label="Save"]').simulate('click'); @@ -146,16 +158,19 @@ describe('', () => { test('should call handleCancel when Cancel button is clicked', async () => { const handleCancel = jest.fn(); - const wrapper = mountWithContexts( - - ); + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0); expect(handleCancel).not.toHaveBeenCalled(); - wrapper.find('button[aria-label="Cancel"]').prop('onClick')(); + wrapper.find('button[aria-label="Cancel"]').invoke('onClick')(); expect(handleCancel).toBeCalled(); }); }); diff --git a/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx b/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx index b03d4e1572..57e4c7b90d 100644 --- a/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mount } from 'enzyme'; import { LabelsAPI } from '@api'; -import { sleep } from '@testUtils/testUtils'; import LabelSelect from './LabelSelect'; jest.mock('@api'); @@ -17,8 +17,10 @@ describe('', () => { LabelsAPI.read.mockReturnValue({ data: { results: options }, }); - const wrapper = mount(); - await sleep(1); + let wrapper; + await act(async () => { + wrapper = mount( {}} />); + }); wrapper.update(); expect(LabelsAPI.read).toHaveBeenCalledTimes(1); @@ -37,8 +39,10 @@ describe('', () => { results: options, }, }); - const wrapper = mount(); - await sleep(1); + let wrapper; + await act(async () => { + wrapper = mount( {}}/>); + }); wrapper.update(); expect(LabelsAPI.read).toHaveBeenCalledTimes(2); diff --git a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx index 3d1a26355a..50baffcd9d 100644 --- a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mountWithContexts } from '@testUtils/enzymeHelpers'; import PlaybookSelect from './PlaybookSelect'; import { ProjectsAPI } from '@api'; @@ -16,19 +17,24 @@ describe('', () => { jest.resetAllMocks(); }); - test('should reload playbooks when project value changes', () => { - const wrapper = mountWithContexts( - {}} - /> - ); + test('should reload playbooks when project value changes', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + {}, value: ''}} + onError={() => {}} + /> + ); + }); expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(1); - wrapper.setProps({ projectId: 15 }); + await act(async () => { + wrapper.setProps({ projectId: 15 }); + }); expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledTimes(2); expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(15); From c7d73c4583a7ab640e91e4009b38399d58741467 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Thu, 10 Oct 2019 09:16:21 -0700 Subject: [PATCH 5/9] lint fixes --- awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx | 2 +- awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx b/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx index 57e4c7b90d..c4cc7ef8a1 100644 --- a/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/LabelSelect.test.jsx @@ -41,7 +41,7 @@ describe('', () => { }); let wrapper; await act(async () => { - wrapper = mount( {}}/>); + wrapper = mount( {}} />); }); wrapper.update(); diff --git a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx index 50baffcd9d..e3fab12024 100644 --- a/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/PlaybookSelect.test.jsx @@ -25,7 +25,7 @@ describe('', () => { projectId={1} isValid form={{}} - field={{onChange: () => {}, value: ''}} + field={{ onChange: () => {}, value: '' }} onError={() => {}} /> ); From 0b190c2d0d7edf63acdecf1b24ab9b5d01ecd8b1 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 15 Oct 2019 10:22:48 -0700 Subject: [PATCH 6/9] fix login/logout redirect behavior --- awx/ui_next/src/App.jsx | 6 +++-- awx/ui_next/src/index.jsx | 54 ++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/awx/ui_next/src/App.jsx b/awx/ui_next/src/App.jsx index 82fb7e99af..e88291fc7c 100644 --- a/awx/ui_next/src/App.jsx +++ b/awx/ui_next/src/App.jsx @@ -1,4 +1,5 @@ import React, { Component, Fragment } from 'react'; +import { withRouter } from 'react-router-dom'; import { global_breakpoint_md } from '@patternfly/react-tokens'; import { Nav, @@ -66,8 +67,9 @@ class App extends Component { // eslint-disable-next-line class-methods-use-this async handleLogout() { + const { history } = this.props; await RootAPI.logout(); - window.location.replace('/#/login'); + history.replace('/login'); } handleAboutOpen() { @@ -193,4 +195,4 @@ class App extends Component { } export { App as _App }; -export default withI18n()(App); +export default withI18n()(withRouter(App)); diff --git a/awx/ui_next/src/index.jsx b/awx/ui_next/src/index.jsx index 9fd10daf47..cd64f64e9d 100644 --- a/awx/ui_next/src/index.jsx +++ b/awx/ui_next/src/index.jsx @@ -43,7 +43,6 @@ export function main(render) { const el = document.getElementById('app'); document.title = `Ansible ${BrandName}`; - const defaultRedirect = () => ; const removeTrailingSlash = ( } /> ); - const loginRoutes = ( - - {removeTrailingSlash} - } - /> - - - ); + + const defaultRedirect = () => { + if (isAuthenticated(document.cookie)) { + return ; + } + return ( + + {removeTrailingSlash} + } + /> + + + ); + }; return render( {({ i18n }) => ( - {!isAuthenticated(document.cookie) ? ( - loginRoutes - ) : ( - - {removeTrailingSlash} - - - ( + + {removeTrailingSlash} + + + { + if (!isAuthenticated(document.cookie)) { + return ; + } + return ( {routeList}; }} /> - )} - /> - - )} + ); + }} + /> + )} From 766f8636557b113757312be500df8d801c325122 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 15 Oct 2019 11:11:44 -0700 Subject: [PATCH 7/9] update ProjectDetails tests with memoryHistory --- .../ProjectDetail/ProjectDetail.test.jsx | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.test.jsx b/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.test.jsx index 8ec8858c67..ab9c024c7e 100644 --- a/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.test.jsx +++ b/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { createMemoryHistory } from 'history'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; import ProjectDetail from './ProjectDetail'; @@ -175,46 +176,26 @@ describe('', () => { }); test('edit button should navigate to project edit', () => { - const context = { - router: { - history: { - push: jest.fn(), - replace: jest.fn(), - createHref: jest.fn(), - }, - }, - }; + const history = createMemoryHistory(); const wrapper = mountWithContexts(, { - context, + context: { router: { history } }, }); expect(wrapper.find('Button[aria-label="edit"]').length).toBe(1); - expect(context.router.history.push).not.toHaveBeenCalled(); wrapper .find('Button[aria-label="edit"] Link') .simulate('click', { button: 0 }); - expect(context.router.history.push).toHaveBeenCalledWith( - '/projects/1/edit' - ); + expect(history.location.pathname).toEqual('/projects/1/edit'); }); test('close button should navigate to projects list', () => { - const context = { - router: { - history: { - push: jest.fn(), - replace: jest.fn(), - createHref: jest.fn(), - }, - }, - }; + const history = createMemoryHistory(); const wrapper = mountWithContexts(, { - context, + context: { router: { history } }, }); expect(wrapper.find('Button[aria-label="close"]').length).toBe(1); - expect(context.router.history.push).not.toHaveBeenCalled(); wrapper .find('Button[aria-label="close"] Link') .simulate('click', { button: 0 }); - expect(context.router.history.push).toHaveBeenCalledWith('/projects'); + expect(history.location.pathname).toEqual('/projects'); }); }); From b318f24490c9526079fef6b9b8aa4c22e67fa2d8 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 15 Oct 2019 12:55:26 -0700 Subject: [PATCH 8/9] don't skip JobDetail test now that async act works --- .../src/screens/Job/JobDetail/JobDetail.test.jsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/awx/ui_next/src/screens/Job/JobDetail/JobDetail.test.jsx b/awx/ui_next/src/screens/Job/JobDetail/JobDetail.test.jsx index ea2e1a54fa..076f16a940 100644 --- a/awx/ui_next/src/screens/Job/JobDetail/JobDetail.test.jsx +++ b/awx/ui_next/src/screens/Job/JobDetail/JobDetail.test.jsx @@ -82,12 +82,8 @@ describe('', () => { modal.find('button[aria-label="Delete"]').simulate('click'); expect(JobsAPI.destroy).toHaveBeenCalledTimes(1); }); - /* - The test below is skipped until react can be upgraded to at least 16.9.0. An upgrade to - react - router will likely be necessary also. - See: https://github.com/ansible/awx/issues/4817 - */ - test.skip('should display error modal when a job does not delete properly', async () => { + + test('should display error modal when a job does not delete properly', async () => { ProjectUpdatesAPI.destroy.mockRejectedValue( new Error({ response: { @@ -102,13 +98,11 @@ describe('', () => { ); const wrapper = mountWithContexts(); - wrapper - .find('button') - .at(0) - .simulate('click'); + wrapper.find('button[aria-label="Delete"]').simulate('click'); const modal = wrapper.find('Modal'); + expect(modal.length).toBe(1); await act(async () => { - await modal.find('Button[variant="danger"]').prop('onClick')(); + modal.find('button[aria-label="Delete"]').simulate('click'); }); wrapper.update(); From cac54179169c9d411ef4d04915ecd17be86ffdd2 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 15 Oct 2019 12:56:39 -0700 Subject: [PATCH 9/9] delete commented code --- awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx index efd57650e5..071edaecf8 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx @@ -82,7 +82,6 @@ describe('', () => { /> ); }); - // await waitForElement(wrapper, 'Form', el => el.length === 0); expect(LabelsAPI.read).toHaveBeenCalled(); expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalled(); wrapper.update();