quasar 2.12.6 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/api/QField.json +0 -3
  2. package/dist/api/QSelect.json +1 -1
  3. package/dist/api/QTable.json +54 -1
  4. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  5. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  6. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  7. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  10. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  11. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  12. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  13. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  14. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  16. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  17. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  18. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  19. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  20. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  21. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  24. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  25. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  26. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +2 -2
  33. package/dist/icon-set/svg-material-icons-round.umd.prod.js +2 -2
  34. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +2 -2
  35. package/dist/icon-set/svg-material-icons.umd.prod.js +2 -2
  36. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +2 -2
  37. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +2 -2
  38. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +2 -2
  39. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  42. package/dist/icon-set/themify.umd.prod.js +1 -1
  43. package/dist/lang/ar-TN.umd.prod.js +1 -1
  44. package/dist/lang/ar.umd.prod.js +1 -1
  45. package/dist/lang/az-Latn.umd.prod.js +1 -1
  46. package/dist/lang/bg.umd.prod.js +1 -1
  47. package/dist/lang/bn.umd.prod.js +1 -1
  48. package/dist/lang/ca.umd.prod.js +1 -1
  49. package/dist/lang/cs.umd.prod.js +1 -1
  50. package/dist/lang/da.umd.prod.js +1 -1
  51. package/dist/lang/de-CH.umd.prod.js +6 -0
  52. package/dist/lang/de-DE.umd.prod.js +6 -0
  53. package/dist/lang/de.umd.prod.js +1 -1
  54. package/dist/lang/el.umd.prod.js +1 -1
  55. package/dist/lang/en-GB.umd.prod.js +1 -1
  56. package/dist/lang/en-US.umd.prod.js +1 -1
  57. package/dist/lang/eo.umd.prod.js +1 -1
  58. package/dist/lang/es.umd.prod.js +1 -1
  59. package/dist/lang/et.umd.prod.js +1 -1
  60. package/dist/lang/eu.umd.prod.js +1 -1
  61. package/dist/lang/fa-IR.umd.prod.js +1 -1
  62. package/dist/lang/fa.umd.prod.js +1 -1
  63. package/dist/lang/fi.umd.prod.js +1 -1
  64. package/dist/lang/fr.umd.prod.js +1 -1
  65. package/dist/lang/gn.umd.prod.js +1 -1
  66. package/dist/lang/he.umd.prod.js +1 -1
  67. package/dist/lang/hi.umd.prod.js +1 -1
  68. package/dist/lang/hr.umd.prod.js +1 -1
  69. package/dist/lang/hu.umd.prod.js +1 -1
  70. package/dist/lang/id.umd.prod.js +1 -1
  71. package/dist/lang/is.umd.prod.js +1 -1
  72. package/dist/lang/it.umd.prod.js +1 -1
  73. package/dist/lang/ja.umd.prod.js +1 -1
  74. package/dist/lang/kk.umd.prod.js +1 -1
  75. package/dist/lang/km.umd.prod.js +1 -1
  76. package/dist/lang/ko-KR.umd.prod.js +1 -1
  77. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  78. package/dist/lang/lt.umd.prod.js +1 -1
  79. package/dist/lang/lu.umd.prod.js +1 -1
  80. package/dist/lang/lv.umd.prod.js +1 -1
  81. package/dist/lang/mk.umd.prod.js +1 -1
  82. package/dist/lang/ml.umd.prod.js +1 -1
  83. package/dist/lang/mm.umd.prod.js +1 -1
  84. package/dist/lang/ms.umd.prod.js +1 -1
  85. package/dist/lang/my.umd.prod.js +1 -1
  86. package/dist/lang/nb-NO.umd.prod.js +1 -1
  87. package/dist/lang/nl.umd.prod.js +1 -1
  88. package/dist/lang/pl.umd.prod.js +1 -1
  89. package/dist/lang/pt-BR.umd.prod.js +1 -1
  90. package/dist/lang/pt.umd.prod.js +1 -1
  91. package/dist/lang/ro.umd.prod.js +1 -1
  92. package/dist/lang/ru.umd.prod.js +1 -1
  93. package/dist/lang/sk.umd.prod.js +1 -1
  94. package/dist/lang/sl.umd.prod.js +1 -1
  95. package/dist/lang/sm.umd.prod.js +1 -1
  96. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  97. package/dist/lang/sr.umd.prod.js +1 -1
  98. package/dist/lang/sv.umd.prod.js +1 -1
  99. package/dist/lang/ta.umd.prod.js +1 -1
  100. package/dist/lang/th.umd.prod.js +1 -1
  101. package/dist/lang/tr.umd.prod.js +1 -1
  102. package/dist/lang/ug.umd.prod.js +1 -1
  103. package/dist/lang/uk.umd.prod.js +1 -1
  104. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  105. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  106. package/dist/lang/vi.umd.prod.js +1 -1
  107. package/dist/lang/zh-CN.umd.prod.js +1 -1
  108. package/dist/lang/zh-TW.umd.prod.js +1 -1
  109. package/dist/quasar.addon.prod.css +1 -1
  110. package/dist/quasar.addon.rtl.prod.css +1 -1
  111. package/dist/quasar.cjs.prod.js +2 -2
  112. package/dist/quasar.esm.js +122 -48
  113. package/dist/quasar.esm.prod.js +2 -2
  114. package/dist/quasar.prod.css +1 -1
  115. package/dist/quasar.rtl.prod.css +1 -1
  116. package/dist/quasar.sass +1 -1
  117. package/dist/quasar.umd.js +122 -48
  118. package/dist/quasar.umd.prod.js +2 -2
  119. package/dist/types/index.d.ts +13 -3
  120. package/dist/vetur/quasar-attributes.json +1 -1
  121. package/dist/web-types/web-types.json +2 -6
  122. package/lang/de-CH.js +98 -0
  123. package/lang/de-CH.mjs +93 -0
  124. package/lang/de-DE.js +98 -0
  125. package/lang/de-DE.mjs +93 -0
  126. package/lang/index.json +8 -0
  127. package/package.json +4 -3
  128. package/src/components/field/__tests__/QField.cy.js +156 -0
  129. package/src/components/input/use-mask.js +6 -1
  130. package/src/components/scroll-area/QScrollArea.js +16 -1
  131. package/src/components/select/QSelect.js +42 -17
  132. package/src/components/select/QSelect.json +1 -1
  133. package/src/components/select/__tests__/QSelect.cy.js +2 -1
  134. package/src/components/slider/use-slider.js +13 -12
  135. package/src/components/table/QTable.json +38 -1
  136. package/src/components/table/table-sort.js +5 -0
  137. package/src/components/time/QTime.js +16 -3
  138. package/src/components/tree/QTree.js +22 -12
  139. package/src/composables/private/__tests__/FieldWrapper.vue +17 -2
  140. package/src/composables/private/__tests__/use-field.cy.js +334 -137
  141. package/src/composables/private/__tests__/use-validate.cy.js +162 -15
@@ -1,37 +1,113 @@
1
1
  import FieldWrapper from './FieldWrapper.vue'
2
+ import { ref } from 'vue'
3
+ import { vModelAdapter } from '@quasar/quasar-app-extension-testing-e2e-cypress'
4
+ import Icons from '../../../../icon-set/material-icons.mjs'
5
+
6
+ function mountQFieldWrapper (options) {
7
+ return cy.mount(FieldWrapper, options)
8
+ }
9
+
10
+ function getHostElement () {
11
+ return cy.get('.select-root')
12
+ }
13
+
14
+ const selectOptions = [ 'Option 1', 'Option 2' ]
2
15
 
3
16
  describe('use-field API', () => {
4
17
  describe('Props', () => {
5
18
  describe('Category: behavior', () => {
6
19
  describe('(prop): autofocus', () => {
7
- it.skip(' ', () => {
8
- //
20
+ it('should autofocus on component', () => {
21
+ mountQFieldWrapper({
22
+ props: {
23
+ autofocus: true
24
+ }
25
+ })
26
+
27
+ getHostElement()
28
+ .get('.q-field--focused')
29
+ .should('exist')
30
+ .get('input')
31
+ .should('have.focus')
9
32
  })
10
33
  })
11
34
 
12
35
  describe('(prop): for', () => {
13
- it.skip(' ', () => {
14
- //
36
+ it('should set the for attribute for the value and the id of the control', () => {
37
+ const forProp = 'hello-there'
38
+
39
+ mountQFieldWrapper({
40
+ props: {
41
+ for: forProp
42
+ }
43
+ })
44
+
45
+ getHostElement().should('have.attr', 'for', forProp)
46
+ getHostElement().get('input').should('have.id', forProp)
15
47
  })
16
48
  })
17
49
 
18
50
  describe('(prop): name', () => {
19
- it.skip(' ', () => {
20
- //
51
+ it('should use the value of the for prop as control name if name is not set', () => {
52
+ const forProp = 'hello-there'
53
+ const model = ref(selectOptions[ 0 ])
54
+
55
+ mountQFieldWrapper({
56
+ props: {
57
+ ...vModelAdapter(model),
58
+ options: selectOptions,
59
+ for: forProp
60
+ }
61
+ })
62
+
63
+ getHostElement().get('select').should('have.attr', 'name', forProp)
64
+ })
65
+
66
+ it('should set the name of the control', () => {
67
+ const name = 'hello-there'
68
+ const model = ref(selectOptions[ 0 ])
69
+
70
+ mountQFieldWrapper({
71
+ props: {
72
+ ...vModelAdapter(model),
73
+ options: selectOptions,
74
+ name
75
+ }
76
+ })
77
+
78
+ getHostElement().get('select').should('have.attr', 'name', name)
21
79
  })
22
80
  })
23
81
  })
24
82
 
25
83
  describe('Category: behavior|content', () => {
26
84
  describe('(prop): loading', () => {
27
- it.skip(' ', () => {
28
- //
85
+ it('should should set the component into a loading state', () => {
86
+ mountQFieldWrapper({
87
+ props: {
88
+ loading: true
89
+ }
90
+ })
91
+
92
+ getHostElement().get('.q-spinner').should('exist')
29
93
  })
30
94
  })
31
95
 
32
96
  describe('(prop): clearable', () => {
33
- it.skip(' ', () => {
34
- //
97
+ it('should append a clear icon', () => {
98
+ const model = ref(selectOptions[ 0 ])
99
+
100
+ mountQFieldWrapper({
101
+ props: {
102
+ ...vModelAdapter(model),
103
+ clearable: true,
104
+ options: selectOptions
105
+ }
106
+ })
107
+
108
+ getHostElement().find('input').should('exist').should('have.value', model.value)
109
+ getHostElement().get('button[type="button"]').contains(Icons.field.clear).click()
110
+ getHostElement().get('input').should('have.value', '')
35
111
  })
36
112
  })
37
113
  })
@@ -133,102 +209,202 @@ describe('use-field API', () => {
133
209
  })
134
210
 
135
211
  describe('(prop): prefix', () => {
136
- it.skip(' ', () => {
137
- //
212
+ it('should display a prefix', () => {
213
+ const prefix = 'Hello there!'
214
+ mountQFieldWrapper({
215
+ props: {
216
+ prefix
217
+ }
218
+ })
219
+
220
+ getHostElement().get('.q-field__prefix').should('exist').should('contain', prefix)
138
221
  })
139
222
  })
140
223
 
141
224
  describe('(prop): suffix', () => {
142
- it.skip(' ', () => {
143
- //
225
+ it('should display a suffix', () => {
226
+ const suffix = 'Hello there!'
227
+ mountQFieldWrapper({
228
+ props: {
229
+ suffix
230
+ }
231
+ })
232
+
233
+ getHostElement().get('.q-field__suffix').should('exist').should('contain', suffix)
144
234
  })
145
235
  })
146
236
 
147
237
  describe('(prop): clear-icon', () => {
148
- it.skip(' ', () => {
149
- //
238
+ it('should display custom clear-icon when one is set', () => {
239
+ const model = ref(selectOptions[ 0 ])
240
+ const clearIcon = 'custom-clear-icon'
241
+ mountQFieldWrapper({
242
+ props: {
243
+ ...vModelAdapter(model),
244
+ options: selectOptions,
245
+ clearable: true,
246
+ clearIcon
247
+ }
248
+ })
249
+
250
+ getHostElement().get('.q-field__append').get('button').should('contain', clearIcon)
150
251
  })
151
252
  })
152
253
 
153
254
  describe('(prop): label-slot', () => {
154
- it.skip(' ', () => {
155
- //
255
+ it('should force the use of the label slot even when a label prop is set', () => {
256
+ const model = ref(selectOptions[ 0 ])
257
+ const labelSlot = 'Hello world'
258
+
259
+ mountQFieldWrapper({
260
+ props: {
261
+ ...vModelAdapter(model),
262
+ options: selectOptions,
263
+ labelSlot: true,
264
+ label: 'Hello there'
265
+ },
266
+ slots: {
267
+ label: () => labelSlot
268
+ }
269
+ })
270
+
271
+ getHostElement().find('.q-field__label').should('contain.text', labelSlot)
156
272
  })
157
273
  })
158
274
 
159
275
  describe('(prop): bottom-slots', () => {
160
- it.skip(' ', () => {
161
- //
276
+ it('should use a bottom error slot', () => {
277
+ const model = ref(selectOptions[ 0 ])
278
+ const bottomSlot = 'Hello there'
279
+
280
+ mountQFieldWrapper({
281
+ props: {
282
+ ...vModelAdapter(model),
283
+ options: selectOptions,
284
+ bottomSlotSlots: true,
285
+ error: true
286
+ },
287
+ slots: {
288
+ error: () => bottomSlot
289
+ }
290
+ })
291
+
292
+ getHostElement().find('.q-field__bottom')
293
+ .should('contain.text', bottomSlot)
294
+ })
295
+
296
+ it('should use a bottom hint slot', () => {
297
+ const model = ref(selectOptions[ 0 ])
298
+ const bottomSlot = 'Hello there'
299
+
300
+ mountQFieldWrapper({
301
+ props: {
302
+ ...vModelAdapter(model),
303
+ options: selectOptions,
304
+ bottomSlots: true
305
+ },
306
+ slots: {
307
+ hint: () => bottomSlot
308
+ }
309
+ })
310
+
311
+ getHostElement().find('.q-field__bottom').should('contain.text', bottomSlot)
312
+ })
313
+
314
+ it('should use a bottom counter slot', () => {
315
+ const model = ref(selectOptions[ 0 ])
316
+
317
+ mountQFieldWrapper({
318
+ props: {
319
+ ...vModelAdapter(model),
320
+ options: selectOptions,
321
+ counter: true
322
+ }
323
+ })
324
+
325
+ getHostElement().find('.q-field__bottom').should('contain.text', model.value.length)
162
326
  })
163
327
  })
164
328
 
165
329
  describe('(prop): counter', () => {
166
- it.skip(' ', () => {
167
- //
330
+ it('should show an automatic counter on bottom right', () => {
331
+ const model = ref(selectOptions[ 0 ])
332
+ mountQFieldWrapper({
333
+ props: {
334
+ ...vModelAdapter(model),
335
+ options: selectOptions,
336
+ counter: true
337
+ }
338
+ })
339
+
340
+ getHostElement().get('.q-field__counter').should('contain', model.value.length)
168
341
  })
169
342
  })
170
343
  })
171
344
 
172
345
  describe('Category: state', () => {
173
346
  describe('(prop): disable', () => {
174
- it.skip(' ', () => {
175
- //
347
+ it('should put the component on disable state', () => {
348
+ mountQFieldWrapper({
349
+ props: {
350
+ disable: true
351
+ }
352
+ })
353
+
354
+ getHostElement().should('have.class', 'q-field--disabled')
176
355
  })
177
356
  })
178
357
 
179
358
  describe('(prop): readonly', () => {
180
- it.skip(' ', () => {
181
- //
359
+ it('should put the component on readonly state', () => {
360
+ mountQFieldWrapper({
361
+ props: {
362
+ readonly: true
363
+ }
364
+ })
365
+
366
+ getHostElement().should('have.class', 'q-field--readonly')
182
367
  })
183
368
  })
184
369
  })
185
370
 
186
371
  describe('Category: style', () => {
187
372
  describe('(prop): label-color', () => {
188
- it.skip(' ', () => {
189
- //
190
- })
191
- })
373
+ it('should display a label color', () => {
374
+ const label = 'Hello there!'
375
+ mountQFieldWrapper({
376
+ props: {
377
+ label,
378
+ labelColor: 'red'
379
+ }
380
+ })
192
381
 
193
- describe('(prop): color', () => {
194
- it.skip(' ', () => {
195
- //
382
+ getHostElement().get('.q-field__label.text-red').should('contain', label)
196
383
  })
197
384
  })
198
385
 
199
- describe('(prop): bg-color', () => {
200
- it.skip(' ', () => {
201
- //
202
- })
203
- })
204
-
205
- describe('(prop): dark', () => {
206
- it.skip(' ', () => {
207
- //
208
- })
209
- })
386
+ describe('(prop): color', () => {
387
+ it('should set a color on the component', () => {
388
+ mountQFieldWrapper()
389
+ getHostElement().get('.q-field__control.text-red').should('not.exist')
210
390
 
211
- describe('(prop): filled', () => {
212
- it.skip(' ', () => {
213
- //
214
- })
215
- })
391
+ getHostElement().get('input').then(() => {
392
+ Cypress.vueWrapper.setProps({ color: 'red' })
216
393
 
217
- describe('(prop): outlined', () => {
218
- it.skip(' ', () => {
219
- //
394
+ getHostElement().get('.q-field__control.text-red').should('exist')
395
+ })
220
396
  })
221
397
  })
222
398
 
223
- describe('(prop): borderless', () => {
224
- it.skip(' ', () => {
225
- //
226
- })
227
- })
399
+ describe('(prop): bg-color', () => {
400
+ it('should display a background color', () => {
401
+ mountQFieldWrapper({
402
+ props: {
403
+ bgColor: 'red'
404
+ }
405
+ })
228
406
 
229
- describe('(prop): standout', () => {
230
- it.skip(' ', () => {
231
- //
407
+ getHostElement().get('.q-field__control.bg-red').should('exist')
232
408
  })
233
409
  })
234
410
 
@@ -238,112 +414,133 @@ describe('use-field API', () => {
238
414
  })
239
415
  })
240
416
 
241
- describe('(prop): rounded', () => {
242
- it.skip(' ', () => {
243
- //
244
- })
245
- })
417
+ const fieldLooks = [ 'item-aligned', 'dark', 'filled', 'outlined', 'borderless', 'standout', 'rounded', 'square', 'dense' ]
418
+ for (const style of fieldLooks) {
419
+ describe(`(prop): ${ style }`, () => {
420
+ it(`should apply ${ style } design style`, () => {
421
+ mountQFieldWrapper({
422
+ props: {
423
+ [ style ]: true
424
+ }
425
+ })
246
426
 
247
- describe('(prop): square', () => {
248
- it.skip(' ', () => {
249
- //
250
- })
251
- })
252
-
253
- describe('(prop): dense', () => {
254
- it.skip(' ', () => {
255
- //
256
- })
257
- })
258
-
259
- describe('(prop): item-aligned', () => {
260
- it.skip(' ', () => {
261
- //
427
+ getHostElement().get(`.q-field--${ style }`).should('exist')
428
+ })
262
429
  })
263
- })
430
+ }
264
431
  })
265
432
  })
266
433
 
267
434
  describe('Slots', () => {
268
- describe('(slot): default', () => {
269
- it.skip(' ', () => {
270
- //
271
- })
272
- })
273
-
274
- describe('(slot): prepend', () => {
275
- it.skip(' ', () => {
276
- //
277
- })
278
- })
435
+ const slots = [ 'prepend', 'append', 'before', 'after', 'label' ]
279
436
 
280
- describe('(slot): append', () => {
281
- it.skip(' ', () => {
282
- //
283
- })
284
- })
285
-
286
- describe('(slot): before', () => {
287
- it.skip(' ', () => {
288
- //
289
- })
290
- })
291
-
292
- describe('(slot): after', () => {
293
- it.skip(' ', () => {
294
- //
295
- })
296
- })
437
+ describe('(slot): default', () => {
438
+ it('should use the default slot', () => {
439
+ const model = ref(selectOptions[ 0 ])
440
+ const labelSlot = 'Hello world'
297
441
 
298
- describe('(slot): label', () => {
299
- it.skip(' ', () => {
300
- //
301
- })
302
- })
442
+ mountQFieldWrapper({
443
+ props: {
444
+ ...vModelAdapter(model),
445
+ options: selectOptions,
446
+ labelSlot: true
447
+ },
448
+ slots: {
449
+ default: () => labelSlot
450
+ }
451
+ })
303
452
 
304
- describe('(slot): error', () => {
305
- it.skip(' ', () => {
306
- //
453
+ getHostElement().should('contain.text', labelSlot)
307
454
  })
308
455
  })
309
456
 
310
- describe('(slot): hint', () => {
311
- it.skip(' ', () => {
312
- //
313
- })
314
- })
457
+ for (const slot of slots) {
458
+ describe(`(slot): ${ slot }`, () => {
459
+ it(`should append a '${ slot }' slot`, () => {
460
+ const model = ref(selectOptions[ 0 ])
461
+ const labelSlot = 'Hello world'
315
462
 
316
- describe('(slot): counter', () => {
317
- it.skip(' ', () => {
318
- //
319
- })
320
- })
463
+ mountQFieldWrapper({
464
+ props: {
465
+ ...vModelAdapter(model),
466
+ options: selectOptions,
467
+ labelSlot: true
468
+ },
469
+ slots: {
470
+ [ slot ]: () => labelSlot
471
+ }
472
+ })
321
473
 
322
- describe('(slot): loading', () => {
323
- it.skip(' ', () => {
324
- //
474
+ getHostElement().get(`.q-field__${ slot }`).should('contain.text', labelSlot)
475
+ })
325
476
  })
326
- })
477
+ }
327
478
  })
328
479
 
329
480
  describe('Events', () => {
330
481
  describe('(event): clear', () => {
331
- it.skip(' ', () => {
332
- //
482
+ it('should emit the clear event when the clear button is clicked', () => {
483
+ const model = ref(selectOptions[ 0 ])
484
+ const fn = cy.stub()
485
+
486
+ mountQFieldWrapper({
487
+ props: {
488
+ ...vModelAdapter(model),
489
+ clearable: true,
490
+ options: selectOptions,
491
+ onClear: fn
492
+ }
493
+ })
494
+
495
+ getHostElement().get('button[type="button"]')
496
+ .contains(Icons.field.clear).click()
497
+ .then(() => {
498
+ expect(fn).to.be.calledWith()
499
+ })
333
500
  })
334
501
  })
335
502
  })
336
503
 
337
504
  describe('Methods', () => {
338
505
  describe('(method): focus', () => {
339
- it.skip(' ', () => {
340
- //
506
+ it('should focus the component', () => {
507
+ mountQFieldWrapper()
508
+
509
+ getHostElement()
510
+ .get('input')
511
+ .should('not.have.focus')
512
+ getHostElement()
513
+ .then(() => {
514
+ Cypress.vueWrapper.vm.focusMethod()
515
+ })
516
+ getHostElement()
517
+ .get('input')
518
+ .should('have.focus')
341
519
  })
342
520
  })
343
521
 
344
522
  describe('(method): blur', () => {
345
- it.skip(' ', () => {
346
- //
523
+ it('should blur the component', () => {
524
+ mountQFieldWrapper()
525
+
526
+ getHostElement()
527
+ .get('input').focus()
528
+ getHostElement()
529
+ .get('.q-field--focused')
530
+ .as('focused-element')
531
+ .should('exist')
532
+
533
+ cy.get('@focused-element')
534
+ .get('input')
535
+ .should('have.focus')
536
+
537
+ getHostElement()
538
+ .then(() => {
539
+ Cypress.vueWrapper.vm.blur()
540
+ })
541
+
542
+ cy.get('@focused-element').should('not.exist')
543
+ getHostElement().get('input').should('not.have.focus')
347
544
  })
348
545
  })
349
546
  })