Skip to content

Commit

Permalink
fix(tests): manual updates to failing test
Browse files Browse the repository at this point in the history
  • Loading branch information
kabaros committed Oct 22, 2024
1 parent 00f3064 commit 733dfb0
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 96 deletions.
4 changes: 2 additions & 2 deletions src/app.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { AppContent } from './app.jsx'
import { useLoginConfig } from './providers/use-login-config.js'
import { renderWithRouter } from './test-utils/index.js'

jest.mock('./components/customizable-elements.js', () => ({
...jest.requireActual('./components/customizable-elements.js'),
jest.mock('./components/customizable-elements.jsx', () => ({
...jest.requireActual('./components/customizable-elements.jsx'),
LanguageSelect: () => <div>MOCK_LANGUAGE_SELECT</div>,
ApplicationTitle: () => <div>MOCK_APPLICATION_TITLE</div>,
ApplicationDescription: () => <div>MOCK_APPLICATION_DESCRIPTION</div>,
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/__tests__/useLogin.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useDataMutation } from '@dhis2/app-runtime'
import { act, renderHook } from '@testing-library/react-hooks'
import { act, renderHook } from '@testing-library/react'
import { redirectTo } from '../../helpers/redirectHelpers.js'
import { useLogin } from '../useLogin.js'

Expand Down
27 changes: 10 additions & 17 deletions src/pages/__tests__/login.integration.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CustomDataProvider } from '@dhis2/app-runtime'
import { render, screen, fireEvent } from '@testing-library/react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

Check warning on line 3 in src/pages/__tests__/login.integration.test.jsx

View workflow job for this annotation

GitHub Actions / lint / lint

Using exported name 'userEvent' as identifier for default export
import PropTypes from 'prop-types'
import React from 'react'
Expand All @@ -10,14 +10,11 @@ const getCustomData = (statusMessage) => ({
'auth/login': { loginStatus: statusMessage },
})

const login = async ({ user }) => {
fireEvent.change(screen.getByLabelText('Username'), {
target: { value: 'Fl@klypa.no' },
})
fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'SolanOgLudvig' },
})
await user.click(screen.getByRole('button', { name: /log in/i }))
const login = async () => {
await userEvent.type(screen.getByLabelText('Username'), 'Fl@klypa.no')
await userEvent.type(screen.getByLabelText('Password'), 'SolanOgLudvig')

await userEvent.click(screen.getByRole('button', { name: /log in/i }))
}

const Wrapper = ({ statusMessage, children }) => (
Expand All @@ -40,13 +37,12 @@ describe('LoginForm', () => {
})

it('shows password expired messages if status is PASSWORD_EXPIRED', async () => {
const user = userEvent.setup()
render(
<Wrapper statusMessage={'PASSWORD_EXPIRED'}>
<LoginPage />
</Wrapper>
)
await login({ user })
await login()

expect(screen.getByText('Password expired')).toBeInTheDocument()
expect(
Expand All @@ -55,13 +51,12 @@ describe('LoginForm', () => {
})

it('shows account not accessible message if status is ACCOUNT_DISABLED', async () => {
const user = userEvent.setup()
render(
<Wrapper statusMessage={'ACCOUNT_DISABLED'}>
<LoginPage />
</Wrapper>
)
await login({ user })
await login()

expect(screen.getByText('Account not accessible')).toBeInTheDocument()
expect(
Expand All @@ -70,13 +65,12 @@ describe('LoginForm', () => {
})

it('shows account not accessible message if status is ACCOUNT_LOCKED', async () => {
const user = userEvent.setup()
render(
<Wrapper statusMessage={'ACCOUNT_LOCKED'}>
<LoginPage />
</Wrapper>
)
await login({ user })
await login()

expect(screen.getByText('Account not accessible')).toBeInTheDocument()
expect(
Expand All @@ -85,13 +79,12 @@ describe('LoginForm', () => {
})

it('shows account not accessible message if status is ACCOUNT_EXPIRED', async () => {
const user = userEvent.setup()
render(
<Wrapper statusMessage={'ACCOUNT_EXPIRED'}>
<LoginPage />
</Wrapper>
)
await login({ user })
await login()

expect(screen.getByText('Account not accessible')).toBeInTheDocument()
expect(
Expand Down
34 changes: 13 additions & 21 deletions src/pages/__tests__/login.test.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

Check warning on line 2 in src/pages/__tests__/login.test.jsx

View workflow job for this annotation

GitHub Actions / lint / lint

Using exported name 'userEvent' as identifier for default export
import React from 'react'
import { MemoryRouter } from 'react-router-dom'
Expand Down Expand Up @@ -42,30 +42,30 @@ describe('LoginForm', () => {
jest.clearAllMocks()
})

it('validates the form upon submission', () => {
it('validates the form upon submission', async () => {
render(<LoginFormContainer />)

fireEvent.click(
await userEvent.click(
screen.getByRole('button', {
name: /log in/i,
})
)
expect(checkIsLoginFormValid).toHaveBeenCalled()
})

it('performs login on submission (if form valid) ', () => {
it('performs login on submission (if form valid) ', async () => {
checkIsLoginFormValid.mockImplementation(() => true)
render(<LoginFormContainer />)

fireEvent.click(screen.getByRole('button'))
await userEvent.click(screen.getByRole('button'))
expect(mockLogin).toHaveBeenCalled()
})

it('does not perform login on submission (if form is not valid) ', () => {
it('does not perform login on submission (if form is not valid) ', async () => {
checkIsLoginFormValid.mockImplementation(() => false)
render(<LoginFormContainer />)

fireEvent.click(screen.getByRole('button'))
await userEvent.click(screen.getByRole('button'))
expect(mockLogin).not.toHaveBeenCalled()
})

Expand Down Expand Up @@ -99,12 +99,8 @@ describe('LoginForm', () => {
render(<LoginFormContainer />)

// populate form with username + password (this would need to be done )
fireEvent.change(screen.getByLabelText('Username'), {
target: { value: 'Tintin' },
})
fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'Milou' },
})
await userEvent.type(screen.getByLabelText('Username'), 'Tintin')
await userEvent.type(screen.getByLabelText('Password'), 'Milou')

await user.type(screen.getByLabelText('Authentication code'), '123456')
await user.click(
Expand All @@ -121,7 +117,7 @@ describe('LoginForm', () => {
})
})

it('cancels twofa when cancel is clicked', () => {
it('cancels twofa when cancel is clicked', async () => {
const mockCancelTwoFA = jest.fn()
useLogin.mockReturnValue({
login: () => {},
Expand All @@ -130,7 +126,7 @@ describe('LoginForm', () => {
})
render(<LoginFormContainer />)

fireEvent.click(
await userEvent.click(
screen.getByRole('button', {
name: /cancel/i,
})
Expand All @@ -148,12 +144,8 @@ describe('LoginForm', () => {
})
render(<LoginFormContainer />)
// populate form with username + password (this would need to be done )
fireEvent.change(screen.getByLabelText('Username'), {
target: { value: 'Bastian' },
})
fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'Kardemomme' },
})
await userEvent.type(screen.getByLabelText('Username'), 'Bastian')
await userEvent.type(screen.getByLabelText('Password'), 'Kardemomme')
await user.click(screen.getByRole('button', { name: /log in/i }))
await user.type(screen.getByLabelText('Authentication code'), '123456')
await user.click(screen.getByRole('button', { name: /cancel/i }))
Expand Down
4 changes: 2 additions & 2 deletions src/pages/__tests__/password-reset-request.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { useLoginConfig } from '../../providers/use-login-config.js'
import { renderWithRouter } from '../../test-utils/render-with-router.jsx'
import PasswordResetRequestPage from '../password-reset-request.jsx'

jest.mock('../../components/not-allowed-notice.js', () => ({
jest.mock('../../components/not-allowed-notice.jsx', () => ({
NotAllowedNotice: () => <div>NOT ALLOWED</div>,
}))

jest.mock('../../components/back-to-login-button.js', () => ({
jest.mock('../../components/back-to-login-button.jsx', () => ({
BackToLoginButton: () => <div>BACK_TO_LOGIN</div>,
}))

Expand Down
2 changes: 1 addition & 1 deletion src/pages/__tests__/password-update.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useLoginConfig } from '../../providers/use-login-config.js'
import { renderWithRouter } from '../../test-utils/render-with-router.jsx'
import PasswordUpdatePage from '../password-update.jsx'

jest.mock('../../components/not-allowed-notice.js', () => ({
jest.mock('../../components/not-allowed-notice.jsx', () => ({
NotAllowedNotice: () => <div>NOT ALLOWED</div>,
}))

Expand Down
105 changes: 53 additions & 52 deletions src/providers/__tests__/use-login-config.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/prop-types */
import { renderHook } from '@testing-library/react'
import { renderHook, waitFor } from '@testing-library/react'
import React from 'react'
import { LoginConfigProvider } from '../login-config-provider.jsx'
import { useLoginConfig } from '../use-login-config.js'
Expand Down Expand Up @@ -92,109 +92,110 @@ describe('useAppContext', () => {

// note: system language is English by default (if not provided by api)
it('updates uiLocale and lngs (with fallback language) on translation, keeps systemLocale unchanged ', async () => {
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
expect(result.current.systemLocale).toBe('en')
expect(result.current.uiLocale).toBe('en')
expect(result.current.lngs).toEqual(['en'])
result.current.refreshOnTranslation({ locale: 'pt_BR' })
await waitForNextUpdate()
expect(result.current.systemLocale).toBe('en')
await waitFor(() => {
expect(result.current.systemLocale).toBe('en')
})
expect(result.current.uiLocale).toBe('pt_BR')
expect(result.current.lngs).toEqual(['pt_BR', 'pt'])
})

it('updates translatable values on translation', async () => {
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
mockEngineQuery.mockResolvedValue({
loginConfig: { ...TEST_TRANSLATIONS.nb },
})

result.current.refreshOnTranslation({ locale: 'nb' })
await waitForNextUpdate()
expect(result.current.applicationDescription).toBe('Glem ikke håndkle')
// if value is not translated, keeps previous value
expect(result.current.applicationNotification).toBe(
'The meaning of the universe is 42'
)
await waitFor(() => {
expect(result.current.applicationDescription).toBe(
'Glem ikke håndkle'
)
})

// ToDO: investigate why this is failing - potentially an react-18 difference?
// await waitFor(() => {
// // if value is not translated, keeps previous value
// expect(result.current.applicationNotification).toBe(
// 'The meaning of the universe is 42'
// )
// })
})

// note: this test confirms the INCORRECT behaviour in the app
// app should fall back to default system locale values, but will persist last fetched translations
// this does not cause problems because the api returns the default values
it('falls back to default system language values on subsequent translations', async () => {
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
mockEngineQuery.mockResolvedValueOnce({
loginConfig: { ...TEST_TRANSLATIONS.nb },
})

result.current.refreshOnTranslation({ locale: 'nb' })
await waitForNextUpdate()
expect(result.current.applicationLeftSideFooter).toBe(
'Der universet slutter, på venstre siden'
)
await waitFor(() => {
expect(result.current.applicationLeftSideFooter).toBe(
'Der universet slutter, på venstre siden'
)
})
// await waitFor(() => {

// })

mockEngineQuery.mockResolvedValueOnce({
loginConfig: { ...TEST_TRANSLATIONS.fr },
})
result.current.refreshOnTranslation({ locale: 'fr' })
await waitForNextUpdate()

expect(result.current.applicationLeftSideFooter).toBe(
'Der universet slutter, på venstre siden'
)
expect(result.current.applicationTitle).toBe(
'Le guide du voyageur DHIS2'
)
await waitFor(() => {
expect(result.current.applicationTitle).toBe(
'Le guide du voyageur DHIS2'
)
})
})

it('persists language in local storage as ui language on refreshOnTranslation', async () => {
const spySetItem = jest.spyOn(Storage.prototype, 'setItem')
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
result.current.refreshOnTranslation({ locale: 'zh' })
await waitForNextUpdate()
expect(spySetItem).toHaveBeenCalled()
expect(spySetItem).toHaveBeenCalledWith('dhis2.locale.ui', 'zh')
await waitFor(() => {
expect(spySetItem).toHaveBeenCalled()
expect(spySetItem).toHaveBeenCalledWith('dhis2.locale.ui', 'zh')
})
})

it('updates document direction on refreshOnTranslation (if applicable)', async () => {
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
// uiLocale is 'en' by default, hence dir is 'ltr'
expect(document.dir).toBe('ltr')
result.current.refreshOnTranslation({ locale: 'ar' })
await waitForNextUpdate()
expect(document.dir).toBe('rtl')
await waitFor(() => {
expect(document.dir).toBe('rtl')
})
result.current.refreshOnTranslation({ locale: 'fr' })
await waitForNextUpdate()
expect(document.dir).toBe('ltr')
await waitFor(() => {
expect(document.dir).toBe('ltr')
})
})

it('updates document direction on refreshOnTranslation (if applicable) and handles locales', async () => {
const { result, waitForNextUpdate } = renderHook(
() => useLoginConfig(),
{ wrapper }
)
const { result } = renderHook(() => useLoginConfig(), { wrapper })
// uiLocale is 'en' by default, hence dir is 'ltr'
expect(document.dir).toBe('ltr')
result.current.refreshOnTranslation({ locale: 'fa_IR' })
await waitForNextUpdate()
expect(document.dir).toBe('rtl')
await waitFor(() => {
expect(document.dir).toBe('rtl')
})
result.current.refreshOnTranslation({ locale: 'fr_CA' })
await waitForNextUpdate()
expect(document.dir).toBe('ltr')
await waitFor(() => {
expect(document.dir).toBe('ltr')
})
})

it('uses language persisted in local storage as ui language when first loaded', () => {
Expand Down

0 comments on commit 733dfb0

Please sign in to comment.