Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@vue/compiler-sfc": "^3.0.0-beta.2",
"babel-jest": "^25.2.3",
"babel-preset-jest": "^25.2.1",
"dom-event-types": "^1.0.0",
"flush-promises": "^1.0.2",
"husky": "^4.2.3",
"jest": "^25.1.0",
Expand Down
3 changes: 2 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ function createEntry(options) {
'lodash/camelCase',
'lodash/upperFirst',
'lodash/kebabCase',
'lodash/flow'
'lodash/flow',
'dom-event-types'
],
plugins: [resolve()],
output: {
Expand Down
98 changes: 98 additions & 0 deletions src/create-dom-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import eventTypes from 'dom-event-types'

interface TriggerOptions {
code?: String
key?: String
keyCode?: Number
[custom: string]: any
}

interface EventParams {
eventType: string
modifier: string
meta: any
options?: TriggerOptions
}

export const keyCodesByKeyName = {
backspace: 8,
tab: 9,
enter: 13,
esc: 27,
space: 32,
pageup: 33,
pagedown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
insert: 45,
delete: 46
}

function getEventProperties(eventParams: EventParams) {
const { modifier, meta, options } = eventParams
const keyCode =
keyCodesByKeyName[modifier] ||
(options && (options.keyCode || options.code))

return {
...options, // What the user passed in as the second argument to #trigger
bubbles: meta.bubbles,
meta: meta.cancelable,
// Any derived options should go here
keyCode,
code: keyCode
}
}

function createEvent(eventParams: EventParams) {
const { eventType, meta } = eventParams
const metaEventInterface = window[meta.eventInterface]

const SupportedEventInterface =
typeof metaEventInterface === 'function' ? metaEventInterface : window.Event

const eventProperties = getEventProperties(eventParams)

const event = new SupportedEventInterface(
eventType,
// event properties can only be added when the event is instantiated
// custom properties must be added after the event has been instantiated
eventProperties
)

return event
}

function createDOMEvent(eventString: String, options?: TriggerOptions) {
const [eventType, modifier] = eventString.split('.')
const meta = eventTypes[eventType] || {
eventInterface: 'Event',
cancelable: true,
bubbles: true
}

const eventParams: EventParams = { eventType, modifier, meta, options }
const event: Event = createEvent(eventParams)
const eventPrototype = Object.getPrototypeOf(event)

options &&
Object.keys(options).forEach((key) => {
const propertyDescriptor = Object.getOwnPropertyDescriptor(
eventPrototype,
key
)
const canSetProperty = !(
propertyDescriptor && propertyDescriptor.set === undefined
)
if (canSetProperty) {
event[key] = options[key]
}
})
return event
}

export { TriggerOptions, createDOMEvent }
38 changes: 33 additions & 5 deletions src/dom-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { nextTick } from 'vue'
import { WrapperAPI } from './types'
import { ErrorWrapper } from './error-wrapper'

import { TriggerOptions, createDOMEvent } from './create-dom-event'

export class DOMWrapper<ElementType extends Element> implements WrapperAPI {
element: ElementType

Expand Down Expand Up @@ -155,12 +157,38 @@ export class DOMWrapper<ElementType extends Element> implements WrapperAPI {
return new DOMWrapper(parentElement).trigger('change')
}

async trigger(eventString: string) {
const evt = document.createEvent('Event')
evt.initEvent(eventString)
async trigger(eventString: string, options?: TriggerOptions) {
if (options && options['target']) {
throw Error(
`[vue-test-utils]: you cannot set the target value of an event. See the notes section ` +
`of the docs for more details—` +
`https://vue-test-utils.vuejs.org/api/wrapper/trigger.html`
)
}

const isDisabled = () => {
const validTagsToBeDisabled = [
'BUTTON',
'COMMAND',
'FIELDSET',
'KEYGEN',
'OPTGROUP',
'OPTION',
'SELECT',
'TEXTAREA',
'INPUT'
]
const hasDisabledAttribute = this.attributes().disabled !== undefined
const elementCanBeDisabled = validTagsToBeDisabled.includes(
this.element.tagName
)

return hasDisabledAttribute && elementCanBeDisabled
}

if (this.element) {
this.element.dispatchEvent(evt)
if (this.element && !isDisabled()) {
const event = createDOMEvent(eventString, options)
this.element.dispatchEvent(event)
}

return nextTick
Expand Down
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export interface WrapperAPI {
findAll<T extends Element>(selector: string): DOMWrapper<T>[]
html: () => string
text: () => string
trigger: (eventString: string) => Promise<(fn?: () => void) => Promise<void>>
trigger: (
eventString: string,
options?: Object
) => Promise<(fn?: () => void) => Promise<void>>
}

interface RefSelector {
Expand Down
5 changes: 3 additions & 2 deletions src/vue-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
WrapperAPI
} from './types'
import { ErrorWrapper } from './error-wrapper'
import { TriggerOptions } from './create-dom-event'
import { find } from './utils/find'

export class VueWrapper<T extends ComponentPublicInstance>
Expand Down Expand Up @@ -145,9 +146,9 @@ export class VueWrapper<T extends ComponentPublicInstance>
return nextTick()
}

trigger(eventString: string) {
trigger(eventString: string, options?: TriggerOptions) {
const rootElementWrapper = new DOMWrapper(this.element)
return rootElementWrapper.trigger(eventString)
return rootElementWrapper.trigger(eventString, options)
}

unmount() {
Expand Down
Loading