diff --git a/projects/testing-library/src/lib/user-events/type.ts b/projects/testing-library/src/lib/user-events/type.ts index 52261f94..22eaf218 100644 --- a/projects/testing-library/src/lib/user-events/type.ts +++ b/projects/testing-library/src/lib/user-events/type.ts @@ -38,11 +38,18 @@ export function createType(fireEvent: FireFunction & FireObject) { return async function type(element: HTMLElement, value: string | number, options?: TypeOptions) { const { allAtOnce = false, delay = 0 } = options || {}; - const initialValue = (element as HTMLInputElement).value; + const inputElement = element as HTMLInputElement; + const initialValue = inputElement.value; + + if (inputElement.disabled) { + return; + } if (allAtOnce || value === '') { - fireEvent.input(element, { target: { value } }); - element.addEventListener('blur', createFireChangeEvent(initialValue)); + if (!inputElement.readOnly) { + fireEvent.input(inputElement, { target: { value } }); + } + inputElement.addEventListener('blur', createFireChangeEvent(initialValue)); return; } @@ -57,14 +64,14 @@ export function createType(fireEvent: FireFunction & FireObject) { await wait(delay); } - const downEvent = fireEvent.keyDown(element, { + const downEvent = fireEvent.keyDown(inputElement, { key: key, keyCode: keyCode, which: keyCode, }); if (downEvent) { - const pressEvent = fireEvent.keyPress(element, { + const pressEvent = fireEvent.keyPress(inputElement, { key: key, keyCode, charCode: keyCode, @@ -72,23 +79,25 @@ export function createType(fireEvent: FireFunction & FireObject) { if (pressEvent) { actuallyTyped += key; - fireEvent.input(element, { - target: { - value: actuallyTyped, - }, - bubbles: true, - cancelable: true, - }); + if (!inputElement.readOnly) { + fireEvent.input(inputElement, { + target: { + value: actuallyTyped, + }, + bubbles: true, + cancelable: true, + }); + } } } - fireEvent.keyUp(element, { + fireEvent.keyUp(inputElement, { key: key, keyCode: keyCode, which: keyCode, }); } - element.addEventListener('blur', createFireChangeEvent(initialValue)); + inputElement.addEventListener('blur', createFireChangeEvent(initialValue)); }; } diff --git a/projects/testing-library/tests/user-events/type.spec.ts b/projects/testing-library/tests/user-events/type.spec.ts index b91d12a1..f42e40e1 100644 --- a/projects/testing-library/tests/user-events/type.spec.ts +++ b/projects/testing-library/tests/user-events/type.spec.ts @@ -178,13 +178,15 @@ describe('options', () => { }); }); -test('does not type when event.preventDefault() is called', async () => { +describe('does not type when ', () => { @Component({ selector: 'fixture', template: ` { `, }) class FixtureComponent { + @Input() disabled = false; + @Input() readonly = false; + onInput($event) {} onChange($event) {} onKeyDown($event) {} @@ -201,23 +206,76 @@ test('does not type when event.preventDefault() is called', async () => { onKeyUp($event) {} } - const componentProperties = { - onChange: jest.fn(), - onKeyDown: jest.fn().mockImplementation(event => event.preventDefault()), - }; + test('input is disabled', async () => { + const componentEvents = { + onInput: jest.fn(), + onChange: jest.fn(), + onKeyDown: jest.fn(), + onKeyPress: jest.fn(), + onKeyUp: jest.fn(), + }; + + const component = await render(FixtureComponent, { + componentProperties: { + disabled: true, + ...componentEvents, + }, + }); + + const inputControl = component.getByTestId('input') as HTMLInputElement; + component.type(inputControl, 'Hello'); - const component = await render(FixtureComponent, { componentProperties }); + Object.values(componentEvents).forEach(evt => expect(evt).not.toHaveBeenCalled()); + expect(inputControl.value).toBe(''); + }); - const inputControl = component.getByTestId('input') as HTMLInputElement; - const inputValue = 'foobar'; - component.type(inputControl, inputValue); + test('input is readonly', async () => { + const componentEvents = { + onInput: jest.fn(), + onChange: jest.fn(), + onKeyDown: jest.fn(), + onKeyPress: jest.fn(), + onKeyUp: jest.fn(), + }; - expect(componentProperties.onKeyDown).toHaveBeenCalledTimes(inputValue.length); + const component = await render(FixtureComponent, { + componentProperties: { + readonly: true, + ...componentEvents, + }, + }); - component.blur(inputControl); - expect(componentProperties.onChange).toBeCalledTimes(0); + const inputControl = component.getByTestId('input') as HTMLInputElement; + const value = 'Hello'; + component.type(inputControl, value); + + expect(componentEvents.onInput).not.toHaveBeenCalled(); + expect(componentEvents.onChange).not.toHaveBeenCalled(); + expect(componentEvents.onKeyDown).toHaveBeenCalledTimes(value.length); + expect(componentEvents.onKeyPress).toHaveBeenCalledTimes(value.length); + expect(componentEvents.onKeyUp).toHaveBeenCalledTimes(value.length); + expect(inputControl.value).toBe(''); + }); - expect(inputControl.value).toBe(''); + test('event.preventDefault() is called', async () => { + const componentProperties = { + onChange: jest.fn(), + onKeyDown: jest.fn().mockImplementation(event => event.preventDefault()), + }; + + const component = await render(FixtureComponent, { componentProperties }); + + const inputControl = component.getByTestId('input') as HTMLInputElement; + const inputValue = 'foobar'; + component.type(inputControl, inputValue); + + expect(componentProperties.onKeyDown).toHaveBeenCalledTimes(inputValue.length); + + component.blur(inputControl); + expect(componentProperties.onChange).toBeCalledTimes(0); + + expect(inputControl.value).toBe(''); + }); }); test('can clear an input field', async () => {