Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit 3359d9d

Browse files
committed
feat(compiler-vapor): component emits
1 parent a531201 commit 3359d9d

File tree

2 files changed

+126
-162
lines changed

2 files changed

+126
-162
lines changed

packages/runtime-vapor/__tests__/componentEmits.spec.ts

Lines changed: 83 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -3,81 +3,69 @@
33
// Note: emits and listener fallthrough is tested in
44
// ./rendererAttrsFallthrough.spec.ts.
55

6-
import { nextTick, onBeforeUnmount } from '../src'
6+
import { toHandlers } from '@vue/runtime-core'
7+
import {
8+
createComponent,
9+
defineComponent,
10+
nextTick,
11+
onBeforeUnmount,
12+
} from '../src'
713
import { isEmitListener } from '../src/componentEmits'
814
import { makeRender } from './_utils'
915

10-
const define = makeRender<any>()
16+
const define = makeRender()
1117

12-
describe.todo('component: emit', () => {
18+
describe('component: emit', () => {
1319
test('trigger handlers', () => {
1420
const { render } = define({
15-
render() {},
16-
setup(_: any, { emit }: any) {
21+
setup(_, { emit }) {
1722
emit('foo')
1823
emit('bar')
1924
emit('!baz')
2025
},
2126
})
22-
const onfoo = vi.fn()
27+
const onFoo = vi.fn()
2328
const onBar = vi.fn()
2429
const onBaz = vi.fn()
2530
render({
26-
get onfoo() {
27-
return onfoo
28-
},
29-
get onBar() {
30-
return onBar
31-
},
32-
get ['on!baz']() {
33-
return onBaz
34-
},
31+
onfoo: () => onFoo,
32+
onBar: () => onBar,
33+
['on!baz']: () => onBaz,
3534
})
3635

37-
expect(onfoo).not.toHaveBeenCalled()
36+
expect(onFoo).not.toHaveBeenCalled()
3837
expect(onBar).toHaveBeenCalled()
3938
expect(onBaz).toHaveBeenCalled()
4039
})
4140

4241
test('trigger camelCase handler', () => {
4342
const { render } = define({
44-
render() {},
45-
setup(_: any, { emit }: any) {
43+
setup(_, { emit }) {
4644
emit('test-event')
4745
},
4846
})
4947

5048
const fooSpy = vi.fn()
51-
render({
52-
get onTestEvent() {
53-
return fooSpy
54-
},
55-
})
49+
render({ onTestEvent: () => fooSpy })
5650
expect(fooSpy).toHaveBeenCalled()
5751
})
5852

5953
test('trigger kebab-case handler', () => {
6054
const { render } = define({
61-
render() {},
62-
setup(_: any, { emit }: any) {
55+
setup(_, { emit }) {
6356
emit('test-event')
6457
},
6558
})
6659

6760
const fooSpy = vi.fn()
68-
render({
69-
get ['onTest-event']() {
70-
return fooSpy
71-
},
72-
})
61+
render({ ['onTest-event']: () => fooSpy })
7362
expect(fooSpy).toHaveBeenCalledTimes(1)
7463
})
7564

7665
// #3527
77-
test.todo('trigger mixed case handlers', () => {
66+
test('trigger mixed case handlers', () => {
7867
const { render } = define({
79-
render() {},
80-
setup(_: any, { emit }: any) {
68+
setup(_, { emit }) {
8169
emit('test-event')
8270
emit('testEvent')
8371
},
@@ -86,15 +74,10 @@ describe.todo('component: emit', () => {
8674
const fooSpy = vi.fn()
8775
const barSpy = vi.fn()
8876
render(
89-
// TODO: impl `toHandlers`
90-
{
91-
get ['onTest-Event']() {
92-
return fooSpy
93-
},
94-
get onTestEvent() {
95-
return barSpy
96-
},
97-
},
77+
toHandlers({
78+
'test-event': () => fooSpy,
79+
testEvent: () => barSpy,
80+
}),
9881
)
9982
expect(fooSpy).toHaveBeenCalledTimes(1)
10083
expect(barSpy).toHaveBeenCalledTimes(1)
@@ -103,8 +86,7 @@ describe.todo('component: emit', () => {
10386
// for v-model:foo-bar usage in DOM templates
10487
test('trigger hyphenated events for update:xxx events', () => {
10588
const { render } = define({
106-
render() {},
107-
setup(_: any, { emit }: any) {
89+
setup(_, { emit }) {
10890
emit('update:fooProp')
10991
emit('update:barProp')
11092
},
@@ -113,12 +95,8 @@ describe.todo('component: emit', () => {
11395
const fooSpy = vi.fn()
11496
const barSpy = vi.fn()
11597
render({
116-
get ['onUpdate:fooProp']() {
117-
return fooSpy
118-
},
119-
get ['onUpdate:bar-prop']() {
120-
return barSpy
121-
},
98+
['onUpdate:fooProp']: () => fooSpy,
99+
['onUpdate:bar-prop']: () => barSpy,
122100
})
123101

124102
expect(fooSpy).toHaveBeenCalled()
@@ -127,38 +105,57 @@ describe.todo('component: emit', () => {
127105

128106
test('should trigger array of listeners', async () => {
129107
const { render } = define({
130-
render() {},
131-
setup(_: any, { emit }: any) {
108+
setup(_, { emit }) {
132109
emit('foo', 1)
133110
},
134111
})
135112

136113
const fn1 = vi.fn()
137114
const fn2 = vi.fn()
138115

139-
render({
140-
onFoo: () => [fn1, fn2],
141-
})
116+
render({ onFoo: () => [fn1, fn2] })
142117
expect(fn1).toHaveBeenCalledTimes(1)
143118
expect(fn1).toHaveBeenCalledWith(1)
144119
expect(fn2).toHaveBeenCalledTimes(1)
145120
expect(fn2).toHaveBeenCalledWith(1)
146121
})
147122

148-
test.todo('warning for undeclared event (array)', () => {
149-
// TODO: warning
123+
test('warning for undeclared event (array)', () => {
124+
const { render } = define({
125+
emits: ['foo'],
126+
127+
setup(_, { emit }) {
128+
emit('bar')
129+
},
130+
})
131+
render()
132+
expect(
133+
`Component emitted event "bar" but it is neither declared`,
134+
).toHaveBeenWarned()
150135
})
151136

152-
test.todo('warning for undeclared event (object)', () => {
153-
// TODO: warning
137+
test('warning for undeclared event (object)', () => {
138+
const { render } = define({
139+
emits: {
140+
foo: null,
141+
},
142+
143+
setup(_, { emit }) {
144+
emit('bar')
145+
},
146+
})
147+
render()
148+
expect(
149+
`Component emitted event "bar" but it is neither declared`,
150+
).toHaveBeenWarned()
154151
})
155152

156153
test('should not warn if has equivalent onXXX prop', () => {
157154
define({
158155
props: ['onFoo'],
159156
emits: [],
160-
render() {},
161-
setup(_: any, { emit }: any) {
157+
158+
setup(_, { emit }) {
162159
emit('foo')
163160
},
164161
}).render()
@@ -182,12 +179,11 @@ describe.todo('component: emit', () => {
182179

183180
test('.once', () => {
184181
const { render } = define({
185-
render() {},
186182
emits: {
187183
foo: null,
188184
bar: null,
189185
},
190-
setup(_: any, { emit }: any) {
186+
setup(_, { emit }) {
191187
emit('foo')
192188
emit('foo')
193189
emit('bar')
@@ -197,71 +193,49 @@ describe.todo('component: emit', () => {
197193
const fn = vi.fn()
198194
const barFn = vi.fn()
199195
render({
200-
get onFooOnce() {
201-
return fn
202-
},
203-
get onBarOnce() {
204-
return barFn
205-
},
196+
onFooOnce: () => fn,
197+
onBarOnce: () => barFn,
206198
})
207199
expect(fn).toHaveBeenCalledTimes(1)
208200
expect(barFn).toHaveBeenCalledTimes(1)
209201
})
210202

211203
test('.once with normal listener of the same name', () => {
212204
const { render } = define({
213-
render() {},
214205
emits: {
215206
foo: null,
216207
},
217-
setup(_: any, { emit }: any) {
208+
setup(_, { emit }) {
218209
emit('foo')
219210
emit('foo')
220211
},
221212
})
222213
const onFoo = vi.fn()
223214
const onFooOnce = vi.fn()
224215
render({
225-
get onFoo() {
226-
return onFoo
227-
},
228-
get onFooOnce() {
229-
return onFooOnce
230-
},
216+
onFoo: () => onFoo,
217+
onFooOnce: () => onFooOnce,
231218
})
232219
expect(onFoo).toHaveBeenCalledTimes(2)
233220
expect(onFooOnce).toHaveBeenCalledTimes(1)
234221
})
235222

236223
test('.number modifier should work with v-model on component', () => {
237224
const { render } = define({
238-
render() {},
239-
setup(_: any, { emit }: any) {
225+
setup(_, { emit }) {
240226
emit('update:modelValue', '1')
241227
emit('update:foo', '2')
242228
},
243229
})
244230
const fn1 = vi.fn()
245231
const fn2 = vi.fn()
246232
render({
247-
modelValue() {
248-
return null
249-
},
250-
modelModifiers() {
251-
return { number: true }
252-
},
253-
['onUpdate:modelValue']() {
254-
return fn1
255-
},
256-
foo() {
257-
return null
258-
},
259-
fooModifiers() {
260-
return { number: true }
261-
},
262-
['onUpdate:foo']() {
263-
return fn2
264-
},
233+
modelValue: () => null,
234+
modelModifiers: () => ({ number: true }),
235+
['onUpdate:modelValue']: () => fn1,
236+
foo: () => null,
237+
fooModifiers: () => ({ number: true }),
238+
['onUpdate:foo']: () => fn2,
265239
})
266240
expect(fn1).toHaveBeenCalledTimes(1)
267241
expect(fn1).toHaveBeenCalledWith(1)
@@ -271,8 +245,7 @@ describe.todo('component: emit', () => {
271245

272246
test('.trim modifier should work with v-model on component', () => {
273247
const { render } = define({
274-
render() {},
275-
setup(_: any, { emit }: any) {
248+
setup(_, { emit }) {
276249
emit('update:modelValue', ' one ')
277250
emit('update:foo', ' two ')
278251
},
@@ -307,8 +280,7 @@ describe.todo('component: emit', () => {
307280

308281
test('.trim and .number modifiers should work with v-model on component', () => {
309282
const { render } = define({
310-
render() {},
311-
setup(_: any, { emit }: any) {
283+
setup(_, { emit }) {
312284
emit('update:modelValue', ' +01.2 ')
313285
emit('update:foo', ' 1 ')
314286
},
@@ -343,8 +315,7 @@ describe.todo('component: emit', () => {
343315

344316
test('only trim string parameter when work with v-model on component', () => {
345317
const { render } = define({
346-
render() {},
347-
setup(_: any, { emit }: any) {
318+
setup(_, { emit }) {
348319
emit('update:modelValue', ' foo ', { bar: ' bar ' })
349320
},
350321
})
@@ -393,22 +364,23 @@ describe.todo('component: emit', () => {
393364
expect(isEmitListener(options, 'onFooBaz')).toBe(true)
394365
})
395366

396-
test('does not emit after unmount', async () => {
367+
test.only('does not emit after unmount', async () => {
397368
const fn = vi.fn()
398-
const { app } = define({
369+
370+
const Foo = defineComponent({
399371
emits: ['closing'],
400-
setup(_: any, { emit }: any) {
372+
setup(_, { emit }) {
401373
onBeforeUnmount(async () => {
402374
await nextTick()
403375
emit('closing', true)
404376
})
405377
},
406-
render() {},
407-
}).render({
408-
get onClosing() {
409-
return fn
410-
},
411378
})
379+
380+
const { app } = define(() =>
381+
createComponent(Foo, { onClosing: () => fn }),
382+
).render()
383+
412384
await nextTick()
413385
app.unmount()
414386
await nextTick()

0 commit comments

Comments
 (0)