quasar 2.12.3 → 2.12.5

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 (211) hide show
  1. package/dist/api/Dialog.json +4 -0
  2. package/dist/api/Loading.json +20 -1
  3. package/dist/api/Notify.json +70 -4
  4. package/dist/api/QAjaxBar.json +2 -0
  5. package/dist/api/QAvatar.json +4 -0
  6. package/dist/api/QBadge.json +4 -0
  7. package/dist/api/QBreadcrumbs.json +4 -0
  8. package/dist/api/QBtn.json +4 -0
  9. package/dist/api/QBtnDropdown.json +4 -0
  10. package/dist/api/QBtnToggle.json +8 -0
  11. package/dist/api/QCarousel.json +4 -0
  12. package/dist/api/QChatMessage.json +4 -0
  13. package/dist/api/QCheckbox.json +2 -0
  14. package/dist/api/QChip.json +4 -0
  15. package/dist/api/QCircularProgress.json +6 -0
  16. package/dist/api/QDate.json +4 -0
  17. package/dist/api/QEditor.json +4 -0
  18. package/dist/api/QFab.json +4 -0
  19. package/dist/api/QFabAction.json +4 -0
  20. package/dist/api/QField.json +6 -0
  21. package/dist/api/QFile.json +6 -0
  22. package/dist/api/QIcon.json +2 -0
  23. package/dist/api/QImg.json +2 -0
  24. package/dist/api/QInnerLoading.json +2 -0
  25. package/dist/api/QInput.json +6 -0
  26. package/dist/api/QKnob.json +6 -0
  27. package/dist/api/QLayout.json +1 -1
  28. package/dist/api/QLinearProgress.json +4 -0
  29. package/dist/api/QOptionGroup.json +2 -0
  30. package/dist/api/QPagination.json +8 -0
  31. package/dist/api/QPopupEdit.json +2 -0
  32. package/dist/api/QPullToRefresh.json +4 -0
  33. package/dist/api/QRadio.json +2 -0
  34. package/dist/api/QRange.json +26 -0
  35. package/dist/api/QRating.json +6 -0
  36. package/dist/api/QSelect.json +6 -0
  37. package/dist/api/QSeparator.json +2 -0
  38. package/dist/api/QSlideItem.json +8 -0
  39. package/dist/api/QSlider.json +14 -0
  40. package/dist/api/QSpinner.json +2 -0
  41. package/dist/api/QSpinnerAudio.json +2 -0
  42. package/dist/api/QSpinnerBall.json +2 -0
  43. package/dist/api/QSpinnerBars.json +2 -0
  44. package/dist/api/QSpinnerBox.json +2 -0
  45. package/dist/api/QSpinnerClock.json +2 -0
  46. package/dist/api/QSpinnerComment.json +2 -0
  47. package/dist/api/QSpinnerCube.json +2 -0
  48. package/dist/api/QSpinnerDots.json +2 -0
  49. package/dist/api/QSpinnerFacebook.json +2 -0
  50. package/dist/api/QSpinnerGears.json +2 -0
  51. package/dist/api/QSpinnerGrid.json +2 -0
  52. package/dist/api/QSpinnerHearts.json +2 -0
  53. package/dist/api/QSpinnerHourglass.json +2 -0
  54. package/dist/api/QSpinnerInfinity.json +2 -0
  55. package/dist/api/QSpinnerIos.json +2 -0
  56. package/dist/api/QSpinnerOrbit.json +2 -0
  57. package/dist/api/QSpinnerOval.json +2 -0
  58. package/dist/api/QSpinnerPie.json +2 -0
  59. package/dist/api/QSpinnerPuff.json +2 -0
  60. package/dist/api/QSpinnerRadio.json +2 -0
  61. package/dist/api/QSpinnerRings.json +2 -0
  62. package/dist/api/QSpinnerTail.json +2 -0
  63. package/dist/api/QStep.json +8 -0
  64. package/dist/api/QStepper.json +8 -0
  65. package/dist/api/QTable.json +20 -0
  66. package/dist/api/QTabs.json +6 -0
  67. package/dist/api/QTime.json +4 -0
  68. package/dist/api/QTimeline.json +2 -0
  69. package/dist/api/QTimelineEntry.json +2 -0
  70. package/dist/api/QToggle.json +4 -0
  71. package/dist/api/QTree.json +8 -0
  72. package/dist/api/QUploader.json +4 -0
  73. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  74. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  75. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  76. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  77. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  78. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  79. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  80. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  81. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  82. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  83. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  84. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  85. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  86. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  87. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  88. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  89. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  90. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  91. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  92. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  93. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  94. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  95. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  96. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  97. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  98. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  99. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  100. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  101. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  102. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  103. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  104. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  105. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  106. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  107. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  108. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  109. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  110. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  111. package/dist/icon-set/themify.umd.prod.js +1 -1
  112. package/dist/lang/ar-TN.umd.prod.js +1 -1
  113. package/dist/lang/ar.umd.prod.js +1 -1
  114. package/dist/lang/az-Latn.umd.prod.js +1 -1
  115. package/dist/lang/bg.umd.prod.js +1 -1
  116. package/dist/lang/bn.umd.prod.js +1 -1
  117. package/dist/lang/ca.umd.prod.js +1 -1
  118. package/dist/lang/cs.umd.prod.js +1 -1
  119. package/dist/lang/da.umd.prod.js +1 -1
  120. package/dist/lang/de.umd.prod.js +1 -1
  121. package/dist/lang/el.umd.prod.js +1 -1
  122. package/dist/lang/en-GB.umd.prod.js +1 -1
  123. package/dist/lang/en-US.umd.prod.js +1 -1
  124. package/dist/lang/eo.umd.prod.js +1 -1
  125. package/dist/lang/es.umd.prod.js +1 -1
  126. package/dist/lang/et.umd.prod.js +1 -1
  127. package/dist/lang/eu.umd.prod.js +1 -1
  128. package/dist/lang/fa-IR.umd.prod.js +1 -1
  129. package/dist/lang/fa.umd.prod.js +1 -1
  130. package/dist/lang/fi.umd.prod.js +1 -1
  131. package/dist/lang/fr.umd.prod.js +1 -1
  132. package/dist/lang/gn.umd.prod.js +1 -1
  133. package/dist/lang/he.umd.prod.js +1 -1
  134. package/dist/lang/hi.umd.prod.js +6 -0
  135. package/dist/lang/hr.umd.prod.js +1 -1
  136. package/dist/lang/hu.umd.prod.js +1 -1
  137. package/dist/lang/id.umd.prod.js +1 -1
  138. package/dist/lang/is.umd.prod.js +1 -1
  139. package/dist/lang/it.umd.prod.js +1 -1
  140. package/dist/lang/ja.umd.prod.js +1 -1
  141. package/dist/lang/kk.umd.prod.js +1 -1
  142. package/dist/lang/km.umd.prod.js +1 -1
  143. package/dist/lang/ko-KR.umd.prod.js +1 -1
  144. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  145. package/dist/lang/lt.umd.prod.js +1 -1
  146. package/dist/lang/lu.umd.prod.js +1 -1
  147. package/dist/lang/lv.umd.prod.js +1 -1
  148. package/dist/lang/mk.umd.prod.js +1 -1
  149. package/dist/lang/ml.umd.prod.js +1 -1
  150. package/dist/lang/mm.umd.prod.js +1 -1
  151. package/dist/lang/ms.umd.prod.js +1 -1
  152. package/dist/lang/my.umd.prod.js +1 -1
  153. package/dist/lang/nb-NO.umd.prod.js +1 -1
  154. package/dist/lang/nl.umd.prod.js +1 -1
  155. package/dist/lang/pl.umd.prod.js +1 -1
  156. package/dist/lang/pt-BR.umd.prod.js +1 -1
  157. package/dist/lang/pt.umd.prod.js +1 -1
  158. package/dist/lang/ro.umd.prod.js +1 -1
  159. package/dist/lang/ru.umd.prod.js +1 -1
  160. package/dist/lang/sk.umd.prod.js +1 -1
  161. package/dist/lang/sl.umd.prod.js +1 -1
  162. package/dist/lang/sm.umd.prod.js +1 -1
  163. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  164. package/dist/lang/sr.umd.prod.js +1 -1
  165. package/dist/lang/sv.umd.prod.js +1 -1
  166. package/dist/lang/ta.umd.prod.js +1 -1
  167. package/dist/lang/th.umd.prod.js +1 -1
  168. package/dist/lang/tr.umd.prod.js +1 -1
  169. package/dist/lang/ug.umd.prod.js +1 -1
  170. package/dist/lang/uk.umd.prod.js +1 -1
  171. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  172. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  173. package/dist/lang/vi.umd.prod.js +1 -1
  174. package/dist/lang/zh-CN.umd.prod.js +1 -1
  175. package/dist/lang/zh-TW.umd.prod.js +1 -1
  176. package/dist/quasar.cjs.prod.js +2 -2
  177. package/dist/quasar.css +5 -8
  178. package/dist/quasar.esm.js +22 -19
  179. package/dist/quasar.esm.prod.js +2 -2
  180. package/dist/quasar.prod.css +1 -1
  181. package/dist/quasar.rtl.css +5 -8
  182. package/dist/quasar.rtl.prod.css +1 -1
  183. package/dist/quasar.sass +5 -4
  184. package/dist/quasar.umd.js +22 -19
  185. package/dist/quasar.umd.prod.js +2 -2
  186. package/dist/transforms/api-list.json +2 -2
  187. package/dist/types/api/color.d.ts +51 -0
  188. package/dist/types/api.d.ts +1 -0
  189. package/dist/types/index.d.ts +240 -219
  190. package/dist/types/utils/colors.d.ts +5 -3
  191. package/dist/types/utils/patterns.d.ts +10 -0
  192. package/dist/types/utils.d.ts +8 -3
  193. package/dist/web-types/web-types.json +138 -138
  194. package/lang/hi.js +98 -0
  195. package/lang/hi.mjs +93 -0
  196. package/lang/index.json +4 -0
  197. package/package.json +2 -2
  198. package/src/api.extends.json +4 -2
  199. package/src/components/input/__tests__/QInput.cy.js +707 -26
  200. package/src/components/input/__tests__/use-mask.cy.js +101 -6
  201. package/src/components/input/use-mask.js +4 -1
  202. package/src/components/layout/QLayout.json +1 -1
  203. package/src/components/select/QSelect.js +2 -2
  204. package/src/components/spinner/QSpinnerComment.js +1 -1
  205. package/src/components/spinner/QSpinnerCube.js +5 -5
  206. package/src/components/spinner/QSpinnerFacebook.js +3 -3
  207. package/src/components/spinner/QSpinnerHourglass.js +2 -2
  208. package/src/css/normalize.sass +5 -9
  209. package/src/plugins/Loading.json +2 -1
  210. package/src/plugins/Notify.json +45 -4
  211. package/src/utils/EventBus.js +2 -2
@@ -1,57 +1,669 @@
1
+ import QInput from '../QInput'
2
+ import { ref } from 'vue'
3
+ import { vModelAdapter } from '@quasar/quasar-app-extension-testing-e2e-cypress'
4
+
5
+ function getHostElement () {
6
+ return cy.get('.q-field')
7
+ }
8
+
9
+ function mountQInput (options) {
10
+ return cy.mount(QInput, options)
11
+ }
12
+
1
13
  describe('Input API', () => {
2
14
  describe('Props', () => {
15
+ describe('Category: behaviour', () => {
16
+ describe('(prop): error', () => {
17
+ it('should mark the field as having an error', () => {
18
+ mountQInput()
19
+ getHostElement().should('not.have.class', 'q-field--error')
20
+
21
+ mountQInput({
22
+ props: {
23
+ error: true
24
+ }
25
+ })
26
+
27
+ getHostElement().should('have.class', 'q-field--error')
28
+ })
29
+ })
30
+
31
+ describe('(prop): rules', () => {
32
+ it('should validate value using custom validation logic', () => {
33
+ const errorMessage = 'Use a max 3 of characters'
34
+ const model = ref('')
35
+ mountQInput({
36
+ props: {
37
+ ...vModelAdapter(model),
38
+ rules: [ val => val.length <= 3 || errorMessage ]
39
+ }
40
+ })
41
+ getHostElement().get('input').type('1234')
42
+ getHostElement().get('.q-field__messages').should('contain', errorMessage)
43
+ })
44
+
45
+ it('should validate email using inbuilt validation logic', () => {
46
+ const errorMessage = 'Enter a valid email address'
47
+ const model = ref('')
48
+ mountQInput({
49
+ props: {
50
+ ...vModelAdapter(model),
51
+ rules: [ (val, rules) => rules.email(val) || errorMessage ]
52
+ }
53
+ })
54
+ getHostElement().get('input').type('1234')
55
+ getHostElement().get('.q-field__messages').should('contain', errorMessage)
56
+ })
57
+ })
58
+
59
+ describe('(prop): loading', () => {
60
+ it('should should set the component into a loading state', () => {
61
+ mountQInput({
62
+ props: {
63
+ loading: true
64
+ }
65
+ })
66
+
67
+ getHostElement().get('.q-spinner').should('exist')
68
+ })
69
+ })
70
+
71
+ describe('(prop): clearable', () => {
72
+ it('should append a cancel icon', () => {
73
+ const model = ref('')
74
+
75
+ mountQInput({
76
+ props: {
77
+ ...vModelAdapter(model),
78
+ clearable: true
79
+ }
80
+ })
81
+
82
+ getHostElement().get('input').type('1')
83
+ getHostElement().get('button').should('exist').should('contain', 'cancel')
84
+ })
85
+ })
86
+
87
+ describe('(prop): autofocus', () => {
88
+ it('should autofocus on component', () => {
89
+ mountQInput({
90
+ props: {
91
+ autofocus: true
92
+ }
93
+ })
94
+
95
+ getHostElement()
96
+ .get('.q-field--focused')
97
+ .should('exist')
98
+ .get('input')
99
+ .should('have.focus')
100
+ })
101
+ })
102
+
103
+ describe('(prop): lazy-rules', () => {
104
+ it('should validate the input only when component loses focus', () => {
105
+ const errorMessage = 'Use a max 3 of characters'
106
+ const model = ref('')
107
+ mountQInput({
108
+ props: {
109
+ ...vModelAdapter(model),
110
+ rules: [ val => val.length <= 3 || errorMessage ],
111
+ lazyRules: true
112
+ }
113
+ })
114
+
115
+ getHostElement().get('input').type('1234')
116
+ getHostElement().get('.q-field__messages').should('not.contain', errorMessage)
117
+
118
+ getHostElement().get('input').then(() => {
119
+ Cypress.vueWrapper.vm.blur()
120
+ getHostElement().get('.q-field__messages').should('contain', errorMessage)
121
+ })
122
+ })
123
+
124
+ it('should validate the input only when component\'s validate() method is called', () => {
125
+ const errorMessage = 'Use a max 3 of characters'
126
+ const model = ref('')
127
+ mountQInput({
128
+ props: {
129
+ ...vModelAdapter(model),
130
+ rules: [ val => val.length <= 3 || errorMessage ],
131
+ lazyRules: 'ondemand'
132
+ }
133
+ })
134
+
135
+ getHostElement().get('input').type('1234')
136
+ getHostElement().get('.q-field__messages').should('not.contain', errorMessage)
137
+
138
+ getHostElement().get('input').then(() => {
139
+ Cypress.vueWrapper.vm.blur()
140
+ getHostElement().get('.q-field__messages').should('not.contain', errorMessage)
141
+ Cypress.vueWrapper.vm.validate()
142
+ getHostElement().get('.q-field__messages').should('contain', errorMessage)
143
+ })
144
+ })
145
+ })
146
+ })
147
+
3
148
  describe('Category: content', () => {
149
+ describe('(prop): error-message', () => {
150
+ it('should display validation error message if error = true', () => {
151
+ const errorMessage = 'Username must have at least 3 characters'
152
+ mountQInput({
153
+ props: {
154
+ errorMessage
155
+ }
156
+ })
157
+ getHostElement().should('not.contain', errorMessage)
158
+
159
+ mountQInput({
160
+ props: {
161
+ error: true,
162
+ errorMessage
163
+ }
164
+ })
165
+ getHostElement().should('contain', errorMessage)
166
+ })
167
+ })
168
+
169
+ describe('(prop): no-error-icon', () => {
170
+ it('should hide error icon when there is an error', () => {
171
+ mountQInput({
172
+ props: {
173
+ error: true,
174
+ errorMessage: 'error message'
175
+ }
176
+ })
177
+
178
+ getHostElement().get('.q-field__append .q-icon').should('contain', 'error')
179
+
180
+ mountQInput({
181
+ props: {
182
+ error: true,
183
+ errorMessage: 'error message',
184
+ noErrorIcon: true
185
+ }
186
+ })
187
+
188
+ getHostElement().get('.q-field__append .q-icon').should('not.exist')
189
+ })
190
+ })
191
+
192
+ describe('(prop): label', () => {
193
+ it('should display the label set', () => {
194
+ const label = 'Hello there!'
195
+
196
+ mountQInput({
197
+ props: {
198
+ label
199
+ }
200
+ })
201
+
202
+ getHostElement().get('.q-field__label').should('contain', label)
203
+ })
204
+ })
205
+
206
+ describe('(prop): stack-label', () => {
207
+ it('should stack label', () => {
208
+ const label = 'Hello there!'
209
+ mountQInput({
210
+ props: {
211
+ label
212
+ }
213
+ })
214
+ getHostElement().should('not.have.class', 'q-field--float')
215
+
216
+ mountQInput({
217
+ props: {
218
+ label,
219
+ stackLabel: true
220
+ }
221
+ })
222
+
223
+ getHostElement().should('have.class', 'q-field--float')
224
+ })
225
+ })
226
+
227
+ describe('(prop): hint', () => {
228
+ it('should display the hint message', () => {
229
+ const hint = 'hint message'
230
+ mountQInput({
231
+ props: {
232
+ hint
233
+ }
234
+ })
235
+
236
+ getHostElement().get('.q-field__messages').should('contain', hint)
237
+ })
238
+ })
239
+
240
+ describe('(prop): hide-hint', () => {
241
+ it('should hide hint when element is not focused', () => {
242
+ const hint = 'hint message'
243
+ mountQInput({
244
+ props: {
245
+ hint,
246
+ hideHint: true
247
+ }
248
+ })
249
+ getHostElement().get('.q-field__messages').should('not.contain', hint)
250
+
251
+ getHostElement().get('input').then(() => {
252
+ Cypress.vueWrapper.vm.focus()
253
+ getHostElement().get('.q-field__messages').should('contain', hint)
254
+ })
255
+ })
256
+ })
257
+
258
+ describe('(prop): prefix', () => {
259
+ it('should display a prefix', () => {
260
+ const prefix = 'Hello there!'
261
+ mountQInput({
262
+ props: {
263
+ prefix
264
+ }
265
+ })
266
+
267
+ getHostElement().get('.q-field__prefix').should('exist').should('contain', prefix)
268
+ })
269
+ })
270
+
271
+ describe('(prop): suffix', () => {
272
+ it('should display a suffix', () => {
273
+ const suffix = 'Hello there!'
274
+ mountQInput({
275
+ props: {
276
+ suffix
277
+ }
278
+ })
279
+
280
+ getHostElement().get('.q-field__suffix').should('exist').should('contain', suffix)
281
+ })
282
+ })
283
+
284
+ describe('(prop): clear-icon', () => {
285
+ it('should display custom clear-icon when one is set', () => {
286
+ const model = ref('')
287
+ const clearIcon = 'custom-clear-icon'
288
+ mountQInput({
289
+ props: {
290
+ ...vModelAdapter(model),
291
+ clearable: true,
292
+ clearIcon
293
+ }
294
+ })
295
+
296
+ getHostElement().get('input').type('123')
297
+ getHostElement().get('.q-field__append').get('button').should('contain', clearIcon)
298
+ })
299
+ })
300
+
301
+ describe('(prop): label-slot', () => {
302
+ it('should force use the label slot when a label is not set', () => {
303
+ const labelSlot = 'Hello there'
304
+ mountQInput({
305
+ props: {
306
+ labelSlot: true
307
+ },
308
+ slots: {
309
+ label: () => labelSlot
310
+ }
311
+ })
312
+
313
+ getHostElement().get('.q-field__label').should('contain', labelSlot)
314
+ })
315
+ })
316
+
317
+ describe('(prop): counter', () => {
318
+ it('should show an automatic counter on bottom right', () => {
319
+ const model = ref('')
320
+ mountQInput({
321
+ props: {
322
+ ...vModelAdapter(model),
323
+ counter: true
324
+ }
325
+ })
326
+
327
+ const value = '1234'
328
+ getHostElement().get('input').type(value)
329
+ getHostElement().get('.q-field__counter').should('contain', value.length)
330
+ })
331
+ })
332
+
4
333
  describe('(prop): shadow-text', () => {
5
- it.skip(' ', () => {
6
- //
334
+ it('should render shadow-text', () => {
335
+ const shadowText = 'Shadow Text'
336
+
337
+ mountQInput({
338
+ props: {
339
+ shadowText
340
+ }
341
+ })
342
+
343
+ getHostElement().get('.q-field__shadow').should('exist').contains(shadowText)
7
344
  })
8
345
  })
9
346
 
10
347
  describe('(prop): autogrow', () => {
11
- it.skip(' ', () => {
12
- //
348
+ it('should use textarea for input field', () => {
349
+ mountQInput()
350
+ getHostElement().get('textarea').should('not.exist').get('input').should('exist')
351
+
352
+ mountQInput({
353
+ props: {
354
+ autogrow: true
355
+ }
356
+ })
357
+
358
+ getHostElement().get('textarea').should('exist')
359
+ getHostElement().get('input').should('not.exist')
13
360
  })
14
361
  })
15
362
  })
16
363
 
17
364
  describe('Category: general', () => {
18
365
  describe('(prop): type', () => {
19
- it.skip(' ', () => {
20
- //
366
+ it('should render an input text type by default', () => {
367
+ mountQInput()
368
+
369
+ getHostElement().get('input[type=text]').should('exist')
370
+ })
371
+
372
+ it('should render with the appropriate type set', () => {
373
+ const types = [ 'text', 'password', 'email', 'search', 'tel', 'file', 'number', 'url', 'time', 'date' ]
374
+
375
+ types.forEach((type) => {
376
+ mountQInput({
377
+ props: {
378
+ type
379
+ }
380
+ })
381
+
382
+ getHostElement().get(`input[type="${ type }"]`).should('exist')
383
+ })
384
+
385
+ mountQInput({
386
+ props: {
387
+ type: 'textarea'
388
+ }
389
+ })
390
+
391
+ getHostElement().get('input').should('not.exist').get('textarea').should('exist')
21
392
  })
22
393
  })
23
394
  })
24
395
 
25
396
  describe('Category: model', () => {
26
397
  describe('(prop): model-value', () => {
27
- it.skip(' ', () => {
28
- //
398
+ it('should render with the correct model value', () => {
399
+ const model = ref('Input Model Value')
400
+ mountQInput()
401
+ getHostElement().get('input').should('not.have.value', model.value)
402
+
403
+ mountQInput({
404
+ props: {
405
+ modelValue: model.value
406
+ }
407
+ })
408
+
409
+ getHostElement().get('input').should('have.value', model.value)
29
410
  })
30
411
  })
31
412
 
32
413
  describe('(prop): debounce', () => {
33
- it.skip(' ', () => {
34
- //
414
+ it('should no input debounce by default', () => {
415
+ const fn = cy.stub()
416
+ const text = 'Hello there'
417
+ mountQInput({
418
+ props: {
419
+ 'onUpdate:modelValue': fn
420
+ }
421
+ })
422
+ getHostElement()
423
+ .get('input')
424
+ .type(text)
425
+ .then(() => {
426
+ expect(fn).to.be.calledWith(text)
427
+ })
428
+ })
429
+
430
+ it('should use a custom input-debounce', () => {
431
+ const fn = cy.stub()
432
+ const text = 'Hello there'
433
+ mountQInput({
434
+ props: {
435
+ 'onUpdate:modelValue': fn,
436
+ debounce: 800
437
+ }
438
+ })
439
+ getHostElement()
440
+ .get('input')
441
+ .type(text)
442
+ .wait(500)
443
+ .then(() => {
444
+ expect(fn).not.to.be.calledWith(text)
445
+ })
446
+ .wait(300)
447
+ .then(() => {
448
+ expect(fn).to.be.calledWith(text)
449
+ })
35
450
  })
36
451
  })
37
452
 
38
453
  describe('(prop): maxlength', () => {
39
- it.skip(' ', () => {
40
- //
454
+ it('should respect the maxLength specified', () => {
455
+ mountQInput()
456
+ getHostElement()
457
+ .get('input')
458
+ .type('1234567890abcdefghij')
459
+ .should('have.value', '1234567890abcdefghij')
460
+
461
+ mountQInput({
462
+ props: {
463
+ maxlength: 10
464
+ }
465
+ })
466
+
467
+ getHostElement()
468
+ .get('input')
469
+ .type('1234567890abcdefghij')
470
+ .should('have.value', '1234567890')
41
471
  })
42
472
  })
43
473
  })
44
474
 
45
475
  describe('Category: style', () => {
46
476
  describe('(prop): input-class', () => {
47
- it.skip(' ', () => {
48
- //
477
+ it('should apply the input class to the underlying element', () => {
478
+ mountQInput()
479
+ getHostElement().get('input.input-class').should('not.exist')
480
+
481
+ mountQInput({
482
+ props: {
483
+ inputClass: 'input-class'
484
+ }
485
+ })
486
+
487
+ getHostElement().get('input.input-class').should('exist')
488
+ })
489
+
490
+ it('should apply the input class specified as an object', () => {
491
+ mountQInput({
492
+ props: {
493
+ inputClass: { 'input-class': true }
494
+ }
495
+ })
496
+
497
+ getHostElement().get('input.input-class').should('exist')
49
498
  })
50
499
  })
51
500
 
52
501
  describe('(prop): input-style', () => {
53
- it.skip(' ', () => {
54
- //
502
+ it('should set input-style as string', () => {
503
+ mountQInput({
504
+ props: {
505
+ inputStyle: 'background-color: red'
506
+ }
507
+ })
508
+
509
+ getHostElement().get('input[style="background-color: red;"]').should('exist')
510
+ })
511
+
512
+ it('should set input-style as an object', () => {
513
+ mountQInput({
514
+ props: {
515
+ inputStyle: { backgroundColor: 'red' }
516
+ }
517
+ })
518
+
519
+ getHostElement().get('input[style="background-color: red;"]').should('exist')
520
+ })
521
+ })
522
+
523
+ describe('(prop): label-color', () => {
524
+ it('should display a label color', () => {
525
+ const label = 'Hello there!'
526
+ mountQInput({
527
+ props: {
528
+ label,
529
+ labelColor: 'red'
530
+ }
531
+ })
532
+
533
+ getHostElement().get('.q-field__label.text-red').should('contain', label)
534
+ })
535
+ })
536
+
537
+ describe('(prop): color', () => {
538
+ it('should set a color on the component', () => {
539
+ mountQInput()
540
+ getHostElement().get('.q-field__control.text-red').should('not.exist')
541
+ mountQInput({
542
+ props: {
543
+ color: 'red'
544
+ }
545
+ })
546
+
547
+ getHostElement().get('input').then(() => {
548
+ Cypress.vueWrapper.vm.focus()
549
+ getHostElement().get('.q-field__control.text-red').should('exist')
550
+ })
551
+ })
552
+ })
553
+
554
+ describe('(prop): bg-color', () => {
555
+ it('should display a background color', () => {
556
+ mountQInput({
557
+ props: {
558
+ bgColor: 'red'
559
+ }
560
+ })
561
+
562
+ getHostElement().get('.q-field__control.bg-red').should('exist')
563
+ })
564
+ })
565
+
566
+ describe('(prop): filled', () => {
567
+ it('should use a filled design', () => {
568
+ mountQInput({
569
+ props: {
570
+ filled: true
571
+ }
572
+ })
573
+
574
+ getHostElement().get('.q-field--filled').should('exist')
575
+ })
576
+ })
577
+
578
+ describe('(prop): outlined', () => {
579
+ it('should use a outlined design', () => {
580
+ mountQInput({
581
+ props: {
582
+ outlined: true
583
+ }
584
+ })
585
+
586
+ getHostElement().get('.q-field--outlined').should('exist')
587
+ })
588
+ })
589
+
590
+ describe('(prop): borderless', () => {
591
+ it('should use a borderless design', () => {
592
+ mountQInput({
593
+ props: {
594
+ borderless: true
595
+ }
596
+ })
597
+
598
+ getHostElement().get('.q-field--borderless').should('exist')
599
+ })
600
+ })
601
+
602
+ describe('(prop): standout', () => {
603
+ it('should display a standout color', () => {
604
+ mountQInput({
605
+ props: {
606
+ standout: true
607
+ }
608
+ })
609
+
610
+ getHostElement().get('.q-field--standout').should('exist')
611
+ })
612
+ })
613
+
614
+ describe('(prop): hide-bottom-space', () => {
615
+ it('should hide bottom space', () => {
616
+ mountQInput({
617
+ props: {
618
+ rules: [ (value) => !!value || '' ]
619
+ }
620
+ })
621
+ getHostElement().get('.q-field__messages').should('exist')
622
+
623
+ mountQInput({
624
+ props: {
625
+ rules: [ (value) => !!value || '' ],
626
+ hideBottomSpace: true
627
+ }
628
+ })
629
+
630
+ getHostElement().get('.q-field__messages').should('not.exist')
631
+ })
632
+ })
633
+
634
+ describe('(prop): rounded', () => {
635
+ it('should use a rounded design', () => {
636
+ mountQInput({
637
+ props: {
638
+ rounded: true
639
+ }
640
+ })
641
+
642
+ getHostElement().get('.q-field--rounded').should('exist')
643
+ })
644
+ })
645
+
646
+ describe('(prop): square', () => {
647
+ it('should use a square design', () => {
648
+ mountQInput({
649
+ props: {
650
+ square: true
651
+ }
652
+ })
653
+
654
+ getHostElement().get('.q-field--square').should('exist')
655
+ })
656
+ })
657
+
658
+ describe('(prop): dense', () => {
659
+ it('should use a dense design', () => {
660
+ mountQInput({
661
+ props: {
662
+ dense: true
663
+ }
664
+ })
665
+
666
+ getHostElement().get('.q-field--dense').should('exist')
55
667
  })
56
668
  })
57
669
  })
@@ -59,34 +671,103 @@ describe('Input API', () => {
59
671
 
60
672
  describe('Events', () => {
61
673
  describe('(event): update:model-value', () => {
62
- it.skip(' ', () => {
63
- //
674
+ it('should emit onUpdate:modelValue event', () => {
675
+ const fn = cy.stub()
676
+ const text = 'Hello there'
677
+ mountQInput({
678
+ props: {
679
+ 'onUpdate:modelValue': fn
680
+ }
681
+ })
682
+ getHostElement()
683
+ .get('input')
684
+ .type(text)
685
+ .then(() => {
686
+ expect(fn).to.be.calledWith(text)
687
+ })
64
688
  })
65
689
  })
66
690
 
67
691
  describe('(event): focus', () => {
68
- it.skip(' ', () => {
69
- //
692
+ it('should emit focus event', () => {
693
+ const fn = cy.stub()
694
+ mountQInput({
695
+ props: {
696
+ onfocus: fn,
697
+ autoFocus: true
698
+ }
699
+ })
700
+
701
+ getHostElement()
702
+ .get('input')
703
+ .as('input')
704
+ .focus()
705
+
706
+ cy.get('@input').then(() => {
707
+ expect(fn).to.be.calledWith()
708
+ })
70
709
  })
71
710
  })
72
711
 
73
712
  describe('(event): blur', () => {
74
- it.skip(' ', () => {
75
- //
713
+ it('should emit blur event', () => {
714
+ const fn = cy.stub()
715
+ mountQInput({
716
+ props: {
717
+ onblur: fn
718
+ }
719
+ })
720
+
721
+ getHostElement()
722
+ .get('input')
723
+ .focus()
724
+ .blur()
725
+ .then(() => {
726
+ expect(fn).to.be.calledWith()
727
+ })
76
728
  })
77
729
  })
78
730
  })
79
731
 
80
732
  describe('Methods', () => {
81
733
  describe('(method): focus', () => {
82
- it.skip(' ', () => {
83
- //
734
+ it('should focus the component', () => {
735
+ mountQInput()
736
+
737
+ getHostElement()
738
+ .get('.q-field--focused')
739
+ .should('not.exist')
740
+ .get('input')
741
+ .should('not.have.focus')
742
+ getHostElement()
743
+ .then(() => {
744
+ Cypress.vueWrapper.vm.focus()
745
+ })
746
+ getHostElement()
747
+ .get('.q-field--focused')
748
+ .should('exist')
749
+ .get('input')
750
+ .should('have.focus')
84
751
  })
85
752
  })
86
753
 
87
754
  describe('(method): blur', () => {
88
- it.skip(' ', () => {
89
- //
755
+ it('should blur the component', () => {
756
+ mountQInput()
757
+ getHostElement()
758
+ .get('input').focus()
759
+ getHostElement()
760
+ .get('.q-field--focused')
761
+ .should('exist')
762
+ .get('input')
763
+ .should('have.focus')
764
+
765
+ getHostElement()
766
+ .then(() => {
767
+ Cypress.vueWrapper.vm.blur()
768
+ })
769
+
770
+ getHostElement().get('.q-field--focused').should('not.exist').get('input').should('not.have.focus')
90
771
  })
91
772
  })
92
773