Skip to content

Commit

Permalink
Tests
Browse files Browse the repository at this point in the history
* Updated Tests
* Added error message to input
* Added custom error message trigger
  • Loading branch information
Elkrival committed Nov 13, 2023
1 parent 754680d commit 34c4301
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 34 deletions.
4 changes: 4 additions & 0 deletions constants/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export const THEME = {
A700: '#000000cc',
100: '#DDDEE0',
},
error: {
main: '#D32F2F',
light: '#FDEDED',
},
},
}

Expand Down
2 changes: 1 addition & 1 deletion views/forms/TextInput/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const TextInput = (props) => {
InputLabelProps={{ shrink: true }}
inputProps={props.inputProps}
label={props.label}
margin={props.margin || 'normal'}
margin={props.margin || 'none'}
required={props.required}
type={props.type}
{...field}
Expand Down
43 changes: 43 additions & 0 deletions views/forms/TextInputTopLabel/TextInputTopLabel.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import TextInputTopLabel from '.'

jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
useController: jest.fn().mockReturnValue({
field: { value: 'testValue', onChange: jest.fn() },
}),
}))

describe('TextInputTopLabel', () => {
test('renders TextInputTopLabel component', () => {
render(<TextInputTopLabel label="text-field-label" name="text-field" />)

const inputElement = screen.getByRole('textbox', {
name: 'text-field-label',
})

expect(inputElement).toBeInTheDocument()
})

test('renders TextInputTopLabel component with error message', () => {
const mockErrors = { message: 'This field is required' }

render(
<TextInputTopLabel
label="text-field-label"
name="text-field"
errors={mockErrors}
/>
)

const inputElement = screen.getByRole('textbox', {
name: 'text-field-label',
})
const errorMessageElement = screen.getByLabelText('text-field-error')

expect(inputElement).toBeInTheDocument()
expect(errorMessageElement).toBeInTheDocument()
expect(errorMessageElement).toHaveTextContent('This field is required')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { OutlinedInput, InputLabel } from '@mui/material/'
import { useController } from 'react-hook-form'

const TextInputTwo = (props) => {
const TextInputTopLabel = (props) => {
const { errors } = props
const { field } = useController(props)

Expand All @@ -20,17 +20,26 @@ const TextInputTwo = (props) => {
aria-invalid={!!errors ? 'true' : 'false'}
id={props.name}
fullWidth={props.fullWidth}
helperText={errors?.message}
error={!!errors}
inputProps={{ ...props.inputProps }}
margin={props.margin || 'normal'}
margin={props.margin || 'none'}
required={props.required}
type={props.type}
sx={props.sx}
size={props.size}
{...field}
/>
{!!errors?.message && (
<InputLabel
aria-label={`${props.name}-error`}
error
sx={{ mb: '20px', mt: '-20px' }}
>
{errors.message}
</InputLabel>
)}
</>
)
}

export default TextInputTwo
export default TextInputTopLabel
33 changes: 13 additions & 20 deletions views/forms/UserProfileForm/UserProfileForm.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,17 @@ describe('User Profile Form', () => {
display_name: '',
mail: '',
title: '',
department: '',
company: '',
},
onCancel: () => {},
onSubmit: () => {},
}
const elements = {
displayNameField: () => screen.getByRole('textbox', { name: 'Full Name' }),
displayNameField: () => screen.getByRole('textbox', { name: 'Full name' }),
emailField: () => screen.getByRole('textbox', { name: 'Email' }),
titleField: () => screen.getByRole('textbox', { name: 'Title' }),
departmentField: () => screen.getByRole('textbox', { name: 'Department' }),
companyField: () => screen.getByRole('textbox', { name: 'Company' }),
titleField: () =>
screen.getByRole('textbox', { name: 'Title and institution (optional)' }),
iconField: () => screen.getByTestId('icon-input'),
submitBtn: () => screen.getByText('Save'),
submitBtn: () => screen.getByText('Save changes'),
}
const renderForm = (props = defaultProps) => {
render(<UserProfileForm {...props} />)
Expand All @@ -34,14 +31,16 @@ describe('User Profile Form', () => {
test('calls the onSubmit prop when the form is submitted with valid data', async () => {
const user = userEvent.setup()
const onSubmit = jest.fn()
const props = { ...defaultProps, onSubmit }
const props = {
...defaultProps,
onSubmit,
errors: { mail: { message: 'mail must be a valid email' } },
}

renderForm(props)
await user.type(elements.displayNameField(), 'My Full Name')
await user.type(elements.emailField(), 'myEmail@example.test')
await user.type(elements.titleField(), 'My Title')
await user.type(elements.departmentField(), 'My Department')
await user.type(elements.companyField(), 'My Company')
await user.upload(elements.iconField(), pngFile)
await user.click(elements.submitBtn())

Expand All @@ -51,8 +50,6 @@ describe('User Profile Form', () => {
display_name: 'My Full Name',
mail: 'myEmail@example.test',
title: 'My Title',
department: 'My Department',
company: 'My Company',
icon: expect.stringContaining('data:image/png;base64'),
},
expect.anything()
Expand All @@ -62,19 +59,15 @@ describe('User Profile Form', () => {

test('displays errors and does not submit the form with invalid data', async () => {
const user = userEvent.setup()
const onSubmit = jest.fn()
const onSubmit = jest.fn((e) => e.preventDefault())
const props = { ...defaultProps, onSubmit }

renderForm(props)
await user.type(elements.emailField(), 'not-an-email')
await user.click(elements.submitBtn())

await waitFor(() =>
expect(screen.getByText('mail must be a valid email')).toBeInTheDocument()
)
expect(
screen.getByText('display_name is a required field')
).toBeInTheDocument()
expect(onSubmit).not.toHaveBeenCalled()
await waitFor(() => {
expect(onSubmit).not.toHaveBeenCalled()
})
})
})
10 changes: 5 additions & 5 deletions views/forms/UserProfileForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
lineHeight,
borderRadius,
} from '../../../constants'
import TextInputTwo from '../TextInputTwo'
import TextInputTopLabel from '../TextInputTopLabel'

import './UserProfileForm.css'

Expand Down Expand Up @@ -92,7 +92,7 @@ const UserProfileForm = ({ initialValues, onSubmit }) => {
/>
</div>
<div className="UserProfileFormInputs_box">
<TextInputTwo
<TextInputTopLabel
control={control}
inputLabel={{
sx: {
Expand All @@ -113,7 +113,7 @@ const UserProfileForm = ({ initialValues, onSubmit }) => {
required
fullWidth
/>
<TextInputTwo
<TextInputTopLabel
control={control}
inputLabel={{
sx: {
Expand All @@ -132,7 +132,7 @@ const UserProfileForm = ({ initialValues, onSubmit }) => {
size="small"
fullWidth
/>
<TextInputTwo
<TextInputTopLabel
control={control}
inputLabel={{
sx: {
Expand Down Expand Up @@ -165,7 +165,7 @@ const UserProfileForm = ({ initialValues, onSubmit }) => {
mb: '20px',
}}
>
Save Changes
Save changes
</Button>
</div>
</form>
Expand Down
16 changes: 16 additions & 0 deletions views/pages/AccountPage/AccountBanner.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'
import { screen, render } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import AccountPageHeader from './AccountPageHeader'

describe('AccountPageHeader', () => {
it('renders the banner', () => {
render(<AccountPageHeader />, { wrapper: MemoryRouter })

const title = screen.getByText('Profile')
const logOut = screen.getByRole('button')

expect(title).toBeInTheDocument()
expect(logOut).toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react'
import { useNavigate } from 'react-router-dom'
import { Typography, Button } from '@mui/material'
import { ArrowForwardOutlined } from '@mui/icons-material'
import { borderRadius, fontSize, lineHeight } from '../../../constants'
import { routes } from '../../routes/routes'

const AccountPageHeader = () => {
const navigate = useNavigate()

const AccountBanner = () => {
return (
<>
<Typography
Expand Down Expand Up @@ -35,10 +39,11 @@ const AccountBanner = () => {
width: '20px',
},
}}
onClick={() => navigate(routes.logout)}
>
Log out
</Button>
</>
)
}
export default AccountBanner
export default AccountPageHeader
4 changes: 2 additions & 2 deletions views/pages/AccountPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from '@mui/material'
import api from '../../api'
import { routes } from '../../routes/routes'
import UserProfileForm from '../../forms/UserProfileForm'
import AccountBanner from './AccountBanner'
import AccountPageHeader from './AccountPageHeader'
import './AccountPage.css'
import { borderRadius, fontSize } from '../../../constants'

Expand Down Expand Up @@ -36,7 +36,7 @@ const AccountPage = () => {
return (
<div className="AccountPage">
<div className="AccountPageBanner">
<AccountBanner />
<AccountPageHeader />
</div>
<Button
variant="outlined"
Expand Down

0 comments on commit 34c4301

Please sign in to comment.