From a55a657f84f54a68e44cc4eb996243b764da4098 Mon Sep 17 00:00:00 2001 From: Pontus Lundin Date: Mon, 8 Jun 2020 19:53:14 +0200 Subject: [PATCH] feat: add support for custom elements (#320) * feat: add support for custom elements Closes #319 * Update src/type.js Co-authored-by: Kent C. Dodds * uncomplicate setup fn * make it untouched Co-authored-by: Pontus Lundin Co-authored-by: Kent C. Dodds --- src/__tests__/helpers/customElement.js | 35 ++++++++++++++++++++++++++ src/__tests__/type.js | 28 ++++++++++++++++++++- src/type.js | 13 ++++++++-- 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/__tests__/helpers/customElement.js diff --git a/src/__tests__/helpers/customElement.js b/src/__tests__/helpers/customElement.js new file mode 100644 index 00000000..e3d1c801 --- /dev/null +++ b/src/__tests__/helpers/customElement.js @@ -0,0 +1,35 @@ +const observed = ['value'] + +class CustomEl extends HTMLElement { + static getObservedAttributes() { + return observed + } + + constructor() { + super() + this.attachShadow({mode: 'open'}) + this.shadowRoot.innerHTML = `` + this.$input = this.shadowRoot.querySelector('input') + } + + connectedCallback() { + observed.forEach(name => { + this.render(name, this.getAttribute(name)) + }) + } + + attributeChangedCallback(name, oldVal, newVal) { + if (oldVal === newVal) return + this.render(name, newVal) + } + + render(name, value) { + if (value == null) { + this.$input.removeAttribute(name) + } else { + this.$input.setAttribute(name, value) + } + } +} + +customElements.define('custom-el', CustomEl) diff --git a/src/__tests__/type.js b/src/__tests__/type.js index 71ab097b..8735dfee 100644 --- a/src/__tests__/type.js +++ b/src/__tests__/type.js @@ -1,7 +1,8 @@ import React, {Fragment} from 'react' import {render, screen} from '@testing-library/react' import userEvent from '..' -import {setup} from './helpers/utils' +import {setup, addListeners} from './helpers/utils' +import './helpers/customElement' it('types text in input', async () => { const {element, getEventCalls} = setup() @@ -23,6 +24,31 @@ it('types text in input', async () => { `) }) +it('types text inside custom element', async () => { + const { + container: {firstChild: customElement}, + } = render() + const inputEl = customElement.shadowRoot.querySelector('input') + const {getEventCalls} = addListeners(inputEl) + + await userEvent.type(inputEl, 'Sup') + expect(getEventCalls()).toMatchInlineSnapshot(` + focus + keydown: S (83) + keypress: S (83) + input: "{CURSOR}" -> "S" + keyup: S (83) + keydown: u (117) + keypress: u (117) + input: "S{CURSOR}" -> "Su" + keyup: u (117) + keydown: p (112) + keypress: p (112) + input: "Su{CURSOR}" -> "Sup" + keyup: p (112) + `) +}) + it('types text in textarea', async () => { const {element, getEventCalls} = setup(