diff --git a/ui/package.json b/ui/package.json index c3f3e581..e4ff9a9b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -61,8 +61,8 @@ "lint": "npm run lint:types & npm run lint:eslint", "lint:eslint": "eslint ./src --max-warnings 0 --cache --config .eslintrc.js", "lint:types": "tsc --noemit", - "jest": "craco test", - "jest:ci": "CI=true craco test --verbose --ci --coverage", + "jest": "craco test --setupFilesAfterEnv ./testing/setupTests.ts", + "jest:ci": "CI=true craco test --setupFilesAfterEnv ./testing/setupTests.ts --verbose --ci --coverage", "genSchemaTypes": "npx apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts", "extractTranslations": "i18next -c i18next-parser.config.js", "prepare": "(cd .. && npx husky install)" diff --git a/ui/src/Pages/PeoplePage/FaceCircleImage.test.tsx b/ui/src/Pages/PeoplePage/FaceCircleImage.test.tsx index d82ffc17..f0a23a15 100644 --- a/ui/src/Pages/PeoplePage/FaceCircleImage.test.tsx +++ b/ui/src/Pages/PeoplePage/FaceCircleImage.test.tsx @@ -1,12 +1,8 @@ -import '@testing-library/jest-dom' - import React from 'react' import { render, screen } from '@testing-library/react' import FaceCircleImage from './FaceCircleImage' import { myFaces_myFaceGroups_imageFaces } from './__generated__/myFaces' -require('../../localization').setupLocalization() - test('face circle image', () => { const imageFace: myFaces_myFaceGroups_imageFaces = { __typename: 'ImageFace', diff --git a/ui/src/Pages/PeoplePage/PeoplePage.test.tsx b/ui/src/Pages/PeoplePage/PeoplePage.test.tsx index 4480f4f3..3a6e9b36 100644 --- a/ui/src/Pages/PeoplePage/PeoplePage.test.tsx +++ b/ui/src/Pages/PeoplePage/PeoplePage.test.tsx @@ -1,5 +1,3 @@ -import '@testing-library/jest-dom' - import React from 'react' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import PeoplePage, { @@ -11,8 +9,6 @@ import { MockedProvider } from '@apollo/client/testing' import { MemoryRouter } from 'react-router' import { myFaces_myFaceGroups } from './__generated__/myFaces' -require('../../localization').setupLocalization() - jest.mock('../../hooks/useScrollPagination') describe('PeoplePage component', () => { diff --git a/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.test.tsx b/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.test.tsx index a0bc0df8..acd0e202 100644 --- a/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.test.tsx +++ b/ui/src/Pages/PeoplePage/SingleFaceGroup/SingleFaceGroup.test.tsx @@ -1,12 +1,8 @@ -import '@testing-library/jest-dom' - import React from 'react' import { render, screen, waitFor } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' import SingleFaceGroup, { SINGLE_FACE_GROUP } from './SingleFaceGroup' -require('../../../localization').setupLocalization() - jest.mock('../../../hooks/useScrollPagination') test('single face group', async () => { diff --git a/ui/src/Pages/SettingsPage/Users/AddUserRow.test.tsx b/ui/src/Pages/SettingsPage/Users/AddUserRow.test.tsx new file mode 100644 index 00000000..eadd6437 --- /dev/null +++ b/ui/src/Pages/SettingsPage/Users/AddUserRow.test.tsx @@ -0,0 +1,93 @@ +import React from 'react' +import { fireEvent, render, screen, waitFor } from '@testing-library/react' +import AddUserRow, { + CREATE_USER_MUTATION, + USER_ADD_ROOT_PATH_MUTATION, +} from './AddUserRow' +import { MockedProvider } from '@apollo/client/testing' + +const gqlMock = [ + { + request: { + query: CREATE_USER_MUTATION, + variables: { username: 'testuser', admin: false }, + }, + result: { + data: { + createUser: { + id: '123', + username: 'testuser', + admin: false, + __typename: 'User', + }, + }, + }, + }, + { + request: { + query: USER_ADD_ROOT_PATH_MUTATION, + variables: { id: '123', rootPath: '/tmp' }, + }, + result: { data: { userAddRootPath: { id: '567', __typename: 'Album' } } }, + }, +] + +test('Add user with username and path', async () => { + const userAdded = jest.fn() + const setShow = jest.fn() + + render( + + + + + +
+
+ ) + + const usernameInput = screen.getByPlaceholderText('Username') + const pathInput = screen.getByPlaceholderText('/path/to/photos') + const addUserBtn = screen.getByText('Add user') + + fireEvent.change(usernameInput, { target: { value: 'testuser' } }) + fireEvent.change(pathInput, { target: { value: '/tmp' } }) + fireEvent.click(addUserBtn) + + await waitFor(() => { + expect(userAdded).toHaveBeenCalledTimes(1) + }) + + expect(setShow).not.toHaveBeenCalled() +}) + +test('Add user with only username', async () => { + const userAdded = jest.fn() + const setShow = jest.fn() + + render( + + + + + +
+
+ ) + + const usernameInput = screen.getByPlaceholderText('Username') + const addUserBtn = screen.getByText('Add user') + + // don't set path + // const pathInput = screen.getByPlaceholderText('/path/to/photos') + // fireEvent.change(pathInput, { target: { value: '/tmp' } }) + + fireEvent.change(usernameInput, { target: { value: 'testuser' } }) + fireEvent.click(addUserBtn) + + await waitFor(() => { + expect(userAdded).toHaveBeenCalledTimes(1) + }) + + expect(setShow).not.toHaveBeenCalled() +}) diff --git a/ui/src/Pages/SettingsPage/Users/AddUserRow.tsx b/ui/src/Pages/SettingsPage/Users/AddUserRow.tsx index b8c28b33..4ff90361 100644 --- a/ui/src/Pages/SettingsPage/Users/AddUserRow.tsx +++ b/ui/src/Pages/SettingsPage/Users/AddUserRow.tsx @@ -5,7 +5,7 @@ import Checkbox from '../../../primitives/form/Checkbox' import { TextField, Button, ButtonGroup } from '../../../primitives/form/Input' import { TableRow, TableCell } from '../../../primitives/Table' -const CREATE_USER_MUTATION = gql` +export const CREATE_USER_MUTATION = gql` mutation createUser($username: String!, $admin: Boolean!) { createUser(username: $username, admin: $admin) { id @@ -41,16 +41,19 @@ const AddUserRow = ({ setShow, show, onUserAdded }: AddUserRowProps) => { const { t } = useTranslation() const [state, setState] = useState(initialState) + const finished = () => { + setState(initialState) + onUserAdded() + } + const [addRootPath, { loading: addRootPathLoading }] = useMutation( USER_ADD_ROOT_PATH_MUTATION, { onCompleted: () => { - setState(initialState) - onUserAdded() + finished() }, onError: () => { - setState(initialState) - onUserAdded() + finished() }, } ) @@ -67,7 +70,7 @@ const AddUserRow = ({ setShow, show, onUserAdded }: AddUserRowProps) => { }, }) } else { - setState(initialState) + finished() } }, } diff --git a/ui/src/Pages/SharePage/SharePage.test.js b/ui/src/Pages/SharePage/SharePage.test.js index 1dbf8d9e..cae0ec7c 100644 --- a/ui/src/Pages/SharePage/SharePage.test.js +++ b/ui/src/Pages/SharePage/SharePage.test.js @@ -1,5 +1,3 @@ -import '@testing-library/jest-dom' - import React from 'react' import { MemoryRouter } from 'react-router-dom' import { MockedProvider } from '@apollo/client/testing' @@ -18,8 +16,6 @@ import SharePage, { import { SIDEBAR_DOWNLOAD_QUERY } from '../../components/sidebar/SidebarDownload' import { SHARE_ALBUM_QUERY } from './AlbumSharePage' -require('../../localization').setupLocalization() - describe('load correct share page, based on graphql query', () => { const token = 'TOKEN123' diff --git a/ui/src/components/layout/Layout.test.js b/ui/src/components/layout/Layout.test.js index 1140b865..b053203f 100644 --- a/ui/src/components/layout/Layout.test.js +++ b/ui/src/components/layout/Layout.test.js @@ -1,10 +1,7 @@ -import '@testing-library/jest-dom' import { render, screen } from '@testing-library/react' import React from 'react' import Layout from './Layout' -require('../../localization').setupLocalization() - test('Layout component', async () => { render( diff --git a/ui/src/components/layout/MainMenu.test.tsx b/ui/src/components/layout/MainMenu.test.tsx index dbb5fb1b..89623ea2 100644 --- a/ui/src/components/layout/MainMenu.test.tsx +++ b/ui/src/components/layout/MainMenu.test.tsx @@ -1,5 +1,3 @@ -import '@testing-library/jest-dom' - import React from 'react' import { MockedProvider } from '@apollo/client/testing' import { render, screen } from '@testing-library/react' @@ -9,8 +7,6 @@ import { ADMIN_QUERY } from './Layout' import { MemoryRouter } from 'react-router-dom' import MainMenu, { MAPBOX_QUERY } from './MainMenu' -require('../../localization').setupLocalization() - jest.mock('../../helpers/authentication.ts') const authTokenMock = authentication.authToken as jest.MockedFunction< diff --git a/ui/src/components/photoGallery/PhotoGallery.test.tsx b/ui/src/components/photoGallery/PhotoGallery.test.tsx index 18fcd55e..8fe4aa0c 100644 --- a/ui/src/components/photoGallery/PhotoGallery.test.tsx +++ b/ui/src/components/photoGallery/PhotoGallery.test.tsx @@ -1,4 +1,3 @@ -import '@testing-library/jest-dom' import { render, screen } from '@testing-library/react' import React from 'react' @@ -6,8 +5,6 @@ import { MediaType } from '../../__generated__/globalTypes' import PhotoGallery from './PhotoGallery' import { PhotoGalleryState } from './photoGalleryReducer' -require('../../localization').setupLocalization() - jest.mock('./photoGalleryMutations', () => ({ useMarkFavoriteMutation: () => [jest.fn()], })) diff --git a/ui/src/components/photoGallery/presentView/PresentMedia.test.tsx b/ui/src/components/photoGallery/presentView/PresentMedia.test.tsx index 027b5fc6..06c3423d 100644 --- a/ui/src/components/photoGallery/presentView/PresentMedia.test.tsx +++ b/ui/src/components/photoGallery/presentView/PresentMedia.test.tsx @@ -1,4 +1,3 @@ -import '@testing-library/jest-dom' import { render, screen } from '@testing-library/react' import React from 'react' diff --git a/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.test.tsx b/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.test.tsx index 89dd1fba..c9561f09 100644 --- a/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.test.tsx +++ b/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.test.tsx @@ -1,6 +1,3 @@ -import '@testing-library/jest-dom' -import '@testing-library/user-event' - import React from 'react' import PresentNavigationOverlay from './PresentNavigationOverlay' import { fireEvent, render, screen, act } from '@testing-library/react' diff --git a/ui/src/components/routes/AuthorizedRoute.test.js b/ui/src/components/routes/AuthorizedRoute.test.js index 50fbf7c4..7bd83715 100644 --- a/ui/src/components/routes/AuthorizedRoute.test.js +++ b/ui/src/components/routes/AuthorizedRoute.test.js @@ -1,5 +1,3 @@ -import '@testing-library/jest-dom' - import React from 'react' import AuthorizedRoute from './AuthorizedRoute' import { render, screen } from '@testing-library/react' diff --git a/ui/src/components/routes/Routes.test.js b/ui/src/components/routes/Routes.test.js index c29bbc1c..1c7c44ee 100644 --- a/ui/src/components/routes/Routes.test.js +++ b/ui/src/components/routes/Routes.test.js @@ -1,5 +1,3 @@ -import '@testing-library/jest-dom' - import React from 'react' import Routes from './Routes' @@ -14,8 +12,6 @@ jest.mock('../../Pages/LoginPage/LoginPage.tsx', () => () => (
mocked login page
)) -require('../../localization').setupLocalization() - describe('routes', () => { test('unauthorized root path should navigate to login page', async () => { render( diff --git a/ui/src/components/sidebar/MediaSidebar.test.js b/ui/src/components/sidebar/MediaSidebar.test.js index d5ca1a7b..7ec5f15f 100644 --- a/ui/src/components/sidebar/MediaSidebar.test.js +++ b/ui/src/components/sidebar/MediaSidebar.test.js @@ -1,11 +1,7 @@ -import '@testing-library/jest-dom' - import React from 'react' import { render, screen } from '@testing-library/react' import { MetadataInfo } from './MediaSidebar' -require('../../localization').setupLocalization() - describe('MetadataInfo', () => { test('without EXIF information', async () => { const media = { diff --git a/ui/testing/setupTests.ts b/ui/testing/setupTests.ts new file mode 100644 index 00000000..99c2dbf0 --- /dev/null +++ b/ui/testing/setupTests.ts @@ -0,0 +1,9 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom' +import '@testing-library/user-event' + +// setup localization to make it easier to select elements by text +require('../src/localization').setupLocalization()