Skip to content

Commit 6e33636

Browse files
authored
fix(trigger('focus')) added natural to jsdom behavior (#1777)
* 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
1 parent f36e088 commit 6e33636

File tree

3 files changed

+109
-2
lines changed

3 files changed

+109
-2
lines changed

packages/test-utils/src/wrapper.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,33 @@ export default class Wrapper implements BaseWrapper {
829829
return this.element.textContent.trim()
830830
}
831831

832+
/**
833+
* Simulates event triggering
834+
*/
835+
__simulateTrigger(type: string, options?: Object): void {
836+
const regularEventTrigger = (type, options) => {
837+
const event = createDOMEvent(type, options)
838+
return this.element.dispatchEvent(event)
839+
}
840+
841+
const focusEventTrigger = (type, options) => {
842+
if (this.element instanceof HTMLElement) {
843+
return this.element.focus()
844+
}
845+
846+
regularEventTrigger(type, options)
847+
}
848+
849+
const triggerProcedureMap = {
850+
focus: focusEventTrigger,
851+
__default: regularEventTrigger
852+
}
853+
854+
const triggerFn = triggerProcedureMap[type] || triggerProcedureMap.__default
855+
856+
return triggerFn(type, options)
857+
}
858+
832859
/**
833860
* Dispatches a DOM event on wrapper
834861
*/
@@ -869,8 +896,7 @@ export default class Wrapper implements BaseWrapper {
869896
return nextTick()
870897
}
871898

872-
const event = createDOMEvent(type, options)
873-
this.element.dispatchEvent(event)
899+
this.__simulateTrigger(type, options)
874900
return nextTick()
875901
}
876902
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<div>
3+
<input
4+
v-for="index of 5"
5+
@focus="onFocus(index)"
6+
:id="index"
7+
:data-test-position="index"
8+
:ref="refNameByIndex(index)"
9+
:key="index"
10+
type="text"
11+
/>
12+
</div>
13+
</template>
14+
15+
<script>
16+
export default {
17+
name: 'component-with-multiple-inputs',
18+
data: () => ({ activeInputIndex: null }),
19+
computed: {
20+
inputRefAtIndex() {
21+
return index => this.$refs[this.refNameByIndex(index)]
22+
}
23+
},
24+
25+
methods: {
26+
refNameByIndex(index) {
27+
return `input${index}`
28+
},
29+
30+
returnToLastSelectedInput() {
31+
return this.focusInput(this.inputRefAtIndex(this.activeInputIndex))
32+
},
33+
34+
onFocus(index) {
35+
const isOdd = Boolean(index % 2)
36+
if (isOdd) {
37+
return this.returnToLastSelectedInput()
38+
}
39+
this.activeInputIndex = index
40+
},
41+
42+
focusInput(inputRef) {
43+
if (!inputRef) {
44+
return
45+
}
46+
const [input] = inputRef
47+
input.focus()
48+
}
49+
},
50+
51+
mounted() {
52+
this.focusInput(this.focusInput(this.inputRefAtIndex(2)))
53+
}
54+
}
55+
</script>
56+
57+
<style scoped></style>

test/specs/wrapper-array/trigger.spec.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { compileToFunctions } from 'vue-template-compiler'
22
import ComponentWithEvents from '~resources/components/component-with-events.vue'
3+
import ComponentWithMultipleInputs from '~resources/components/component-with-multiple-inputs.vue'
34
import { describeWithShallowAndMount } from '~resources/utils'
45

6+
const assertElementIsFocused = element =>
7+
expect(document.activeElement.id).toEqual(element.id)
8+
59
describeWithShallowAndMount('trigger', mountingMethod => {
610
it('causes click handler to fire when wrapper.trigger("click") is called on a Component', async () => {
711
const clickHandler = jest.fn()
@@ -34,6 +38,26 @@ describeWithShallowAndMount('trigger', mountingMethod => {
3438
expect(keydownHandler).toHaveBeenCalled()
3539
})
3640

41+
it('should really focus element when trigger focus was called', async () => {
42+
const wrapper = mountingMethod(ComponentWithMultipleInputs, {
43+
attachTo: document.body
44+
})
45+
46+
assertElementIsFocused(wrapper.get('[data-test-position="2"]').element)
47+
48+
await wrapper.get('[data-test-position="4"]').trigger('focus')
49+
50+
assertElementIsFocused(wrapper.get('[data-test-position="4"]').element)
51+
52+
await wrapper.get('[data-test-position="3"]').trigger('focus')
53+
54+
assertElementIsFocused(wrapper.get('[data-test-position="4"]').element)
55+
56+
await wrapper.get('[data-test-position="2"]').trigger('focus')
57+
58+
assertElementIsFocused(wrapper.get('[data-test-position="2"]').element)
59+
})
60+
3761
it('throws an error if type is not a string', () => {
3862
const wrapper = mountingMethod(ComponentWithEvents)
3963
const invalidSelectors = [

0 commit comments

Comments
 (0)