@webitel/ui-sdk 26.8.56 → 26.8.57

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 (34) hide show
  1. package/dist/clients-B8MJJx6E.js +39958 -0
  2. package/dist/{components-CWSUHV29.js → components-BWyW5EEY.js} +3 -3
  3. package/dist/{engineCallFileType.zod-C-t93kQg.js → engineCallFileType-D7QVFOac.js} +1 -1
  4. package/dist/{generateInstance-C9d7J_TX.js → genClient-HHiOUj56.js} +969 -755
  5. package/dist/ui-sdk.js +2 -2
  6. package/dist/ui-sdk.umd.cjs +2056 -2056
  7. package/dist/{wt-call-media-action-Bn2bGCWs.js → wt-call-media-action-Bkyppnsm.js} +1 -1
  8. package/dist/{wt-chat-emoji-DRK_E-lD.js → wt-chat-emoji-Cj3B8oR5.js} +1 -1
  9. package/dist/{wt-display-chip-items-C5z7aCDZ.js → wt-display-chip-items-Cvm5rOYr.js} +1 -1
  10. package/dist/{wt-screen-recordings-action-Dj6ITuhE.js → wt-screen-recordings-action-DI1qlUi1.js} +1 -1
  11. package/dist/{wt-send-message-popup-G26F9NPH.js → wt-send-message-popup-OYvzhdyL.js} +2 -2
  12. package/dist/{wt-type-extension-value-input--Vc1cs5d.js → wt-type-extension-value-input-BfUPxO-s.js} +2 -2
  13. package/dist/{wt-vidstack-player-FD4gfDSE.js → wt-vidstack-player-DjQEPOTu.js} +1 -1
  14. package/package.json +6 -2
  15. package/src/modules/UploadCsvPopup/components/__tests__/wt-upload-csv-popup.spec.js +32 -0
  16. package/src/modules/UploadCsvPopup/components/wt-upload-csv-popup.vue +15 -26
  17. package/src/modules/UploadCsvPopup/composable/__tests__/useUploadCsv.spec.js +393 -0
  18. package/src/modules/UploadCsvPopup/composable/useUploadCsv.ts +36 -19
  19. package/src/modules/UploadCsvPopup/index.ts +11 -0
  20. package/src/modules/UploadCsvPopup/scripts/__tests__/normalizeCSVData.spec.js +125 -0
  21. package/src/modules/UploadCsvPopup/scripts/__tests__/parseCSV.spec.js +63 -0
  22. package/src/modules/UploadCsvPopup/scripts/normalizeCSVData.ts +2 -0
  23. package/src/modules/UploadCsvPopup/scripts/parseCSV.ts +0 -23
  24. package/types/.tsbuildinfo +1 -1
  25. package/types/api/defaults/getDefaultInstance/getDefaultInstance.d.ts +1 -1
  26. package/types/modules/UploadCsvPopup/components/__tests__/wt-upload-csv-popup.spec.d.ts +1 -0
  27. package/types/modules/UploadCsvPopup/components/wt-upload-csv-popup.vue.d.ts +5 -5
  28. package/types/modules/UploadCsvPopup/composable/__tests__/useUploadCsv.spec.d.ts +1 -0
  29. package/types/modules/UploadCsvPopup/composable/useUploadCsv.d.ts +7 -3
  30. package/types/modules/UploadCsvPopup/index.d.ts +5 -0
  31. package/types/modules/UploadCsvPopup/scripts/__tests__/normalizeCSVData.spec.d.ts +1 -0
  32. package/types/modules/UploadCsvPopup/scripts/__tests__/parseCSV.spec.d.ts +1 -0
  33. package/types/modules/UploadCsvPopup/scripts/normalizeCSVData.d.ts +2 -0
  34. package/dist/clients-CWSXQd89.js +0 -40124
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./_plugin-vue_export-helper-B3ysoDQm.js";
2
- import { t } from "./engineCallFileType.zod-C-t93kQg.js";
2
+ import { t } from "./engineCallFileType-D7QVFOac.js";
3
3
  import { computed as n, createBlock as r, createCommentVNode as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, openBlock as l, resolveComponent as u, toDisplayString as d, withCtx as f } from "vue";
4
4
  //#region src/components/on-demand/wt-call-media-action/wt-call-media-action.vue?vue&type=script&setup=true&lang.ts
5
5
  var p = { class: "wt-call-media-action__option" }, m = /*#__PURE__*/ e(/* @__PURE__ */ c({
@@ -1,4 +1,4 @@
1
- import "./components-CWSUHV29.js";
1
+ import "./components-BWyW5EEY.js";
2
2
  import { t as e } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { l as t } from "./enums-DY3jIXFF.js";
4
4
  import { t as n } from "./wt-button-2_aOV7LX.js";
@@ -1,4 +1,4 @@
1
- import { C as e, i as t } from "./components-CWSUHV29.js";
1
+ import { C as e, i as t } from "./components-BWyW5EEY.js";
2
2
  import { t as n } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { t as r } from "./displayText-CtaxzaBz.js";
4
4
  import { Fragment as i, computed as a, createCommentVNode as o, createElementBlock as s, createTextVNode as c, createVNode as l, defineComponent as u, openBlock as d, renderList as f, renderSlot as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./_plugin-vue_export-helper-B3ysoDQm.js";
2
- import { t } from "./engineCallFileType.zod-C-t93kQg.js";
2
+ import { t } from "./engineCallFileType-D7QVFOac.js";
3
3
  import { computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, defineComponent as l, openBlock as u, resolveComponent as d, toDisplayString as f, unref as p, withCtx as m } from "vue";
4
4
  //#region src/components/on-demand/wt-screen-recordings-action/wt-screen-recordings-action.vue?vue&type=script&setup=true&lang.ts
5
5
  var h = { class: "wt-screen-recordings-action" }, g = { class: "wt-screen-recordings-action__option" }, _ = /*#__PURE__*/ e(/* @__PURE__ */ l({
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./rolldown-runtime-BEcgMyyN.js";
2
- import { n as t, r as n } from "./clients-CWSXQd89.js";
3
- import { T as r, n as i, w as a } from "./components-CWSUHV29.js";
2
+ import { n as t, r as n } from "./clients-B8MJJx6E.js";
3
+ import { T as r, n as i, w as a } from "./components-BWyW5EEY.js";
4
4
  import { t as o } from "./vue-i18n-Db_oYfO8.js";
5
5
  import { n as s } from "./useEventBus-B-ZeklLu.js";
6
6
  import { createBlock as c, createTextVNode as l, createVNode as u, defineComponent as d, mergeProps as f, onMounted as p, openBlock as m, ref as h, resolveComponent as g, toDisplayString as _, unref as v, withCtx as y } from "vue";
@@ -1,5 +1,5 @@
1
- import { t as e } from "./clients-CWSXQd89.js";
2
- import { a as t, o as n, r, s as i } from "./components-CWSUHV29.js";
1
+ import { t as e } from "./clients-B8MJJx6E.js";
2
+ import { a as t, o as n, r, s as i } from "./components-BWyW5EEY.js";
3
3
  import { t as a } from "./enums-DY3jIXFF.js";
4
4
  import { t as o } from "./vue-i18n-Db_oYfO8.js";
5
5
  import { computed as s, createBlock as c, createCommentVNode as l, createVNode as u, defineComponent as d, mergeModels as f, mergeProps as p, openBlock as m, renderSlot as h, resolveComponent as g, unref as _, useModel as v } from "vue";
@@ -1,4 +1,4 @@
1
- import { D as e } from "./components-CWSUHV29.js";
1
+ import { D as e } from "./components-BWyW5EEY.js";
2
2
  import { t } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
3
  import { l as n } from "./enums-DY3jIXFF.js";
4
4
  import "./wt-button-2_aOV7LX.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "26.8.56",
3
+ "version": "26.8.57",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "npm run docs:dev",
@@ -62,6 +62,7 @@
62
62
  "@vuepic/vue-datepicker": "^4.5.1",
63
63
  "@vueuse/components": "^14.0.0",
64
64
  "autosize": "^6.0.1",
65
+ "csv-parse": "^6.1.0",
65
66
  "csv-stringify": "^5.5.3",
66
67
  "date-fns-tz": "^3.2.0",
67
68
  "dompurify": "^3.3.1",
@@ -139,7 +140,6 @@
139
140
  "@vuelidate/validators": "^2.0.4",
140
141
  "@webitel/styleguide": "~26.2",
141
142
  "clipboard-copy": "^4.x",
142
- "csv-parse": "^6.1.0",
143
143
  "globals": "^16.0.0",
144
144
  "globby": "^16.x",
145
145
  "happy-dom": "^20.x",
@@ -355,6 +355,10 @@
355
355
  "types": "./types/modules/ObjectPermissions/index.d.ts",
356
356
  "import": "./src/modules/ObjectPermissions/index.ts"
357
357
  },
358
+ "./modules/UploadCsvPopup": {
359
+ "types": "./types/modules/UploadCsvPopup/index.d.ts",
360
+ "import": "./src/modules/UploadCsvPopup/index.ts"
361
+ },
358
362
  "./plugins*": {
359
363
  "types": "./types/plugins*",
360
364
  "import": "./src/plugins*"
@@ -0,0 +1,32 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+
3
+ import WtUploadCsvPopup from '../wt-upload-csv-popup.vue';
4
+
5
+ describe('WtUploadCsvPopup', () => {
6
+ it('renders a component', () => {
7
+ const wrapper = shallowMount(WtUploadCsvPopup, {
8
+ props: {
9
+ file: null,
10
+ mappingFields: [],
11
+ },
12
+ });
13
+
14
+ expect(wrapper).toBeTruthy();
15
+ });
16
+
17
+ /*
18
+ An undeclared prop silently falls through as an attribute, so the composable
19
+ would never see the saver and the import would close as a success without
20
+ saving anything. Props extends UseUploadCsvProps to prevent that — this
21
+ guards the contract.
22
+ */
23
+ it.each([
24
+ 'file',
25
+ 'mappingFields',
26
+ 'addBulkItems',
27
+ 'handlingMode',
28
+ 'fileUploadHandler',
29
+ ])('declares the %s prop', (prop) => {
30
+ expect(Object.keys(WtUploadCsvPopup.props)).toContain(prop);
31
+ });
32
+ });
@@ -79,8 +79,8 @@
79
79
  :key="key"
80
80
  class="wt-upload-csv-popup-mapping-item"
81
81
  >
82
- <p class="wt-upload-csv-popup-mapping-item__field">
83
- {{ t(field.locale) }}<span v-if="field.required">*</span>
82
+ <p class="wt-upload-csv-popup-mapping-item__field typo-body-1">
83
+ {{ getFieldLabel(field) }}<span v-if="field.required">*</span>
84
84
  </p>
85
85
 
86
86
  <wt-single-select
@@ -88,34 +88,29 @@
88
88
  v-model:model-value="field.csv"
89
89
  :show-clear="!field.required"
90
90
  :options="csvColumns"
91
- :placeholder="t(field.locale)"
91
+ :placeholder="getFieldLabel(field)"
92
92
  :data-key="null"
93
93
  class="wt-upload-csv-popup-mapping-item__select"
94
94
  />
95
95
  <wt-multi-select
96
96
  v-else
97
97
  v-model:model-value="field.csv"
98
+ chips-view
98
99
  :options="csvColumns"
99
- :placeholder="t(field.locale)"
100
+ :placeholder="getFieldLabel(field)"
101
+ :data-key="null"
100
102
  class="wt-upload-csv-popup-mapping-item__select"
101
103
  />
102
104
 
103
105
  <div
104
106
  v-if="field.tooltip"
105
- class="upload-tooltip"
107
+ class="upload-tooltip typo-caption"
106
108
  >
107
109
  {{ field.tooltip }}
108
110
  </div>
109
111
  </div>
110
112
  </div>
111
113
  </section>
112
-
113
- <div
114
- v-show="!isParsingPreview && parseErrorStackTrace"
115
- class="wt-upload-csv-popup-form__error-stack-trace"
116
- >
117
- {{ parseErrorStackTrace }}
118
- </div>
119
114
  </template>
120
115
 
121
116
  <template
@@ -143,7 +138,10 @@
143
138
  import { ref, toRefs } from 'vue';
144
139
  import { useI18n } from 'vue-i18n';
145
140
 
146
- import useUploadCsv from '../composable/useUploadCsv';
141
+ import useUploadCsv, {
142
+ type UseUploadCsvProps,
143
+ } from '../composable/useUploadCsv';
144
+ import type { CsvMappingField } from '../scripts/normalizeCSVData';
147
145
  import HandlingCSVMode from '../types/WtUploadCSVHandlingMode.enum';
148
146
 
149
147
  interface CharsetOption {
@@ -151,12 +149,9 @@ interface CharsetOption {
151
149
  value: string;
152
150
  }
153
151
 
154
- interface Props {
152
+ interface Props extends UseUploadCsvProps {
155
153
  file: File | null;
156
154
  mappingFields: CsvMappingField[];
157
- addBulkItems?: (items: unknown[]) => unknown | Promise<unknown>;
158
- handlingMode?: string;
159
- fileUploadHandler?: () => unknown | Promise<unknown>;
160
155
  }
161
156
 
162
157
  const props = withDefaults(defineProps<Props>(), {
@@ -173,6 +168,9 @@ const emit = defineEmits<{
173
168
 
174
169
  const { t } = useI18n();
175
170
 
171
+ const getFieldLabel = (field: CsvMappingField) =>
172
+ field.locale ? t(field.locale) : field.name;
173
+
176
174
  const skipHeaders = ref(true);
177
175
  const separator = ref(',');
178
176
  const charsetOptions = ref<CharsetOption[]>([]);
@@ -187,7 +185,6 @@ const {
187
185
  isReadingFile,
188
186
  isParsingCSV,
189
187
  isParsingPreview,
190
- parseErrorStackTrace,
191
188
  csvPreviewTableData,
192
189
  csvPreviewTableHeaders,
193
190
  csvColumns,
@@ -254,13 +251,5 @@ const {
254
251
  }
255
252
  }
256
253
  }
257
-
258
- .wt-upload-csv-popup-form__error-stack-trace {
259
- margin-top: var(--spacing-sm);
260
- padding: var(--spacing-sm);
261
- color: var(--error-color);
262
- border-radius: var(--border-radius);
263
- background: var(--secondary-color);
264
- }
265
254
  }
266
255
  </style>
@@ -0,0 +1,393 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { ref } from 'vue';
3
+
4
+ import HandlingCSVMode from '../../types/WtUploadCSVHandlingMode.enum';
5
+ import useUploadCsv from '../useUploadCsv';
6
+
7
+ const Component = {
8
+ props: {
9
+ file: {
10
+ default: null,
11
+ },
12
+ mappingFields: {
13
+ type: Array,
14
+ default: () => [],
15
+ },
16
+ addBulkItems: {
17
+ type: Function,
18
+ default: undefined,
19
+ },
20
+ handlingMode: {
21
+ type: String,
22
+ default: HandlingCSVMode.PROCESS,
23
+ },
24
+ fileUploadHandler: {
25
+ type: Function,
26
+ default: undefined,
27
+ },
28
+ },
29
+ emits: [
30
+ 'changeMappingFields',
31
+ 'save',
32
+ 'close',
33
+ ],
34
+ setup(props, { emit }) {
35
+ const skipHeaders = ref(true);
36
+ const separator = ref(',');
37
+
38
+ return {
39
+ skipHeaders,
40
+ separator,
41
+ ...useUploadCsv({
42
+ props,
43
+ emit,
44
+ skipHeaders,
45
+ separator,
46
+ }),
47
+ };
48
+ },
49
+ render: () => null,
50
+ };
51
+
52
+ const makeFile = (content) => {
53
+ const blob = new Blob(
54
+ [
55
+ content,
56
+ ],
57
+ {
58
+ type: 'text/csv',
59
+ },
60
+ );
61
+
62
+ return new File(
63
+ [
64
+ blob,
65
+ ],
66
+ 'test.csv',
67
+ {
68
+ type: 'text/csv',
69
+ },
70
+ );
71
+ };
72
+
73
+ // the composable reads the file through a watcher, so give FileReader a tick
74
+ const mountWithFile = async (csv, props = {}) => {
75
+ const wrapper = shallowMount(Component, {
76
+ props,
77
+ });
78
+
79
+ await wrapper.setProps({
80
+ file: makeFile(csv),
81
+ });
82
+
83
+ await new Promise((resolve) => {
84
+ setTimeout(resolve, 100);
85
+ });
86
+
87
+ return wrapper;
88
+ };
89
+
90
+ describe('useUploadCsv', () => {
91
+ it('mounts a component with the composable', () => {
92
+ const wrapper = shallowMount(Component, {
93
+ props: {
94
+ file: {},
95
+ },
96
+ });
97
+
98
+ expect(wrapper.exists()).toBe(true);
99
+ });
100
+
101
+ it('parses and saves simple csv', async () => {
102
+ const csv = `
103
+ col1,col2
104
+ John,30
105
+ Jane,25
106
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
107
+
108
+ const saveCallback = vi.fn();
109
+
110
+ const wrapper = await mountWithFile(csv, {
111
+ addBulkItems: saveCallback,
112
+ mappingFields: [
113
+ {
114
+ name: 'name',
115
+ csv: 'col1',
116
+ },
117
+ {
118
+ name: 'age',
119
+ csv: 'col2',
120
+ },
121
+ ],
122
+ });
123
+
124
+ await wrapper.vm.processCSV();
125
+
126
+ expect(saveCallback).toHaveBeenCalledWith([
127
+ {
128
+ name: 'John',
129
+ age: '30',
130
+ },
131
+ {
132
+ name: 'Jane',
133
+ age: '25',
134
+ },
135
+ ]);
136
+ });
137
+
138
+ it('parsing of csv with empty required throws error', async () => {
139
+ const csv = `
140
+ col1,col2
141
+ John,
142
+ Jane,25
143
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
144
+
145
+ const saveCallback = vi.fn();
146
+
147
+ const wrapper = await mountWithFile(csv, {
148
+ addBulkItems: saveCallback,
149
+ mappingFields: [
150
+ {
151
+ name: 'name',
152
+ csv: 'col1',
153
+ required: true,
154
+ },
155
+ {
156
+ name: 'age',
157
+ csv: 'col2',
158
+ required: true,
159
+ },
160
+ ],
161
+ });
162
+
163
+ await expect(wrapper.vm.processCSV()).rejects.toBeTruthy();
164
+ expect(saveCallback).not.toHaveBeenCalled();
165
+ });
166
+
167
+ it('parsing of csv with multiple columns selected to required field', async () => {
168
+ const csv = `
169
+ col1,col2,col3
170
+ John,,30
171
+ Jane,25,
172
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
173
+
174
+ const saveCallback = vi.fn();
175
+
176
+ const wrapper = await mountWithFile(csv, {
177
+ addBulkItems: saveCallback,
178
+ mappingFields: [
179
+ {
180
+ name: 'name',
181
+ csv: 'col1',
182
+ required: true,
183
+ },
184
+ {
185
+ name: 'age',
186
+ csv: [
187
+ 'col2',
188
+ 'col3',
189
+ ],
190
+ required: true,
191
+ },
192
+ ],
193
+ });
194
+
195
+ await wrapper.vm.processCSV();
196
+
197
+ expect(saveCallback).toHaveBeenCalledWith([
198
+ {
199
+ name: 'John',
200
+ age: [
201
+ '',
202
+ '30',
203
+ ],
204
+ },
205
+ {
206
+ name: 'Jane',
207
+ age: [
208
+ '25',
209
+ '',
210
+ ],
211
+ },
212
+ ]);
213
+ });
214
+
215
+ /*
216
+ WTEL-10058: guards the admin data that the parser never touched — queue
217
+ member variables, blacklist descriptions, device passwords. Type casting
218
+ lives in CRM now, so everything reaching a consumer is a string.
219
+ */
220
+ it('keeps plain values as strings, so text columns are not coerced', async () => {
221
+ const csv = `
222
+ col1,col2
223
+ true,"[1,2]"
224
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
225
+
226
+ const saveCallback = vi.fn();
227
+
228
+ const wrapper = await mountWithFile(csv, {
229
+ addBulkItems: saveCallback,
230
+ mappingFields: [
231
+ {
232
+ name: 'flag',
233
+ csv: 'col1',
234
+ },
235
+ {
236
+ name: 'list',
237
+ csv: 'col2',
238
+ },
239
+ ],
240
+ });
241
+
242
+ await wrapper.vm.processCSV();
243
+
244
+ expect(saveCallback).toHaveBeenCalledWith([
245
+ {
246
+ flag: 'true',
247
+ list: '[1,2]',
248
+ },
249
+ ]);
250
+ });
251
+
252
+ it('uploads the whole file in the upload handling mode', async () => {
253
+ const csv = `
254
+ col1
255
+ John
256
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
257
+
258
+ const saveCallback = vi.fn();
259
+ const fileUploadHandler = vi.fn();
260
+
261
+ const wrapper = await mountWithFile(csv, {
262
+ handlingMode: HandlingCSVMode.UPLOAD,
263
+ addBulkItems: saveCallback,
264
+ fileUploadHandler,
265
+ mappingFields: [
266
+ {
267
+ name: 'name',
268
+ csv: 'col1',
269
+ },
270
+ ],
271
+ });
272
+
273
+ await wrapper.vm.processCSV();
274
+
275
+ expect(fileUploadHandler).toHaveBeenCalled();
276
+ expect(saveCallback).not.toHaveBeenCalled();
277
+ });
278
+
279
+ /*
280
+ WTEL-10058: the popup owns the separator, so a consumer that ships the raw
281
+ file to the backend has no other way to learn which one the user picked.
282
+ */
283
+ it('hands the chosen separator to the file upload handler', async () => {
284
+ const csv = 'col1;col2\nJohn;30';
285
+
286
+ const fileUploadHandler = vi.fn();
287
+
288
+ const wrapper = await mountWithFile(csv, {
289
+ handlingMode: HandlingCSVMode.UPLOAD,
290
+ fileUploadHandler,
291
+ mappingFields: [
292
+ {
293
+ name: 'name',
294
+ csv: 'col1',
295
+ },
296
+ ],
297
+ });
298
+
299
+ wrapper.vm.separator = ';';
300
+ await wrapper.vm.processCSV();
301
+
302
+ expect(fileUploadHandler).toHaveBeenCalledWith({
303
+ separator: ';',
304
+ });
305
+ });
306
+
307
+ it('emits save and closes on a successful handleSave', async () => {
308
+ const csv = `
309
+ col1
310
+ John
311
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
312
+
313
+ const wrapper = await mountWithFile(csv, {
314
+ addBulkItems: vi.fn(),
315
+ mappingFields: [
316
+ {
317
+ name: 'name',
318
+ csv: 'col1',
319
+ },
320
+ ],
321
+ });
322
+
323
+ await wrapper.vm.handleSave();
324
+
325
+ expect(wrapper.emitted('save')).toHaveLength(1);
326
+ expect(wrapper.emitted('close')).toHaveLength(1);
327
+ });
328
+
329
+ it('does not close the popup when saving fails', async () => {
330
+ const csv = `
331
+ col1
332
+ John
333
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
334
+
335
+ const wrapper = await mountWithFile(csv, {
336
+ addBulkItems: vi.fn(() => Promise.reject(new Error('nope'))),
337
+ mappingFields: [
338
+ {
339
+ name: 'name',
340
+ csv: 'col1',
341
+ },
342
+ ],
343
+ });
344
+
345
+ await expect(wrapper.vm.processCSV()).rejects.toThrow();
346
+ expect(wrapper.emitted('close')).toBeUndefined();
347
+ });
348
+
349
+ it('resets the mappings when the parse options change', async () => {
350
+ const csv = `
351
+ col1,col2
352
+ John,30
353
+ `.replaceAll(/ +?/g, ''); // replace all whitespaces, but not newlines
354
+
355
+ const wrapper = await mountWithFile(csv, {
356
+ mappingFields: [
357
+ {
358
+ name: 'name',
359
+ csv: 'col1',
360
+ },
361
+ {
362
+ name: 'tags',
363
+ csv: [
364
+ 'col2',
365
+ ],
366
+ multiple: true,
367
+ },
368
+ ],
369
+ });
370
+
371
+ wrapper.vm.separator = ';';
372
+
373
+ // the parse options watcher is debounced by 1s
374
+ await new Promise((resolve) => {
375
+ setTimeout(resolve, 1200);
376
+ });
377
+
378
+ const emitted = wrapper.emitted('changeMappingFields');
379
+
380
+ expect(emitted).toBeTruthy();
381
+ expect(emitted.at(-1)[0]).toEqual([
382
+ {
383
+ name: 'name',
384
+ csv: '',
385
+ },
386
+ {
387
+ name: 'tags',
388
+ csv: [],
389
+ multiple: true,
390
+ },
391
+ ]);
392
+ });
393
+ });