Skip to content

Commit

Permalink
Merge pull request #296 from cuixiaorui/master
Browse files Browse the repository at this point in the history
refactor: use devtools realize emit
  • Loading branch information
lmiller1990 committed Jan 24, 2021
2 parents 4c959da + 4e43570 commit 4d030bb
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 55 deletions.
47 changes: 47 additions & 0 deletions src/emit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { setDevtoolsHook, devtools } from 'vue'

const enum DevtoolsHooks {
COMPONENT_EMIT = 'component:emit'
}

let events: Record<string, unknown[]>

export function emitted<T = unknown>(
eventName?: string
): T[] | Record<string, T[]> {
if (eventName) {
const emitted = (events as Record<string, T[]>)[eventName]
return emitted
}

return events as Record<string, T[]>
}

export const attachEmitListener = () => {
events = {}
// use devtools to capture this "emit"
setDevtoolsHook(createDevTools(events))
}

function createDevTools(events): any {
const devTools: Partial<typeof devtools> = {
emit(eventType, ...payload) {
if (eventType !== DevtoolsHooks.COMPONENT_EMIT) return

// The first argument is root component
// The second argument is vm
// The third argument is event
// The fourth argument is args of event
recordEvent(events, payload[2], payload[3])
}
}

return devTools
}

function recordEvent(events, event, args) {
// Record the event message sent by the emit
events[event]
? (events[event] = [...events[event], [...args]])
: (events[event] = [[...args]])
}
34 changes: 0 additions & 34 deletions src/emitMixin.ts

This file was deleted.

18 changes: 5 additions & 13 deletions src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
} from './utils'
import { processSlot } from './utils/compileSlots'
import { createWrapper, VueWrapper } from './vueWrapper'
import { attachEmitListener } from './emitMixin'
import { attachEmitListener } from './emit'
import { createDataMixin } from './dataMixin'
import { MOUNT_COMPONENT_REF, MOUNT_PARENT_NAME } from './constants'
import { createStub, stubComponents } from './stubs'
Expand Down Expand Up @@ -233,16 +233,8 @@ export function mount(
let component

if (isFunctionalComponent(originalComponent)) {
// we need to wrap it like this so we can capture emitted events.
// we capture events using a mixin that mutates `emit` in `beforeCreate`,
// but functional components do not support mixins, so we need to wrap it
// and make it a non-functional component for testing purposes.
component = defineComponent({
setup: (_, { attrs, slots, emit }) => () => {
return h((props: any, ctx: any) =>
originalComponent(props, { ...ctx, ...attrs, emit, slots })
)
}
setup: (_, { attrs, slots }) => () => h(originalComponent, attrs, slots)
})
} else if (isObjectComponent(originalComponent)) {
component = { ...originalComponent }
Expand Down Expand Up @@ -346,6 +338,9 @@ export function mount(
return vm.$nextTick()
}

// add tracking for emitted events
attachEmitListener()

// create the app
const app = createApp(Parent)

Expand Down Expand Up @@ -408,9 +403,6 @@ export function mount(
}
}

// add tracking for emitted events
app.mixin(attachEmitListener())

// stubs
// even if we are using `mount`, we will still
// stub out Transition and Transition Group by default.
Expand Down
8 changes: 2 additions & 6 deletions src/vueWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { createWrapperError } from './errorWrapper'
import { TriggerOptions } from './createDomEvent'
import { find, matches } from './utils/find'
import { mergeDeep } from './utils'
import { emitted } from './emit'

export class VueWrapper<T extends ComponentPublicInstance> {
private componentVM: T
Expand Down Expand Up @@ -72,12 +73,7 @@ export class VueWrapper<T extends ComponentPublicInstance> {
emitted<T = unknown>(): Record<string, T[]>
emitted<T = unknown>(eventName?: string): T[]
emitted<T = unknown>(eventName?: string): T[] | Record<string, T[]> {
if (eventName) {
const emitted = (this.vm['__emitted'] as Record<string, T[]>)[eventName]
return emitted
}

return this.vm['__emitted'] as Record<string, T[]>
return emitted(eventName)
}

html() {
Expand Down
10 changes: 10 additions & 0 deletions tests/emit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,14 @@ describe('emitted', () => {
expect(wrapper.emitted('hello')).toHaveLength(1)
expect(wrapper.emitted('hello')[0]).toEqual(['foo', 'bar'])
})

it('captures an event emitted in setup', () => {
const Comp = {
setup(_, { emit }) {
emit('foo')
}
}
const wrapper = mount(Comp)
expect(wrapper.emitted().foo).toBeTruthy()
})
})
1 change: 1 addition & 0 deletions tests/mountingOptions/props.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe('mountingOptions.props', () => {

test('assigns event listeners', async () => {
const Component = {
emits: ['customEvent'],
template: '<button @click="$emit(\'customEvent\', true)">Click</button>'
}
const onCustomEvent = jest.fn()
Expand Down
4 changes: 2 additions & 2 deletions tests/setValue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ describe('setValue', () => {

describe('on component instance', () => {
const PlainInputComponent = defineComponent({
props: ['modelValue'],
props: ['modelValue', 'onUpdate:modelValue'],
template: '<div>{{ modelValue }}</div>'
})

const MultiInputComponent = defineComponent({
props: ['foo', 'bar'],
props: ['foo', 'bar', 'onUpdate:bar', 'onUpdate:foo'],
template: '<div>{{ foo }} {{ bar }}</div>'
})

Expand Down

0 comments on commit 4d030bb

Please sign in to comment.