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

Commit 37df043

Browse files
Jevon617sxzz
andauthored
feat(runtime-vapor): runtime for v-on in component (#178)
Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent 7cacb65 commit 37df043

File tree

4 files changed

+179
-146
lines changed

4 files changed

+179
-146
lines changed

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

Lines changed: 103 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -3,81 +3,91 @@
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
31+
onfoo: () => onFoo,
32+
onBar: () => onBar,
33+
['on!baz']: () => onBaz,
34+
})
35+
36+
expect(onFoo).not.toHaveBeenCalled()
37+
expect(onBar).toHaveBeenCalled()
38+
expect(onBaz).toHaveBeenCalled()
39+
})
40+
41+
test('trigger dynamic emits', () => {
42+
const { render } = define({
43+
setup(_, { emit }) {
44+
emit('foo')
45+
emit('bar')
46+
emit('!baz')
3447
},
3548
})
49+
const onFoo = vi.fn()
50+
const onBar = vi.fn()
51+
const onBaz = vi.fn()
52+
render(() => ({
53+
onfoo: onFoo,
54+
onBar,
55+
['on!baz']: onBaz,
56+
}))
3657

37-
expect(onfoo).not.toHaveBeenCalled()
58+
expect(onFoo).not.toHaveBeenCalled()
3859
expect(onBar).toHaveBeenCalled()
3960
expect(onBaz).toHaveBeenCalled()
4061
})
4162

4263
test('trigger camelCase handler', () => {
4364
const { render } = define({
44-
render() {},
45-
setup(_: any, { emit }: any) {
65+
setup(_, { emit }) {
4666
emit('test-event')
4767
},
4868
})
4969

5070
const fooSpy = vi.fn()
51-
render({
52-
get onTestEvent() {
53-
return fooSpy
54-
},
55-
})
71+
render({ onTestEvent: () => fooSpy })
5672
expect(fooSpy).toHaveBeenCalled()
5773
})
5874

5975
test('trigger kebab-case handler', () => {
6076
const { render } = define({
61-
render() {},
62-
setup(_: any, { emit }: any) {
77+
setup(_, { emit }) {
6378
emit('test-event')
6479
},
6580
})
6681

6782
const fooSpy = vi.fn()
68-
render({
69-
get ['onTest-event']() {
70-
return fooSpy
71-
},
72-
})
83+
render({ ['onTest-event']: () => fooSpy })
7384
expect(fooSpy).toHaveBeenCalledTimes(1)
7485
})
7586

7687
// #3527
77-
test.todo('trigger mixed case handlers', () => {
88+
test('trigger mixed case handlers', () => {
7889
const { render } = define({
79-
render() {},
80-
setup(_: any, { emit }: any) {
90+
setup(_, { emit }) {
8191
emit('test-event')
8292
emit('testEvent')
8393
},
@@ -86,15 +96,10 @@ describe.todo('component: emit', () => {
8696
const fooSpy = vi.fn()
8797
const barSpy = vi.fn()
8898
render(
89-
// TODO: impl `toHandlers`
90-
{
91-
get ['onTest-Event']() {
92-
return fooSpy
93-
},
94-
get onTestEvent() {
95-
return barSpy
96-
},
97-
},
99+
toHandlers({
100+
'test-event': () => fooSpy,
101+
testEvent: () => barSpy,
102+
}),
98103
)
99104
expect(fooSpy).toHaveBeenCalledTimes(1)
100105
expect(barSpy).toHaveBeenCalledTimes(1)
@@ -103,8 +108,7 @@ describe.todo('component: emit', () => {
103108
// for v-model:foo-bar usage in DOM templates
104109
test('trigger hyphenated events for update:xxx events', () => {
105110
const { render } = define({
106-
render() {},
107-
setup(_: any, { emit }: any) {
111+
setup(_, { emit }) {
108112
emit('update:fooProp')
109113
emit('update:barProp')
110114
},
@@ -113,12 +117,8 @@ describe.todo('component: emit', () => {
113117
const fooSpy = vi.fn()
114118
const barSpy = vi.fn()
115119
render({
116-
get ['onUpdate:fooProp']() {
117-
return fooSpy
118-
},
119-
get ['onUpdate:bar-prop']() {
120-
return barSpy
121-
},
120+
['onUpdate:fooProp']: () => fooSpy,
121+
['onUpdate:bar-prop']: () => barSpy,
122122
})
123123

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

128128
test('should trigger array of listeners', async () => {
129129
const { render } = define({
130-
render() {},
131-
setup(_: any, { emit }: any) {
130+
setup(_, { emit }) {
132131
emit('foo', 1)
133132
},
134133
})
135134

136135
const fn1 = vi.fn()
137136
const fn2 = vi.fn()
138137

139-
render({
140-
onFoo: () => [fn1, fn2],
141-
})
138+
render({ onFoo: () => [fn1, fn2] })
142139
expect(fn1).toHaveBeenCalledTimes(1)
143140
expect(fn1).toHaveBeenCalledWith(1)
144141
expect(fn2).toHaveBeenCalledTimes(1)
145142
expect(fn2).toHaveBeenCalledWith(1)
146143
})
147144

148-
test.todo('warning for undeclared event (array)', () => {
149-
// TODO: warning
145+
test('warning for undeclared event (array)', () => {
146+
const { render } = define({
147+
emits: ['foo'],
148+
149+
setup(_, { emit }) {
150+
emit('bar')
151+
},
152+
})
153+
render()
154+
expect(
155+
`Component emitted event "bar" but it is neither declared`,
156+
).toHaveBeenWarned()
150157
})
151158

152-
test.todo('warning for undeclared event (object)', () => {
153-
// TODO: warning
159+
test('warning for undeclared event (object)', () => {
160+
const { render } = define({
161+
emits: {
162+
foo: null,
163+
},
164+
165+
setup(_, { emit }) {
166+
emit('bar')
167+
},
168+
})
169+
render()
170+
expect(
171+
`Component emitted event "bar" but it is neither declared`,
172+
).toHaveBeenWarned()
154173
})
155174

156175
test('should not warn if has equivalent onXXX prop', () => {
157176
define({
158177
props: ['onFoo'],
159178
emits: [],
160-
render() {},
161-
setup(_: any, { emit }: any) {
179+
180+
setup(_, { emit }) {
162181
emit('foo')
163182
},
164183
}).render()
@@ -182,12 +201,11 @@ describe.todo('component: emit', () => {
182201

183202
test('.once', () => {
184203
const { render } = define({
185-
render() {},
186204
emits: {
187205
foo: null,
188206
bar: null,
189207
},
190-
setup(_: any, { emit }: any) {
208+
setup(_, { emit }) {
191209
emit('foo')
192210
emit('foo')
193211
emit('bar')
@@ -197,71 +215,49 @@ describe.todo('component: emit', () => {
197215
const fn = vi.fn()
198216
const barFn = vi.fn()
199217
render({
200-
get onFooOnce() {
201-
return fn
202-
},
203-
get onBarOnce() {
204-
return barFn
205-
},
218+
onFooOnce: () => fn,
219+
onBarOnce: () => barFn,
206220
})
207221
expect(fn).toHaveBeenCalledTimes(1)
208222
expect(barFn).toHaveBeenCalledTimes(1)
209223
})
210224

211225
test('.once with normal listener of the same name', () => {
212226
const { render } = define({
213-
render() {},
214227
emits: {
215228
foo: null,
216229
},
217-
setup(_: any, { emit }: any) {
230+
setup(_, { emit }) {
218231
emit('foo')
219232
emit('foo')
220233
},
221234
})
222235
const onFoo = vi.fn()
223236
const onFooOnce = vi.fn()
224237
render({
225-
get onFoo() {
226-
return onFoo
227-
},
228-
get onFooOnce() {
229-
return onFooOnce
230-
},
238+
onFoo: () => onFoo,
239+
onFooOnce: () => onFooOnce,
231240
})
232241
expect(onFoo).toHaveBeenCalledTimes(2)
233242
expect(onFooOnce).toHaveBeenCalledTimes(1)
234243
})
235244

236245
test('.number modifier should work with v-model on component', () => {
237246
const { render } = define({
238-
render() {},
239-
setup(_: any, { emit }: any) {
247+
setup(_, { emit }) {
240248
emit('update:modelValue', '1')
241249
emit('update:foo', '2')
242250
},
243251
})
244252
const fn1 = vi.fn()
245253
const fn2 = vi.fn()
246254
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-
},
255+
modelValue: () => null,
256+
modelModifiers: () => ({ number: true }),
257+
['onUpdate:modelValue']: () => fn1,
258+
foo: () => null,
259+
fooModifiers: () => ({ number: true }),
260+
['onUpdate:foo']: () => fn2,
265261
})
266262
expect(fn1).toHaveBeenCalledTimes(1)
267263
expect(fn1).toHaveBeenCalledWith(1)
@@ -271,8 +267,7 @@ describe.todo('component: emit', () => {
271267

272268
test('.trim modifier should work with v-model on component', () => {
273269
const { render } = define({
274-
render() {},
275-
setup(_: any, { emit }: any) {
270+
setup(_, { emit }) {
276271
emit('update:modelValue', ' one ')
277272
emit('update:foo', ' two ')
278273
},
@@ -307,8 +302,7 @@ describe.todo('component: emit', () => {
307302

308303
test('.trim and .number modifiers should work with v-model on component', () => {
309304
const { render } = define({
310-
render() {},
311-
setup(_: any, { emit }: any) {
305+
setup(_, { emit }) {
312306
emit('update:modelValue', ' +01.2 ')
313307
emit('update:foo', ' 1 ')
314308
},
@@ -343,8 +337,7 @@ describe.todo('component: emit', () => {
343337

344338
test('only trim string parameter when work with v-model on component', () => {
345339
const { render } = define({
346-
render() {},
347-
setup(_: any, { emit }: any) {
340+
setup(_, { emit }) {
348341
emit('update:modelValue', ' foo ', { bar: ' bar ' })
349342
},
350343
})
@@ -395,20 +388,21 @@ describe.todo('component: emit', () => {
395388

396389
test('does not emit after unmount', async () => {
397390
const fn = vi.fn()
398-
const { app } = define({
391+
392+
const Foo = defineComponent({
399393
emits: ['closing'],
400-
setup(_: any, { emit }: any) {
394+
setup(_, { emit }) {
401395
onBeforeUnmount(async () => {
402396
await nextTick()
403397
emit('closing', true)
404398
})
405399
},
406-
render() {},
407-
}).render({
408-
get onClosing() {
409-
return fn
410-
},
411400
})
401+
402+
const { app } = define(() =>
403+
createComponent(Foo, { onClosing: () => fn }),
404+
).render()
405+
412406
await nextTick()
413407
app.unmount()
414408
await nextTick()

0 commit comments

Comments
 (0)