radio.test.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. import { nextTick, ref } from 'vue'
  2. import { mount } from '@vue/test-utils'
  3. import { describe, expect, it, test } from 'vitest'
  4. import { ElFormItem } from '@element-plus/components/form'
  5. import Radio from '../src/radio.vue'
  6. import RadioGroup from '../src/radio-group.vue'
  7. import RadioButton from '../src/radio-button.vue'
  8. import type { RadioProps } from '../src/radio'
  9. describe('Radio', () => {
  10. test('create', async () => {
  11. const radio = ref('')
  12. const wrapper = mount(() => <Radio v-model={radio.value} label="a" />)
  13. expect(wrapper.classes()).toContain('el-radio')
  14. await wrapper.trigger('click')
  15. expect(wrapper.classes()).toContain('is-checked')
  16. })
  17. test('disabled', async () => {
  18. const radio = ref('')
  19. const wrapper = mount(() => (
  20. <Radio v-model={radio.value} label="3" disabled />
  21. ))
  22. await wrapper.trigger('click')
  23. expect(radio.value).toBe('')
  24. expect(wrapper.classes()).toContain('is-disabled')
  25. })
  26. test('border', () => {
  27. const radio = ref('')
  28. const wrapper = mount(() => (
  29. <Radio v-model={radio.value} label="3" border />
  30. ))
  31. expect(wrapper.classes()).toContain('is-bordered')
  32. })
  33. test('change event', async () => {
  34. const radio = ref('')
  35. const changeData = ref<RadioProps['modelValue']>('')
  36. function handleChange(val: RadioProps['modelValue']) {
  37. changeData.value = val
  38. }
  39. const wrapper = mount(() => (
  40. <Radio v-model={radio.value} label="3" onChange={handleChange} />
  41. ))
  42. await wrapper.trigger('click')
  43. await nextTick()
  44. expect(changeData.value).toEqual('3')
  45. })
  46. test('change event only triggers on user input', async () => {
  47. const radio = ref('')
  48. const changeData = ref<RadioProps['modelValue']>('')
  49. function handleChange(val: RadioProps['modelValue']) {
  50. changeData.value = val
  51. }
  52. mount(() => (
  53. <Radio v-model={radio.value} label="3" onChange={handleChange} />
  54. ))
  55. radio.value = '3'
  56. await nextTick()
  57. expect(changeData.value).toEqual('')
  58. expect(radio.value).toEqual('3')
  59. })
  60. })
  61. describe('Radio group', () => {
  62. it('create', async () => {
  63. const radio = ref(3)
  64. const wrapper = mount(() => (
  65. <RadioGroup v-model={radio.value}>
  66. <Radio label={3} ref="radio1">
  67. 3
  68. </Radio>
  69. <Radio label={6} ref="radio2">
  70. 6
  71. </Radio>
  72. <Radio label={9}>9</Radio>
  73. </RadioGroup>
  74. ))
  75. await nextTick()
  76. const [radio1, radio2] = wrapper.findAll('.el-radio')
  77. expect(radio1.classes()).toContain('is-checked')
  78. await radio2.trigger('click')
  79. expect(radio2.classes()).toContain('is-checked')
  80. expect(radio.value).toEqual(6)
  81. })
  82. it('id auto derive', async () => {
  83. const radioValue1 = ref(3)
  84. const wrapper1 = mount(() => (
  85. <RadioGroup v-model={radioValue1.value}>
  86. <Radio label={3} ref="radio1">
  87. 3
  88. </Radio>
  89. <Radio label={6} ref="radio2">
  90. 6
  91. </Radio>
  92. <Radio label={9}>9</Radio>
  93. </RadioGroup>
  94. ))
  95. const radioValue2 = ref(3)
  96. const wrapper2 = mount(() => (
  97. <RadioGroup v-model={radioValue2.value}>
  98. <Radio label={3} ref="radio1">
  99. 3
  100. </Radio>
  101. <Radio label={6} ref="radio2">
  102. 6
  103. </Radio>
  104. <Radio label={9}>9</Radio>
  105. </RadioGroup>
  106. ))
  107. const id1 = wrapper1.find('.el-radio').find('input').attributes('name')
  108. const id2 = wrapper2.find('.el-radio').find('input').attributes('name')
  109. expect(id1).not.toEqual(id2)
  110. })
  111. it('disabled', async () => {
  112. const radio = ref(3)
  113. const wrapper = mount(() => (
  114. <RadioGroup v-model={radio.value} disabled>
  115. <Radio label={3} ref="radio1">
  116. 3
  117. </Radio>
  118. <Radio label={6} ref="radio2">
  119. 6
  120. </Radio>
  121. <Radio label={9}>9</Radio>
  122. </RadioGroup>
  123. ))
  124. expect(wrapper.find('label.is-disabled').exists()).toBe(true)
  125. const [radio1, radio2] = wrapper.findAll('.el-radio')
  126. expect(radio1.classes()).toContain('is-checked')
  127. await radio2.trigger('click')
  128. expect(radio.value).toEqual(3)
  129. expect(radio1.classes()).toContain('is-checked')
  130. })
  131. it('change event', async () => {
  132. const radio = ref(3)
  133. const data = ref<RadioProps['modelValue']>(0)
  134. function onChange(val: RadioProps['modelValue']) {
  135. data.value = val
  136. }
  137. const wrapper = mount(() => (
  138. <RadioGroup v-model={radio.value} onChange={onChange}>
  139. <Radio label={3}>3</Radio>
  140. <Radio label={6} ref="radio2">
  141. 6
  142. </Radio>
  143. <Radio label={9}>9</Radio>
  144. </RadioGroup>
  145. ))
  146. const radio2 = wrapper.findAll('.el-radio').at(1)
  147. await radio2?.trigger('click')
  148. await nextTick()
  149. expect(data.value).toEqual(6)
  150. })
  151. it('change event only triggers on user input', async () => {
  152. const radio = ref(3)
  153. const data = ref<RadioProps['modelValue']>(0)
  154. function onChange(val: RadioProps['modelValue']) {
  155. data.value = val
  156. }
  157. mount(() => (
  158. <RadioGroup v-model={radio.value} onChange={onChange}>
  159. <Radio label={3}>3</Radio>
  160. <Radio label={6} ref="radio2">
  161. 6
  162. </Radio>
  163. <Radio label={9}>9</Radio>
  164. </RadioGroup>
  165. ))
  166. radio.value = 6
  167. await nextTick()
  168. expect(data.value).toEqual(0)
  169. })
  170. it('disabled when children is radio button', async () => {
  171. const radio = ref(3)
  172. const wrapper = mount(() => (
  173. <RadioGroup v-model={radio.value} disabled>
  174. <RadioButton label={3} ref="radio1">
  175. 3
  176. </RadioButton>
  177. <RadioButton label={6} ref="radio2">
  178. 6
  179. </RadioButton>
  180. <RadioButton label={9}>9</RadioButton>
  181. </RadioGroup>
  182. ))
  183. const [radio1, radio2] = wrapper.findAll('.el-radio-button')
  184. expect(radio1.classes()).toContain('is-active')
  185. expect(wrapper.findAll('.is-disabled').length).toBe(3)
  186. await radio2.trigger('click')
  187. expect(radio.value).toEqual(3)
  188. expect(radio1.classes()).toContain('is-active')
  189. })
  190. })
  191. describe('Radio Button', () => {
  192. it('create', async () => {
  193. const radio = ref(3)
  194. const wrapper = mount(() => (
  195. <RadioGroup v-model={radio.value}>
  196. <RadioButton label={3} ref="radio1">
  197. 3
  198. </RadioButton>
  199. <RadioButton label={6} ref="radio2">
  200. 6
  201. </RadioButton>
  202. <RadioButton label={9}>9</RadioButton>
  203. </RadioGroup>
  204. ))
  205. const [radio1, radio2] = wrapper.findAll('.el-radio-button')
  206. expect(radio1.classes()).toContain('is-active')
  207. await radio2.trigger('click')
  208. expect(radio2.classes()).toContain('is-active')
  209. expect(radio.value).toEqual(6)
  210. })
  211. it('custom color', () => {
  212. const radio = ref(3)
  213. const wrapper = mount(() => (
  214. <RadioGroup v-model={radio.value} fill="#000" text-color="#ff0">
  215. <RadioButton label={3} ref="radio1">
  216. 3
  217. </RadioButton>
  218. <RadioButton label={6} ref="radio2">
  219. 6
  220. </RadioButton>
  221. <RadioButton label={9}>9</RadioButton>
  222. </RadioGroup>
  223. ))
  224. const radio1 = wrapper.find('.el-radio-button')
  225. expect(radio1.find('span').attributes('style')).toContain(
  226. 'background-color: rgb(0, 0, 0); border-color: #000; box-shadow: -1px 0 0 0 #000; color: rgb(255, 255, 0);'
  227. )
  228. })
  229. it('change event', async () => {
  230. const radio = ref(3)
  231. const data = ref<RadioProps['modelValue']>(0)
  232. function onChange(val: RadioProps['modelValue']) {
  233. data.value = val
  234. }
  235. const wrapper = mount(() => (
  236. <RadioGroup v-model={radio.value} onChange={onChange}>
  237. <RadioButton label={3} ref="radio1">
  238. 3
  239. </RadioButton>
  240. <RadioButton label={6} ref="radio2">
  241. 6
  242. </RadioButton>
  243. <RadioButton label={9}>9</RadioButton>
  244. </RadioGroup>
  245. ))
  246. const radio2 = wrapper.findAll('.el-radio-button').at(1)
  247. await radio2?.trigger('click')
  248. expect(radio.value).toEqual(6)
  249. })
  250. it('change event only triggers on user input', async () => {
  251. const radio = ref(3)
  252. const data = ref<RadioProps['modelValue']>(0)
  253. function onChange(val: RadioProps['modelValue']) {
  254. data.value = val
  255. }
  256. mount(() => (
  257. <RadioGroup v-model={radio.value} onChange={onChange}>
  258. <RadioButton label={3} ref="radio1">
  259. 3
  260. </RadioButton>
  261. <RadioButton label={6} ref="radio2">
  262. 6
  263. </RadioButton>
  264. <RadioButton label={9}>9</RadioButton>
  265. </RadioGroup>
  266. ))
  267. radio.value = 6
  268. await nextTick()
  269. expect(data.value).toEqual(0)
  270. })
  271. it('size', () => {
  272. const radio = ref(3)
  273. const wrapper = mount(() => (
  274. <RadioGroup v-model={radio.value} size="large">
  275. <RadioButton label={3} ref="radio1">
  276. 3
  277. </RadioButton>
  278. <RadioButton label={6} ref="radio2">
  279. 6
  280. </RadioButton>
  281. <RadioButton label={9}>9</RadioButton>
  282. </RadioGroup>
  283. ))
  284. expect(wrapper.findAll('.el-radio-button--large').length).toBe(3)
  285. })
  286. describe('form item accessibility integration', () => {
  287. test('single radio group in form item', async () => {
  288. const wrapper = mount(() => (
  289. <ElFormItem ref="item" label="Test">
  290. <RadioGroup ref="radioGroup">
  291. <Radio label="Foo" />
  292. <Radio label="Bar" />
  293. </RadioGroup>
  294. </ElFormItem>
  295. ))
  296. await nextTick()
  297. const formItem = await wrapper.findComponent(ElFormItem)
  298. const radioGroup = await wrapper.findComponent(RadioGroup)
  299. const formItemLabel = formItem.find('.el-form-item__label')
  300. expect(formItem.attributes().role).toBeFalsy()
  301. expect(radioGroup.attributes().role).toBe('radiogroup')
  302. expect(formItemLabel.attributes().for).toBe(radioGroup.attributes().id)
  303. expect(formItemLabel.attributes().id).toBe(
  304. radioGroup.attributes()['aria-labelledby']
  305. )
  306. })
  307. test('single radio group in form item, override label', async () => {
  308. const wrapper = mount(() => (
  309. <ElFormItem ref="item" label="Test">
  310. <RadioGroup label="Foo" ref="radioGroup">
  311. <Radio label="Foo" />
  312. <Radio label="Bar" />
  313. </RadioGroup>
  314. </ElFormItem>
  315. ))
  316. await nextTick()
  317. const formItem = await wrapper.findComponent(ElFormItem)
  318. const radioGroup = await wrapper.findComponent(RadioGroup)
  319. const formItemLabel = formItem.find('.el-form-item__label')
  320. expect(formItemLabel.attributes().for).toBe(radioGroup.attributes().id)
  321. expect(radioGroup.attributes().role).toBe('radiogroup')
  322. expect(radioGroup.attributes()['aria-label']).toBe('Foo')
  323. expect(radioGroup.attributes()['aria-labelledby']).toBeFalsy()
  324. })
  325. test('multiple radio groups in form item', async () => {
  326. const wrapper = mount(() => (
  327. <ElFormItem ref="item" label="Test">
  328. <RadioGroup label="Foo" ref="radioGroup1">
  329. <Radio label="Foo" />
  330. <Radio label="Bar" />
  331. </RadioGroup>
  332. <RadioGroup label="Bar" ref="radioGroup2">
  333. <Radio label="Foo" />
  334. <Radio label="Bar" />
  335. </RadioGroup>
  336. </ElFormItem>
  337. ))
  338. await nextTick()
  339. const formItem = await wrapper.findComponent(ElFormItem)
  340. const [radioGroup1, radioGroup2] = await wrapper.findAllComponents(
  341. RadioGroup
  342. )
  343. const formItemLabel = formItem.find('.el-form-item__label')
  344. expect(formItem.attributes().role).toBe('group')
  345. expect(formItem.attributes()['aria-labelledby']).toBe(
  346. formItemLabel.attributes().id
  347. )
  348. expect(radioGroup1.attributes().role).toBe('radiogroup')
  349. expect(radioGroup1.attributes()['aria-label']).toBe('Foo')
  350. expect(radioGroup1.attributes()['aria-labelledby']).toBeFalsy()
  351. expect(radioGroup2.attributes().role).toBe('radiogroup')
  352. expect(radioGroup2.attributes()['aria-label']).toBe('Bar')
  353. expect(radioGroup2.attributes()['aria-labelledby']).toBeFalsy()
  354. })
  355. })
  356. })