Skip to content

Instantly share code, notes, and snippets.

@lmiller1990
Last active October 8, 2020 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lmiller1990/4a15e496772802b213608111590a1221 to your computer and use it in GitHub Desktop.
Save lmiller1990/4a15e496772802b213608111590a1221 to your computer and use it in GitHub Desktop.
import { mount } from '@vue/test-utils'
import FormValidation from './form-validation.vue'
describe('FormValidation', () => {
it('fills out form correctly', async () => {
const wrapper = mount(FormValidation)
await wrapper.find('#name').setValue('lachlan')
await wrapper.find('#weight-units').setValue('lb')
await wrapper.find('#weight').setValue('150')
expect(wrapper.findAll('.error')).toHaveLength(0)
})
it('shows errors for invalid inputs', async () => {
const wrapper = mount(FormValidation)
await wrapper.find('#name').setValue('')
await wrapper.find('#weight-units').setValue('lb')
await wrapper.find('#weight').setValue('50')
expect(wrapper.findAll('.error')).toHaveLength(2)
})
it('emits a submit event with patientForm when valid form submitted', async () => {
const wrapper = mount(FormValidation)
await wrapper.find('#name').setValue('lachlan')
await wrapper.find('#weight-units').setValue('kg')
await wrapper.find('#weight').setValue('100')
await wrapper.find('form').trigger('submit.prevent')
expect(wrapper.emitted('submit')[0]).toEqual([
{
patient: {
name: 'lachlan',
weight: {
value: 100,
units: 'kg'
}
}
}
])
})
})
/**
* name
* weight (imp|metric)
*/
export function required(value) {
if (!value) {
return {
valid: false,
message: 'Required'
}
}
return { valid: true }
}
export function isBetween(value, { min, max }) {
if (value < min || value > max) {
return {
valid: false,
message: `Must be between ${min} and ${max}`
}
}
return { valid: true }
}
const limits = {
kg: { min: 30, max: 200 },
lb: { min: 66, max: 440 },
}
export function validateMeasurement(value, { constraints }) {
const result = required(value)
if (!result.valid) {
return result
}
return isBetween(value, constraints)
}
export function isFormValid(form) {
return form.name.valid && form.weight.valid
}
export function patientForm(patient) {
const name = required(patient.name)
const weight = validateMeasurement(patient.weight.value, {
nullable: false,
constraints: limits[patient.weight.units]
})
return {
name,
weight,
}
}
import {
required,
isBetween,
validateMeasurement,
patientForm,
isFormValid
} from './form.js'
describe('required', () => {
it('is invalid when undefined', () => {
expect(required(undefined)).toEqual({ valid: false, message: 'Required' })
})
it('is invalid when empty string', () => {
expect(required('')).toEqual({ valid: false, message: 'Required' })
})
it('returns true false value is present', () => {
expect(required('some value')).toEqual({ valid: true })
})
})
describe('isBetween', () => {
it('returns true when value is equal to min', () => {
expect(isBetween(5, { min: 5, max: 10 })).toEqual({ valid: true })
})
it('returns true when value is between min/max', () => {
expect(isBetween(7, { min: 5, max: 10 })).toEqual({ valid: true })
})
it('returns true when value is equal to max', () => {
expect(isBetween(10, { min: 5, max: 10 })).toEqual({ valid: true })
})
it('returns false when value is less than min', () => {
expect(isBetween(4, { min: 5, max: 10 })).toEqual({ valid: false, message: 'Must be between 5 and 10' })
})
it('returns false when value is greater than max', () => {
expect(isBetween(11, { min: 5, max: 10 })).toEqual({ valid: false, message: 'Must be between 5 and 10' })
})
})
describe('validateMeasurement', () => {
it('returns invalid for input', () => {
const constraints = { min: 10, max: 30 }
const actual = validateMeasurement(undefined, { constraints, nullable: false })
expect(actual).toEqual({ valid: false, message: 'Required' })
})
it('returns invalid when outside range', () => {
const constraints = { min: 10, max: 30 }
const actual = validateMeasurement(40, { constraints, nullable: false })
expect(actual).toEqual({ valid: false, message: 'Must be between 10 and 30' })
})
it('returns valid when value is in range', () => {
const constraints = { min: 10, max: 30 }
const actual = validateMeasurement(20, { constraints, nullable: false })
expect(actual).toEqual({ valid: true })
})
})
describe('isFormValid', () => {
it('returns true when name and weight field are valid', () => {
const form = {
name: { valid: true },
weight: { valid: true }
}
expect(isFormValid(form)).toBe(true)
})
it('returns false when any field is invalid', () => {
const form = {
name: { valid: false },
weight: { valid: true }
}
expect(isFormValid(form)).toBe(false)
})
})
describe('patientForm', () => {
const validPatient = {
name: 'test patient',
weight: { value: 100, units: 'kg' }
}
it('is valid when form is filled out correctly', () => {
const form = patientForm(validPatient)
expect(form.name).toEqual({ valid: true })
expect(form.weight).toEqual({ valid: true })
})
it('is invalid when name is null', () => {
const form = patientForm({ ...validPatient, name: '' })
expect(form.name).toEqual({ valid: false, message: 'Required' })
})
it('validates weight in imperial', () => {
const form = patientForm({
...validPatient,
weight: {
value: 65,
units: 'lb'
}
})
expect(form.weight).toEqual({ valid: false, message: 'Must be between 66 and 440' })
})
it('validates weight in metric', () => {
const form = patientForm({
...validPatient,
weight: {
value: 29,
units: 'kg'
}
})
expect(form.weight).toEqual({ valid: false, message: 'Must be between 30 and 200' })
})
})
<template>
<h3>Patient Data</h3>
<form @submit.prevent="submit">
<div class="field">
<div v-if="!validatedForm.name.valid" class="error">
{{ validatedForm.name.message }}
</div>
<label for="name">Name</label>
<input id="name" name="name" v-model="form.name" />
</div>
<div class="field">
<div v-if="!validatedForm.weight.valid" class="error">
{{ validatedForm.weight.message }}
</div>
<label for="weight">Weight</label>
<input id="weight" name="weight" v-model.number="form.weight.value" />
<select id="weight-units" v-model="form.weight.units">
<option value="kg">kg</option>
<option value="lb">lb</option>
</select>
</div>
<div class="field">
<button :disabled="!valid">Submit</button>
</div>
</form>
<pre>
Patient Data
{{ form }}
</pre>
<br />
<pre>
Form State
{{ validatedForm }}
</pre>
</template>
<script>
import { reactive, computed, ref } from 'vue'
import { patientForm, isFormValid } from './form.js'
export default {
setup(props, { emit }) {
const form = reactive({
name: '',
weight: {
value: '',
units: 'kg'
}
})
const validatedForm = computed(() => {
return patientForm(form)
})
const submit = () => {
emit('submit', { patient: form })
}
const valid = computed(() => isFormValid(validatedForm.value))
return {
form,
validatedForm,
submit,
valid,
}
}
}
</script>
<style>
.field > label {
display: inline-block;
width: 50px;
margin: 0 0 20px 0;
}
.field > input {
display: inline-block;
margin: 2px;
}
.error {
color: red;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment