From c8128a52b7b6e4c66cf5c409b36dd06a8f96ff48 Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Tue, 27 Jun 2023 16:46:00 -0400 Subject: [PATCH 1/7] fix: env custom pages conditional render --- .env.development | 2 +- src/pages-and-resources/pages/PageCard.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index b7006f0ad0..76be662fde 100644 --- a/.env.development +++ b/.env.development @@ -41,7 +41,7 @@ ENABLE_NEW_ADVANCED_SETTINGS_PAGE = false ENABLE_NEW_IMPORT_PAGE = false ENABLE_NEW_EXPORT_PAGE = false ENABLE_UNIT_PAGE = false -ENABLE_NEW_CUSTOM_PAGES = true +ENABLE_NEW_CUSTOM_PAGES = false ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN = false BBB_LEARN_MORE_URL='' HOTJAR_APP_ID='' diff --git a/src/pages-and-resources/pages/PageCard.jsx b/src/pages-and-resources/pages/PageCard.jsx index 8d9f85a446..5891b01ce6 100644 --- a/src/pages-and-resources/pages/PageCard.jsx +++ b/src/pages-and-resources/pages/PageCard.jsx @@ -35,7 +35,7 @@ const PageCard = ({ // eslint-disable-next-line react/no-unstable-nested-components const SettingsButton = () => { if (page.legacyLink) { - if (process.env.ENABLE_NEW_CUSTOM_PAGES && page.name === 'Custom pages') { + if (process.env.ENABLE_NEW_CUSTOM_PAGES === 'true' && page.name === 'Custom pages') { return ( Date: Thu, 27 Jul 2023 13:58:52 -0400 Subject: [PATCH 2/7] fix: ui bugs --- src/advanced-settings/AdvancedSettings.jsx | 56 ++++++++++-------- src/advanced-settings/data/thunks.js | 15 ++++- ...cedSettings.scss => AdvancedSettings.scss} | 32 +++++------ .../setting-card/SettingCard.jsx | 57 ++++++++++++------- src/custom-pages/CustomPages.jsx | 5 +- src/index.scss | 2 +- 6 files changed, 100 insertions(+), 67 deletions(-) rename src/advanced-settings/scss/{AdvencedSettings.scss => AdvancedSettings.scss} (85%) diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index c019fbfdb8..9a0ac99ea3 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { - Container, Button, Layout, StatefulButton, + Container, Button, Layout, StatefulButton, TransitionReplace, } from '@edx/paragon'; import { CheckCircle, Info, Warning } from '@edx/paragon/icons'; import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; @@ -58,6 +58,7 @@ const AdvancedSettings = ({ intl, courseId }) => { if (savingStatus === RequestStatus.SUCCESSFUL) { setIsQueryPending(false); setShowSuccessAlert(true); + setTimeout(() => setShowSuccessAlert(false), 15000); window.scrollTo({ top: 0, behavior: 'smooth' }); if (!isEditableState) { @@ -140,7 +141,7 @@ const AdvancedSettings = ({ intl, courseId }) => { return ( <> - +
{(proctoringExamErrors?.length > 0) && ( { aria-describedby={intl.formatMessage(messages.alertProctoringDescribedby)} /> )} -
+
{
- Warning: }} - /> - )} - /> +
+ Warning: }} + /> +
    - {Object.keys(advancedSettingsData).sort().map((settingName) => { + {Object.keys(advancedSettingsData).map((settingName) => { const settingData = advancedSettingsData[settingName]; const editedValue = editedSettings[settingName] !== undefined ? editedSettings[settingName] : JSON.stringify(settingData.value, null, 4); diff --git a/src/advanced-settings/data/thunks.js b/src/advanced-settings/data/thunks.js index 99a421ffd8..db9030fa39 100644 --- a/src/advanced-settings/data/thunks.js +++ b/src/advanced-settings/data/thunks.js @@ -19,7 +19,20 @@ export function fetchCourseAppSettings(courseId) { try { const settingValues = await getCourseAdvancedSettings(courseId); - dispatch(fetchCourseAppsSettingsSuccess(settingValues)); + const sortedDisplayName = []; + Object.values(settingValues).forEach(value => { + const { displayName } = value; + sortedDisplayName.push(displayName); + }); + const sortedSettingValues = {}; + sortedDisplayName.sort().forEach((displayName => { + Object.entries(settingValues).forEach(([key, value]) => { + if (value.displayName === displayName) { + sortedSettingValues[key] = value; + } + }); + })); + dispatch(fetchCourseAppsSettingsSuccess(sortedSettingValues)); dispatch(updateLoadingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { if (error.response && error.response.status === 403) { diff --git a/src/advanced-settings/scss/AdvencedSettings.scss b/src/advanced-settings/scss/AdvancedSettings.scss similarity index 85% rename from src/advanced-settings/scss/AdvencedSettings.scss rename to src/advanced-settings/scss/AdvancedSettings.scss index 81234d81b2..91124d9e7c 100644 --- a/src/advanced-settings/scss/AdvencedSettings.scss +++ b/src/advanced-settings/scss/AdvancedSettings.scss @@ -8,8 +8,8 @@ .instructions, strong { - font: normal $font-weight-normal .875rem/1.5rem $font-family-base; color: $text-color-base; + font-weight: 400; } } @@ -18,11 +18,6 @@ .pgn__card-header .pgn__card-header-title-md { font-size: 1.125rem; - padding-top: .625rem; - } - - .pgn__icon { - color: $headings-color; } } @@ -44,9 +39,8 @@ } .form-control { - resize: none; min-height: 2.75rem; - width: $setting-form-control-width; + max-width: $setting-form-control-width; } .pgn__card-section { @@ -54,7 +48,8 @@ } .pgn__card-header { - padding: 0 1.5rem; + padding: 0 0 0 1.5rem; + flex-grow: 1; } .pgn__card-status { @@ -66,17 +61,10 @@ margin-bottom: 1.438rem; display: flex; flex-direction: revert; - - .pgn__card-header-subtitle-md { - margin-left: .375rem; - margin-top: .125rem; - } } } .setting-sidebar-supplementary { - margin-top: 1.875rem; - .setting-sidebar-supplementary-about { .setting-sidebar-supplementary-about-title { font: normal $font-weight-bold 1.125rem/1.5rem $font-family-base; @@ -123,3 +111,15 @@ align-items: center; } } + +.modal-popup-content { + max-width: 200px; + color: $white; + background-color: $black; + filter: drop-shadow(0 2px 4px rgba(0 0 0 / .15)); + font-weight: 400; +} + +.pgn__modal-popup__arrow::after { + border-top-color: $black; +} diff --git a/src/advanced-settings/setting-card/SettingCard.jsx b/src/advanced-settings/setting-card/SettingCard.jsx index b4ff22aad8..10115b53f7 100644 --- a/src/advanced-settings/setting-card/SettingCard.jsx +++ b/src/advanced-settings/setting-card/SettingCard.jsx @@ -1,8 +1,14 @@ -import React from 'react'; +import React, { useState } from 'react'; import { - Card, Form, Icon, IconButton, OverlayTrigger, Popover, + ActionRow, + Card, + Form, + Icon, + IconButton, + ModalPopup, + useToggle, } from '@edx/paragon'; -import { Info, Warning } from '@edx/paragon/icons'; +import { InfoOutline, Warning } from '@edx/paragon/icons'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { capitalize } from 'lodash'; @@ -15,33 +21,40 @@ const SettingCard = ({ intl, showDeprecated, name, onChange, value, settingData, handleBlur, }) => { const { deprecated, help, displayName } = settingData; + const [isOpen, open, close] = useToggle(false); + const [target, setTarget] = useState(null); return (
  • - + - - {/* eslint-disable-next-line react/no-danger */} -
    - - - )} - > + title={( + + {capitalize(displayName)} - + +
    + + )} /> diff --git a/src/custom-pages/CustomPages.jsx b/src/custom-pages/CustomPages.jsx index 8b82cf0d0e..b7019ba10e 100644 --- a/src/custom-pages/CustomPages.jsx +++ b/src/custom-pages/CustomPages.jsx @@ -16,6 +16,7 @@ import { useToggle, Image, ModalDialog, + Container, } from '@edx/paragon'; import { Add, SpinnerSimple } from '@edx/paragon/icons'; import Placeholder, { @@ -110,7 +111,7 @@ const CustomPages = ({ } return ( -
    +
    -
    +
    ); }; diff --git a/src/index.scss b/src/index.scss index 2fc551b64f..46234d2893 100755 --- a/src/index.scss +++ b/src/index.scss @@ -6,5 +6,5 @@ @import "~@edx/frontend-component-footer/dist/footer"; @import "proctored-exam-settings/proctoredExamSettings"; @import "pages-and-resources/discussions/app-list/AppList"; -@import "advanced-settings/scss/AdvencedSettings"; +@import "advanced-settings/scss/AdvancedSettings"; @import "generic/styles"; From d4cdbbe4af7171f73a7650b73f2d5b4e3f76d4fd Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Fri, 28 Jul 2023 11:45:19 -0400 Subject: [PATCH 3/7] fix: input text lag --- src/advanced-settings/AdvancedSettings.jsx | 64 +++++++---------- .../AdvancedSettings.test.jsx | 6 +- .../scss/AdvancedSettings.scss | 2 +- .../setting-card/SettingCard.jsx | 69 ++++++++++++++----- .../setting-card/SettingCard.test.jsx | 22 ++++-- 5 files changed, 95 insertions(+), 68 deletions(-) diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index 9a0ac99ea3..44ec24388d 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -25,10 +25,6 @@ import messages from './messages'; import ModalError from './modal-error/ModalError'; const AdvancedSettings = ({ intl, courseId }) => { - const advancedSettingsData = useSelector(getCourseAppSettings); - const savingStatus = useSelector(getSavingStatus); - const proctoringExamErrors = useSelector(getProctoringExamErrors); - const settingsWithSendErrors = useSelector(getSendRequestErrors) || {}; const dispatch = useDispatch(); const [saveSettingsPrompt, showSaveSettingsPrompt] = useState(false); const [showDeprecated, setShowDeprecated] = useState(false); @@ -36,10 +32,21 @@ const AdvancedSettings = ({ intl, courseId }) => { const [editedSettings, setEditedSettings] = useState({}); const [errorFields, setErrorFields] = useState([]); const [showSuccessAlert, setShowSuccessAlert] = useState(false); - const loadingSettingsStatus = useSelector(getLoadingStatus); const [isQueryPending, setIsQueryPending] = useState(false); const [isEditableState, setIsEditableState] = useState(false); const [hasInternetConnectionError, setInternetConnectionError] = useState(false); + + useEffect(() => { + dispatch(fetchCourseAppSettings(courseId)); + dispatch(fetchProctoringExamErrors(courseId)); + }, [courseId]); + + const advancedSettingsData = useSelector(getCourseAppSettings); + const savingStatus = useSelector(getSavingStatus); + const proctoringExamErrors = useSelector(getProctoringExamErrors); + const settingsWithSendErrors = useSelector(getSendRequestErrors) || {}; + const loadingSettingsStatus = useSelector(getLoadingStatus); + const isLoading = loadingSettingsStatus === RequestStatus.IN_PROGRESS; const updateSettingsButtonState = { labels: { @@ -49,11 +56,6 @@ const AdvancedSettings = ({ intl, courseId }) => { disabledStates: ['pending'], }; - useEffect(() => { - dispatch(fetchCourseAppSettings(courseId)); - dispatch(fetchProctoringExamErrors(courseId)); - }, [courseId]); - useEffect(() => { if (savingStatus === RequestStatus.SUCCESSFUL) { setIsQueryPending(false); @@ -82,19 +84,6 @@ const AdvancedSettings = ({ intl, courseId }) => { ); } - const handleSettingChange = (e, settingName) => { - const { value } = e.target; - if (!saveSettingsPrompt) { - showSaveSettingsPrompt(true); - } - setIsEditableState(true); - setShowSuccessAlert(false); - setEditedSettings((prevEditedSettings) => ({ - ...prevEditedSettings, - [settingName]: value, - })); - }; - const handleResetSettingsValues = () => { setIsEditableState(false); showErrorModal(false); @@ -112,7 +101,6 @@ const AdvancedSettings = ({ intl, courseId }) => { const isValid = validateAdvancedSettingsData(editedSettings, setErrorFields, setEditedSettings); if (isValid) { setIsQueryPending(true); - setIsEditableState(false); } else { setIsQueryPending(false); showSaveSettingsPrompt(false); @@ -212,18 +200,20 @@ const AdvancedSettings = ({ intl, courseId }) => {
      {Object.keys(advancedSettingsData).map((settingName) => { const settingData = advancedSettingsData[settingName]; - const editedValue = editedSettings[settingName] !== undefined - ? editedSettings[settingName] : JSON.stringify(settingData.value, null, 4); - + if (settingData.deprecated && !showDeprecated) { + return null; + } return ( handleSettingChange(e, settingName)} - showDeprecated={showDeprecated} name={settingName} - value={editedValue} + showSaveSettingsPrompt={showSaveSettingsPrompt} + saveSettingsPrompt={saveSettingsPrompt} + setEdited={setEditedSettings} handleBlur={handleSettingBlur} + isEditableState={isEditableState} + setIsEditableState={setIsEditableState} /> ); })} @@ -239,14 +229,12 @@ const AdvancedSettings = ({ intl, courseId }) => {
- {!isEditableState && ( - - )} + ', () => { expect(textarea.value).toBe('[]'); }); }); - it('should update the textarea value and display the updated value after clicking "Change manually"', async () => { - const { getByLabelText, getByText } = render(); + it('should update the textarea value and display the updated value', async () => { + const { getByLabelText } = render(); await waitFor(() => { const textarea = getByLabelText(/Advanced Module List/i); fireEvent.change(textarea, { target: { value: '[3, 2, 1' } }); - fireEvent.click(getByText(messages.buttonSaveText.defaultMessage)); - fireEvent.click(getByText(/Change manually/i)); expect(textarea.value).toBe('[3, 2, 1'); }); }); diff --git a/src/advanced-settings/scss/AdvancedSettings.scss b/src/advanced-settings/scss/AdvancedSettings.scss index 91124d9e7c..676c6dc81c 100644 --- a/src/advanced-settings/scss/AdvancedSettings.scss +++ b/src/advanced-settings/scss/AdvancedSettings.scss @@ -40,7 +40,7 @@ .form-control { min-height: 2.75rem; - max-width: $setting-form-control-width; + width: $setting-form-control-width; } .pgn__card-section { diff --git a/src/advanced-settings/setting-card/SettingCard.jsx b/src/advanced-settings/setting-card/SettingCard.jsx index 10115b53f7..15cef8ad9f 100644 --- a/src/advanced-settings/setting-card/SettingCard.jsx +++ b/src/advanced-settings/setting-card/SettingCard.jsx @@ -10,7 +10,6 @@ import { } from '@edx/paragon'; import { InfoOutline, Warning } from '@edx/paragon/icons'; import PropTypes from 'prop-types'; -import classNames from 'classnames'; import { capitalize } from 'lodash'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import TextareaAutosize from 'react-textarea-autosize'; @@ -18,13 +17,46 @@ import TextareaAutosize from 'react-textarea-autosize'; import messages from './messages'; const SettingCard = ({ - intl, showDeprecated, name, onChange, value, settingData, handleBlur, + name, + settingData, + handleBlur, + setEdited, + showSaveSettingsPrompt, + saveSettingsPrompt, + isEditableState, + setIsEditableState, + // injected + intl, }) => { const { deprecated, help, displayName } = settingData; + const initialValue = JSON.stringify(settingData.value, null, 4); const [isOpen, open, close] = useToggle(false); const [target, setTarget] = useState(null); + const [newValue, setNewValue] = useState(initialValue); + + const handleSettingChange = (e) => { + const { value } = e.target; + setNewValue(e.target.value); + if (value !== initialValue) { + if (!saveSettingsPrompt) { + showSaveSettingsPrompt(true); + } + if (!isEditableState) { + setIsEditableState(true); + } + } + }; + + const handleCardBlur = () => { + setEdited((prevEditedSettings) => ({ + ...prevEditedSettings, + [name]: newValue, + })); + handleBlur(); + }; + return ( -
  • +
  • @@ -86,22 +118,21 @@ SettingCard.propTypes = { deprecated: PropTypes.bool, help: PropTypes.string, displayName: PropTypes.string, + value: PropTypes.PropTypes.oneOfType([ + PropTypes.string, + PropTypes.bool, + PropTypes.number, + PropTypes.object, + PropTypes.array, + ]), }).isRequired, - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.bool, - PropTypes.number, - PropTypes.object, - PropTypes.array, - ]), - onChange: PropTypes.func.isRequired, - showDeprecated: PropTypes.bool.isRequired, + setEdited: PropTypes.func.isRequired, + showSaveSettingsPrompt: PropTypes.func.isRequired, name: PropTypes.string.isRequired, handleBlur: PropTypes.func.isRequired, -}; - -SettingCard.defaultProps = { - value: undefined, + saveSettingsPrompt: PropTypes.bool.isRequired, + isEditableState: PropTypes.bool.isRequired, + setIsEditableState: PropTypes.func.isRequired, }; export default injectIntl(SettingCard); diff --git a/src/advanced-settings/setting-card/SettingCard.test.jsx b/src/advanced-settings/setting-card/SettingCard.test.jsx index cb3aef74a3..4f45906db0 100644 --- a/src/advanced-settings/setting-card/SettingCard.test.jsx +++ b/src/advanced-settings/setting-card/SettingCard.test.jsx @@ -5,12 +5,15 @@ import { IntlProvider } from '@edx/frontend-platform/i18n'; import SettingCard from './SettingCard'; import messages from './messages'; -const handleChange = jest.fn(); +const setEdited = jest.fn(); +const showSaveSettingsPrompt = jest.fn(); +const setIsEditableState = jest.fn(); const settingData = { deprecated: false, help: 'This is a help message', displayName: 'Setting Name', + value: 'Setting Value', }; jest.mock('react-textarea-autosize', () => jest.fn((props) => ( @@ -27,9 +30,13 @@ const RootWrapper = () => ( intl={{}} isOn name="settingName" - onChange={handleChange} - value="Setting Value" + setEdited={setEdited} + setIsEditableState={setIsEditableState} + showSaveSettingsPrompt={showSaveSettingsPrompt} settingData={settingData} + onBlur={jest.fn()} + isEditableState + saveSettingsPrompt /> ); @@ -42,7 +49,7 @@ describe('', () => { const input = getByLabelText(/Setting Name/i); expect(cardTitle).toBeInTheDocument(); expect(input).toBeInTheDocument(); - expect(input.value).toBe('Setting Value'); + expect(input.value).toBe(JSON.stringify(settingData.value, null, 4)); }); it('displays the deprecated status when the setting is deprecated', () => { const deprecatedSettingData = { ...settingData, deprecated: true }; @@ -52,9 +59,12 @@ describe('', () => { intl={{}} isOn name="settingName" - onChange={handleChange} - value="Setting Value" + setEdited={setEdited} + setIsEditableState={setIsEditableState} + showSaveSettingsPrompt={showSaveSettingsPrompt} settingData={deprecatedSettingData} + isEditable + saveSettingsPrompt /> , ); From 43aac4ea5dad6db45a3902f3cc4989661cb7188a Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Fri, 28 Jul 2023 11:59:27 -0400 Subject: [PATCH 4/7] fix: showSaveSettingsProp not hiding on success --- src/advanced-settings/AdvancedSettings.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index 44ec24388d..f2fc915e03 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -60,12 +60,10 @@ const AdvancedSettings = ({ intl, courseId }) => { if (savingStatus === RequestStatus.SUCCESSFUL) { setIsQueryPending(false); setShowSuccessAlert(true); + setIsEditableState(false); setTimeout(() => setShowSuccessAlert(false), 15000); window.scrollTo({ top: 0, behavior: 'smooth' }); - - if (!isEditableState) { - showSaveSettingsPrompt(false); - } + showSaveSettingsPrompt(false); } else if (savingStatus === RequestStatus.FAILED && !hasInternetConnectionError) { setErrorFields(settingsWithSendErrors); showErrorModal(true); From 7f36c954f90434d9788ecb8b201999df75d89004 Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Mon, 31 Jul 2023 13:19:21 -0400 Subject: [PATCH 5/7] feat: update setting cards test --- .../setting-card/SettingCard.test.jsx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/advanced-settings/setting-card/SettingCard.test.jsx b/src/advanced-settings/setting-card/SettingCard.test.jsx index 4f45906db0..91b3eb8a12 100644 --- a/src/advanced-settings/setting-card/SettingCard.test.jsx +++ b/src/advanced-settings/setting-card/SettingCard.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { IntlProvider } from '@edx/frontend-platform/i18n'; import SettingCard from './SettingCard'; @@ -8,6 +9,7 @@ import messages from './messages'; const setEdited = jest.fn(); const showSaveSettingsPrompt = jest.fn(); const setIsEditableState = jest.fn(); +const handleBlur = jest.fn(); const settingData = { deprecated: false, @@ -34,9 +36,9 @@ const RootWrapper = () => ( setIsEditableState={setIsEditableState} showSaveSettingsPrompt={showSaveSettingsPrompt} settingData={settingData} - onBlur={jest.fn()} + handleBlur={handleBlur} isEditableState - saveSettingsPrompt + saveSettingsPrompt={false} /> ); @@ -63,7 +65,8 @@ describe('', () => { setIsEditableState={setIsEditableState} showSaveSettingsPrompt={showSaveSettingsPrompt} settingData={deprecatedSettingData} - isEditable + handleBlur={handleBlur} + isEditable={false} saveSettingsPrompt /> , @@ -75,4 +78,13 @@ describe('', () => { const { queryByText } = render(); expect(queryByText(messages.deprecated.defaultMessage)).toBeNull(); }); + it('calls setEdited on blur', () => { + const { getByLabelText } = render(); + const inputBox = getByLabelText(/Setting Name/i); + fireEvent.focus(inputBox); + userEvent.clear(inputBox); + userEvent.type(inputBox, '3, 2, 1'); + fireEvent.focusOut(inputBox); + expect(inputBox).toHaveValue('3, 2, 1'); + }); }); From 5b986906a00ec21ff54feddd257532a9c63ba0ab Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Mon, 31 Jul 2023 14:03:04 -0400 Subject: [PATCH 6/7] chore: add onblur test --- .../setting-card/SettingCard.test.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/advanced-settings/setting-card/SettingCard.test.jsx b/src/advanced-settings/setting-card/SettingCard.test.jsx index 91b3eb8a12..a03f51a985 100644 --- a/src/advanced-settings/setting-card/SettingCard.test.jsx +++ b/src/advanced-settings/setting-card/SettingCard.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { IntlProvider } from '@edx/frontend-platform/i18n'; @@ -78,13 +78,19 @@ describe('', () => { const { queryByText } = render(); expect(queryByText(messages.deprecated.defaultMessage)).toBeNull(); }); - it('calls setEdited on blur', () => { + it('calls setEdited on blur', async () => { const { getByLabelText } = render(); const inputBox = getByLabelText(/Setting Name/i); fireEvent.focus(inputBox); userEvent.clear(inputBox); userEvent.type(inputBox, '3, 2, 1'); + await waitFor(() => { + expect(inputBox).toHaveValue('3, 2, 1'); + }); + await (async () => { + expect(setEdited).toHaveBeenCalled(); + expect(handleBlur).toHaveBeenCalled(); + }); fireEvent.focusOut(inputBox); - expect(inputBox).toHaveValue('3, 2, 1'); }); }); From d9ee6cdef02f3477413d6c863eeeb9bc3f7f8c60 Mon Sep 17 00:00:00 2001 From: KristinAoki Date: Mon, 31 Jul 2023 16:09:54 -0400 Subject: [PATCH 7/7] chore: update advanced setting tests --- src/advanced-settings/AdvancedSettings.jsx | 20 +++----- .../AdvancedSettings.test.jsx | 51 +++++++++++++++---- .../__mocks__/advancedSettings.js | 7 +++ 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index f2fc915e03..29ef4639fc 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -87,8 +87,6 @@ const AdvancedSettings = ({ intl, courseId }) => { showErrorModal(false); setEditedSettings({}); showSaveSettingsPrompt(false); - setInternetConnectionError(false); - setIsQueryPending(false); }; const handleSettingBlur = () => { @@ -100,7 +98,6 @@ const AdvancedSettings = ({ intl, courseId }) => { if (isValid) { setIsQueryPending(true); } else { - setIsQueryPending(false); showSaveSettingsPrompt(false); showErrorModal(!errorModal); } @@ -110,7 +107,6 @@ const AdvancedSettings = ({ intl, courseId }) => { setInternetConnectionError(true); showSaveSettingsPrompt(false); setShowSuccessAlert(false); - setIsQueryPending(false); }; const handleQueryProcessing = () => { @@ -119,10 +115,8 @@ const AdvancedSettings = ({ intl, courseId }) => { }; const handleManuallyChangeClick = (setToState) => { - setIsEditableState(true); showErrorModal(setToState); showSaveSettingsPrompt(true); - setIsQueryPending(false); }; return ( @@ -227,12 +221,14 @@ const AdvancedSettings = ({ intl, courseId }) => {
  • - + {isQueryPending && ( + + )} ', () => { }); }); it('should render setting element', async () => { - const { getByText } = render(); + const { getByText, queryByText } = render(); await waitFor(() => { const advancedModuleListTitle = getByText(/Advanced Module List/i); expect(advancedModuleListTitle).toBeInTheDocument(); + expect(queryByText('Certificate web/html view enabled')).toBeNull(); }); }); it('should change to onŠ”hange', async () => { @@ -112,22 +115,50 @@ describe('', () => { fireEvent.click(showDeprecatedItemsBtn); expect(getByText(/Hide Deprecated Settings/i)).toBeInTheDocument(); }); + expect(getByText('Certificate web/html view enabled')).toBeInTheDocument(); }); it('should reset to default value on click on Cancel button', async () => { const { getByLabelText, getByText } = render(); + let textarea; await waitFor(() => { - const textarea = getByLabelText(/Advanced Module List/i); - fireEvent.change(textarea, { target: { value: '[3, 2, 1]' } }); - fireEvent.click(getByText(messages.buttonCancelText.defaultMessage)); - expect(textarea.value).toBe('[]'); + textarea = getByLabelText(/Advanced Module List/i); }); + fireEvent.change(textarea, { target: { value: '[3, 2, 1]' } }); + expect(textarea.value).toBe('[3, 2, 1]'); + fireEvent.click(getByText(messages.buttonCancelText.defaultMessage)); + expect(textarea.value).toBe('[]'); }); - it('should update the textarea value and display the updated value', async () => { - const { getByLabelText } = render(); + it('should update the textarea value and display the updated value after clicking "Change manually"', async () => { + const { getByLabelText, getByText } = render(); + let textarea; await waitFor(() => { - const textarea = getByLabelText(/Advanced Module List/i); - fireEvent.change(textarea, { target: { value: '[3, 2, 1' } }); - expect(textarea.value).toBe('[3, 2, 1'); + textarea = getByLabelText(/Advanced Module List/i); }); + fireEvent.change(textarea, { target: { value: '[3, 2, 1,' } }); + expect(textarea.value).toBe('[3, 2, 1,'); + fireEvent.click(getByText('Save changes')); + fireEvent.click(getByText('Change manually')); + expect(textarea.value).toBe('[3, 2, 1,'); + }); + it('should show success alert after save', async () => { + const { getByLabelText, getByText } = render(); + let textarea; + await waitFor(() => { + textarea = getByLabelText(/Advanced Module List/i); + }); + fireEvent.change(textarea, { target: { value: '[3, 2, 1]' } }); + expect(textarea.value).toBe('[3, 2, 1]'); + axiosMock + .onPatch(`${getCourseAdvancedSettingsApiUrl(courseId)}`) + .reply(200, { + ...advancedSettingsMock, + advancedModules: { + ...advancedSettingsMock.advancedModules, + value: [3, 2, 1], + }, + }); + fireEvent.click(getByText('Save changes')); + await executeThunk(updateCourseAppSetting(courseId, [3, 2, 1]), store.dispatch); + expect(getByText('Your policy changes have been saved.')).toBeInTheDocument(); }); }); diff --git a/src/advanced-settings/__mocks__/advancedSettings.js b/src/advanced-settings/__mocks__/advancedSettings.js index 52d5bed6b0..ead6c3528b 100644 --- a/src/advanced-settings/__mocks__/advancedSettings.js +++ b/src/advanced-settings/__mocks__/advancedSettings.js @@ -6,4 +6,11 @@ module.exports = { hideOnEnabledPublisher: false, value: [], }, + certHtmlViewEnabled: { + deprecated: true, + display_name: 'Certificate web/html view enabled', + help: 'If true, certificate Web/HTML views are enabled for the course.', + hide_on_enabled_publisher: false, + value: true, + }, };