@saooti/octopus-sdk 41.11.1 → 41.12.0-beta2

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 (33) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/eslint-config.mjs +10 -2
  3. package/index.ts +5 -2
  4. package/package.json +4 -1
  5. package/src/api/radioApi.ts +14 -1
  6. package/src/components/buttons/ClassicButton.vue +18 -1
  7. package/src/components/composable/form/useOctopusDropdown.ts +104 -0
  8. package/src/components/composable/useSticky.ts +45 -0
  9. package/src/components/display/emission/EmissionGroupChooser.vue +22 -24
  10. package/src/components/display/podcasts/PodcastPlayButton.vue +3 -3
  11. package/src/components/form/ClassicButtonGroup.vue +15 -13
  12. package/src/components/form/ClassicSelect.vue +11 -2
  13. package/src/components/form/OctopusMultiselect.vue +236 -109
  14. package/src/components/form/OctopusSelect.vue +278 -0
  15. package/src/components/misc/ClassicPopover.vue +9 -2
  16. package/src/components/misc/modal/ClassicModal.vue +3 -0
  17. package/src/components/misc/player/elements/PlayerPlayButton.vue +22 -18
  18. package/src/components/pages/PlaylistsPage.vue +1 -0
  19. package/src/helper/colorFromString.ts +12 -5
  20. package/src/helper/equals.ts +21 -9
  21. package/src/stores/ParamSdkStore.ts +1 -0
  22. package/src/stores/class/general/organisation.ts +6 -0
  23. package/src/stores/class/general/podcast.ts +8 -0
  24. package/src/stores/class/rubrique/rubrique.ts +1 -1
  25. package/src/style/_utilities.scss +1 -0
  26. package/src/style/_variables.scss +11 -0
  27. package/src/style/bootstrap.scss +9 -2
  28. package/tests/components/form/ClassicButtonGroup.spec.ts +10 -10
  29. package/tests/components/form/OctopusMultiselect.spec.ts +84 -39
  30. package/tests/components/form/OctopusSelect.spec.ts +168 -0
  31. package/tsconfig.json +3 -7
  32. package/tsconfig.test.json +13 -0
  33. package/vitest.config.js +2 -1
@@ -1,8 +1,9 @@
1
1
  import '@tests/mocks/i18n';
2
2
 
3
3
  import OctopusMultiselect from '@/components/form/OctopusMultiselect.vue';
4
+ import { DOMWrapper, type VueWrapper } from '@vue/test-utils';
4
5
  import { mount } from '@tests/utils';
5
- import { describe, expect, it, vi } from 'vitest';
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
6
7
 
7
8
  const options = [
8
9
  { id: 1, name: 'Alpha' },
@@ -10,66 +11,89 @@ const options = [
10
11
  { id: 3, name: 'Gamma' },
11
12
  ];
12
13
 
14
+ // The dropdown is teleported to .octopus-app — helper to query it from the document.
15
+ function getDropdown(): Element | null {
16
+ return document.body.querySelector('.octopus-multiselect-dropdown');
17
+ }
18
+
13
19
  describe('OctopusMultiselect', () => {
20
+ // The dropdown teleports to .octopus-app, which is normally the app root (see App.vue).
21
+ // It doesn't exist in the test DOM, so it must be created before mount.
22
+ let appElement: HTMLElement;
23
+
24
+ beforeEach(() => {
25
+ appElement = document.createElement('div');
26
+ appElement.className = 'octopus-app';
27
+ document.body.appendChild(appElement);
28
+ });
29
+
30
+ // Shared wrapper ref so afterEach can properly unmount it.
31
+ // Proper unmount lets Vue clean up the teleport target before the next test starts.
32
+ let wrapper: VueWrapper;
33
+ afterEach(() => {
34
+ wrapper?.unmount();
35
+ appElement.remove();
36
+ });
37
+
14
38
  it('renders label when provided', async () => {
15
- const wrapper = await mount(OctopusMultiselect, {
39
+ wrapper = await mount(OctopusMultiselect, {
16
40
  props: { options, optionLabel: 'name', label: 'My label' },
17
41
  });
18
42
  expect(wrapper.find('label.form-label').text()).toBe('My label');
19
43
  });
20
44
 
21
45
  it('does not render label when not provided', async () => {
22
- const wrapper = await mount(OctopusMultiselect, {
46
+ wrapper = await mount(OctopusMultiselect, {
23
47
  props: { options, optionLabel: 'name' },
24
48
  });
25
49
  expect(wrapper.find('label.form-label').exists()).toBe(false);
26
50
  });
27
51
 
28
52
  it('opens dropdown on input focus', async () => {
29
- const wrapper = await mount(OctopusMultiselect, {
53
+ wrapper = await mount(OctopusMultiselect, {
30
54
  props: { options, optionLabel: 'name' },
31
55
  });
32
- expect(wrapper.find('.octopus-multiselect-dropdown').exists()).toBe(false);
56
+ expect(getDropdown()).toBeNull();
33
57
  await wrapper.find('input').trigger('focus');
34
- expect(wrapper.find('.octopus-multiselect-dropdown').exists()).toBe(true);
58
+ expect(getDropdown()).not.toBeNull();
35
59
  });
36
60
 
37
61
  it('shows "All" checkbox and one checkbox per option when open', async () => {
38
- const wrapper = await mount(OctopusMultiselect, {
62
+ wrapper = await mount(OctopusMultiselect, {
39
63
  props: { options, optionLabel: 'name' },
40
64
  });
41
65
  await wrapper.find('input').trigger('focus');
42
- const checkboxes = wrapper.findAll('input[type="checkbox"]');
66
+ const checkboxes = document.body.querySelectorAll('input[type="checkbox"]');
43
67
  // 1 for "All" + 3 for options
44
68
  expect(checkboxes).toHaveLength(4);
45
69
  });
46
70
 
47
71
  it('filters options locally by search query', async () => {
48
- const wrapper = await mount(OctopusMultiselect, {
72
+ wrapper = await mount(OctopusMultiselect, {
49
73
  props: { options, optionLabel: 'name' },
50
74
  });
51
75
  await wrapper.find('input').trigger('focus');
52
76
  await wrapper.find('input').setValue('al');
53
77
  await wrapper.find('input').trigger('input');
54
- const checkboxes = wrapper.findAll('input[type="checkbox"]');
78
+ const checkboxes = document.body.querySelectorAll('input[type="checkbox"]');
55
79
  // 1 for "All" + 1 matching "Alpha"
56
80
  expect(checkboxes).toHaveLength(2);
57
81
  });
58
82
 
59
83
  it('shows no-results message when filter matches nothing', async () => {
60
- const wrapper = await mount(OctopusMultiselect, {
84
+ wrapper = await mount(OctopusMultiselect, {
61
85
  props: { options, optionLabel: 'name' },
62
86
  });
63
87
  await wrapper.find('input').trigger('focus');
64
88
  await wrapper.find('input').setValue('zzz');
65
89
  await wrapper.find('input').trigger('input');
66
- expect(wrapper.find('.text-indic').exists()).toBe(true);
90
+ expect(document.body.querySelector('.text-indic')).not.toBeNull();
67
91
  });
68
92
 
69
93
  it('calls onSearch with current query and updates displayed options', async () => {
70
94
  const searchResult = [{ id: 4, name: 'Delta' }];
71
95
  const onSearch = vi.fn().mockResolvedValue(searchResult);
72
- const wrapper = await mount(OctopusMultiselect, {
96
+ wrapper = await mount(OctopusMultiselect, {
73
97
  props: { options, optionLabel: 'name', onSearch },
74
98
  });
75
99
  await wrapper.find('input').trigger('focus');
@@ -80,83 +104,104 @@ describe('OctopusMultiselect', () => {
80
104
  });
81
105
 
82
106
  it('emits update:selected when toggling a single option', async () => {
83
- const wrapper = await mount(OctopusMultiselect, {
107
+ wrapper = await mount(OctopusMultiselect, {
84
108
  props: { options, optionLabel: 'name', selected: [] },
85
109
  });
86
110
  await wrapper.find('input').trigger('focus');
87
- const optionCheckboxes = wrapper.findAll('.octopus-multiselect-options input[type="checkbox"]');
88
- await optionCheckboxes[0].trigger('input');
111
+ const optionCheckboxes = document.body.querySelectorAll('.octopus-multiselect-options input[type="checkbox"]');
112
+ await new DOMWrapper(optionCheckboxes[0] as Element).trigger('input');
89
113
  expect(wrapper.emitted('update:selected')?.[0]).toEqual([[options[0]]]);
90
114
  });
91
115
 
92
116
  it('deselects an already-selected option', async () => {
93
- const wrapper = await mount(OctopusMultiselect, {
117
+ wrapper = await mount(OctopusMultiselect, {
94
118
  props: { options, optionLabel: 'name', selected: [options[0]] },
95
119
  });
96
120
  await wrapper.find('input').trigger('focus');
97
- const optionCheckboxes = wrapper.findAll('.octopus-multiselect-options input[type="checkbox"]');
98
- await optionCheckboxes[0].trigger('input');
121
+ const optionCheckboxes = document.body.querySelectorAll('.octopus-multiselect-options input[type="checkbox"]');
122
+ await new DOMWrapper(optionCheckboxes[0] as Element).trigger('input');
99
123
  expect(wrapper.emitted('update:selected')?.[0]).toEqual([[]]);
100
124
  });
101
125
 
102
126
  it('toggleAll selects all displayed options', async () => {
103
- const wrapper = await mount(OctopusMultiselect, {
127
+ wrapper = await mount(OctopusMultiselect, {
104
128
  props: { options, optionLabel: 'name', selected: [] },
105
129
  });
106
130
  await wrapper.find('input').trigger('focus');
107
- const allCheckbox = wrapper.find('.octopus-multiselect-dropdown > .octopus-form-item input[type="checkbox"]');
108
- await allCheckbox.trigger('input');
131
+ const allCheckbox = document.body.querySelector('.octopus-multiselect-dropdown > .octopus-form-item input[type="checkbox"]')!;
132
+ await new DOMWrapper(allCheckbox).trigger('input');
109
133
  const emitted = wrapper.emitted('update:selected')?.[0]?.[0] as unknown[];
110
134
  expect(emitted).toHaveLength(3);
111
135
  });
112
136
 
113
137
  it('toggleAll deselects all displayed options when all are selected', async () => {
114
- const wrapper = await mount(OctopusMultiselect, {
138
+ wrapper = await mount(OctopusMultiselect, {
115
139
  props: { options, optionLabel: 'name', selected: [...options] },
116
140
  });
117
141
  await wrapper.find('input').trigger('focus');
118
- const allCheckbox = wrapper.find('.octopus-multiselect-dropdown > .octopus-form-item input[type="checkbox"]');
119
- await allCheckbox.trigger('input');
142
+ const allCheckbox = document.body.querySelector('.octopus-multiselect-dropdown > .octopus-form-item input[type="checkbox"]')!;
143
+ await new DOMWrapper(allCheckbox).trigger('input');
120
144
  expect(wrapper.emitted('update:selected')?.[0]).toEqual([[]]);
121
145
  });
122
146
 
123
- it('shows selected items summary in placeholder', async () => {
124
- const wrapper = await mount(OctopusMultiselect, {
147
+ it('shows selected items in the selection display', async () => {
148
+ wrapper = await mount(OctopusMultiselect, {
125
149
  props: { options, optionLabel: 'name', selected: [options[0], options[1]] },
126
150
  });
127
- const input = wrapper.find('input');
128
- expect(input.attributes('placeholder')).toBe('Alpha, Beta');
151
+ expect(wrapper.find('.octopus-multiselect-selection-text').text()).toBe('Alpha, Beta');
152
+ expect(wrapper.find('.octopus-multiselect-selection-count').exists()).toBe(false);
129
153
  });
130
154
 
131
- it('shows count in placeholder when more than 2 items selected', async () => {
132
- const wrapper = await mount(OctopusMultiselect, {
155
+ it('shows overflow count badge when more than visible items are selected', async () => {
156
+ wrapper = await mount(OctopusMultiselect, {
133
157
  props: { options, optionLabel: 'name', selected: [...options] },
134
158
  });
135
- const input = wrapper.find('input');
136
- expect(input.attributes('placeholder')).toBe('Alpha, Beta (+1)');
159
+ expect(wrapper.find('.octopus-multiselect-selection-count').exists()).toBe(true);
137
160
  });
138
161
 
139
162
  it('disables input when isDisabled is true', async () => {
140
- const wrapper = await mount(OctopusMultiselect, {
163
+ wrapper = await mount(OctopusMultiselect, {
141
164
  props: { options, optionLabel: 'name', isDisabled: true },
142
165
  });
143
166
  expect(wrapper.find('input').attributes('disabled')).toBeDefined();
144
167
  });
145
168
 
146
169
  it('does not open dropdown when disabled', async () => {
147
- const wrapper = await mount(OctopusMultiselect, {
170
+ wrapper = await mount(OctopusMultiselect, {
148
171
  props: { options, optionLabel: 'name', isDisabled: true },
149
172
  });
150
173
  await wrapper.find('input').trigger('focus');
151
- expect(wrapper.find('.octopus-multiselect-dropdown').exists()).toBe(false);
174
+ expect(getDropdown()).toBeNull();
152
175
  });
153
176
 
154
177
  it('uses selectAllText as the "All" checkbox label when provided', async () => {
155
- const wrapper = await mount(OctopusMultiselect, {
178
+ wrapper = await mount(OctopusMultiselect, {
156
179
  props: { options, optionLabel: 'name', selectAllText: 'Tout' },
157
180
  });
158
181
  await wrapper.find('input').trigger('focus');
159
- const allCheckboxLabel = wrapper.find('.octopus-multiselect-dropdown > .octopus-form-item label');
160
- expect(allCheckboxLabel.text()).toBe('Tout');
182
+ const allCheckboxLabel = document.body.querySelector('.octopus-multiselect-dropdown > .octopus-form-item label')!;
183
+ expect(allCheckboxLabel.textContent?.trim()).toBe('Tout');
184
+ });
185
+
186
+ it('deselects by optionKey even when selected objects are different references', async () => {
187
+ const selected = [{ id: 1, name: 'Alpha' }];
188
+ wrapper = await mount(OctopusMultiselect, {
189
+ props: { options, optionLabel: 'name', optionKey: 'id', selected },
190
+ });
191
+ await wrapper.find('input').trigger('focus');
192
+ const optionCheckboxes = document.body.querySelectorAll('.octopus-multiselect-options input[type="checkbox"]');
193
+ await new DOMWrapper(optionCheckboxes[0] as Element).trigger('input');
194
+ expect(wrapper.emitted('update:selected')?.[0]).toEqual([[]]);
195
+ });
196
+
197
+ it('toggleAll deselects by optionKey even when selected objects are different references', async () => {
198
+ const selected = options.map((o) => ({ ...o }));
199
+ wrapper = await mount(OctopusMultiselect, {
200
+ props: { options, optionLabel: 'name', optionKey: 'id', selected },
201
+ });
202
+ await wrapper.find('input').trigger('focus');
203
+ const allCheckbox = document.body.querySelector('.octopus-multiselect-dropdown > .octopus-form-item input[type="checkbox"]')!;
204
+ await new DOMWrapper(allCheckbox).trigger('input');
205
+ expect(wrapper.emitted('update:selected')?.[0]).toEqual([[]]);
161
206
  });
162
207
  });
@@ -0,0 +1,168 @@
1
+ import '@tests/mocks/i18n';
2
+
3
+ import OctopusSelect from '@/components/form/OctopusSelect.vue';
4
+ import { DOMWrapper, type VueWrapper } from '@vue/test-utils';
5
+ import { mount } from '@tests/utils';
6
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
+
8
+ const options = [
9
+ { id: 1, name: 'Alpha' },
10
+ { id: 2, name: 'Beta' },
11
+ { id: 3, name: 'Gamma' },
12
+ ];
13
+
14
+ // The dropdown is teleported to .octopus-app — helper to query it from the document.
15
+ function getDropdown(): Element | null {
16
+ return document.body.querySelector('.octopus-select-dropdown');
17
+ }
18
+
19
+ describe('OctopusSelect', () => {
20
+ // The dropdown teleports to .octopus-app, which is normally the app root (see App.vue).
21
+ // It doesn't exist in the test DOM, so it must be created before mount.
22
+ let appElement: HTMLElement;
23
+
24
+ beforeEach(() => {
25
+ appElement = document.createElement('div');
26
+ appElement.className = 'octopus-app';
27
+ document.body.appendChild(appElement);
28
+ });
29
+
30
+ // Shared wrapper ref so afterEach can properly unmount it.
31
+ // Proper unmount lets Vue clean up the teleport target before the next test starts.
32
+ let wrapper: VueWrapper;
33
+ afterEach(() => {
34
+ wrapper?.unmount();
35
+ appElement.remove();
36
+ });
37
+
38
+ it('renders label when provided', async () => {
39
+ wrapper = await mount(OctopusSelect, {
40
+ props: { options, optionLabel: 'name', label: 'My label' },
41
+ });
42
+ expect(wrapper.find('label.form-label').text()).toBe('My label');
43
+ });
44
+
45
+ it('does not render label when not provided', async () => {
46
+ wrapper = await mount(OctopusSelect, {
47
+ props: { options, optionLabel: 'name' },
48
+ });
49
+ expect(wrapper.find('label.form-label').exists()).toBe(false);
50
+ });
51
+
52
+ it('opens dropdown on input focus', async () => {
53
+ wrapper = await mount(OctopusSelect, {
54
+ props: { options, optionLabel: 'name' },
55
+ });
56
+ expect(getDropdown()).toBeNull();
57
+ await wrapper.find('input').trigger('focus');
58
+ expect(getDropdown()).not.toBeNull();
59
+ });
60
+
61
+ it('shows one button per option when open', async () => {
62
+ wrapper = await mount(OctopusSelect, {
63
+ props: { options, optionLabel: 'name' },
64
+ });
65
+ await wrapper.find('input').trigger('focus');
66
+ const optionButtons = document.body.querySelectorAll('.octopus-select-option');
67
+ expect(optionButtons).toHaveLength(3);
68
+ expect(optionButtons[0].textContent?.trim()).toBe('Alpha');
69
+ });
70
+
71
+ it('filters options locally by search query', async () => {
72
+ wrapper = await mount(OctopusSelect, {
73
+ props: { options, optionLabel: 'name' },
74
+ });
75
+ await wrapper.find('input').trigger('focus');
76
+ await wrapper.find('input').setValue('al');
77
+ await wrapper.find('input').trigger('input');
78
+ expect(document.body.querySelectorAll('.octopus-select-option')).toHaveLength(1);
79
+ });
80
+
81
+ it('shows no-results message when filter matches nothing', async () => {
82
+ wrapper = await mount(OctopusSelect, {
83
+ props: { options, optionLabel: 'name' },
84
+ });
85
+ await wrapper.find('input').trigger('focus');
86
+ await wrapper.find('input').setValue('zzz');
87
+ await wrapper.find('input').trigger('input');
88
+ expect(document.body.querySelector('.text-indic')).not.toBeNull();
89
+ });
90
+
91
+ it('emits update:value with the clicked option', async () => {
92
+ wrapper = await mount(OctopusSelect, {
93
+ props: { options, optionLabel: 'name' },
94
+ });
95
+ await wrapper.find('input').trigger('focus');
96
+ await new DOMWrapper(document.body.querySelectorAll('.octopus-select-option')[1]).trigger('click');
97
+ expect(wrapper.emitted('update:value')?.[0]).toEqual([options[1]]);
98
+ });
99
+
100
+ it('closes dropdown after selecting an option', async () => {
101
+ wrapper = await mount(OctopusSelect, {
102
+ props: { options, optionLabel: 'name' },
103
+ });
104
+ await wrapper.find('input').trigger('focus');
105
+ await new DOMWrapper(document.body.querySelectorAll('.octopus-select-option')[0]).trigger('click');
106
+ expect(getDropdown()).toBeNull();
107
+ });
108
+
109
+ it('shows selected item label in the field when closed', async () => {
110
+ wrapper = await mount(OctopusSelect, {
111
+ props: { options, optionLabel: 'name', value: options[0] },
112
+ });
113
+ expect(wrapper.find('.octopus-select-value').text()).toBe('Alpha');
114
+ });
115
+
116
+ it('marks the selected option with the selected class', async () => {
117
+ wrapper = await mount(OctopusSelect, {
118
+ props: { options, optionLabel: 'name', value: options[0] },
119
+ });
120
+ await wrapper.find('.octopus-select-field').trigger('click');
121
+ const optionButtons = document.body.querySelectorAll('.octopus-select-option');
122
+ expect(optionButtons[0].classList).toContain('selected');
123
+ expect(optionButtons[1].classList).not.toContain('selected');
124
+ });
125
+
126
+ it('deselects the current option by default (allowDeselect defaults to true)', async () => {
127
+ wrapper = await mount(OctopusSelect, {
128
+ props: { options, optionLabel: 'name', optionKey: 'id', value: options[0] },
129
+ });
130
+ await wrapper.find('.octopus-select-field').trigger('click');
131
+ await new DOMWrapper(document.body.querySelectorAll('.octopus-select-option')[0]).trigger('click');
132
+ expect(wrapper.emitted('update:value')?.[0]).toEqual([undefined]);
133
+ });
134
+
135
+ it('does not deselect when allowDeselect is false', async () => {
136
+ wrapper = await mount(OctopusSelect, {
137
+ props: { options, optionLabel: 'name', optionKey: 'id', value: options[0], allowDeselect: false as boolean },
138
+ });
139
+ await wrapper.find('.octopus-select-field').trigger('click');
140
+ await new DOMWrapper(document.body.querySelectorAll('.octopus-select-option')[0]).trigger('click');
141
+ expect(wrapper.emitted('update:value')?.[0]).toEqual([options[0]]);
142
+ });
143
+
144
+ it('does not open dropdown when disabled', async () => {
145
+ wrapper = await mount(OctopusSelect, {
146
+ props: { options, optionLabel: 'name', isDisabled: true },
147
+ });
148
+ await wrapper.find('input').trigger('focus');
149
+ expect(getDropdown()).toBeNull();
150
+ });
151
+
152
+ it('disables input when isDisabled is true', async () => {
153
+ wrapper = await mount(OctopusSelect, {
154
+ props: { options, optionLabel: 'name', isDisabled: true },
155
+ });
156
+ expect(wrapper.find('input').attributes('disabled')).toBeDefined();
157
+ });
158
+
159
+ it('matches by optionKey when checking selection', async () => {
160
+ const value = { id: 1, name: 'Alpha' };
161
+ wrapper = await mount(OctopusSelect, {
162
+ props: { options, optionLabel: 'name', optionKey: 'id', value },
163
+ });
164
+ await wrapper.find('.octopus-select-field').trigger('click');
165
+ const optionButtons = document.body.querySelectorAll('.octopus-select-option');
166
+ expect(optionButtons[0].classList).toContain('selected');
167
+ });
168
+ });
package/tsconfig.json CHANGED
@@ -5,15 +5,13 @@
5
5
  // "strict": true,
6
6
  "jsx": "preserve",
7
7
  "importHelpers": true,
8
- "moduleResolution": "node",
8
+ "moduleResolution": "bundler",
9
9
  "experimentalDecorators": true,
10
10
  "skipLibCheck": true,
11
11
  "esModuleInterop": true,
12
12
  "allowSyntheticDefaultImports": true,
13
13
  "sourceMap": true,
14
- "baseUrl": ".",
15
14
  "types": [
16
- "webpack-env",
17
15
  "sockjs-client"
18
16
  ],
19
17
  "paths": {
@@ -21,7 +19,7 @@
21
19
  "./src/*"
22
20
  ],
23
21
  "@tests/*": [
24
- "tests/*"
22
+ "./tests/*"
25
23
  ]
26
24
  },
27
25
  "lib": [
@@ -34,9 +32,7 @@
34
32
  "include": [
35
33
  "src/**/*.ts",
36
34
  "src/**/*.tsx",
37
- "src/**/*.vue",
38
- "tests/**/*.ts",
39
- "tests/**/*.tsx"
35
+ "src/**/*.vue"
40
36
  ],
41
37
  "exclude": [
42
38
  "node_modules"
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": ["sockjs-client", "vitest/globals"]
5
+ },
6
+ "include": [
7
+ "src/**/*.ts",
8
+ "src/**/*.tsx",
9
+ "src/**/*.vue",
10
+ "tests/**/*.ts",
11
+ "tests/**/*.tsx"
12
+ ]
13
+ }
package/vitest.config.js CHANGED
@@ -12,7 +12,8 @@ export default defineConfig(env => mergeConfig(viteConfig(env), defineConfig({
12
12
  environment: 'happy-dom',
13
13
  //setupFiles: ['./tests/setup.ts'],
14
14
  typecheck: {
15
- enabled: true
15
+ enabled: true,
16
+ tsconfig: './tsconfig.test.json'
16
17
  }
17
18
  }
18
19
  })));