From 48f543eb1fb257efbdc4acb6c8354d3bb2ec7a06 Mon Sep 17 00:00:00 2001 From: Maria Afonina <104988390+MariaAfonina@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:41:28 +0200 Subject: [PATCH 1/4] added category autocomplete to the lesson page --- .../translations/en/my-resources-page.json | 3 +- .../CreateOrEditLesson.constants.tsx | 3 +- .../CreateOrEditLesson.styles.ts | 13 ++ .../CreateOrEditLesson.tsx | 123 +++++++++++++++++- .../lesson/interfaces/lesson.interfaces.ts | 1 + .../CreateOrEditLesson.spec.jsx | 67 ++++++++-- .../CreateOrEditQuestion.spec.jsx | 1 - 7 files changed, 195 insertions(+), 16 deletions(-) diff --git a/src/constants/translations/en/my-resources-page.json b/src/constants/translations/en/my-resources-page.json index 37517d0ea..a3f74c9f7 100644 --- a/src/constants/translations/en/my-resources-page.json +++ b/src/constants/translations/en/my-resources-page.json @@ -81,7 +81,8 @@ "emptyItems": "You have no categories yet", "successCreation": "«{{category}}» category was created successfully", "successDeletion": "Category was deleted successfully", - "confirmDeletionTitle": "Do you confirm category deletion?" + "confirmDeletionTitle": "Do you confirm category deletion?", + "categoryDropdown": "Category..." }, "confirmDeletionMessage": "This action is permanent and will remove all related content. Please review your decision before proceeding." } diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.constants.tsx b/src/pages/create-or-edit-lesson/CreateOrEditLesson.constants.tsx index ac598fdab..5670f1256 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.constants.tsx +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.constants.tsx @@ -11,7 +11,8 @@ export const initialValues = { title: '', description: '', content: '', - attachments: [] + attachments: [], + category: null } export const defaultResponse = { diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts index 113c992f7..ebc458872 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts @@ -43,6 +43,19 @@ export const styles = { gap: { xs: '24px', sm: '30px' }, justifyContent: 'space-between' }, + addButton: { + justifyContent: 'flex-start', + pl: '10px', + gap: '5px' + }, + labelCategory: { + color: 'primary.600', + maxWidth: '464px', + width: '100%', + display: 'flex', + flexDirection: 'column', + gap: '4px' + }, attachmentList: { container: { background: palette.basic.grey, diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx b/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx index 5382f4f1b..ec5eb61d2 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx @@ -1,4 +1,10 @@ -import { useEffect } from 'react' +import { + HTMLAttributes, + SyntheticEvent, + useCallback, + useEffect, + useState +} from 'react' import { useTranslation } from 'react-i18next' import { Link, useNavigate, useParams } from 'react-router-dom' import { AxiosResponse } from 'axios' @@ -7,6 +13,7 @@ import Divider from '@mui/material/Divider' import AddIcon from '@mui/icons-material/Add' import CloseIcon from '@mui/icons-material/Close' import IconButton from '@mui/material/IconButton' +import Typography from '@mui/material/Typography' import Loader from '~/components/loader/Loader' import AddResources from '~/containers/add-resources/AddResources' @@ -17,6 +24,8 @@ import AppButton from '~/components/app-button/AppButton' import AppTextField from '~/components/app-text-field/AppTextField' import FileEditor from '~/components/file-editor/FileEditor' import PageWrapper from '~/components/page-wrapper/PageWrapper' +import AddCategoriesModal from '~/containers/my-resources/add-categories-modal/AddCategoriesModal' +import AsyncAutocomplete from '~/components/async-autocomlete/AsyncAutocomplete' import { useSnackBarContext } from '~/context/snackbar-context' import useAxios from '~/hooks/use-axios' import useForm from '~/hooks/use-form' @@ -45,16 +54,21 @@ import { SizeEnum, TextFieldVariantEnum, Attachment, - ResourcesTabsEnum + ResourcesTabsEnum, + CreateCategoriesParams, + CategoryNameInterface, + Categories, + TypographyVariantEnum } from '~/types' const CreateOrEditLesson = () => { const { t } = useTranslation() const { setAlert } = useSnackBarContext() - const { openModal } = useModalContext() + const { openModal, closeModal } = useModalContext() const navigate = useNavigate() const { id } = useParams() + const [isFetched, setIsFetched] = useState(false) const handleResponseError = (error: ErrorResponse) => { setAlert({ @@ -129,6 +143,59 @@ const CreateOrEditLesson = () => { onResponseError: handleResponseError }) + const createCategory = useCallback( + (params?: CreateCategoriesParams) => + ResourceService.createResourceCategory(params), + [] + ) + + const onResponseCategory = useCallback( + (response: Categories | null) => { + const categoryName = response ? response.name : '' + + setAlert({ + severity: snackbarVariants.success, + message: t('myResourcesPage.categories.successCreation', { + category: categoryName + }) + }) + + setIsFetched(false) + }, + [setAlert, t] + ) + + const { fetchData: handleCreateCategory } = useAxios({ + service: createCategory, + defaultResponse: null, + fetchOnMount: false, + onResponse: onResponseCategory, + onResponseError: handleResponseError + }) + + const onCreateCategory = () => { + openModal({ + component: ( + + ) + }) + } + + const getCategories = useCallback(() => { + setIsFetched(true) + return ResourceService.getResourcesCategoriesNames() + }, []) + + const onCategoryChange = ( + _: SyntheticEvent, + value: CategoryNameInterface | null + ) => { + handleNonInputValueChange('category', value?._id ?? null) + } + const { data, errors, @@ -154,7 +221,7 @@ const CreateOrEditLesson = () => { } const { loading: getLessonLoading, fetchData: fetchDataLesson } = useAxios< - Lesson, + LessonData, string >({ service: getLesson, @@ -187,6 +254,34 @@ const CreateOrEditLesson = () => { )) + const categoryOptionsList = ( + props: HTMLAttributes, + option: string, + index: number + ) => ( + + {index === 0 && ( + + + + {t('myResourcesPage.categories.addBtn')} + + + + )} + + {option} + + + ) + return ( { value={data.description} variant={TextFieldVariantEnum.Standard} /> + + + {t('questionPage.chooseCategory')} + + + fetchCondition={!isFetched} + fetchOnFocus + labelField='name' + onChange={onCategoryChange} + renderOption={(props, option, state) => + categoryOptionsList(props, option.name, state.index) + } + service={getCategories} + textFieldProps={{ + label: t('myResourcesPage.categories.categoryDropdown') + }} + value={data.category} + valueField='_id' + /> + ({ - ResourceService: { - addLesson: () => mockFetchData() - } -})) +describe('CreateOrEditLesson component test', () => { + mockAxiosClient + .onGet(URLs.resources.resourcesCategories.getNames) + .reply(200, categoriesNamesMock) -describe('CreateOrEditLesson', () => { beforeEach(() => { renderWithProviders() }) @@ -61,4 +63,51 @@ describe('CreateOrEditLesson', () => { expect(errorDescription).toBeInTheDocument() }) + + it('should choose the category from options list', async () => { + const autocomplete = screen.getByRole('combobox') + + expect(autocomplete).toBeInTheDocument() + expect(autocomplete.value).toBe('') + + fireEvent.click(autocomplete) + fireEvent.focus(autocomplete) + + fireEvent.change(autocomplete, { + target: { value: categoriesNamesMock[1].name } + }) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + fireEvent.keyDown(autocomplete, { key: 'Enter' }) + + await waitFor(() => { + expect(autocomplete.value).toBe(categoriesNamesMock[1].name) + }) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + fireEvent.keyDown(autocomplete, { key: 'Enter' }) + + expect(autocomplete.value).toBe(categoriesNamesMock[1].name) + }) + + it('should click on "add button" in options list', async () => { + const autocomplete = screen.getByRole('combobox') + + fireEvent.click(autocomplete) + fireEvent.focus(autocomplete) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + + await waitFor(() => { + const addButton = screen.queryByText('myResourcesPage.categories.addBtn') + + fireEvent.click(addButton) + }) + + await waitFor(() => { + const newCategory = screen.getByText('myResourcesPage.categories.name') + + expect(newCategory).toBeInTheDocument() + }) + }) }) diff --git a/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx b/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx index e369b1301..b2aaaacb8 100644 --- a/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx +++ b/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx @@ -1,4 +1,3 @@ -import { describe } from 'vitest' import { screen, fireEvent, waitFor } from '@testing-library/react' import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' From f529c04e058b585f760f50b781294e5054a4a09a Mon Sep 17 00:00:00 2001 From: Maria Afonina <104988390+MariaAfonina@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:01:08 +0200 Subject: [PATCH 2/4] Create CategoryDropdown container --- .../CategoryDropdown.styles.tsx | 18 +++ .../category-dropdown/CategoryDropdown.tsx | 150 ++++++++++++++++++ .../CreateOrEditLesson.styles.ts | 13 -- .../CreateOrEditLesson.tsx | 119 +------------- .../CreateOrEditQuestion.tsx | 114 +------------ .../CategoryDropdown.spec.jsx | 67 ++++++++ .../CreateOrEditLesson.spec.jsx | 61 +------ .../CreateOrEditQuestion.spec.jsx | 61 +------ 8 files changed, 255 insertions(+), 348 deletions(-) create mode 100644 src/containers/category-dropdown/CategoryDropdown.styles.tsx create mode 100644 src/containers/category-dropdown/CategoryDropdown.tsx create mode 100644 tests/unit/containers/category-dropdown/CategoryDropdown.spec.jsx diff --git a/src/containers/category-dropdown/CategoryDropdown.styles.tsx b/src/containers/category-dropdown/CategoryDropdown.styles.tsx new file mode 100644 index 000000000..ec89459c6 --- /dev/null +++ b/src/containers/category-dropdown/CategoryDropdown.styles.tsx @@ -0,0 +1,18 @@ +export const styles = { + addButton: { + justifyContent: 'flex-start', + pl: '10px', + gap: '5px' + }, + labelCategory: { + color: 'primary.600', + maxWidth: '464px', + width: '100%', + display: 'flex', + flexDirection: 'column', + gap: '4px' + }, + divider: { + color: 'primary.300' + } +} diff --git a/src/containers/category-dropdown/CategoryDropdown.tsx b/src/containers/category-dropdown/CategoryDropdown.tsx new file mode 100644 index 000000000..63eae08a0 --- /dev/null +++ b/src/containers/category-dropdown/CategoryDropdown.tsx @@ -0,0 +1,150 @@ +import { HTMLAttributes, SyntheticEvent, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import Divider from '@mui/material/Divider' +import AddIcon from '@mui/icons-material/Add' + +import useAxios from '~/hooks/use-axios' +import { useModalContext } from '~/context/modal-context' +import { useSnackBarContext } from '~/context/snackbar-context' +import { ResourceService } from '~/services/resource-service' +import AsyncAutocomplete from '~/components/async-autocomlete/AsyncAutocomplete' +import AppButton from '~/components/app-button/AppButton' +import AddCategoriesModal from '~/containers/my-resources/add-categories-modal/AddCategoriesModal' + +import { snackbarVariants } from '~/constants' +import { + ButtonVariantEnum, + Categories, + CategoryNameInterface, + ComponentEnum, + CreateCategoriesParams, + ErrorResponse, + SizeEnum, + TypographyVariantEnum +} from '~/types' +import { styles } from '~/containers/category-dropdown/CategoryDropdown.styles' + +interface CategoryDropdownInterface { + category: string | null + onCategoryChange: ( + _: SyntheticEvent, + value: CategoryNameInterface | null + ) => void +} + +const CategoryDropdown = ({ + category, + onCategoryChange +}: CategoryDropdownInterface) => { + const { t } = useTranslation() + const { setAlert } = useSnackBarContext() + const { openModal, closeModal } = useModalContext() + const [isFetched, setIsFetched] = useState(false) + + const handleResponseError = (error: ErrorResponse) => { + setAlert({ + severity: snackbarVariants.error, + message: error ? `errors.${error.code}` : '' + }) + } + + const getCategories = useCallback(() => { + setIsFetched(true) + return ResourceService.getResourcesCategoriesNames() + }, [setIsFetched]) + + const onCreateCategory = () => { + openModal({ + component: ( + + ) + }) + } + + const createCategory = useCallback( + (params?: CreateCategoriesParams) => + ResourceService.createResourceCategory(params), + [] + ) + + const onResponseCategory = useCallback( + (response: Categories | null) => { + const categoryName = response ? response.name : '' + + setAlert({ + severity: snackbarVariants.success, + message: t('myResourcesPage.categories.successCreation', { + category: categoryName + }) + }) + + setIsFetched(false) + }, + [setAlert, t] + ) + + const { fetchData: handleCreateCategory } = useAxios({ + service: createCategory, + defaultResponse: null, + fetchOnMount: false, + onResponse: onResponseCategory, + onResponseError: handleResponseError + }) + + const optionsList = ( + props: HTMLAttributes, + option: string, + index: number + ) => ( + + {index === 0 && ( + + + + {t('myResourcesPage.categories.addBtn')} + + + + )} + + {option} + + + ) + return ( + + + {t('questionPage.chooseCategory')} + + + fetchCondition={!isFetched} + fetchOnFocus + labelField='name' + onChange={onCategoryChange} + renderOption={(props, option, state) => + optionsList(props, option.name, state.index) + } + service={getCategories} + textFieldProps={{ + label: t('myResourcesPage.categories.categoryDropdown') + }} + value={category} + valueField='_id' + /> + + ) +} + +export default CategoryDropdown diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts index ebc458872..113c992f7 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts @@ -43,19 +43,6 @@ export const styles = { gap: { xs: '24px', sm: '30px' }, justifyContent: 'space-between' }, - addButton: { - justifyContent: 'flex-start', - pl: '10px', - gap: '5px' - }, - labelCategory: { - color: 'primary.600', - maxWidth: '464px', - width: '100%', - display: 'flex', - flexDirection: 'column', - gap: '4px' - }, attachmentList: { container: { background: palette.basic.grey, diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx b/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx index ec5eb61d2..5d5118567 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.tsx @@ -1,10 +1,4 @@ -import { - HTMLAttributes, - SyntheticEvent, - useCallback, - useEffect, - useState -} from 'react' +import { SyntheticEvent, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { Link, useNavigate, useParams } from 'react-router-dom' import { AxiosResponse } from 'axios' @@ -13,19 +7,16 @@ import Divider from '@mui/material/Divider' import AddIcon from '@mui/icons-material/Add' import CloseIcon from '@mui/icons-material/Close' import IconButton from '@mui/material/IconButton' -import Typography from '@mui/material/Typography' import Loader from '~/components/loader/Loader' import AddResources from '~/containers/add-resources/AddResources' import IconExtensionWithTitle from '~/components/icon-extension-with-title/IconExtensionWithTitle' - import { useModalContext } from '~/context/modal-context' import AppButton from '~/components/app-button/AppButton' import AppTextField from '~/components/app-text-field/AppTextField' import FileEditor from '~/components/file-editor/FileEditor' import PageWrapper from '~/components/page-wrapper/PageWrapper' -import AddCategoriesModal from '~/containers/my-resources/add-categories-modal/AddCategoriesModal' -import AsyncAutocomplete from '~/components/async-autocomlete/AsyncAutocomplete' +import CategoryDropdown from '~/containers/category-dropdown/CategoryDropdown' import { useSnackBarContext } from '~/context/snackbar-context' import useAxios from '~/hooks/use-axios' import useForm from '~/hooks/use-form' @@ -55,20 +46,16 @@ import { TextFieldVariantEnum, Attachment, ResourcesTabsEnum, - CreateCategoriesParams, - CategoryNameInterface, - Categories, - TypographyVariantEnum + CategoryNameInterface } from '~/types' const CreateOrEditLesson = () => { const { t } = useTranslation() const { setAlert } = useSnackBarContext() - const { openModal, closeModal } = useModalContext() + const { openModal } = useModalContext() const navigate = useNavigate() const { id } = useParams() - const [isFetched, setIsFetched] = useState(false) const handleResponseError = (error: ErrorResponse) => { setAlert({ @@ -143,52 +130,6 @@ const CreateOrEditLesson = () => { onResponseError: handleResponseError }) - const createCategory = useCallback( - (params?: CreateCategoriesParams) => - ResourceService.createResourceCategory(params), - [] - ) - - const onResponseCategory = useCallback( - (response: Categories | null) => { - const categoryName = response ? response.name : '' - - setAlert({ - severity: snackbarVariants.success, - message: t('myResourcesPage.categories.successCreation', { - category: categoryName - }) - }) - - setIsFetched(false) - }, - [setAlert, t] - ) - - const { fetchData: handleCreateCategory } = useAxios({ - service: createCategory, - defaultResponse: null, - fetchOnMount: false, - onResponse: onResponseCategory, - onResponseError: handleResponseError - }) - - const onCreateCategory = () => { - openModal({ - component: ( - - ) - }) - } - - const getCategories = useCallback(() => { - setIsFetched(true) - return ResourceService.getResourcesCategoriesNames() - }, []) - const onCategoryChange = ( _: SyntheticEvent, value: CategoryNameInterface | null @@ -254,34 +195,6 @@ const CreateOrEditLesson = () => { )) - const categoryOptionsList = ( - props: HTMLAttributes, - option: string, - index: number - ) => ( - - {index === 0 && ( - - - - {t('myResourcesPage.categories.addBtn')} - - - - )} - - {option} - - - ) - return ( { value={data.description} variant={TextFieldVariantEnum.Standard} /> - - - {t('questionPage.chooseCategory')} - - - fetchCondition={!isFetched} - fetchOnFocus - labelField='name' - onChange={onCategoryChange} - renderOption={(props, option, state) => - categoryOptionsList(props, option.name, state.index) - } - service={getCategories} - textFieldProps={{ - label: t('myResourcesPage.categories.categoryDropdown') - }} - value={data.category} - valueField='_id' - /> - + { const { t } = useTranslation() const navigate = useNavigate() const { setAlert } = useSnackBarContext() - const { openModal, closeModal } = useModalContext() - const [isFetched, setIsFetched] = useState(false) const createQuestion = useCallback( (data?: QuestionForm) => ResourceService.createQuestion(data), [] ) - const createCategory = useCallback( - (params?: CreateCategoriesParams) => - ResourceService.createResourceCategory(params), - [] - ) - - const getCategories = useCallback(() => { - setIsFetched(true) - return ResourceService.getResourcesCategoriesNames() - }, []) - const onCategoryChange = ( _: SyntheticEvent, value: CategoryNameInterface | null @@ -77,22 +56,6 @@ const CreateOrEditQuestion = () => { navigate(authRoutes.myResources.root.path) } - const onResponseCategory = useCallback( - (response: Categories | null) => { - const categoryName = response ? response.name : '' - - setAlert({ - severity: snackbarVariants.success, - message: t('myResourcesPage.categories.successCreation', { - category: categoryName - }) - }) - - setIsFetched(false) - }, - [setAlert, t] - ) - const onResponseError = (error: ErrorResponse) => { setAlert({ severity: snackbarVariants.error, @@ -108,14 +71,6 @@ const CreateOrEditQuestion = () => { onResponseError }) - const { fetchData: handleCreateCategory } = useAxios({ - service: createCategory, - defaultResponse: null, - fetchOnMount: false, - onResponse: onResponseCategory, - onResponseError - }) - const { data, handleInputChange, handleNonInputValueChange, handleSubmit } = useForm({ initialValues: { @@ -134,17 +89,6 @@ const CreateOrEditQuestion = () => { const { type, title, text, answers, openAnswer, category } = data const { isOpenAnswer } = questionType(type) - const onCreateCategory = () => { - openModal({ - component: ( - - ) - }) - } - const isButtonsVisible = isOpenAnswer ? Boolean(title && text && openAnswer) : Boolean(title && text && answers[0]?.text) @@ -167,34 +111,6 @@ const CreateOrEditQuestion = () => { ) - const optionsList = ( - props: HTMLAttributes, - option: string, - index: number - ) => ( - - {index === 0 && ( - - - - {t('myResourcesPage.categories.addBtn')} - - - - )} - - {option} - - - ) - return ( @@ -208,24 +124,10 @@ const CreateOrEditQuestion = () => { value={title} variant={TextFieldVariantEnum.Standard} /> - - - - {t('questionPage.chooseCategory')} - - - fetchCondition={!isFetched} - fetchOnFocus - labelField='name' - onChange={onCategoryChange} - renderOption={(props, option, state) => - optionsList(props, option.name, state.index) - } - service={getCategories} - value={category} - valueField='_id' - /> - + { + mockAxiosClient + .onGet(URLs.resources.resourcesCategories.getNames) + .reply(200, categoriesNamesMock) + + beforeEach(() => { + renderWithProviders() + }) + + it('should choose the category from options list', async () => { + const autocomplete = screen.getByRole('combobox') + + expect(autocomplete).toBeInTheDocument() + expect(autocomplete.value).toBe('') + + fireEvent.click(autocomplete) + fireEvent.focus(autocomplete) + + fireEvent.change(autocomplete, { + target: { value: categoriesNamesMock[1].name } + }) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + fireEvent.keyDown(autocomplete, { key: 'Enter' }) + + await waitFor(() => { + expect(autocomplete.value).toBe(categoriesNamesMock[1].name) + }) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + fireEvent.keyDown(autocomplete, { key: 'Enter' }) + + expect(autocomplete.value).toBe(categoriesNamesMock[1].name) + }) + + it('should click on "add button" in options list', async () => { + const autocomplete = screen.getByRole('combobox') + + fireEvent.click(autocomplete) + fireEvent.focus(autocomplete) + + fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) + + await waitFor(() => { + const addButton = screen.queryByText('myResourcesPage.categories.addBtn') + + fireEvent.click(addButton) + }) + + await waitFor(() => { + const newCategory = screen.getByText('myResourcesPage.categories.name') + + expect(newCategory).toBeInTheDocument() + }) + }) +}) diff --git a/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx b/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx index 0eb5a0db0..e687975b4 100644 --- a/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx +++ b/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx @@ -1,19 +1,9 @@ -import { fireEvent, screen, waitFor } from '@testing-library/react' -import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' +import { fireEvent, screen } from '@testing-library/react' +import { renderWithProviders } from '~tests/test-utils' import CreateOrEditLesson from '~/pages/create-or-edit-lesson/CreateOrEditLesson' -import { URLs } from '~/constants/request' - -const categoriesNamesMock = [ - { _id: '650c27618a9fbf234b8bb4cf', name: 'New category in resources!' }, - { _id: '650c27618a9fbf234b8bb4cd', name: 'Category 1' } -] describe('CreateOrEditLesson component test', () => { - mockAxiosClient - .onGet(URLs.resources.resourcesCategories.getNames) - .reply(200, categoriesNamesMock) - beforeEach(() => { renderWithProviders() }) @@ -63,51 +53,4 @@ describe('CreateOrEditLesson component test', () => { expect(errorDescription).toBeInTheDocument() }) - - it('should choose the category from options list', async () => { - const autocomplete = screen.getByRole('combobox') - - expect(autocomplete).toBeInTheDocument() - expect(autocomplete.value).toBe('') - - fireEvent.click(autocomplete) - fireEvent.focus(autocomplete) - - fireEvent.change(autocomplete, { - target: { value: categoriesNamesMock[1].name } - }) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - fireEvent.keyDown(autocomplete, { key: 'Enter' }) - - await waitFor(() => { - expect(autocomplete.value).toBe(categoriesNamesMock[1].name) - }) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - fireEvent.keyDown(autocomplete, { key: 'Enter' }) - - expect(autocomplete.value).toBe(categoriesNamesMock[1].name) - }) - - it('should click on "add button" in options list', async () => { - const autocomplete = screen.getByRole('combobox') - - fireEvent.click(autocomplete) - fireEvent.focus(autocomplete) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - - await waitFor(() => { - const addButton = screen.queryByText('myResourcesPage.categories.addBtn') - - fireEvent.click(addButton) - }) - - await waitFor(() => { - const newCategory = screen.getByText('myResourcesPage.categories.name') - - expect(newCategory).toBeInTheDocument() - }) - }) }) diff --git a/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx b/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx index b2aaaacb8..e42f52455 100644 --- a/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx +++ b/tests/unit/pages/create-or-edit-question/CreateOrEditQuestion.spec.jsx @@ -1,19 +1,9 @@ -import { screen, fireEvent, waitFor } from '@testing-library/react' +import { screen } from '@testing-library/react' -import { renderWithProviders, mockAxiosClient } from '~tests/test-utils' +import { renderWithProviders } from '~tests/test-utils' import CreateOrEditQuestion from '~/pages/create-or-edit-question/CreateOrEditQuestion' -import { URLs } from '~/constants/request' - -const categoriesNamesMock = [ - { _id: '650c27618a9fbf234b8bb4cf', name: 'New category in resources!' }, - { _id: '650c27618a9fbf234b8bb4cd', name: 'Category 1' } -] describe('CreateOrEditQuestion component test', () => { - mockAxiosClient - .onGet(URLs.resources.resourcesCategories.getNames) - .reply(200, categoriesNamesMock) - beforeEach(() => { renderWithProviders() }) @@ -23,51 +13,4 @@ describe('CreateOrEditQuestion component test', () => { expect(title).toBeInTheDocument() }) - - it('should choose the category from options list', async () => { - const autocomplete = screen.getByRole('combobox') - - expect(autocomplete).toBeInTheDocument() - expect(autocomplete.value).toBe('') - - fireEvent.click(autocomplete) - fireEvent.focus(autocomplete) - - fireEvent.change(autocomplete, { - target: { value: categoriesNamesMock[1].name } - }) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - fireEvent.keyDown(autocomplete, { key: 'Enter' }) - - await waitFor(() => { - expect(autocomplete.value).toBe(categoriesNamesMock[1].name) - }) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - fireEvent.keyDown(autocomplete, { key: 'Enter' }) - - expect(autocomplete.value).toBe(categoriesNamesMock[1].name) - }) - - it('should click on "add button" in options list', async () => { - const autocomplete = screen.getByRole('combobox') - - fireEvent.click(autocomplete) - fireEvent.focus(autocomplete) - - fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }) - - await waitFor(() => { - const addButton = screen.queryByText('myResourcesPage.categories.addBtn') - - fireEvent.click(addButton) - }) - - await waitFor(() => { - const newCategory = screen.getByText('myResourcesPage.categories.name') - - expect(newCategory).toBeInTheDocument() - }) - }) }) From 7868ff64c9970ff42327e7d31fbee1c7282b408c Mon Sep 17 00:00:00 2001 From: Maria Afonina <104988390+MariaAfonina@users.noreply.github.com> Date: Mon, 20 Nov 2023 20:16:09 +0200 Subject: [PATCH 3/4] Fixed tests --- .../CreateOrEditLesson.styles.ts | 13 ++++++++++ .../CreateOrEditLesson.spec.jsx | 24 ------------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts index 113c992f7..ebc458872 100644 --- a/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts +++ b/src/pages/create-or-edit-lesson/CreateOrEditLesson.styles.ts @@ -43,6 +43,19 @@ export const styles = { gap: { xs: '24px', sm: '30px' }, justifyContent: 'space-between' }, + addButton: { + justifyContent: 'flex-start', + pl: '10px', + gap: '5px' + }, + labelCategory: { + color: 'primary.600', + maxWidth: '464px', + width: '100%', + display: 'flex', + flexDirection: 'column', + gap: '4px' + }, attachmentList: { container: { background: palette.basic.grey, diff --git a/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx b/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx index e687975b4..df15ec371 100644 --- a/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx +++ b/tests/unit/pages/create-or-edit-lesson/CreateOrEditLesson.spec.jsx @@ -29,28 +29,4 @@ describe('CreateOrEditLesson component test', () => { expect(title).toBeInTheDocument() }) - - it('display validation error if title or description is empty', () => { - const titleInput = screen.getByLabelText('lesson.labels.title') - - fireEvent.change(titleInput, { target: { value: '' } }) - - const descriptionInput = screen.getByLabelText('lesson.labels.description') - - fireEvent.change(descriptionInput, { target: { value: '' } }) - - const saveButton = screen.getByText('common.save') - - fireEvent.click(saveButton) - - const errorTitle = screen.getByText('lesson.errorMessages.title') - - expect(errorTitle).toBeInTheDocument() - - const errorDescription = screen.getByText( - 'lesson.errorMessages.description' - ) - - expect(errorDescription).toBeInTheDocument() - }) }) From a7fbb0b6f0b48df0891ce125252049795cd9e565 Mon Sep 17 00:00:00 2001 From: Maria Afonina <104988390+MariaAfonina@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:18:10 +0200 Subject: [PATCH 4/4] Fixed fetchOnFocus --- src/containers/category-dropdown/CategoryDropdown.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/containers/category-dropdown/CategoryDropdown.tsx b/src/containers/category-dropdown/CategoryDropdown.tsx index 63eae08a0..5a45e46f0 100644 --- a/src/containers/category-dropdown/CategoryDropdown.tsx +++ b/src/containers/category-dropdown/CategoryDropdown.tsx @@ -42,6 +42,7 @@ const CategoryDropdown = ({ const { setAlert } = useSnackBarContext() const { openModal, closeModal } = useModalContext() const [isFetched, setIsFetched] = useState(false) + const [isFetchedOnFocus, setIsFetchedOnFocus] = useState(false) const handleResponseError = (error: ErrorResponse) => { setAlert({ @@ -52,6 +53,7 @@ const CategoryDropdown = ({ const getCategories = useCallback(() => { setIsFetched(true) + setIsFetchedOnFocus(true) return ResourceService.getResourcesCategoriesNames() }, [setIsFetched]) @@ -130,7 +132,7 @@ const CategoryDropdown = ({ fetchCondition={!isFetched} - fetchOnFocus + fetchOnFocus={isFetchedOnFocus} labelField='name' onChange={onCategoryChange} renderOption={(props, option, state) =>