diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/String/__tests__/String.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/String/__tests__/String.test.tsx
index ccf47a55194..bfd137344c7 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Field/String/__tests__/String.test.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Field/String/__tests__/String.test.tsx
@@ -663,10 +663,10 @@ describe('Field.String', () => {
render()
const input = document.querySelector('input')
await userEvent.type(input, 'def')
- expect(onChange.mock.calls).toHaveLength(3)
- expect(onChange.mock.calls[0][0]).toEqual('abcd')
- expect(onChange.mock.calls[1][0]).toEqual('abcde')
- expect(onChange.mock.calls[2][0]).toEqual('abcdef')
+ expect(onChange).toHaveBeenCalledTimes(3)
+ expect(onChange).toHaveBeenNthCalledWith(1, 'abcd')
+ expect(onChange).toHaveBeenNthCalledWith(2, 'abcde')
+ expect(onChange).toHaveBeenNthCalledWith(3, 'abcdef')
})
it('calls onFocus with current value', () => {
@@ -676,8 +676,8 @@ describe('Field.String', () => {
act(() => {
input.focus()
})
- expect(onFocus.mock.calls).toHaveLength(1)
- expect(onFocus.mock.calls[0][0]).toEqual('blah')
+ expect(onFocus).toHaveBeenCalledTimes(1)
+ expect(onFocus).toHaveBeenNthCalledWith(1, 'blah')
})
it('calls onBlur with current value', async () => {
@@ -687,12 +687,12 @@ describe('Field.String', () => {
input.focus()
fireEvent.blur(input)
await wait(0)
- expect(onBlur.mock.calls).toHaveLength(1)
- expect(onBlur.mock.calls[0][0]).toEqual('song2')
+ expect(onBlur).toHaveBeenCalledTimes(1)
+ expect(onBlur).toHaveBeenNthCalledWith(1, 'song2')
await userEvent.type(input, '345')
fireEvent.blur(input)
- expect(onBlur.mock.calls).toHaveLength(2)
- expect(onBlur.mock.calls[1][0]).toEqual('song2345')
+ expect(onBlur).toHaveBeenCalledTimes(2)
+ expect(onBlur).toHaveBeenNthCalledWith(2, 'song2345')
})
})
@@ -881,8 +881,12 @@ describe('Field.String', () => {
)
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(1)
- expect((validator.mock.calls[0] as unknown[])[0]).toEqual('abc')
+ expect(validator).toHaveBeenCalledTimes(1)
+ expect(validator).toHaveBeenNthCalledWith(
+ 1,
+ 'abc',
+ expect.anything()
+ )
expect(
screen.getByText('I think this is wrong')
).toBeInTheDocument()
@@ -893,13 +897,21 @@ describe('Field.String', () => {
fireEvent.blur(input)
await waitFor(() => {
- expect(validator.mock.calls).toHaveLength(4)
- expect((validator.mock.calls[1] as unknown[])[0]).toEqual('abcd')
- expect((validator.mock.calls[2] as unknown[])[0]).toEqual(
- 'abcde'
+ expect(validator).toHaveBeenCalledTimes(4)
+ expect(validator).toHaveBeenNthCalledWith(
+ 2,
+ 'abcd',
+ expect.anything()
+ )
+ expect(validator).toHaveBeenNthCalledWith(
+ 3,
+ 'abcde',
+ expect.anything()
)
- expect((validator.mock.calls[3] as unknown[])[0]).toEqual(
- 'abcdef'
+ expect(validator).toHaveBeenNthCalledWith(
+ 4,
+ 'abcdef',
+ expect.anything()
)
expect(
screen.getByText('I think this is wrong')
@@ -935,8 +947,12 @@ describe('Field.String', () => {
)
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(1)
- expect((validator.mock.calls[0] as unknown[])[0]).toEqual('abc')
+ expect(validator).toHaveBeenCalledTimes(1)
+ expect(validator).toHaveBeenNthCalledWith(
+ 1,
+ 'abc',
+ expect.anything()
+ )
expect(
screen.getByText('Whats left when nothing is right?')
).toBeInTheDocument()
@@ -949,10 +965,22 @@ describe('Field.String', () => {
fireEvent.blur(input)
})
- expect(validator.mock.calls).toHaveLength(4)
- expect((validator.mock.calls[1] as unknown[])[0]).toEqual('abcd')
- expect((validator.mock.calls[2] as unknown[])[0]).toEqual('abcde')
- expect((validator.mock.calls[3] as unknown[])[0]).toEqual('abcdef')
+ expect(validator).toHaveBeenCalledTimes(4)
+ expect(validator).toHaveBeenNthCalledWith(
+ 2,
+ 'abcd',
+ expect.anything()
+ )
+ expect(validator).toHaveBeenNthCalledWith(
+ 3,
+ 'abcde',
+ expect.anything()
+ )
+ expect(validator).toHaveBeenNthCalledWith(
+ 4,
+ 'abcdef',
+ expect.anything()
+ )
expect(
screen.getByText('Whats left when nothing is right?')
).toBeInTheDocument()
@@ -988,8 +1016,8 @@ describe('Field.String', () => {
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(0)
- expect(screen.queryByRole('alert')).not.toBeInTheDocument()
+ expect(validator).toHaveBeenCalledTimes(1)
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
})
const input = document.querySelector('input')
await userEvent.type(input, 'def')
@@ -997,9 +1025,16 @@ describe('Field.String', () => {
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(1)
- expect((validator.mock.calls[0] as unknown[])[0]).toEqual(
- 'abcdef'
+ expect(validator).toHaveBeenCalledTimes(2)
+ expect(validator).toHaveBeenNthCalledWith(
+ 1,
+ 'abc',
+ expect.anything()
+ )
+ expect(validator).toHaveBeenNthCalledWith(
+ 2,
+ 'abcdef',
+ expect.anything()
)
expect(
@@ -1040,8 +1075,8 @@ describe('Field.String', () => {
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(0)
- expect(screen.queryByRole('alert')).not.toBeInTheDocument()
+ expect(validator).toHaveBeenCalledTimes(1)
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
})
const input = document.querySelector('input')
await userEvent.type(input, 'def')
@@ -1049,9 +1084,16 @@ describe('Field.String', () => {
await waitFor(() => {
// Wait for since external validators are processed asynchronously
- expect(validator.mock.calls).toHaveLength(1)
- expect((validator.mock.calls[0] as unknown[])[0]).toEqual(
- 'abcdef'
+ expect(validator).toHaveBeenCalledTimes(2)
+ expect(validator).toHaveBeenNthCalledWith(
+ 1,
+ 'abc',
+ expect.anything()
+ )
+ expect(validator).toHaveBeenNthCalledWith(
+ 2,
+ 'abcdef',
+ expect.anything()
)
expect(
@@ -1153,29 +1195,36 @@ describe('Field.String', () => {
await userEvent.type(input, 'O!')
await waitFor(() => {
- expect(inputOnChange.mock.calls).toHaveLength(2)
- expect(inputOnChange.mock.calls[0][0]).toEqual('FOOO')
- expect(inputOnChange.mock.calls[1][0]).toEqual('FOOO!')
-
- expect(dataContextOnChange.mock.calls).toHaveLength(2)
- expect(dataContextOnChange.mock.calls[0][0]).toEqual({
- foo: 'FOOO',
- bar: 'BAAAR',
- })
- expect(dataContextOnChange.mock.calls[1][0]).toEqual({
- foo: 'FOOO!',
- bar: 'BAAAR',
- })
+ expect(inputOnChange).toHaveBeenNthCalledWith(1, 'FOOO')
+ expect(inputOnChange).toHaveBeenNthCalledWith(2, 'FOOO!')
- expect(dataContextOnPathChange.mock.calls).toHaveLength(2)
- expect(dataContextOnPathChange.mock.calls[0]).toEqual([
+ expect(dataContextOnChange).toHaveBeenNthCalledWith(
+ 1,
+ {
+ foo: 'FOOO',
+ bar: 'BAAAR',
+ },
+ expect.anything()
+ )
+ expect(dataContextOnChange).toHaveBeenNthCalledWith(
+ 2,
+ {
+ foo: 'FOOO!',
+ bar: 'BAAAR',
+ },
+ expect.anything()
+ )
+
+ expect(dataContextOnPathChange).toHaveBeenNthCalledWith(
+ 1,
'/foo',
- 'FOOO',
- ])
- expect(dataContextOnPathChange.mock.calls[1]).toEqual([
+ 'FOOO'
+ )
+ expect(dataContextOnPathChange).toHaveBeenNthCalledWith(
+ 2,
'/foo',
- 'FOOO!',
- ])
+ 'FOOO!'
+ )
})
})
})
diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useFieldProps.test.tsx b/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useFieldProps.test.tsx
index e0a1e95e030..fafba2acdf5 100644
--- a/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useFieldProps.test.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useFieldProps.test.tsx
@@ -2968,6 +2968,46 @@ describe('useFieldProps', () => {
})
describe('validator', () => {
+ describe('validateInitially', () => {
+ it('should show error message initially', async () => {
+ const validator = jest.fn(() => {
+ return new Error('My Error')
+ })
+
+ render(
+
+
+
+ )
+
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ })
+ expect(validator).toHaveBeenCalledTimes(1)
+ })
+
+ it('should show error message initially when validator is async', async () => {
+ const validator = jest.fn(async () => {
+ return new Error('My Error')
+ })
+
+ render(
+
+
+
+ )
+
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ })
+ expect(validator).toHaveBeenCalledTimes(1)
+ })
+ })
+
describe('connectWithPath', () => {
const validatorFn: UseFieldProps['validator'] = (
num,
@@ -3773,6 +3813,36 @@ describe('useFieldProps', () => {
expect(internalValidators).toHaveBeenCalledTimes(0)
})
+ it('should show error when validateInitially is set to true', async () => {
+ const exportedValidator = jest.fn(() => {
+ return Error('Error message')
+ })
+
+ const myValidator = jest.fn((value, { validators }) => {
+ const { exportedValidator } = validators
+ return [exportedValidator]
+ })
+
+ const MockComponent = (props) => {
+ return (
+
+ )
+ }
+
+ render()
+
+ await waitFor(() => {
+ expect(
+ document.querySelector('.dnb-form-status')
+ ).toBeInTheDocument()
+ })
+ })
+
it('should call internal validates when they are not returned in the publicValidator', async () => {
let internalValidators, barValidator, bazValidator
@@ -3866,6 +3936,49 @@ describe('useFieldProps', () => {
})
describe('onBlurValidator', () => {
+ describe('validateInitially', () => {
+ it('should show error message initially', async () => {
+ const onBlurValidator = jest.fn(() => {
+ return new Error('My Error')
+ })
+
+ render(
+
+
+
+ )
+
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ })
+ expect(onBlurValidator).toHaveBeenCalledTimes(1)
+ })
+
+ it('should show error message initially when validator is async', async () => {
+ const onBlurValidator = jest.fn(async () => {
+ return new Error('My Error')
+ })
+
+ render(
+
+
+
+ )
+
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ })
+ expect(onBlurValidator).toHaveBeenCalledTimes(1)
+ })
+ })
+
describe('connectWithPath', () => {
const validatorFn: UseFieldProps['validator'] = (
num,
@@ -4262,6 +4375,35 @@ describe('useFieldProps', () => {
expect(internalValidators).toHaveBeenCalledTimes(0)
})
})
+
+ it('should show error when validateInitially is set to true', async () => {
+ const exportedValidator = jest.fn(() => {
+ return Error('Error message')
+ })
+
+ const myValidator = jest.fn((value, { validators }) => {
+ const { exportedValidator } = validators
+ return [exportedValidator]
+ })
+
+ const MockComponent = (props) => {
+ return (
+
+ )
+ }
+
+ render()
+
+ await waitFor(() => {
+ expect(
+ document.querySelector('.dnb-form-status')
+ ).toBeInTheDocument()
+ })
+ })
})
describe('setMountedFieldState', () => {
diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
index c33d0155924..a382858069b 100644
--- a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
+++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
@@ -1027,6 +1027,19 @@ export default function useFieldProps(
}
}
+ // Only for when "validateInitially" is set to true
+ if (
+ onBlurValidatorRef.current &&
+ validateInitially &&
+ !changedRef.current
+ ) {
+ const { result } = await callOnBlurValidator()
+
+ if (result instanceof Error) {
+ throw result
+ }
+ }
+
if (isProcessActive()) {
clearErrorState()
}
@@ -1051,6 +1064,7 @@ export default function useFieldProps(
validateInitially,
validateUnchanged,
startOnChangeValidatorValidation,
+ callOnBlurValidator,
persistErrorState,
])