Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 555a928

Browse files
committed
feat(number-input): unit test & e2e
1 parent 79da4e1 commit 555a928

File tree

9 files changed

+498
-9
lines changed

9 files changed

+498
-9
lines changed

demos/vue-3/src/router/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ const routes: Array<RouteRecordRaw> = [
3434
component: () =>
3535
import(/* webpackChunkName: "text-fields" */ '../views/TextFields.vue'),
3636
},
37+
{
38+
path: '/number-fields',
39+
name: 'Number Fields',
40+
meta: {
41+
title: 'Number Fields',
42+
},
43+
component: () =>
44+
import(/* webpackChunkName: "text-fields" */ '../views/NumberFields.vue'),
45+
},
3746
{
3847
path: '/login',
3948
name: 'Login',

demos/vue-3/src/views/Home.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ export default defineComponent({
5151
route: '/text-fields',
5252
tags: ['text-field', 'email-input', 'password-input'],
5353
},
54+
{
55+
name: 'Number Fields',
56+
route: '/number-fields',
57+
tags: ['number-field'],
58+
},
5459
{
5560
name: 'Login',
5661
route: '/login',
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<template>
2+
<div class="page container">
3+
<div class="mx-auto w-full sm:w-1/2 relative mb-24">
4+
<div
5+
class="absolute inset-0 bg-gradient-to-r from-blue-400 to-green-200 shadow-xl transform -skew-y-3 sm:skew-y-0 sm:-rotate-3 sm:rounded-3xl"
6+
></div>
7+
<div class="relative card p-6 bg-white">
8+
<dynamic-form
9+
:form="form"
10+
@submitted="handleSubmit"
11+
@change="valueChanged"
12+
@error="handleError"
13+
/>
14+
<button
15+
data-cy="submit"
16+
class="btn bg-green-500 text-white hover:bg-green-700 mt-4"
17+
submit="true"
18+
:form="form?.id"
19+
>
20+
Submit
21+
</button>
22+
</div>
23+
</div>
24+
<div class="mx-auto w-full sm:w-1/2"><Console :content="formValues" /></div>
25+
</div>
26+
</template>
27+
28+
<script lang="ts">
29+
import {
30+
FormValidator,
31+
min,
32+
max,
33+
Validator,
34+
NumberField,
35+
required,
36+
FormOptions,
37+
} from '@/';
38+
import { computed, defineComponent, reactive } from 'vue';
39+
import Console from '../components/Console.vue';
40+
41+
const components = {
42+
Console,
43+
};
44+
/* } from '../../dist/as-dynamic-forms.esm'; */
45+
export default defineComponent({
46+
name: 'TextFieldsDemo',
47+
components,
48+
setup() {
49+
const formValues = reactive({});
50+
const minValidator: FormValidator = Validator({
51+
validator: min(18),
52+
text: 'Number must be greater than 18',
53+
});
54+
55+
const maxValidator: FormValidator = Validator({
56+
validator: max(100),
57+
58+
text: 'Number must be less than 100',
59+
});
60+
61+
const form = computed(() => ({
62+
id: 'text-fields-demo',
63+
fields: {
64+
qty: NumberField({
65+
label: 'Quantity',
66+
}),
67+
stock: NumberField({
68+
label: 'Stock',
69+
validations: [
70+
Validator({ validator: required, text: 'This field is required' }),
71+
],
72+
}),
73+
age: NumberField({
74+
label: 'Age',
75+
min: 18,
76+
validations: [Validator(minValidator)],
77+
}),
78+
percentage: NumberField({
79+
label: 'Percentage',
80+
max: 100,
81+
step: 5,
82+
validations: [Validator(maxValidator)],
83+
}),
84+
},
85+
options: {
86+
customClass: 'grid gap-4 grid-cols-2',
87+
},
88+
}));
89+
90+
function handleSubmit(values) {
91+
console.log('Values Submitted', values);
92+
}
93+
94+
function valueChanged(values) {
95+
Object.assign(formValues, values);
96+
console.log('Values', values);
97+
}
98+
99+
function handleError(errors) {
100+
console.error('Errors', errors);
101+
}
102+
103+
return {
104+
form,
105+
formValues,
106+
handleSubmit,
107+
valueChanged,
108+
handleError,
109+
};
110+
},
111+
});
112+
</script>
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import { shallowMount } from '@vue/test-utils';
2+
import NumberInput from './NumberInput.vue';
3+
import { FieldControl, NumberField, Validator, required } from '../../index';
4+
5+
describe('Numberinput', () => {
6+
let cmp;
7+
8+
beforeEach(() => {
9+
cmp = shallowMount(NumberInput, {
10+
props: {
11+
control: FieldControl({
12+
name: 'test-input',
13+
...NumberField({
14+
label: 'Test Input',
15+
}),
16+
}),
17+
},
18+
});
19+
});
20+
21+
test('renders an input of type number', () => {
22+
const input = cmp.find('input[type="number"]');
23+
expect(input.exists()).toBe(true);
24+
});
25+
test(`renders an input with class 'form-control'`, () => {
26+
const input = cmp.find('input');
27+
expect(input.classes()).toContain('form-control');
28+
});
29+
30+
test(`renders an input with id equal to field name`, () => {
31+
const input = cmp.find('input');
32+
expect(input.attributes('id')).toBe('test-input');
33+
});
34+
35+
test(`input gets disabled when form control does it`, async () => {
36+
await cmp.setProps({
37+
control: FieldControl({
38+
name: 'test-input',
39+
...NumberField({
40+
label: 'Test Input',
41+
disabled: true,
42+
}),
43+
}),
44+
});
45+
const input = cmp.find('input');
46+
expect(input.attributes('disabled')).toBe('');
47+
});
48+
49+
test(`renders an input with placeholder`, async () => {
50+
await cmp.setProps({
51+
control: FieldControl({
52+
name: 'test-input',
53+
...NumberField({
54+
label: 'Test Input',
55+
placeholder: 'Nº',
56+
}),
57+
}),
58+
});
59+
const input = cmp.find('input');
60+
expect(input.attributes('placeholder')).toBe('Nº');
61+
});
62+
63+
test(`renders a required input`, async () => {
64+
await cmp.setProps({
65+
control: FieldControl({
66+
name: 'test-input',
67+
...NumberField({
68+
label: 'Test Input',
69+
validations: [
70+
Validator({ validator: required, text: 'This field is required' }),
71+
],
72+
}),
73+
}),
74+
});
75+
const input = cmp.find('input');
76+
expect(input.attributes('required')).toBe('');
77+
});
78+
79+
test(`sets ariaRequired when required`, async () => {
80+
await cmp.setProps({
81+
control: FieldControl({
82+
name: 'test-input',
83+
...NumberField({
84+
label: 'Test Input',
85+
validations: [
86+
Validator({ validator: required, text: 'This field is required' }),
87+
],
88+
}),
89+
}),
90+
});
91+
const input = cmp.find('input');
92+
expect(input.attributes('ariarequired')).toBeTruthy;
93+
});
94+
95+
test(`renders a readonly input`, async () => {
96+
await cmp.setProps({
97+
control: FieldControl({
98+
name: 'test-input',
99+
...NumberField({
100+
label: 'Test Input',
101+
readonly: true,
102+
}),
103+
}),
104+
});
105+
const input = cmp.find('input');
106+
expect(input.attributes('readonly')).toBe('');
107+
});
108+
109+
test(`renders a input with autocomplete`, async () => {
110+
await cmp.setProps({
111+
control: FieldControl({
112+
name: 'test-input',
113+
...NumberField({
114+
label: 'Test Input',
115+
autocomplete: 'username',
116+
}),
117+
}),
118+
});
119+
const input = cmp.find('input');
120+
expect(input.attributes('autocomplete')).toBe('username');
121+
});
122+
123+
test(`renders an input with aria labels`, async () => {
124+
await cmp.setProps({
125+
control: FieldControl({
126+
name: 'test-input',
127+
...NumberField({
128+
label: 'Test Input',
129+
ariaLabel: 'Im a test input',
130+
}),
131+
}),
132+
});
133+
const input = cmp.find('input');
134+
expect(input.attributes('arialabel')).toBe('Im a test input');
135+
});
136+
137+
test(`renders an input with min attribute`, async () => {
138+
await cmp.setProps({
139+
control: FieldControl({
140+
name: 'test-input',
141+
...NumberField({
142+
label: 'Test Input',
143+
min: 50,
144+
}),
145+
}),
146+
});
147+
const input = cmp.find('input');
148+
expect(input.attributes('min')).toBe('50');
149+
});
150+
151+
test(`renders an input with max attribute`, async () => {
152+
await cmp.setProps({
153+
control: FieldControl({
154+
name: 'test-input',
155+
...NumberField({
156+
label: 'Test Input',
157+
max: 100,
158+
}),
159+
}),
160+
});
161+
const input = cmp.find('input');
162+
expect(input.attributes('max')).toBe('100');
163+
});
164+
165+
test(`renders an input with step attribute`, async () => {
166+
await cmp.setProps({
167+
control: FieldControl({
168+
name: 'test-input',
169+
...NumberField({
170+
label: 'Test Input',
171+
step: 5,
172+
}),
173+
}),
174+
});
175+
const input = cmp.find('input');
176+
expect(input.attributes('step')).toBe('5');
177+
});
178+
179+
test('emits an event when value changed', async () => {
180+
const input = cmp.find('input');
181+
await input.setValue(2);
182+
183+
expect(cmp.emitted()).toHaveProperty('change');
184+
expect(cmp.emitted('change')[0][0].value).toBe('2');
185+
expect(cmp.emitted('change')[0][0].name).toBe('test-input');
186+
});
187+
188+
test('emits the control name when value change', async () => {
189+
const input = cmp.find('input');
190+
await input.setValue(2);
191+
192+
expect(cmp.emitted('change')[0][0].name).toBe('test-input');
193+
});
194+
195+
test('emits an event when blur', async () => {
196+
const input = cmp.find('input');
197+
await input.trigger('blur');
198+
199+
expect(cmp.emitted()).toHaveProperty('blur');
200+
});
201+
202+
test('emits an event when focus', async () => {
203+
const input = cmp.find('input');
204+
await input.trigger('focus');
205+
206+
expect(cmp.emitted()).toHaveProperty('focus');
207+
});
208+
});

src/components/number-input/NumberInput.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ export default defineComponent({
1717
inheritAttrs: false,
1818
props,
1919
setup(props, { emit }) {
20-
const { onInput, onChange, onFocus, onBlur } = useInputEvents(props, emit);
20+
const { onInput, onChange, onFocus, onBlur, getClasses } = useInputEvents(
21+
props,
22+
emit,
23+
);
2124
const {
2225
isRequired,
2326
errorMessages,
@@ -29,7 +32,7 @@ export default defineComponent({
2932
id: props.control.name,
3033
name: props.control.name || '',
3134
type: props.control.type,
32-
class: ['form-control'],
35+
class: getClasses.value,
3336
value: props.control.value,
3437
min: props.control.min,
3538
max: props.control.max,

0 commit comments

Comments
 (0)