Files
directus/app/src/components/v-input.test.ts
Azri Kahar ce8f571c72 Fix key combinations being prevented in dbSafe v-input when it's a leading number (#16668)
* Fix key combinations being prevented in v-input

* should normalize accented characters first

* add tests for processValue and emitValue

* export keyMap from use-shortcut to keep things DRY

* try to add test for use-shortcut composable

* move systemKeys to use-shortcut

* add "capslock" & "enter" to systemKeys
2022-11-30 19:56:44 +08:00

237 lines
5.6 KiB
TypeScript

import { Focus } from '@/__utils__/focus';
import { mount } from '@vue/test-utils';
import { GlobalMountOptions } from '@vue/test-utils/dist/types';
import { describe, expect, test } from 'vitest';
import VInput from './v-input.vue';
const global: GlobalMountOptions = {
stubs: ['v-icon'],
directives: {
focus: Focus,
},
};
test('Mount component', () => {
expect(VInput).toBeTruthy();
const wrapper = mount(VInput, {
global,
});
expect(wrapper.html()).toMatchSnapshot();
});
test('modelValue prop', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: 'my value',
},
global,
});
expect(wrapper.get('input').element.value).toBe('my value');
await wrapper.find('input').setValue('my value1');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['my value1']);
});
test('modelValue trim', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: ' please trim that beard ',
trim: true,
},
global,
});
await wrapper.find('input').trigger('blur');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['please trim that beard']);
});
test('modelValue dbSafe', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: 'this $hould be Dß save!!',
dbSafe: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['this_hould_be_D_save']);
});
describe('processValue', () => {
const commonTestScenarios = [
{
scenario: 'should allow slug safe characters',
event: { key: 'a' },
shouldDefaultPrevented: false,
},
{
scenario: 'should not allow non slug safe characters',
event: { key: '$' },
shouldDefaultPrevented: true,
},
{
scenario: 'should allow system keys',
event: { key: 'Control' }, // also tests whether "Control" is mapped to "meta"
shouldDefaultPrevented: false,
},
{
scenario: 'should allow arrow keys',
event: { key: 'ArrowUp' },
shouldDefaultPrevented: false,
},
];
test.each([
...commonTestScenarios,
{
scenario: 'should not allow trailing space after the slug separator',
event: { key: ' ' },
shouldDefaultPrevented: true,
},
])('slug input %scenario', async ({ event, shouldDefaultPrevented }) => {
const wrapper = mount(VInput, {
props: {
// default slug separator to test the "should not allow trailing space after slug separator" scenario
modelValue: '-',
slug: true,
},
global,
});
const inputElement = wrapper.find('input').element;
// mock keyboard event
const keyboardEvent = new KeyboardEvent('keydown', event);
// manually attach the input element as the mocked event's target
Object.defineProperty(keyboardEvent, 'target', { value: inputElement });
wrapper.vm.processValue(keyboardEvent);
expect(keyboardEvent.defaultPrevented).toBe(shouldDefaultPrevented);
});
test.each([
...commonTestScenarios,
{
scenario: 'should allow system key combinations with number when entering the first character',
event: { key: '1', shiftKey: true },
shouldDefaultPrevented: false,
},
{
scenario: 'should not allow number when entering the first character',
event: { key: '1' },
shouldDefaultPrevented: true,
},
])('dbSafe input %scenario', async ({ event, shouldDefaultPrevented }) => {
const wrapper = mount(VInput, {
props: {
dbSafe: true,
},
global,
});
const inputElement = wrapper.find('input').element;
// mock keyboard event
const keyboardEvent = new KeyboardEvent('keydown', event);
// manually attach the input element as the mocked event's target
Object.defineProperty(keyboardEvent, 'target', { value: inputElement });
wrapper.vm.processValue(keyboardEvent);
expect(keyboardEvent.defaultPrevented).toBe(shouldDefaultPrevented);
});
});
describe('emitValue', () => {
test('should emit null value when empty', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: '',
nullable: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([null]);
});
test('should emit number when type is number', async () => {
const wrapper = mount(VInput, {
props: {
type: 'number',
modelValue: '1',
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([1]);
});
test('should turn ending space into slug separator for slug input', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: 'test ',
slug: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['test-']);
});
test('should turn space into underscores for dbSafe input', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: 'a custom field',
dbSafe: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['a_custom_field']);
});
test('should prevent pasting of non db safe characters for dbSafe input', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: '$test_field',
dbSafe: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['test_field']);
});
test('should normalize accented characters for dbSafe input', async () => {
const wrapper = mount(VInput, {
props: {
modelValue: 'à_test_field',
dbSafe: true,
},
global,
});
await wrapper.find('input').trigger('input');
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['a_test_field']);
});
});