slim-select 2.8.2 → 2.9.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 (69) hide show
  1. package/.prettierignore +1 -0
  2. package/.prettierrc +4 -3
  3. package/README.md +2 -0
  4. package/dist/classes.d.ts +43 -0
  5. package/dist/helpers.d.ts +1 -1
  6. package/dist/index.d.ts +5 -2
  7. package/dist/render.d.ts +4 -44
  8. package/dist/select.d.ts +4 -2
  9. package/dist/settings.d.ts +2 -1
  10. package/dist/slimselect.cjs.js +248 -120
  11. package/dist/slimselect.css +1 -1
  12. package/dist/slimselect.css.map +1 -1
  13. package/dist/slimselect.es.js +248 -120
  14. package/dist/slimselect.global.js +248 -120
  15. package/dist/slimselect.js +248 -120
  16. package/dist/slimselect.min.js +1 -1
  17. package/dist/slimselect.umd.js +248 -120
  18. package/dist/slimselect.umd.min.js +1 -1
  19. package/dist/store.d.ts +4 -2
  20. package/index.html +1 -4
  21. package/jest.config.js +6 -0
  22. package/package.json +30 -39
  23. package/src/slim-select/classes.test.ts +72 -0
  24. package/src/slim-select/classes.ts +109 -0
  25. package/src/slim-select/helpers.test.ts +160 -0
  26. package/src/slim-select/helpers.ts +3 -12
  27. package/src/slim-select/index.test.ts +109 -16
  28. package/src/slim-select/index.ts +41 -12
  29. package/src/slim-select/render.test.ts +1169 -18
  30. package/src/slim-select/render.ts +75 -96
  31. package/src/slim-select/rollup.config.mjs +28 -28
  32. package/src/slim-select/select.test.ts +306 -156
  33. package/src/slim-select/select.ts +69 -20
  34. package/src/slim-select/settings.test.ts +257 -0
  35. package/src/slim-select/settings.ts +4 -0
  36. package/src/slim-select/slimselect.scss +7 -3
  37. package/src/slim-select/store.test.ts +986 -235
  38. package/src/slim-select/store.ts +70 -28
  39. package/src/{vue/slimselect.vue → slim-select/vue.vue} +19 -17
  40. package/tsconfig.json +2 -3
  41. package/src/react/.eslintignore +0 -2
  42. package/src/react/.eslintrc.cjs +0 -24
  43. package/src/react/index.html +0 -14
  44. package/src/react/jestconfig.json +0 -11
  45. package/src/react/package.json +0 -32
  46. package/src/react/src/frameworkpage.tsx +0 -133
  47. package/src/react/src/index.ts +0 -3
  48. package/src/react/src/slimselect.tsx +0 -148
  49. package/src/react/tests/slimselect.test.tsx +0 -52
  50. package/src/react/tsconfig.json +0 -37
  51. package/src/react/tsconfig.node.json +0 -10
  52. package/src/react/vite.config.ts +0 -55
  53. package/src/vue/README.md +0 -48
  54. package/src/vue/dist/slim-select/helpers.d.ts +0 -5
  55. package/src/vue/dist/slim-select/index.d.ts +0 -46
  56. package/src/vue/dist/slim-select/render.d.ts +0 -120
  57. package/src/vue/dist/slim-select/select.d.ts +0 -28
  58. package/src/vue/dist/slim-select/settings.d.ts +0 -34
  59. package/src/vue/dist/slim-select/store.d.ts +0 -80
  60. package/src/vue/dist/slimselectvue.es.js +0 -1978
  61. package/src/vue/dist/slimselectvue.global.js +0 -1981
  62. package/src/vue/dist/slimselectvue.ssr.js +0 -1980
  63. package/src/vue/dist/vue/hello.d.ts +0 -2
  64. package/src/vue/dist/vue/slimselect.vue.d.ts +0 -326
  65. package/src/vue/hello.ts +0 -5
  66. package/src/vue/package.json +0 -28
  67. package/src/vue/rollup.config.mjs +0 -44
  68. package/src/vue/tsconfig.json +0 -14
  69. /package/{vite.config.ts → vite.config.mts} +0 -0
@@ -1,242 +1,993 @@
1
1
  'use strict'
2
2
 
3
3
  import { describe, expect, test } from '@jest/globals'
4
- import Store, { Optgroup, Option } from './store'
4
+ import Store, { DataArray, DataObjectPartial, Optgroup, Option } from './store'
5
5
 
6
6
  describe('store module', () => {
7
- test('constructor', () => {
8
- let store = new Store('single', [])
9
- expect(store).toBeInstanceOf(Store)
10
- })
11
-
12
- test('set data', () => {
13
- let store = new Store('single', [
14
- {
15
- text: 'test',
16
- },
17
- ])
18
-
19
- let data = store.getData()
20
-
21
- // Make sure data has one item and that it has the correct text
22
- expect(data.length).toBe(1)
23
- expect((data[0] as Option).text).toBe('test')
24
-
25
- // Make sure the data has all the default fields
26
- expect((data[0] as Option).id).toBeDefined()
27
- expect((data[0] as Option).value).toBeDefined()
28
- expect((data[0] as Option).text).toBeDefined()
29
- expect((data[0] as Option).html).toBeDefined()
30
- expect((data[0] as Option).selected).toBeDefined()
31
- expect((data[0] as Option).display).toBeDefined()
32
- expect((data[0] as Option).disabled).toBeDefined()
33
- expect((data[0] as Option).placeholder).toBeDefined()
34
- expect((data[0] as Option).class).toBeDefined()
35
- expect((data[0] as Option).style).toBeDefined()
36
- expect((data[0] as Option).data).toBeDefined()
37
- expect((data[0] as Option).mandatory).toBeDefined()
38
- })
39
-
40
- test('set data with optgroup', () => {
41
- let store = new Store('single', [
42
- {
43
- label: 'test',
44
- options: [
45
- {
46
- text: 'test',
47
- },
48
- ],
49
- },
50
- ])
51
-
52
- let data = store.getData()
53
-
54
- // Make sure data has one item and that it has the correct text
55
- expect(data.length).toBe(1)
56
- expect((data[0] as Optgroup).label).toBe('test')
57
- expect((data[0] as Optgroup).options?.length).toBe(1)
58
- expect((data[0] as Optgroup).options?.[0].text).toBe('test')
59
- })
60
-
61
- test('set data with optgroup and option', () => {
62
- let store = new Store('single', [
63
- {
64
- label: 'test',
65
- options: [
66
- {
67
- text: 'test',
68
- },
69
- ],
70
- },
71
- {
72
- text: 'test',
73
- },
74
- ])
75
-
76
- let data = store.getData()
77
-
78
- // Make sure data has one item and that it has the correct text
79
- expect(data.length).toBe(2)
80
- expect((data[0] as Optgroup).label).toBe('test')
81
- expect((data[0] as Optgroup).options?.length).toBe(1)
82
- expect((data[0] as Optgroup).options?.[0].text).toBe('test')
83
- expect((data[1] as Option).text).toBe('test')
84
- })
85
-
86
- test('set data and set selected by ID', () => {
87
- let store = new Store('single', [
88
- {
89
- id: '8675309',
90
- text: 'test',
91
- },
92
- ])
93
- store.setSelectedBy('id', ['8675309'])
94
-
95
- let data = store.getData()
96
-
97
- // Make sure data has one item and that it has the correct text
98
- expect(data.length).toBe(1)
99
- expect((data[0] as Option).text).toBe('test')
100
- expect((data[0] as Option).selected).toBe(true)
101
- })
102
-
103
- test('set data and set selected by value', () => {
104
- let store = new Store('single', [
105
- {
106
- text: 'test',
107
- value: 'hello',
108
- },
109
- ])
110
- store.setSelectedBy('value', ['hello'])
111
-
112
- let data = store.getData()
113
-
114
- // Make sure data has one item and that it has the correct text
115
- expect(data.length).toBe(1)
116
- expect((data[0] as Option).text).toBe('test')
117
- expect((data[0] as Option).selected).toBe(true)
118
- })
119
-
120
- test('set data and set selected to empty string', () => {
121
- let store = new Store('single', [
122
- {
123
- text: 'all',
124
- value: '',
125
- },
126
- {
127
- text: 'Value 1',
128
- value: '1',
129
- selected: true,
130
- },
131
- ])
132
- store.setSelectedBy('value', [''])
133
-
134
- let data = store.getData()
135
-
136
- // Make sure data has one item and that it has the correct text
137
- expect(data.length).toBe(2)
138
- expect((data[0] as Option).text).toBe('all')
139
- expect((data[0] as Option).selected).toBe(true)
140
- })
141
-
142
- test('set data and set selected by value multiple for single element', () => {
143
- let store = new Store('single', [
144
- {
145
- text: 'test1',
146
- },
147
- {
148
- text: 'test2',
149
- },
150
- ])
151
- store.setSelectedBy('value', ['test1', 'test2'])
152
-
153
- let data = store.getData()
154
-
155
- // Make sure data has one item and that it has the correct text
156
- expect(data.length).toBe(2)
157
- expect((data[0] as Option).text).toBe('test1')
158
- expect((data[0] as Option).selected).toBe(true)
159
- expect((data[1] as Option).text).toBe('test2')
160
- expect((data[1] as Option).selected).toBe(false)
161
- })
162
-
163
- test('set data and search', () => {
164
- let store = new Store('single', [
165
- {
166
- text: 'test1',
167
- },
168
- {
169
- text: 'test2',
170
- value: 'test2',
171
- },
172
- {
173
- text: 'test3',
174
- },
175
- ])
176
-
177
- let data = store.getData()
178
-
179
- const searchFilter = (opt: Option, search: string): boolean => {
180
- return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1
181
- }
182
-
183
- // With searchFilter search against current store data set
184
- let search = store.search('test2', searchFilter)
185
- expect(search.length).toBe(1)
186
- expect((search[0] as Option).value).toBe('test2')
187
- })
188
-
189
- test('set data with non selected on single select', () => {
190
- let store = new Store('single', [
191
- {
192
- text: 'test1',
193
- },
194
- {
195
- text: 'test2',
196
- value: 'test2',
197
- },
198
- {
199
- text: 'test3',
200
- },
201
- ])
202
-
203
- let data = store.getData()
204
-
205
- // Make sure data has one item and that it has the correct text
206
- expect(data.length).toBe(3)
207
- expect((data[0] as Option).text).toBe('test1')
208
- expect((data[0] as Option).selected).toBe(true)
209
- expect((data[1] as Option).text).toBe('test2')
210
- expect((data[1] as Option).selected).toBe(false)
211
- expect((data[2] as Option).text).toBe('test3')
212
- expect((data[2] as Option).selected).toBe(false)
213
- })
214
-
215
- test('set data with multiple selected on single select', () => {
216
- let store = new Store('single', [
217
- {
218
- text: 'test1',
219
- },
220
- {
221
- text: 'test2',
222
- value: 'test2',
223
- selected: true,
224
- },
225
- {
226
- text: 'test3',
227
- selected: true,
228
- },
229
- ])
230
-
231
- let data = store.getData()
232
-
233
- // Make sure data has one item and that it has the correct text
234
- expect(data.length).toBe(3)
235
- expect((data[0] as Option).text).toBe('test1')
236
- expect((data[0] as Option).selected).toBe(false)
237
- expect((data[1] as Option).text).toBe('test2')
238
- expect((data[1] as Option).selected).toBe(true)
239
- expect((data[2] as Option).text).toBe('test3')
240
- expect((data[2] as Option).selected).toBe(false)
7
+ describe('constructor', () => {
8
+ test('constructor without data', () => {
9
+ let store = new Store('single', [])
10
+ expect(store).toBeInstanceOf(Store)
11
+ })
12
+
13
+ test('constructor with single option', () => {
14
+ const store = new Store('single', [
15
+ {
16
+ text: 'test'
17
+ }
18
+ ])
19
+
20
+ const data = store.getData()
21
+
22
+ // Make sure data has one item and that it has the correct text
23
+ expect(data).toHaveLength(1)
24
+ expect(data[0]).toBeInstanceOf(Option)
25
+
26
+ const option = data[0] as Option
27
+
28
+ expect(option.text).toBe('test')
29
+ expect(option.id).toBeDefined()
30
+ expect(option.value).toBeDefined()
31
+ expect(option.text).toBeDefined()
32
+ expect(option.html).toBeDefined()
33
+ expect(option.selected).toBeDefined()
34
+ expect(option.display).toBeDefined()
35
+ expect(option.disabled).toBeDefined()
36
+ expect(option.placeholder).toBeDefined()
37
+ expect(option.class).toBeDefined()
38
+ expect(option.style).toBeDefined()
39
+ expect(option.data).toBeDefined()
40
+ expect(option.mandatory).toBeDefined()
41
+ })
42
+
43
+ test('constructor with optgroup', () => {
44
+ const store = new Store('single', [
45
+ {
46
+ label: 'opt group',
47
+ options: [
48
+ {
49
+ text: 'test'
50
+ }
51
+ ]
52
+ }
53
+ ])
54
+
55
+ const data = store.getData()
56
+
57
+ expect(data).toHaveLength(1)
58
+
59
+ expect(data[0]).toBeInstanceOf(Optgroup)
60
+ const optGroup = data[0] as Optgroup
61
+
62
+ expect(optGroup.label).toBe('opt group')
63
+ expect(optGroup.options).toHaveLength(1)
64
+ expect(optGroup.options?.[0].text).toBe('test')
65
+ })
66
+
67
+ test('constructor with optgroup and option', () => {
68
+ const store = new Store('single', [
69
+ {
70
+ label: 'opt group',
71
+ options: [
72
+ {
73
+ text: 'opt group option'
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ text: 'option'
79
+ }
80
+ ])
81
+
82
+ const data = store.getData()
83
+
84
+ expect(data).toHaveLength(2)
85
+
86
+ expect(data[0]).toBeInstanceOf(Optgroup)
87
+ const optGroup = data[0] as Optgroup
88
+
89
+ expect(optGroup.label).toBe('opt group')
90
+ expect(optGroup.options).toHaveLength(1)
91
+ expect(optGroup.options?.[0].text).toBe('opt group option')
92
+
93
+ expect(data[1]).toBeInstanceOf(Option)
94
+ expect((data[1] as Option).text).toBe('option')
95
+ })
96
+
97
+ test('constructor with multiple selected on single select only registers first selected', () => {
98
+ const store = new Store('single', [
99
+ {
100
+ text: 'test1'
101
+ },
102
+ {
103
+ text: 'test2',
104
+ value: 'test2',
105
+ selected: true
106
+ },
107
+ {
108
+ text: 'test3',
109
+ selected: true
110
+ }
111
+ ])
112
+
113
+ // cast to an option array here, so we don't need casts in the comparisons
114
+ const data = store.getData() as Array<Option>
115
+
116
+ expect(data).toHaveLength(3)
117
+ expect(data[0].text).toBe('test1')
118
+ expect(data[0].selected).toBe(false)
119
+ expect(data[1].text).toBe('test2')
120
+ expect(data[1].selected).toBe(true)
121
+ expect(data[2].text).toBe('test3')
122
+ expect(data[2].selected).toBe(false)
123
+ })
124
+
125
+ test('constructor without a selected element on single select selects first option', () => {
126
+ const store = new Store('single', [
127
+ {
128
+ text: 'test1'
129
+ },
130
+ {
131
+ text: 'test2',
132
+ value: 'test2'
133
+ },
134
+ {
135
+ text: 'test3'
136
+ }
137
+ ])
138
+
139
+ // cast to an option array here, so we don't need casts in the comparisons
140
+ const data = store.getData() as Array<Option>
141
+
142
+ expect(data).toHaveLength(3)
143
+ expect(data[0].text).toBe('test1')
144
+ expect(data[0].selected).toBe(true)
145
+ expect(data[1].text).toBe('test2')
146
+ expect(data[1].selected).toBe(false)
147
+ expect(data[2].text).toBe('test3')
148
+ expect(data[2].selected).toBe(false)
149
+ })
150
+
151
+ test('constructor with multiple selected on multiple select registers all selected', () => {
152
+ const store = new Store('multiple', [
153
+ {
154
+ text: 'test1'
155
+ },
156
+ {
157
+ text: 'test2',
158
+ value: 'test2',
159
+ selected: true
160
+ },
161
+ {
162
+ text: 'test3',
163
+ selected: true
164
+ }
165
+ ])
166
+
167
+ // cast to an option array here, so we don't need casts in the comparisons
168
+ const data = store.getData() as Array<Option>
169
+
170
+ expect(data).toHaveLength(3)
171
+ expect(data[0].text).toBe('test1')
172
+ expect(data[0].selected).toBe(false)
173
+ expect(data[1].text).toBe('test2')
174
+ expect(data[1].selected).toBe(true)
175
+ expect(data[2].text).toBe('test3')
176
+ expect(data[2].selected).toBe(true)
177
+ })
178
+
179
+ test('constructor without a selected element on multiple select does not select anything', () => {
180
+ const store = new Store('multiple', [
181
+ {
182
+ text: 'test1'
183
+ },
184
+ {
185
+ text: 'test2',
186
+ value: 'test2'
187
+ },
188
+ {
189
+ text: 'test3'
190
+ }
191
+ ])
192
+
193
+ // cast to an option array here, so we don't need casts in the comparisons
194
+ const data = store.getData() as Array<Option>
195
+
196
+ expect(data).toHaveLength(3)
197
+ data.forEach((option) => {
198
+ expect(option.selected).toBe(false)
199
+ })
200
+ })
201
+ })
202
+
203
+ describe('validateDataArray', () => {
204
+ let store: Store
205
+
206
+ beforeAll(() => {
207
+ store = new Store('single', [])
208
+ })
209
+
210
+ test('invalid data returns error', () => {
211
+ const invalidData = { test: true }
212
+
213
+ const res = store.validateDataArray(invalidData as unknown as DataArray)
214
+ expect(res).toBeInstanceOf(Error)
215
+ expect(res?.message).toBe('Data must be an array')
216
+ })
217
+
218
+ test('single invalid data entry returns error', () => {
219
+ const invalidData = [{ name: 'this is invalid' }]
220
+
221
+ const res = store.validateDataArray(invalidData as unknown as DataArray)
222
+ expect(res).toBeInstanceOf(Error)
223
+ expect(res?.message).toBe('Data object must be a valid optgroup or option')
224
+ })
225
+
226
+ test('invalid data and valid option returns error', () => {
227
+ const invalidData = [
228
+ {
229
+ name: 'invalid data'
230
+ },
231
+ {
232
+ text: 'valid option'
233
+ }
234
+ ]
235
+
236
+ const res = store.validateDataArray(invalidData as unknown as DataArray)
237
+ expect(res).toBeInstanceOf(Error)
238
+ expect(res?.message).toBe('Data object must be a valid optgroup or option')
239
+ })
240
+
241
+ test('valid option and invalid data returns error', () => {
242
+ const invalidData = [
243
+ {
244
+ text: 'valid'
245
+ },
246
+ {
247
+ name: 'this is invalid'
248
+ }
249
+ ]
250
+
251
+ const res = store.validateDataArray(invalidData as unknown as DataArray)
252
+ expect(res).toBeInstanceOf(Error)
253
+ expect(res?.message).toBe('Data object must be a valid optgroup or option')
254
+ })
255
+
256
+ test('valid opt group with invalid data returns error', () => {
257
+ const invalidData = [
258
+ {
259
+ label: 'valid',
260
+ options: [
261
+ {
262
+ invalid: 'asdf'
263
+ }
264
+ ]
265
+ }
266
+ ]
267
+
268
+ const res = store.validateDataArray(invalidData as unknown as DataArray)
269
+ expect(res).toBeInstanceOf(Error)
270
+ expect(res?.message).toBe('Option must have a text')
271
+ })
272
+
273
+ test('single valid option validates', () => {
274
+ const validData = [
275
+ {
276
+ text: 'valid option'
277
+ }
278
+ ]
279
+
280
+ const res = store.validateDataArray(validData)
281
+ expect(res).toBeNull()
282
+ })
283
+
284
+ test('multiple valid options validates', () => {
285
+ const validData = [
286
+ {
287
+ text: 'valid option 1'
288
+ },
289
+ {
290
+ text: 'valid option 2'
291
+ }
292
+ ]
293
+
294
+ const res = store.validateDataArray(validData)
295
+ expect(res).toBeNull()
296
+ })
297
+
298
+ test('single valid opt group validates', () => {
299
+ const validData = [
300
+ {
301
+ label: 'valid opt group'
302
+ }
303
+ ]
304
+
305
+ const res = store.validateDataArray(validData)
306
+ expect(res).toBeNull()
307
+ })
308
+
309
+ test('valid opt group with options validates', () => {
310
+ const validData = [
311
+ {
312
+ label: 'valid opt group',
313
+ options: [
314
+ {
315
+ text: 'option 1'
316
+ },
317
+ {
318
+ text: 'option 2'
319
+ }
320
+ ]
321
+ }
322
+ ]
323
+
324
+ const res = store.validateDataArray(validData)
325
+ expect(res).toBeNull()
326
+ })
327
+ test('valid opt group with options and separate options validates', () => {
328
+ const validData = [
329
+ {
330
+ label: 'valid opt group',
331
+ options: [
332
+ {
333
+ text: 'option 1'
334
+ },
335
+ {
336
+ text: 'option 2'
337
+ }
338
+ ]
339
+ },
340
+ {
341
+ text: 'main option 1'
342
+ },
343
+ {
344
+ text: 'main option 2'
345
+ }
346
+ ]
347
+
348
+ const res = store.validateDataArray(validData)
349
+ expect(res).toBeNull()
350
+ })
351
+ })
352
+
353
+ describe('validateOption', () => {
354
+ let store: Store
355
+
356
+ beforeAll(() => {
357
+ store = new Store('single', [])
358
+ })
359
+
360
+ test('empty option returns error', () => {
361
+ const res = store.validateOption({} as Option)
362
+ expect(res).toBeInstanceOf(Error)
363
+ expect(res?.message).toBe('Option must have a text')
364
+ })
365
+
366
+ test('invalid data returns error', () => {
367
+ const res = store.validateOption({ label: 'text' } as unknown as Option)
368
+ expect(res).toBeInstanceOf(Error)
369
+ expect(res?.message).toBe('Option must have a text')
370
+ })
371
+
372
+ test('valid data returns null', () => {
373
+ const res = store.validateOption({ text: 'text' })
374
+ expect(res).toBeNull()
375
+ })
376
+ })
377
+
378
+ describe('partialToFullData', () => {
379
+ let store: Store
380
+
381
+ beforeAll(() => {
382
+ store = new Store('single', [])
383
+ })
384
+
385
+ test('empty partial returns empty data array', () => {
386
+ const res = store.partialToFullData([])
387
+ expect(res).toBeInstanceOf(Array)
388
+ expect(res).toHaveLength(0)
389
+ })
390
+
391
+ test("invalid data get's ignored", () => {
392
+ const res = store.partialToFullData([
393
+ { error: 'this is invalid' } as unknown as DataObjectPartial,
394
+ { text: 'valid' }
395
+ ])
396
+ expect(res).toBeInstanceOf(Array)
397
+ expect(res).toHaveLength(1)
398
+
399
+ expect(res[0]).toBeInstanceOf(Option)
400
+
401
+ const option = res[0] as Option
402
+ expect(option.text).toBe('valid')
403
+ })
404
+
405
+ test('valid data gets filled correctly', () => {
406
+ const res = store.partialToFullData([
407
+ {
408
+ label: 'opt group',
409
+ options: [{ text: 'opt 1' }, { text: 'opt 2' }]
410
+ },
411
+ {
412
+ text: 'opt 3'
413
+ }
414
+ ])
415
+
416
+ expect(res).toHaveLength(2)
417
+ expect(res[0]).toBeInstanceOf(Optgroup)
418
+
419
+ const optGroup = res[0] as Optgroup
420
+ expect(optGroup.label).toBe('opt group')
421
+ expect(optGroup.options).toHaveLength(2)
422
+ expect(optGroup.options[0]).toBeInstanceOf(Option)
423
+ expect(optGroup.options[0].text).toBe('opt 1')
424
+ expect(optGroup.options[1]).toBeInstanceOf(Option)
425
+ expect(optGroup.options[1].text).toBe('opt 2')
426
+ })
427
+ })
428
+
429
+ describe('setData', () => {
430
+ let store: Store
431
+
432
+ beforeEach(() => {
433
+ store = new Store('single', [
434
+ {
435
+ text: 'initial option'
436
+ },
437
+ {
438
+ text: 'initial selected option',
439
+ selected: true
440
+ }
441
+ ])
442
+ })
443
+
444
+ test('invalid data does override existing data', () => {
445
+ store.setData([{ invalid: true } as unknown as Option])
446
+
447
+ const data = store.getData()
448
+ expect(data).toHaveLength(0)
449
+ })
450
+
451
+ test('valid data overrides existing data', () => {
452
+ store.setData([
453
+ {
454
+ text: 'opt 1'
455
+ },
456
+ {
457
+ text: 'opt 2'
458
+ },
459
+ {
460
+ text: 'opt 3'
461
+ }
462
+ ])
463
+
464
+ const data = store.getData() as Array<Option>
465
+ expect(data).toHaveLength(3)
466
+ expect(data[0].text).toBe('opt 1')
467
+ expect(data[1].text).toBe('opt 2')
468
+ expect(data[2].text).toBe('opt 3')
469
+ })
470
+
471
+ test('valid data on single select automatically selects first option', () => {
472
+ store.setData([
473
+ {
474
+ text: 'opt 1'
475
+ },
476
+ {
477
+ text: 'opt 2'
478
+ }
479
+ ])
480
+
481
+ const data = store.getData() as Array<Option>
482
+ expect(data).toHaveLength(2)
483
+ expect(data[0].selected).toBe(true)
484
+ })
485
+
486
+ test('valid data on single select selects correct option', () => {
487
+ store.setData([
488
+ {
489
+ text: 'opt 1'
490
+ },
491
+ {
492
+ text: 'opt 2',
493
+ selected: true
494
+ }
495
+ ])
496
+
497
+ const data = store.getData() as Array<Option>
498
+ expect(data).toHaveLength(2)
499
+ expect(data[1].text).toBe('opt 2')
500
+ expect(data[1].selected).toBe(true)
501
+ })
502
+ })
503
+
504
+ describe('getData', () => {
505
+ test('getData gets all options', () => {
506
+ const data = [
507
+ {
508
+ label: 'group test',
509
+ options: [
510
+ {
511
+ text: 'sub opt 1'
512
+ },
513
+ {
514
+ text: 'sub opt 2'
515
+ }
516
+ ]
517
+ },
518
+ {
519
+ text: 'test1'
520
+ },
521
+ {
522
+ text: 'test2',
523
+ value: 'test2'
524
+ },
525
+ {
526
+ text: 'test3'
527
+ }
528
+ ]
529
+
530
+ const flatData = [
531
+ {
532
+ text: 'sub opt 1'
533
+ },
534
+ {
535
+ text: 'sub opt 2'
536
+ },
537
+ {
538
+ text: 'test1'
539
+ },
540
+ {
541
+ text: 'test2',
542
+ value: 'test2'
543
+ },
544
+ {
545
+ text: 'test3'
546
+ }
547
+ ]
548
+
549
+ const store = new Store('single', data)
550
+
551
+ const storedData = store.getData()
552
+ storedData.forEach((dataObject, index) => {
553
+ if ('label' in dataObject) {
554
+ expect(dataObject.label).toBe(data[index].label)
555
+ dataObject.options.forEach((subOpt, subIndex) => {
556
+ expect(subOpt.text).toBe(data[index].options![subIndex].text)
557
+ expect(subOpt.value).toBe(data[index].options![subIndex].text)
558
+ })
559
+ } else {
560
+ expect(dataObject.text).toBe(data[index].text)
561
+ expect(dataObject.value).toBe(data[index].text)
562
+ }
563
+ })
564
+
565
+ // test flat array directly
566
+ const storedDataOptions = store.getDataOptions()
567
+ storedDataOptions.forEach((option, index) => {
568
+ expect(option.text).toBe(flatData[index].text)
569
+ expect(option.value).toBe(flatData[index].text)
570
+ })
571
+ })
572
+ })
573
+
574
+ describe('getDataOptions', () => {
575
+ test('options only store returns same structure', () => {
576
+ const store = new Store('single', [
577
+ {
578
+ text: 'opt 0'
579
+ },
580
+ {
581
+ text: 'opt 1'
582
+ }
583
+ ])
584
+
585
+ const data = store.getDataOptions()
586
+ expect(data).toHaveLength(2)
587
+ data.forEach((option, index) => {
588
+ expect(option).toBeInstanceOf(Option)
589
+ expect(option.text).toBe(`opt ${index}`)
590
+ })
591
+ })
592
+
593
+ test('option group gets flattened', () => {
594
+ const store = new Store('single', [
595
+ {
596
+ label: 'opt group',
597
+ options: [
598
+ {
599
+ text: 'opt 0'
600
+ },
601
+ {
602
+ text: 'opt 1'
603
+ }
604
+ ]
605
+ },
606
+ {
607
+ text: 'opt 2'
608
+ },
609
+ {
610
+ text: 'opt 3'
611
+ }
612
+ ])
613
+
614
+ const data = store.getDataOptions()
615
+ expect(data).toHaveLength(4)
616
+ data.forEach((option, index) => {
617
+ expect(option).toBeInstanceOf(Option)
618
+ expect(option.text).toBe(`opt ${index}`)
619
+ })
620
+ })
621
+ })
622
+
623
+ describe('addOption', () => {
624
+ test('append option', () => {
625
+ const store = new Store('single', [
626
+ {
627
+ text: 'test1'
628
+ }
629
+ ])
630
+
631
+ store.addOption({ text: 'test2' })
632
+
633
+ const storeData = store.getDataOptions()
634
+ expect(storeData).toHaveLength(2)
635
+ expect(storeData[0].text).toBe('test1')
636
+ expect(storeData[1].text).toBe('test2')
637
+ })
638
+ })
639
+
640
+ describe('setSelectedBy', () => {
641
+ let store: Store
642
+
643
+ beforeEach(() => {
644
+ store = new Store('single', [
645
+ {
646
+ text: 'opt 1'
647
+ },
648
+ {
649
+ id: '12345678',
650
+ text: 'id opt'
651
+ },
652
+ {
653
+ text: 'opt 2'
654
+ },
655
+ {
656
+ text: 'opt 3'
657
+ }
658
+ ])
659
+ })
660
+
661
+ test('set selected by ID', () => {
662
+ store.setSelectedBy('id', ['12345678'])
663
+ const data = store.getDataOptions()
664
+
665
+ expect(data[0].text).toBe('opt 1')
666
+ expect(data[0].selected).toBe(false)
667
+
668
+ expect(data[1].text).toBe('id opt')
669
+ expect(data[1].selected).toBe(true)
670
+ })
671
+
672
+ test('set selected by value', () => {
673
+ store.setSelectedBy('value', ['opt 3'])
674
+
675
+ const data = store.getDataOptions()
676
+
677
+ expect(data[0].text).toBe('opt 1')
678
+ expect(data[0].selected).toBe(false)
679
+
680
+ expect(data[3].text).toBe('opt 3')
681
+ expect(data[3].selected).toBe(true)
682
+ })
683
+
684
+ test('set selected to empty string selects first option', () => {
685
+ const store = new Store('single', [
686
+ {
687
+ text: 'all',
688
+ value: ''
689
+ },
690
+ {
691
+ text: 'Value 1',
692
+ value: '1',
693
+ selected: true
694
+ }
695
+ ])
696
+ store.setSelectedBy('value', [''])
697
+
698
+ const data = store.getDataOptions()
699
+
700
+ expect(data[0].text).toBe('all')
701
+ expect(data[0].selected).toBe(true)
702
+ expect(data[1].selected).toBe(false)
703
+ })
704
+
705
+ test('set multiple selected by value on single select only selects the first element', () => {
706
+ store.setSelectedBy('value', ['opt 2', 'opt 3'])
707
+
708
+ const data = store.getDataOptions()
709
+
710
+ expect(data[2].selected).toBe(true)
711
+ expect(data[3].selected).toBe(false)
712
+ })
713
+ })
714
+
715
+ describe('getSelected', () => {
716
+ test('get correct value when one option is selected', () => {
717
+ const store = new Store('single', [
718
+ {
719
+ text: 'opt 0'
720
+ },
721
+ {
722
+ text: 'opt 1'
723
+ }
724
+ ])
725
+
726
+ const selected = store.getSelectedValues()
727
+ expect(selected).toHaveLength(1)
728
+ expect(selected[0]).toBe('opt 0')
729
+ })
730
+
731
+ test('get correct value when two options is selected', () => {
732
+ const store = new Store('multiple', [
733
+ {
734
+ text: 'opt 0'
735
+ },
736
+ {
737
+ text: 'opt 1',
738
+ selected: true
739
+ },
740
+ {
741
+ text: 'opt 2',
742
+ selected: true
743
+ }
744
+ ])
745
+
746
+ const selected = store.getSelectedValues()
747
+ expect(selected).toHaveLength(2)
748
+
749
+ expect(selected[0]).toBe('opt 1')
750
+ expect(selected[1]).toBe('opt 2')
751
+ })
752
+
753
+ test('get correct order when using reorder options', () => {
754
+ const store = new Store('multiple', [
755
+ {
756
+ text: 'opt 0'
757
+ },
758
+ {
759
+ text: 'opt 1'
760
+ },
761
+ {
762
+ text: 'opt 2'
763
+ }
764
+ ])
765
+
766
+ store.setSelectedBy('value', ['opt 2', 'opt 0'])
767
+
768
+ let selected = store.getSelectedOptions()
769
+ selected = store.selectedOrderOptions(selected)
770
+ expect(selected.map((opt) => opt.text)).toEqual(['opt 2', 'opt 0'])
771
+ })
772
+ })
773
+
774
+ describe('getSelectedOptions', () => {
775
+ test('get correct value when one option is selected', () => {
776
+ const store = new Store('single', [
777
+ {
778
+ text: 'opt 0'
779
+ },
780
+ {
781
+ text: 'opt 1'
782
+ }
783
+ ])
784
+
785
+ const selected = store.getSelectedOptions()
786
+ expect(selected).toHaveLength(1)
787
+ expect(selected[0].text).toBe('opt 0')
788
+ })
789
+
790
+ test('get correct value when two options is selected', () => {
791
+ const store = new Store('multiple', [
792
+ {
793
+ text: 'opt 0'
794
+ },
795
+ {
796
+ text: 'opt 1',
797
+ selected: true
798
+ },
799
+ {
800
+ text: 'opt 2',
801
+ selected: true
802
+ }
803
+ ])
804
+
805
+ const selected = store.getSelectedOptions()
806
+ expect(selected).toHaveLength(2)
807
+ expect(selected[0].text).toBe('opt 1')
808
+ expect(selected[1].text).toBe('opt 2')
809
+ })
810
+ })
811
+
812
+ describe('getOptionByID', () => {
813
+ let store: Store
814
+
815
+ beforeAll(() => {
816
+ store = new Store('single', [
817
+ {
818
+ text: 'opt 1'
819
+ },
820
+ {
821
+ id: '12345678',
822
+ text: 'id opt'
823
+ },
824
+ {
825
+ text: 'opt 2'
826
+ },
827
+ {
828
+ text: 'opt 3'
829
+ }
830
+ ])
831
+ })
832
+
833
+ test('invalid id gets null as result', () => {
834
+ const res = store.getOptionByID('0000')
835
+ expect(res).toBeNull()
836
+ })
837
+
838
+ test('valid id gets correct result', () => {
839
+ const res = store.getOptionByID('12345678')
840
+ expect(res).toBeInstanceOf(Option)
841
+ expect((res as Option).text).toBe('id opt')
842
+ })
843
+ })
844
+
845
+ describe('getSelectType', () => {
846
+ test('get correct type on single select', () => {
847
+ const store = new Store('single', [])
848
+ expect(store.getSelectType()).toBe('single')
849
+ })
850
+
851
+ test('get correct type on multiple select', () => {
852
+ const store = new Store('multiple', [])
853
+ expect(store.getSelectType()).toBe('multiple')
854
+ })
855
+ })
856
+
857
+ describe('getFirstOption', () => {
858
+ test('getFirstOption returns first option', () => {
859
+ const flatStore = new Store('single', [
860
+ {
861
+ text: 'test0'
862
+ },
863
+ {
864
+ text: 'test1'
865
+ }
866
+ ])
867
+
868
+ expect(flatStore.getFirstOption()?.text).toBe('test0')
869
+
870
+ const store = new Store('single', [
871
+ {
872
+ label: 'group0',
873
+ options: [
874
+ {
875
+ text: 'test0'
876
+ },
877
+ {
878
+ text: 'test1'
879
+ }
880
+ ]
881
+ },
882
+ {
883
+ text: 'test2'
884
+ }
885
+ ])
886
+
887
+ expect(store.getFirstOption()?.text).toBe('test0')
888
+ })
889
+ })
890
+
891
+ describe('search', () => {
892
+ test('search with term returns correct option', () => {
893
+ const store = new Store('single', [
894
+ {
895
+ text: 'test1'
896
+ },
897
+ {
898
+ text: 'test2',
899
+ value: 'test2'
900
+ },
901
+ {
902
+ text: 'test3'
903
+ }
904
+ ])
905
+
906
+ const searchFilter = (opt: Option, search: string): boolean => {
907
+ return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1
908
+ }
909
+
910
+ // With searchFilter search against current store data set
911
+ const searchResults = store.search('test2', searchFilter)
912
+ expect(searchResults).toHaveLength(1)
913
+ expect((searchResults[0] as Option).value).toBe('test2')
914
+ })
915
+
916
+ test('empty search term returns all options', () => {
917
+ const store = new Store('single', [
918
+ {
919
+ text: 'test1'
920
+ },
921
+ {
922
+ text: 'test2',
923
+ value: 'test2'
924
+ },
925
+ {
926
+ text: 'test3'
927
+ }
928
+ ])
929
+
930
+ const searchFilter = (opt: Option, search: string): boolean => {
931
+ return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1
932
+ }
933
+
934
+ // Test empty search term
935
+ const searchResults = store.search('', searchFilter)
936
+ expect(searchResults).toHaveLength(3)
937
+ })
938
+ })
939
+
940
+ describe('filter', () => {
941
+ let store: Store
942
+
943
+ beforeAll(() => {
944
+ store = new Store('single', [
945
+ {
946
+ label: 'group 0',
947
+ options: [
948
+ {
949
+ text: 'opt 0',
950
+ class: 'filter-me'
951
+ },
952
+ {
953
+ text: 'opt 1'
954
+ }
955
+ ]
956
+ },
957
+ {
958
+ text: 'opt 2',
959
+ class: 'filter-me'
960
+ }
961
+ ])
962
+ })
963
+
964
+ test('empty filter function returns all options (with opt group)', () => {
965
+ const res = store.filter(null, true)
966
+ expect(res).toHaveLength(2)
967
+ expect(res[0]).toBeInstanceOf(Optgroup)
968
+ expect((res[0] as Optgroup).label).toBe('group 0')
969
+ expect((res[0] as Optgroup).options).toHaveLength(2)
970
+ expect(res[1]).toBeInstanceOf(Option)
971
+ })
972
+
973
+ test('empty filter function returns all options without optgroups flattens results', () => {
974
+ const res = store.filter(null, false)
975
+ expect(res).toHaveLength(3)
976
+ expect(res[0]).toBeInstanceOf(Option)
977
+ expect((res[0] as Option).text).toBe('opt 0')
978
+ expect(res[1]).toBeInstanceOf(Option)
979
+ expect((res[1] as Option).text).toBe('opt 1')
980
+ expect(res[2]).toBeInstanceOf(Option)
981
+ expect((res[2] as Option).text).toBe('opt 2')
982
+ })
983
+
984
+ test('filter function filters results accordingly', () => {
985
+ const res = store.filter((o) => o.class === 'filter-me', false)
986
+ expect(res).toHaveLength(2)
987
+ expect(res[0]).toBeInstanceOf(Option)
988
+ expect((res[0] as Option).text).toBe('opt 0')
989
+ expect(res[1]).toBeInstanceOf(Option)
990
+ expect((res[1] as Option).text).toBe('opt 2')
991
+ })
241
992
  })
242
993
  })