Skip to content

Commit

Permalink
test(react-form): add on change validation tests (#425)
Browse files Browse the repository at this point in the history
Co-authored-by: João Pedro Magalhães <[email protected]>
  • Loading branch information
joaom00 and João Pedro Magalhães authored Sep 2, 2023
1 parent c6b246d commit 09edc1f
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 1 deletion.
210 changes: 210 additions & 0 deletions packages/react-form/src/tests/useField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import * as React from 'react'
import { render, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom'
import { createFormFactory } from '..'
import { sleep } from './utils'

const user = userEvent.setup()

describe('useField', () => {
it('should allow to set default value', () => {
type Person = {
firstName: string
lastName: string
}

const formFactory = createFormFactory<Person>()

function Comp() {
const form = formFactory.useForm()

return (
<form.Provider>
<form.Field
name="firstName"
defaultValue="FirstName"
children={(field) => {
return (
<input data-testid="fieldinput" {...field.getInputProps()} />
)
}}
/>
</form.Provider>
)
}

const { getByTestId } = render(<Comp />)
const input = getByTestId('fieldinput')
expect(input).toHaveValue('FirstName')
})

it('should not validate on change if isTouched is false', async () => {
type Person = {
firstName: string
lastName: string
}
const error = 'Please enter a different value'

const formFactory = createFormFactory<Person>()

function Comp() {
const form = formFactory.useForm()

return (
<form.Provider>
<form.Field
name="firstName"
onChange={(value) => (value === 'other' ? error : undefined)}
children={(field) => (
<div>
<input
data-testid="fieldinput"
name={field.name}
{...field.getInputProps()}
/>
<p>{field.getMeta().error}</p>
</div>
)}
/>
</form.Provider>
)
}

const { getByTestId, queryByText } = render(<Comp />)
const input = getByTestId('fieldinput')
await user.type(input, 'other')
expect(queryByText(error)).not.toBeInTheDocument()
})

it('should validate on change if isTouched is true', async () => {
type Person = {
firstName: string
lastName: string
}
const error = 'Please enter a different value'

const formFactory = createFormFactory<Person>()

function Comp() {
const form = formFactory.useForm()

return (
<form.Provider>
<form.Field
name="firstName"
defaultMeta={{ isTouched: true }}
onChange={(value) => (value === 'other' ? error : undefined)}
children={(field) => (
<div>
<input
data-testid="fieldinput"
name={field.name}
{...field.getInputProps()}
/>
<p>{field.getMeta().error}</p>
</div>
)}
/>
</form.Provider>
)
}

const { getByTestId, getByText, queryByText } = render(<Comp />)
const input = getByTestId('fieldinput')
expect(queryByText(error)).not.toBeInTheDocument()
await user.type(input, 'other')
expect(getByText(error)).toBeInTheDocument()
})

it('should validate async on change', async () => {
type Person = {
firstName: string
lastName: string
}
const error = 'Please enter a different value'

const formFactory = createFormFactory<Person>()

function Comp() {
const form = formFactory.useForm()

return (
<form.Provider>
<form.Field
name="firstName"
defaultMeta={{ isTouched: true }}
onChangeAsync={async () => {
await sleep(10)
return error
}}
children={(field) => (
<div>
<input
data-testid="fieldinput"
name={field.name}
{...field.getInputProps()}
/>
<p>{field.getMeta().error}</p>
</div>
)}
/>
</form.Provider>
)
}

const { getByTestId, getByText, queryByText } = render(<Comp />)
const input = getByTestId('fieldinput')
await user.type(input, 'other')
expect(queryByText(error)).not.toBeInTheDocument()
await waitFor(() => getByText(error))
expect(getByText(error)).toBeInTheDocument()
})

it('should validate async on change with debounce', async () => {
type Person = {
firstName: string
lastName: string
}
const mockFn = vi.fn()
const error = 'Please enter a different value'
const formFactory = createFormFactory<Person>()

function Comp() {
const form = formFactory.useForm()

return (
<form.Provider>
<form.Field
name="firstName"
defaultMeta={{ isTouched: true }}
onChangeAsyncDebounceMs={10}
onChangeAsync={async () => {
mockFn()
await sleep(10)
return error
}}
children={(field) => (
<div>
<input
data-testid="fieldinput"
name={field.name}
{...field.getInputProps()}
/>
<p>{field.getMeta().error}</p>
</div>
)}
/>
</form.Provider>
)
}

const { getByTestId, getByText } = render(<Comp />)
const input = getByTestId('fieldinput')
await user.type(input, 'other')
// mockFn will have been called 5 times without onChangeAsyncDebounceMs
expect(mockFn).toHaveBeenCalledTimes(0)
await waitFor(() => getByText(error))
expect(getByText(error)).toBeInTheDocument()
})
})
2 changes: 1 addition & 1 deletion packages/react-form/src/tests/useForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fireEvent, render } from '@testing-library/react'
import { render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom'
import * as React from 'react'
Expand Down
5 changes: 5 additions & 0 deletions packages/react-form/src/tests/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function sleep(timeout: number): Promise<void> {
return new Promise((resolve, _reject) => {
setTimeout(resolve, timeout)
})
}

0 comments on commit 09edc1f

Please sign in to comment.