From 361418a3b5d87a1e396320756554224aac6c2e50 Mon Sep 17 00:00:00 2001 From: Karolina Malyjurkova Date: Mon, 24 Apr 2023 14:42:31 +0200 Subject: [PATCH] WIP --- .../PersonalAccessTokenModal.js | 51 ++++++++++++------- .../PersonalAccessTokenModal.test.js | 28 +++++++--- .../PersonalAccessTokensSelectors.js | 17 +++++++ 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.js b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.js index 3d7c605a097d..8d35b7f48813 100644 --- a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.js +++ b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.js @@ -14,8 +14,12 @@ import { } from '@patternfly/react-core'; import PropTypes from 'prop-types'; import { translate as __ } from '../../../common/I18n'; -import { submitForm } from '../../../redux/actions/common/forms'; -import { selectTokens } from './PersonalAccessTokensSelectors'; +import { + selectTokens, + selectIsSubmitting, +} from './PersonalAccessTokensSelectors'; +import { APIActions } from '../../../redux/API'; +import { PERSONAL_ACCESS_TOKEN_FORM_SUBMITTED } from './PersonalAccessTokensConstants'; import './personalAccessToken.scss'; const PersonalAccessTokenModal = ({ controller, url }) => { @@ -30,6 +34,8 @@ const PersonalAccessTokenModal = ({ controller, url }) => { const [isTimeValid, setIsTimeValid] = useState(true); const [showNameErrors, setShowNameErrors] = useState(false); + const isSubmitting = useSelector(selectIsSubmitting); + const clearDateTimeState = () => { setDate(''); setTime(''); @@ -106,23 +112,28 @@ const PersonalAccessTokenModal = ({ controller, url }) => { return true; }; - const submitTokenForm = actions => { - submitForm({ - url, - values: { name, expires_at: `${date} ${time}`, controller }, - item: 'personal_access_token', - message: __('Personal Access Token was successfully created.'), - actions, - successCallback: handleModalToggle, - }); - }; - - const handleSubmit = actions => { + const handleSubmit = () => { if (isDateTimeInFuture() && isDateValid && isTimeValid) { - dispatch({ - type: 'SUBMIT_FORM', - payload: { ...submitTokenForm(actions) }, - }); + dispatch( + APIActions.post({ + key: PERSONAL_ACCESS_TOKEN_FORM_SUBMITTED, + url, + params: { name, expires_at: `${date} ${time}`, controller }, + handleSuccess: ({ data }) => { + handleModalToggle(); + dispatch({ + type: PERSONAL_ACCESS_TOKEN_FORM_SUBMITTED, + payload: { item: 'personal_access_token', data }, + }); + }, + successToast: () => + __('Personal Access Token was successfully created.'), + errorToast: ({ response }) => + response?.data?.error?.message || + response?.message || + response?.statusText, + }) + ); } }; @@ -152,6 +163,7 @@ const PersonalAccessTokenModal = ({ controller, url }) => { handleSubmit(); setShowNameErrors(true); }} + isDisabled={isSubmitting} > Confirm , @@ -218,12 +230,13 @@ const PersonalAccessTokenModal = ({ controller, url }) => { isDisabled={isDateTimeDisabled} value={date} onChange={(_e, v) => validateDateChange(v)} + appendTo={() => document.body} invalidFormatText={ isDateValid ? '' : __('Enter valid date: YYYY-MM-DD') } - appendTo={() => document.body} + // for undisplaying invalidFormatText when changing to 'Never' dateParse={() => date === '' ? new Date() diff --git a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.test.js b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.test.js index 8479b013a17e..9d1c30b94c61 100644 --- a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.test.js +++ b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokenModal.test.js @@ -1,6 +1,8 @@ import React from 'react'; import { Provider } from 'react-redux'; -import store from '../../../redux'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +// import store from '../../../redux'; import { fireEvent, screen, @@ -10,13 +12,17 @@ import { } from '@testing-library/react'; import '@testing-library/jest-dom'; import PersonalAccessTokenModal from './PersonalAccessTokenModal'; -import * as formActions from '/home/kmalyjur/foreman/webpack/assets/javascripts/react_app/redux/actions/common/forms.js'; +import * as APIActions from '../../../redux/API/APIActions'; jest.useFakeTimers(); +jest.mock('../../../redux/API/APIActions'); +const middlewares = [thunk]; +const mockStore = configureMockStore(middlewares); +const store = mockStore({}); describe('Personal access token modal', () => { - it('fills input fields and submits form with errors', async () => { - const spy = jest.spyOn(formActions, 'submitForm'); + /*it('fills input fields and submits form with errors', async () => { + const spy = jest.spyOn(APIActions, 'post'); render( @@ -63,10 +69,16 @@ describe('Personal access token modal', () => { expect(screen.queryAllByText('Enter valid time: HH:MM:SS')).toHaveLength(1); await waitFor(() => expect(spy).toThrow()); - }); + });*/ + + it.only('fills input fields and successfully submits form', async () => { + //console.log(APIActions); + const spy = jest.spyOn(APIActions, 'post'); + APIActions.post.mockImplementation(async () => { + console.log('PIZZA'); + }); - it('fills input fields and successfully submits form', async () => { - const spy = jest.spyOn(formActions, 'submitForm'); + //API.post.mockClear(); render( @@ -110,7 +122,7 @@ describe('Personal access token modal', () => { fireEvent.click(screen.getByLabelText('confirm-button')); }); - await waitFor(() => expect(spy).toHaveBeenCalled()); + await waitFor(() => expect(spy).toBeCalled()); expect(spy).toHaveBeenCalledWith({ url: '/url', values: { diff --git a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokensSelectors.js b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokensSelectors.js index 615474c307b0..dba28c3f08eb 100644 --- a/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokensSelectors.js +++ b/webpack/assets/javascripts/react_app/components/users/PersonalAccessTokens/PersonalAccessTokensSelectors.js @@ -1,4 +1,21 @@ +import { STATUS } from '../../../constants'; +import { + selectAPIStatus, + selectAPIResponse, +} from '../../../redux/API/APISelectors'; +import { + PERSONAL_ACCESS_TOKENS_REQUEST, + PERSONAL_ACCESS_TOKEN_FORM_SUBMITTED, +} from './PersonalAccessTokensConstants'; + export const selectNewPersonalAccessToken = state => state.personalAccessTokens.newPersonalAccessToken; export const selectTokens = state => state.personalAccessTokens.tokens; + +export const selectIsSubmitting = state => + selectAPIStatus(state, PERSONAL_ACCESS_TOKENS_REQUEST) === STATUS.PENDING || + selectAPIStatus(state, PERSONAL_ACCESS_TOKENS_REQUEST) === STATUS.RESOLVED; + +export const selectTokenForm = state => + selectAPIResponse(state, PERSONAL_ACCESS_TOKEN_FORM_SUBMITTED);