Skip to content

Commit

Permalink
feat(cdk:forms): add useFormControl and Validtors
Browse files Browse the repository at this point in the history
* test(cdk:forms): add test

fix #115
  • Loading branch information
lcx15831 authored and danranVm committed Jan 9, 2021
1 parent 552bd95 commit 1f32f10
Show file tree
Hide file tree
Showing 14 changed files with 858 additions and 2 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = {
'no-trailing-spaces': 'error',
'object-curly-spacing': ['error', 'always'],
quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
'prefer-const': ['error', { destructuring: 'all' }],
semi: ['error', 'never'],

// ts
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
// u can change this option to a more specific folder for test single component or util when dev
// for example, ['<rootDir>/packages/components/button']
roots: ['<rootDir>'],

testEnvironment: 'jsdom',
transform: {
'^.+\\.vue$': 'vue-jest',
Expand Down
1 change: 1 addition & 0 deletions packages/cdk/breakpoint/src/breakpoints.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// PascalCase is being used as Breakpoints is used like an enum.
export const Breakpoints = {
XSmall: '(max-width: 767.99px)',
Small: '(min-width: 768px) and (max-width: 1023.99px)',
Expand Down
12 changes: 12 additions & 0 deletions packages/cdk/forms/__tests__/typeof.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { isFormControl } from '../src/typeof'
import { ModelType } from '../src/constant'
import { useFormControl } from '../src/useFormControl'

describe('typeof.ts', () => {
test('isFormControl work', () => {
expect(isFormControl(null)).toEqual(false)
expect(isFormControl({})).toEqual(false)
expect(isFormControl({ __type: ModelType.Control })).toEqual(true)
expect(isFormControl(useFormControl())).toEqual(true)
})
})
149 changes: 149 additions & 0 deletions packages/cdk/forms/__tests__/useFormControl.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { flushPromises } from '@vue/test-utils'

import { AsyncValidatorFn, Errors } from '../src/types'
import { FormControl, useFormControl } from '../src/useFormControl'
import { Validators } from '../src/validators'

describe('useFormControl.ts', () => {
describe('basic work', () => {
let control: FormControl

beforeEach(() => {
control = useFormControl()
})

test('init modelRef work', () => {
expect(control.modelRef.value).toBeNull()
})

test('init status work', () => {
expect(control.status.value).toEqual('valid')
expect(control.valid.value).toEqual(true)
expect(control.invalid.value).toEqual(false)
expect(control.validating.value).toEqual(false)
})

test('init errors work', () => {
expect(control.errors.value).toBeNull()
})

test('init blurred work', () => {
expect(control.blurred.value).toEqual(false)
expect(control.unblurred.value).toEqual(true)
})

test('validate work', async () => {
expect(await control.validate()).toBeNull()
})

test('reset work', async () => {
control.setValue('test')
control.markAsBlurred()

expect(control.modelRef.value).toEqual('test')
expect(control.blurred.value).toEqual(true)

control.reset()

expect(control.modelRef.value).toBeNull()
expect(control.blurred.value).toEqual(false)
})

test('setValue work', async () => {
expect(control.modelRef.value).toBeNull()

control.setValue('test')

expect(control.modelRef.value).toEqual('test')

control.setValue('')

expect(control.modelRef.value).toEqual('')
})

test('setValidator work', async () => {
const { required, minLength, email } = Validators
control.setValidator(required)

expect(await control.validate()).toEqual({ required: { message: '' } })

control.setValidator([email, minLength(5)])
control.setValue('test')

expect(await control.validate()).toEqual({
email: { message: '', actual: 'test' },
minLength: { message: '', minLength: 5, actual: 4 },
})
})

test('setAsyncValidator work', async () => {
const _asyncValidator = (key: string, error: unknown): AsyncValidatorFn => {
return (_: unknown) => {
return Promise.resolve({ [key]: error } as Errors)
}
}
const message1 = { message: 1 }
const message2 = { message: 2 }

control.setAsyncValidator(_asyncValidator('a', message1))

expect(await control.validate()).toEqual({ a: message1 })

control.setAsyncValidator([_asyncValidator('a', message1), _asyncValidator('b', message2)])

expect(await control.validate()).toEqual({ a: message1, b: message2 })
})

test('setErrors work', async () => {
expect(control.errors.value).toBeNull()
expect(control.getError('required')).toBeNull()

const errors = { required: { message: '' } }
control.setErrors(errors)

expect(control.errors.value).toEqual(errors)

expect(control.getError('required')).toEqual(errors.required)
expect(control.getError('max')).toBeNull()

expect(control.hasError('required')).toEqual(true)
expect(control.hasError('max')).toEqual(false)
})
})

describe('trigger work', () => {
let control: FormControl

test('default change work', async () => {
control = useFormControl(null, { validators: Validators.required })

control.setValue('')
await flushPromises()

expect(control.errors.value).toEqual({ required: { message: '' } })
})

test('blur trigger validate work', async () => {
control = useFormControl(null, { trigger: 'blur', validators: Validators.required })
control.markAsBlurred()
await flushPromises()
expect(control.errors.value).toEqual({ required: { message: '' } })
})
})

describe('validator work', () => {
let control: FormControl

test('validate work', async () => {
control = useFormControl(null, [Validators.required])

control.setValue('test')
await flushPromises()
expect(control.errors.value).toBeNull()

control.setValue('')
await flushPromises()
expect(control.errors.value).toEqual({ required: { message: '' } })
})
})
})
206 changes: 206 additions & 0 deletions packages/cdk/forms/__tests__/validators.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { AsyncValidatorFn, ErrorMessages, Errors, ValidatorFn } from '../src/types'
import { Validators } from '../src/validators'

describe('validators.ts', () => {
test('required work', () => {
const required = Validators.required

expect(required(0)).toBeNull()
expect(required('value')).toBeNull()
expect(required([1, 2])).toBeNull()

const errorMessage = { required: { message: '' } }
expect(required(null)).toEqual(errorMessage)
expect(required(undefined)).toEqual(errorMessage)
expect(required('')).toEqual(errorMessage)
expect(required([])).toEqual(errorMessage)
})

test('requiredTrue work', () => {
const requiredTrue = Validators.requiredTrue

expect(requiredTrue(true)).toBeNull()

const errorMessage = (actual: unknown) => ({ requiredTrue: { message: '', actual } })
expect(requiredTrue(null)).toEqual(errorMessage(null))
expect(requiredTrue(undefined)).toEqual(errorMessage(undefined))
expect(requiredTrue('')).toEqual(errorMessage(''))
expect(requiredTrue([])).toEqual(errorMessage([]))
expect(requiredTrue({})).toEqual(errorMessage({}))
expect(requiredTrue(false)).toEqual(errorMessage(false))
})

test('email work', () => {
const email = Validators.email

expect(email('')).toBeNull()
expect(email(null)).toBeNull()
expect(email('test@gmail.com')).toBeNull()

const errorMessage = (actual: unknown) => ({ email: { message: '', actual } })
expect(email({})).toEqual(errorMessage({}))
expect(email('test')).toEqual(errorMessage('test'))
})

test('min work', () => {
const minOne = Validators.min(1)

expect(minOne('')).toBeNull()
expect(minOne(null)).toBeNull()
expect(minOne('test')).toBeNull()
expect(minOne('1')).toBeNull()
expect(minOne(1)).toBeNull()
expect(minOne(2)).toBeNull()

const errorMessage = (actual: unknown) => ({ min: { message: '', min: 1, actual } })
expect(minOne(0)).toEqual(errorMessage(0))
expect(minOne('0')).toEqual(errorMessage('0'))
})

test('max work', () => {
const maxOne = Validators.max(1)

expect(maxOne('')).toBeNull()
expect(maxOne(null)).toBeNull()
expect(maxOne('test')).toBeNull()
expect(maxOne('1')).toBeNull()
expect(maxOne(1)).toBeNull()
expect(maxOne(0)).toBeNull()

const errorMessage = (actual: unknown) => ({ max: { message: '', max: 1, actual } })
expect(maxOne(2)).toEqual(errorMessage(2))
expect(maxOne('2')).toEqual(errorMessage('2'))
})

test('minLength work', () => {
const minLengthTwo = Validators.minLength(2)

expect(minLengthTwo('')).toBeNull()
expect(minLengthTwo(null)).toBeNull()
expect(minLengthTwo(1)).toBeNull()
expect(minLengthTwo('te')).toBeNull()
expect(minLengthTwo('test')).toBeNull()
expect(minLengthTwo([])).toBeNull()
expect(minLengthTwo([1, 2])).toBeNull()
expect(minLengthTwo([1, 2, 3])).toBeNull()

const errorMessage = (actual: unknown) => ({ minLength: { message: '', minLength: 2, actual } })
expect(minLengthTwo('t')).toEqual(errorMessage(1))
expect(minLengthTwo([1])).toEqual(errorMessage(1))
})

test('maxLength work', () => {
const maxLengthTwo = Validators.maxLength(2)

expect(maxLengthTwo('')).toBeNull()
expect(maxLengthTwo(1)).toBeNull()
expect(maxLengthTwo(null)).toBeNull()
expect(maxLengthTwo('te')).toBeNull()
expect(maxLengthTwo('t')).toBeNull()
expect(maxLengthTwo([])).toBeNull()
expect(maxLengthTwo([1, 2])).toBeNull()
expect(maxLengthTwo([1])).toBeNull()

const errorMessage = (actual: unknown) => ({ maxLength: { message: '', maxLength: 2, actual } })
expect(maxLengthTwo('test')).toEqual(errorMessage(4))
expect(maxLengthTwo([1, 2, 3])).toEqual(errorMessage(3))
})

test('pattern work', () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(Validators.pattern(null!)('test')).toBeNull()

let stringPattern = Validators.pattern('[a-zA-Z]+')

expect(stringPattern('')).toBeNull()
expect(stringPattern(null)).toBeNull()
expect(stringPattern('test')).toBeNull()

let errorMessage = (actual: unknown) => ({ pattern: { message: '', pattern: '^[a-zA-Z]+$', actual } })
expect(stringPattern('test1')).toEqual(errorMessage('test1'))
expect(stringPattern(1)).toEqual(errorMessage(1))

stringPattern = Validators.pattern('^[a-zA-Z]+$')
expect(stringPattern('test1')).toEqual(errorMessage('test1'))
expect(stringPattern(1)).toEqual(errorMessage(1))

const regExpPattern = Validators.pattern(new RegExp('[a-zA-Z]+'))

expect(regExpPattern('')).toBeNull()
expect(regExpPattern(null)).toBeNull()
expect(regExpPattern('test')).toBeNull()
expect(regExpPattern('test1')).toBeNull()

errorMessage = (actual: unknown) => ({ pattern: { message: '', pattern: '/[a-zA-Z]+/', actual } })
expect(regExpPattern(1)).toEqual(errorMessage(1))

const regExpPattern2 = Validators.pattern(new RegExp('^[a-zA-Z]+$'))

expect(regExpPattern2('test')).toBeNull()

errorMessage = (actual: unknown) => ({ pattern: { message: '', pattern: '/^[a-zA-Z]+$/', actual } })
expect(regExpPattern2('test1')).toEqual(errorMessage('test1'))
expect(regExpPattern2(1)).toEqual(errorMessage(1))
})

test('compose work', () => {
const _validator = (key: string, error: unknown): ValidatorFn => {
return (_: unknown) => {
return { [key]: error } as Errors
}
}
const message1 = { message: 1 }
const message2 = { message: 2 }
const { compose, nullValidator, required } = Validators

expect(compose(null)).toBeNull()
expect(compose([])).toBe(null)
expect(compose([nullValidator, nullValidator])!('test')).toBeNull()

expect(compose([_validator('a', message1), _validator('b', message2)])!('test')).toEqual({
a: message1,
b: message2,
})
expect(compose([_validator('a', message1), _validator('a', message2)])!('test')).toEqual({ a: message2 })
expect(compose([null, nullValidator, required])!('')).toEqual({ required: { message: '' } })
})

test('composeAsync work', async () => {
const _asyncValidator = (key: string, error: unknown): AsyncValidatorFn => {
return (_: unknown) => {
return Promise.resolve({ [key]: error } as Errors)
}
}
const message1 = { message: 1 }
const message2 = { message: 2 }
const composeAsync = Validators.composeAsync

expect(composeAsync(null)).toBe(null)
expect(composeAsync([])).toBe(null)

let errors = await composeAsync([_asyncValidator('a', message1), _asyncValidator('b', message2)])!('test')

expect(errors).toEqual({ a: message1, b: message2 })

errors = await composeAsync([_asyncValidator('a', message1), _asyncValidator('a', message2)])!('test')
expect(errors).toEqual({ a: message2 })

errors = await composeAsync([null, _asyncValidator('a', message1)])!('test')
expect(errors).toEqual({ a: message1 })
})

test('setMessages work', () => {
const { setMessages, required, requiredTrue } = Validators

const messages: ErrorMessages = { default: 'invalid input', required: 'please input' }
setMessages(messages)

expect(required('')).toEqual({ required: { message: messages.required } })
expect(requiredTrue(false)).toEqual({ requiredTrue: { message: messages.default, actual: false } })

setMessages({ requiredTrue: () => 'please input true' })

expect(requiredTrue(false)).toEqual({ requiredTrue: { message: 'please input true', actual: false } })
})
})
4 changes: 4 additions & 0 deletions packages/cdk/forms/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './src/typeof'
export * from './src/types'
export * from './src/useFormControl'
export * from './src/validators'
Loading

0 comments on commit 1f32f10

Please sign in to comment.