From ecb1b9facbc13da89c77d5afce1d0967eef30427 Mon Sep 17 00:00:00 2001 From: mfrachet Date: Mon, 1 Feb 2021 16:02:47 +0100 Subject: [PATCH] Add delete modal and tests for that --- package.json | 2 +- .../admin/src/components/LocaleRow/index.js | 18 ++- .../src/containers/SettingsPage/index.js | 37 +++++- .../SettingsPage/tests/SettingsPage.test.js | 85 ++++++++++++++ .../src/hooks/useDeleteLocale/constants.js | 4 + .../admin/src/hooks/useDeleteLocale/index.js | 25 +++++ .../src/hooks/useDeleteLocale/reducer.js | 41 +++++++ .../useDeleteLocale/tests/reducer.test.js | 105 ++++++++++++++++++ .../admin/src/translations/en.json | 5 +- test/config/front/strapi.js | 2 + 10 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js create mode 100644 packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js create mode 100644 packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js create mode 100644 packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js create mode 100644 packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js diff --git a/package.json b/package.json index 7177002b46..2711cfcca6 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "prettier:code": "prettier \"**/*.js\"", "prettier:other": "prettier \"**/*.{md,css,scss,yaml,yml}\"", "test:clean": "rimraf ./coverage", - "test:front": "npm run test:clean && cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --coverage", + "test:front": "npm run test:clean && cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js", "test:front:watch": "cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --watchAll", "test:front:update": "cross-env NODE_ENV=test IS_EE=true jest --config ./jest.config.front.js --u", "test:front:ce": "npm run test:clean && cross-env NODE_ENV=test IS_EE=false jest --config ./jest.config.front.js --coverage", diff --git a/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js b/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js index f83fe6771e..2d11addc00 100644 --- a/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js +++ b/packages/strapi-plugin-i18n/admin/src/components/LocaleRow/index.js @@ -12,7 +12,7 @@ import { getTrad } from '../../utils'; const canUpdate = true; const canDelete = true; -const LocaleSettingsPage = ({ locale }) => { +const LocaleSettingsPage = ({ locale, onDelete }) => { const { formatMessage } = useIntl(); return ( @@ -34,12 +34,21 @@ const LocaleSettingsPage = ({ locale }) => { : null, + icon: canUpdate ? ( + + + + ) : null, onClick: () => console.log('edit'), }, { - icon: canDelete && !locale.isDefault ? : null, - onClick: () => console.log('open delete modal'), + icon: + canDelete && !locale.isDefault ? ( + + + + ) : null, + onClick: onDelete, }, ]} /> @@ -54,6 +63,7 @@ LocaleSettingsPage.propTypes = { displayName: PropTypes.string, code: PropTypes.string.isRequired, }).isRequired, + onDelete: PropTypes.func.isRequired, }; export default LocaleSettingsPage; diff --git a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js index 9ca033fd0c..effba33468 100644 --- a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js +++ b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/index.js @@ -1,17 +1,25 @@ import React from 'react'; import { useIntl } from 'react-intl'; -import { BaselineAlignment } from 'strapi-helper-plugin'; +import { BaselineAlignment, ModalConfirm } from 'strapi-helper-plugin'; import { Header, List } from '@buffetjs/custom'; -import { Button } from '@buffetjs/core'; - +import { Button, Text } from '@buffetjs/core'; import { LocaleRow } from '../../components'; import { useLocales } from '../../hooks'; import { getTrad } from '../../utils'; +import useDeleteLocale from '../../hooks/useDeleteLocale'; // Fake permissions const canCreate = true; const LocaleSettingsPage = () => { + const { + isDeleting, + isDeleteModalOpen, + deleteLocale, + showDeleteModal, + hideDeleteModal, + } = useDeleteLocale(); + const { formatMessage } = useIntl(); const { locales, isLoading } = useLocales(); @@ -59,8 +67,29 @@ const LocaleSettingsPage = () => { title={listTitle} items={locales} isLoading={isLoading} - customRowComponent={locale => } + customRowComponent={locale => ( + showDeleteModal(locale)} /> + )} /> + + + + {formatMessage({ id: getTrad('Settings.locales.modal.delete.secondMessage') })} + + ); }; diff --git a/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js new file mode 100644 index 0000000000..808d9f2318 --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js @@ -0,0 +1,85 @@ +import React from 'react'; +import { fireEvent, render, screen, within, waitFor } from '@testing-library/react'; +import { ThemeProvider } from 'styled-components'; +import LocaleSettingsPage from '..'; +import themes from '../../../../../../strapi-admin/admin/src/themes'; + +// TODO: we should not be forced to mock this module +// but it bugs somehow when run with jest +jest.mock('strapi-helper-plugin', () => ({ + BaselineAlignment: () =>
, + // eslint-disable-next-line react/prop-types + ModalConfirm: ({ onConfirm, isOpen }) => + isOpen ? ( +
+ +
+ ) : null, +})); + +jest.mock('../../../utils', () => ({ + getTrad: x => x, +})); + +jest.mock('react-intl', () => ({ + useIntl: () => ({ + formatMessage: ({ id }) => id, + }), +})); + +describe('i18n settings page', () => { + describe('initial state', () => { + it('shows default EN locale with edit button but no delete button', async () => { + render( + + + + ); + + const row = await waitFor(() => screen.getByText('English').closest('tr')); + const rowUtils = within(row); + + expect(rowUtils.queryByLabelText('Delete locale')).toBeFalsy(); + expect(rowUtils.getByLabelText('Edit locale')).toBeVisible(); + expect(rowUtils.getByText('Settings.locales.row.default-locale')).toBeVisible(); + expect(rowUtils.getByText('en-US')).toBeVisible(); + }); + + it('shows FR locale with edit button and delete button', async () => { + render( + + + + ); + + const row = await waitFor(() => screen.getByText('French').closest('tr')); + const rowUtils = within(row); + + expect(rowUtils.getByLabelText('Delete locale')).toBeVisible(); + expect(rowUtils.getByLabelText('Edit locale')).toBeVisible(); + expect(rowUtils.getByText('fr-FR')).toBeVisible(); + }); + }); + + describe('delete', () => { + it('removes the locale when clicking the confirmation button', async () => { + render( + + + + ); + + const row = await waitFor(() => screen.getByText('French').closest('tr')); + const rowUtils = within(row); + + fireEvent.click(rowUtils.getByLabelText('Delete locale')); + + const dialog = screen.getByRole('dialog'); + expect(dialog).toBeVisible(); + + fireEvent.click(screen.getByText('Confirm')); + }); + }); +}); diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js new file mode 100644 index 0000000000..80998d9d21 --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/constants.js @@ -0,0 +1,4 @@ +export const SHOW_MODAL = 'SHOW_MODAL'; +export const HIDE_MODAL = 'HIDE_MODAL'; +export const DELETE_LOCALE = 'DELETE_LOCALE'; +export const RESOLVE_LOCALE = 'RESOLVE_LOCALE'; diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js new file mode 100644 index 0000000000..6973bbc1e8 --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/index.js @@ -0,0 +1,25 @@ +import { useReducer } from 'react'; +import reducer, { initialState } from './reducer'; +import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from './constants'; + +const useDeleteLocale = () => { + const [{ isDeleteModalOpen, isDeleting }, dispatch] = useReducer(reducer, initialState); + + const deleteLocale = () => { + dispatch({ type: DELETE_LOCALE }); + + return new Promise(resolve => + setTimeout(() => { + dispatch({ type: RESOLVE_LOCALE }); + resolve(); + }, 1000) + ); + }; + + const showDeleteModal = localeToDelete => dispatch({ type: SHOW_MODAL, localeToDelete }); + const hideDeleteModal = () => dispatch({ type: HIDE_MODAL }); + + return { isDeleting, isDeleteModalOpen, deleteLocale, showDeleteModal, hideDeleteModal }; +}; + +export default useDeleteLocale; diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js new file mode 100644 index 0000000000..6125e08878 --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/reducer.js @@ -0,0 +1,41 @@ +/* eslint-disable consistent-return */ +import produce from 'immer'; +import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from './constants'; + +export const initialState = { + localeToDelete: null, + isDeleteModalOpen: false, + isDeleting: false, +}; + +const reducer = (state, action) => + produce(state, draftState => { + switch (action.type) { + case SHOW_MODAL: { + draftState.isDeleteModalOpen = true; + draftState.localeToDelete = action.localeToDelete; + break; + } + case HIDE_MODAL: { + draftState.isDeleteModalOpen = false; + draftState.localeToDelete = null; + break; + } + case DELETE_LOCALE: { + draftState.isDeleting = true; + break; + } + + case RESOLVE_LOCALE: { + draftState.isDeleting = false; + draftState.isDeleteModalOpen = false; + draftState.localeToDelete = null; + break; + } + + default: + return draftState; + } + }); + +export default reducer; diff --git a/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js new file mode 100644 index 0000000000..257349753c --- /dev/null +++ b/packages/strapi-plugin-i18n/admin/src/hooks/useDeleteLocale/tests/reducer.test.js @@ -0,0 +1,105 @@ +import reducer from '../reducer'; +import { SHOW_MODAL, HIDE_MODAL, RESOLVE_LOCALE, DELETE_LOCALE } from '../constants'; + +describe(`I18N Settings page reducer`, () => { + describe(`Initial state`, () => { + it('returns the initialState', () => { + const state = { + localeToDelete: null, + isDeleteModalOpen: false, + isDeleting: false, + }; + + expect(reducer(state, {})).toEqual(state); + }); + }); + + describe(SHOW_MODAL, () => { + it('set the isDeleteModalOpen key to true', () => { + const state = { + localeToDelete: null, + isDeleteModalOpen: false, + isDeleting: false, + }; + + const action = { + type: SHOW_MODAL, + localeToDelete: 'en-EN', + }; + + const expected = { + localeToDelete: 'en-EN', + isDeleteModalOpen: true, + isDeleting: false, + }; + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe(HIDE_MODAL, () => { + it('sets the isDeleteModalOpen value to false when it was true', () => { + const state = { + localeToDelete: 'en-EN', + isDeleteModalOpen: true, + isDeleting: false, + }; + + const action = { + type: HIDE_MODAL, + }; + + const expected = { + localeToDelete: null, + isDeleteModalOpen: false, + isDeleting: false, + }; + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe(DELETE_LOCALE, () => { + it('sets the isDeleting value to true', () => { + const state = { + localeToDelete: 'en-EN', + isDeleteModalOpen: true, + isDeleting: false, + }; + + const action = { + type: DELETE_LOCALE, + }; + + const expected = { + localeToDelete: 'en-EN', + isDeleteModalOpen: true, + isDeleting: true, + }; + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe(RESOLVE_LOCALE, () => { + it('resets the state to its initial values when they were true', () => { + const state = { + localeToDelete: 'en-EN', + isDeleteModalOpen: true, + isDeleting: true, + }; + + const action = { + type: RESOLVE_LOCALE, + }; + + const expected = { + localeToDelete: null, + isDeleteModalOpen: false, + isDeleting: false, + }; + + expect(reducer(state, action)).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-plugin-i18n/admin/src/translations/en.json b/packages/strapi-plugin-i18n/admin/src/translations/en.json index 92679eab18..6c2efff9a3 100644 --- a/packages/strapi-plugin-i18n/admin/src/translations/en.json +++ b/packages/strapi-plugin-i18n/admin/src/translations/en.json @@ -5,5 +5,8 @@ "Settings.list.description": "Configure the settings for the internationalization plugin", "Settings.locales.list.title.singular": "{number} Locale", "Settings.locales.list.title.plural": "{number} Locales", - "Settings.locales.row.default-locale": "Default locale" + "Settings.locales.row.default-locale": "Default locale", + "Settings.locales.modal.delete.confirm": "Yes, delete", + "Settings.locales.modal.delete.message": "Deleting this locale will delete all associated content. If you want to keep some content, make sure to reallocate it to another locale first.", + "Settings.locales.modal.delete.secondMessage": "Do you want to delete this locale?" } diff --git a/test/config/front/strapi.js b/test/config/front/strapi.js index 182c0a6e71..1ea0728f8d 100644 --- a/test/config/front/strapi.js +++ b/test/config/front/strapi.js @@ -7,6 +7,8 @@ // Setup the strapi functioon global variable +import '@testing-library/jest-dom/extend-expect'; + const React = require('react'); const hoistNonReactStatics = require('hoist-non-react-statics');