import { mount } from 'enzyme';
import React from 'react';
import type { IValidator } from '../../../forms/validation';
import type { IFormInputProps, IFormInputValidation } from '../interface';
import { useInternalValidator } from './useInternalValidator.hook';
function TestInputComponent(props: IFormInputProps & { validator?: IValidator; revalidateDeps?: any[] }) {
const { validator = () => null as string, validation, revalidateDeps = [], ...rest } = props;
useInternalValidator(validation, validator, revalidateDeps);
return ;
}
interface IFormInputValidationMock extends IFormInputValidation {
revalidate: jasmine.Spy & IFormInputValidation['revalidate'];
addValidator: jasmine.Spy & IFormInputValidation['addValidator'];
removeValidator: jasmine.Spy & IFormInputValidation['removeValidator'];
}
function validationMock(): IFormInputValidationMock {
return {
touched: true,
hidden: false,
category: null,
messageNode: null,
revalidate: jasmine.createSpy('validation.revalidate'),
addValidator: jasmine.createSpy('validation.addValidator'),
removeValidator: jasmine.createSpy('validation.removeValidator'),
};
}
describe('useInternalValidator', () => {
it('should call addValidator once when mounted', () => {
const validation = validationMock();
mount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(0);
});
it('should call revalidate when the deps list changes', () => {
const validation = validationMock();
const component = mount();
expect(validation.revalidate).toHaveBeenCalledTimes(0);
component.setProps({ revalidateDeps: ['c', 'd'] });
expect(validation.revalidate).toHaveBeenCalledTimes(1);
});
it('should call removeValidator when unmounted', () => {
const validation = validationMock();
const component = mount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(0);
component.unmount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(1);
});
it('should call removeValidator with the same validator object reference', () => {
const validation = validationMock();
let addedValidator: any, removedValidator: any;
validation.addValidator.and.callFake((arg: any) => (addedValidator = arg));
validation.removeValidator.and.callFake((arg: any) => (removedValidator = arg));
const component = mount();
component.unmount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(1);
expect(addedValidator).toBe(removedValidator);
});
it('should call removeValidator with the same validator object reference after multiple renders', () => {
const validation = validationMock();
let addedValidator: any, removedValidator: any;
validation.addValidator.and.callFake((arg: any) => (addedValidator = arg));
validation.removeValidator.and.callFake((arg: any) => (removedValidator = arg));
const component = mount();
component.render();
component.render();
component.unmount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(1);
expect(addedValidator).toBe(removedValidator);
});
it('should call the latest validate function prop', () => {
const validation = validationMock();
let validators: IValidator[] = [];
validation.addValidator.and.callFake((v: IValidator) => validators.push(v));
validation.removeValidator.and.callFake((v: IValidator) => (validators = validators.filter((x) => x !== v)));
validation.revalidate.and.callFake(() => validators.forEach((v) => v(null, null)));
const initialValidator: IValidator = jasmine.createSpy('initialValidator', () => 'initial');
const component = mount();
validation.revalidate();
expect(initialValidator).toHaveBeenCalledTimes(1);
const updatedValidator: IValidator = jasmine.createSpy('updatedValidator', () => 'updated');
component.setProps({ validator: updatedValidator });
validation.revalidate();
expect(initialValidator).toHaveBeenCalledTimes(1); // Didn't get called again
expect(updatedValidator).toHaveBeenCalledTimes(1);
});
it('should call removeValidator with the same validator object reference even after updating the validator', () => {
const validation = validationMock();
let addedValidator: any, removedValidator: any;
validation.addValidator.and.callFake((arg: any) => (addedValidator = arg));
validation.removeValidator.and.callFake((arg: any) => (removedValidator = arg));
const component = mount( 'Error: 1'} />);
component.render();
component.setProps({ validator: () => 'Error: 2' });
component.render();
component.unmount();
expect(validation.addValidator).toHaveBeenCalledTimes(1);
expect(validation.removeValidator).toHaveBeenCalledTimes(1);
expect(addedValidator).toBe(removedValidator);
});
});