Skip to content

Commit

Permalink
fix(trigger('focus')) added natural to jsdom behavior (#1777)
Browse files Browse the repository at this point in the history
* Fix for trigger('focus')

Added test case and the fix for wrapper trigger

* Extended types notation and jsdoc

* Added type check and fallback for focus processing
  • Loading branch information
Th3Un1q3 committed Feb 10, 2021
1 parent f36e088 commit 6e33636
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 2 deletions.
30 changes: 28 additions & 2 deletions packages/test-utils/src/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,33 @@ export default class Wrapper implements BaseWrapper {
return this.element.textContent.trim()
}

/**
* Simulates event triggering
*/
__simulateTrigger(type: string, options?: Object): void {
const regularEventTrigger = (type, options) => {
const event = createDOMEvent(type, options)
return this.element.dispatchEvent(event)
}

const focusEventTrigger = (type, options) => {
if (this.element instanceof HTMLElement) {
return this.element.focus()
}

regularEventTrigger(type, options)
}

const triggerProcedureMap = {
focus: focusEventTrigger,
__default: regularEventTrigger
}

const triggerFn = triggerProcedureMap[type] || triggerProcedureMap.__default

return triggerFn(type, options)
}

/**
* Dispatches a DOM event on wrapper
*/
Expand Down Expand Up @@ -869,8 +896,7 @@ export default class Wrapper implements BaseWrapper {
return nextTick()
}

const event = createDOMEvent(type, options)
this.element.dispatchEvent(event)
this.__simulateTrigger(type, options)
return nextTick()
}
}
57 changes: 57 additions & 0 deletions test/resources/components/component-with-multiple-inputs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<template>
<div>
<input
v-for="index of 5"
@focus="onFocus(index)"
:id="index"
:data-test-position="index"
:ref="refNameByIndex(index)"
:key="index"
type="text"
/>
</div>
</template>

<script>
export default {
name: 'component-with-multiple-inputs',
data: () => ({ activeInputIndex: null }),
computed: {
inputRefAtIndex() {
return index => this.$refs[this.refNameByIndex(index)]
}
},
methods: {
refNameByIndex(index) {
return `input${index}`
},
returnToLastSelectedInput() {
return this.focusInput(this.inputRefAtIndex(this.activeInputIndex))
},
onFocus(index) {
const isOdd = Boolean(index % 2)
if (isOdd) {
return this.returnToLastSelectedInput()
}
this.activeInputIndex = index
},
focusInput(inputRef) {
if (!inputRef) {
return
}
const [input] = inputRef
input.focus()
}
},
mounted() {
this.focusInput(this.focusInput(this.inputRefAtIndex(2)))
}
}
</script>

<style scoped></style>
24 changes: 24 additions & 0 deletions test/specs/wrapper-array/trigger.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { compileToFunctions } from 'vue-template-compiler'
import ComponentWithEvents from '~resources/components/component-with-events.vue'
import ComponentWithMultipleInputs from '~resources/components/component-with-multiple-inputs.vue'
import { describeWithShallowAndMount } from '~resources/utils'

const assertElementIsFocused = element =>
expect(document.activeElement.id).toEqual(element.id)

describeWithShallowAndMount('trigger', mountingMethod => {
it('causes click handler to fire when wrapper.trigger("click") is called on a Component', async () => {
const clickHandler = jest.fn()
Expand Down Expand Up @@ -34,6 +38,26 @@ describeWithShallowAndMount('trigger', mountingMethod => {
expect(keydownHandler).toHaveBeenCalled()
})

it('should really focus element when trigger focus was called', async () => {
const wrapper = mountingMethod(ComponentWithMultipleInputs, {
attachTo: document.body
})

assertElementIsFocused(wrapper.get('[data-test-position="2"]').element)

await wrapper.get('[data-test-position="4"]').trigger('focus')

assertElementIsFocused(wrapper.get('[data-test-position="4"]').element)

await wrapper.get('[data-test-position="3"]').trigger('focus')

assertElementIsFocused(wrapper.get('[data-test-position="4"]').element)

await wrapper.get('[data-test-position="2"]').trigger('focus')

assertElementIsFocused(wrapper.get('[data-test-position="2"]').element)
})

it('throws an error if type is not a string', () => {
const wrapper = mountingMethod(ComponentWithEvents)
const invalidSelectors = [
Expand Down

0 comments on commit 6e33636

Please sign in to comment.