defineEmits.spec.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { BindingTypes } from '@vue/compiler-core'
  2. import { compileSFCScript as compile, assertCode } from '../utils'
  3. describe('defineEmits', () => {
  4. test('basic usage', () => {
  5. const { content, bindings } = compile(`
  6. <script setup>
  7. const myEmit = defineEmits(['foo', 'bar'])
  8. </script>
  9. `)
  10. assertCode(content)
  11. expect(bindings).toStrictEqual({
  12. myEmit: BindingTypes.SETUP_CONST
  13. })
  14. // should remove defineEmits import and call
  15. expect(content).not.toMatch('defineEmits')
  16. // should generate correct setup signature
  17. expect(content).toMatch(
  18. `setup(__props, { expose: __expose, emit: myEmit }) {`
  19. )
  20. // should include context options in default export
  21. expect(content).toMatch(`export default {
  22. emits: ['foo', 'bar'],`)
  23. })
  24. test('w/ runtime options', () => {
  25. const { content } = compile(`
  26. <script setup lang="ts">
  27. const emit = defineEmits(['a', 'b'])
  28. </script>
  29. `)
  30. assertCode(content)
  31. expect(content).toMatch(`export default /*#__PURE__*/_defineComponent({
  32. emits: ['a', 'b'],
  33. setup(__props, { expose: __expose, emit }) {`)
  34. })
  35. test('w/ type', () => {
  36. const { content } = compile(`
  37. <script setup lang="ts">
  38. const emit = defineEmits<(e: 'foo' | 'bar') => void>()
  39. </script>
  40. `)
  41. assertCode(content)
  42. expect(content).toMatch(`emits: ["foo", "bar"]`)
  43. })
  44. test('w/ type (union)', () => {
  45. const type = `((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void)`
  46. const { content } = compile(`
  47. <script setup lang="ts">
  48. const emit = defineEmits<${type}>()
  49. </script>
  50. `)
  51. assertCode(content)
  52. expect(content).toMatch(`emits: ["foo", "bar", "baz"]`)
  53. })
  54. test('w/ type (type literal w/ call signatures)', () => {
  55. const type = `{(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;}`
  56. const { content } = compile(`
  57. <script setup lang="ts">
  58. const emit = defineEmits<${type}>()
  59. </script>
  60. `)
  61. assertCode(content)
  62. expect(content).toMatch(`emits: ["foo", "bar", "baz"]`)
  63. })
  64. test('w/ type (interface)', () => {
  65. const { content } = compile(`
  66. <script setup lang="ts">
  67. interface Emits { (e: 'foo' | 'bar'): void }
  68. const emit = defineEmits<Emits>()
  69. </script>
  70. `)
  71. assertCode(content)
  72. expect(content).toMatch(`emits: ["foo", "bar"]`)
  73. })
  74. test('w/ type (exported interface)', () => {
  75. const { content } = compile(`
  76. <script setup lang="ts">
  77. export interface Emits { (e: 'foo' | 'bar'): void }
  78. const emit = defineEmits<Emits>()
  79. </script>
  80. `)
  81. assertCode(content)
  82. expect(content).toMatch(`emits: ["foo", "bar"]`)
  83. })
  84. test('w/ type from normal script', () => {
  85. const { content } = compile(`
  86. <script lang="ts">
  87. export interface Emits { (e: 'foo' | 'bar'): void }
  88. </script>
  89. <script setup lang="ts">
  90. const emit = defineEmits<Emits>()
  91. </script>
  92. `)
  93. assertCode(content)
  94. expect(content).toMatch(`emits: ["foo", "bar"]`)
  95. })
  96. test('w/ type (type alias)', () => {
  97. const { content } = compile(`
  98. <script setup lang="ts">
  99. type Emits = { (e: 'foo' | 'bar'): void }
  100. const emit = defineEmits<Emits>()
  101. </script>
  102. `)
  103. assertCode(content)
  104. expect(content).toMatch(`emits: ["foo", "bar"]`)
  105. })
  106. test('w/ type (exported type alias)', () => {
  107. const { content } = compile(`
  108. <script setup lang="ts">
  109. export type Emits = { (e: 'foo' | 'bar'): void }
  110. const emit = defineEmits<Emits>()
  111. </script>
  112. `)
  113. assertCode(content)
  114. expect(content).toMatch(`emits: ["foo", "bar"]`)
  115. })
  116. test('w/ type (referenced function type)', () => {
  117. const { content } = compile(`
  118. <script setup lang="ts">
  119. type Emits = (e: 'foo' | 'bar') => void
  120. const emit = defineEmits<Emits>()
  121. </script>
  122. `)
  123. assertCode(content)
  124. expect(content).toMatch(`emits: ["foo", "bar"]`)
  125. })
  126. test('w/ type (referenced exported function type)', () => {
  127. const { content } = compile(`
  128. <script setup lang="ts">
  129. export type Emits = (e: 'foo' | 'bar') => void
  130. const emit = defineEmits<Emits>()
  131. </script>
  132. `)
  133. assertCode(content)
  134. expect(content).toMatch(`emits: ["foo", "bar"]`)
  135. })
  136. // #5393
  137. test('w/ type (interface ts type)', () => {
  138. const { content } = compile(`
  139. <script setup lang="ts">
  140. interface Emits { (e: 'foo'): void }
  141. const emit: Emits = defineEmits(['foo'])
  142. </script>
  143. `)
  144. assertCode(content)
  145. expect(content).toMatch(`emits: ['foo']`)
  146. })
  147. test('w/ type (property syntax)', () => {
  148. const { content } = compile(`
  149. <script setup lang="ts">
  150. const emit = defineEmits<{ foo: [], bar: [] }>()
  151. </script>
  152. `)
  153. expect(content).toMatch(`emits: ["foo", "bar"]`)
  154. assertCode(content)
  155. })
  156. // #8040
  157. test('w/ type (property syntax string literal)', () => {
  158. const { content } = compile(`
  159. <script setup lang="ts">
  160. const emit = defineEmits<{ 'foo:bar': [] }>()
  161. </script>
  162. `)
  163. expect(content).toMatch(`emits: ["foo:bar"]`)
  164. assertCode(content)
  165. })
  166. describe('errors', () => {
  167. test('w/ both type and non-type args', () => {
  168. expect(() => {
  169. compile(`<script setup lang="ts">
  170. defineEmits<{}>({})
  171. </script>`)
  172. }).toThrow(`cannot accept both type and non-type arguments`)
  173. })
  174. test('mixed usage of property / call signature', () => {
  175. expect(() =>
  176. compile(`<script setup lang="ts">
  177. defineEmits<{
  178. foo: []
  179. (e: 'hi'): void
  180. }>()
  181. </script>`)
  182. ).toThrow(
  183. `defineEmits() type cannot mixed call signature and property syntax.`
  184. )
  185. })
  186. })
  187. })