@weni/unnnic-system 2.14.2 → 2.15.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.
@@ -0,0 +1,256 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, vi } from 'vitest';
3
+ import ModalDialog from '../ModalDialog.vue';
4
+
5
+ describe('ModalDialog.vue', () => {
6
+ let wrapper;
7
+
8
+ beforeEach(() => {
9
+ wrapper = mount(ModalDialog, {
10
+ props: {
11
+ title: 'Test Title',
12
+ icon: 'test-icon',
13
+ modelValue: true,
14
+ showCloseIcon: true,
15
+ primaryButtonProps: { text: 'Confirm' },
16
+ 'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
17
+ },
18
+ global: {
19
+ stubs: ['UnnnicIcon', 'UnnnicButton'],
20
+ },
21
+ });
22
+ });
23
+
24
+ describe('Elements rendering', () => {
25
+ it('matches the snapshot', () => {
26
+ expect(wrapper.html()).toMatchSnapshot();
27
+ });
28
+
29
+ it('should render correctly when modelValue is true', () => {
30
+ const modal = wrapper.find('[data-testid="modal-dialog"]');
31
+ expect(modal.exists()).toBe(true);
32
+ });
33
+
34
+ it('should not render when modelValue is false', async () => {
35
+ await wrapper.setProps({ modelValue: false });
36
+
37
+ const modal = wrapper.find('[data-testid="modal-dialog"]');
38
+ expect(modal.exists()).toBe(false);
39
+ });
40
+
41
+ it('should apply the correct size class based on the size prop', async () => {
42
+ const modalContainer = wrapper.find('[data-testid="modal-container"]');
43
+ const defaultClass = 'unnnic-modal-dialog__container';
44
+
45
+ expect(modalContainer.classes()).toContain(defaultClass + '--md');
46
+
47
+ await wrapper.setProps({ size: 'lg' });
48
+ expect(modalContainer.classes()).toContain(defaultClass + '--lg');
49
+
50
+ await wrapper.setProps({ size: 'sm' });
51
+ expect(modalContainer.classes()).toContain(defaultClass + '--sm');
52
+ });
53
+
54
+ it('should render the icon and title when provided', () => {
55
+ const title = wrapper.find('[data-testid="title-text"]');
56
+ expect(title.exists()).toBe(true);
57
+ expect(title.text()).toBe('Test Title');
58
+
59
+ const icon = wrapper.findComponent('[data-testid="title-icon"]');
60
+ expect(icon.exists()).toBe(true);
61
+ expect(icon.props('icon')).toBe('test-icon');
62
+ });
63
+
64
+ it('should render the icon from iconsMapper when type prop is provided', async () => {
65
+ await wrapper.setProps({
66
+ type: 'success',
67
+ icon: '',
68
+ });
69
+
70
+ const icon = wrapper.findComponent('[data-testid="title-icon"]');
71
+ expect(icon.exists()).toBe(true);
72
+ expect(icon.props().icon).toBe(wrapper.vm.iconsMapper['success'].icon);
73
+ });
74
+
75
+ it('should not render the icon when both icon and type props are not provided', async () => {
76
+ await wrapper.setProps({
77
+ icon: '',
78
+ type: '',
79
+ });
80
+
81
+ const icon = wrapper.find('[data-testid="title-icon"]');
82
+ expect(icon.exists()).toBe(false);
83
+ });
84
+
85
+ it('should render the close icon when showCloseIcon is true', () => {
86
+ const closeIcon = wrapper.find('[data-testid="close-icon"]');
87
+ expect(closeIcon.exists()).toBe(true);
88
+ });
89
+
90
+ it('should not render buttons when primaryButtonProps is not provided', async () => {
91
+ await wrapper.setProps({ primaryButtonProps: undefined });
92
+
93
+ const primaryButton = wrapper.find('[data-testid="primary-button"]');
94
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
95
+ expect(primaryButton.exists()).toBe(false);
96
+ expect(secondaryButton.exists()).toBe(false);
97
+ });
98
+ });
99
+
100
+ describe('Overlay behavior', () => {
101
+ it('should close the modal when clicking on the overlay if persistent is false', async () => {
102
+ expect(wrapper.props().modelValue).toBe(true);
103
+
104
+ const overlay = wrapper.find('[data-testid="modal-overlay"]');
105
+ await overlay.trigger('click');
106
+
107
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
108
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual([false]);
109
+ expect(wrapper.props().modelValue).toBe(false);
110
+ });
111
+
112
+ it('should not close the modal when clicking on the overlay if persistent is true', async () => {
113
+ await wrapper.setProps({ persistent: true });
114
+
115
+ const overlay = wrapper.find('[data-testid="modal-overlay"]');
116
+ await overlay.trigger('click');
117
+
118
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy();
119
+ expect(wrapper.props().modelValue).toBe(true);
120
+ });
121
+ });
122
+
123
+ describe('Slot rendering', () => {
124
+ it('should render leftSidebar slot when provided', () => {
125
+ const wrapper = mount(ModalDialog, {
126
+ props: {
127
+ modelValue: true,
128
+ },
129
+ slots: {
130
+ leftSidebar:
131
+ '<div data-testid="left-sidebar">Left Sidebar Content</div>',
132
+ },
133
+ });
134
+
135
+ const leftSidebar = wrapper.find('[data-testid="left-sidebar"]');
136
+ expect(leftSidebar.exists()).toBe(true);
137
+ expect(leftSidebar.text()).toBe('Left Sidebar Content');
138
+ });
139
+
140
+ it('should render default slot content', () => {
141
+ const wrapper = mount(ModalDialog, {
142
+ props: {
143
+ modelValue: true,
144
+ },
145
+ slots: {
146
+ default: '<div data-testid="default-slot">Default Slot Content</div>',
147
+ },
148
+ });
149
+
150
+ const defaultSlot = wrapper.find('[data-testid="default-slot"]');
151
+ expect(defaultSlot.exists()).toBe(true);
152
+ expect(defaultSlot.text()).toBe('Default Slot Content');
153
+ });
154
+ });
155
+
156
+ describe('Buttons actions', () => {
157
+ it('should close the modal when clicking on close icon', async () => {
158
+ const closeIcon = wrapper.find('[data-testid="close-icon"]');
159
+ await closeIcon.trigger('click');
160
+
161
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
162
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual([false]);
163
+ expect(wrapper.props().modelValue).toBe(false);
164
+ });
165
+
166
+ it('should emit primaryButtonClick event when the primary button is clicked', async () => {
167
+ const primaryButton = wrapper.find('[data-testid="primary-button"]');
168
+ await primaryButton.trigger('click');
169
+
170
+ expect(wrapper.emitted('primaryButtonClick')).toBeTruthy();
171
+ });
172
+
173
+ it('should emit secondaryButtonClick event when the secondary button is clicked', async () => {
174
+ await wrapper.setProps({
175
+ secondaryButtonProps: { text: 'Cancel' },
176
+ });
177
+
178
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
179
+ await secondaryButton.trigger('click');
180
+
181
+ expect(wrapper.emitted('secondaryButtonClick')).toBeTruthy();
182
+ });
183
+
184
+ it('should close the modal when the secondary button is clicked and no secondaryButtonClick event is provided', async () => {
185
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
186
+ await secondaryButton.trigger('click');
187
+
188
+ const emittedValue = wrapper.emitted('update:modelValue');
189
+
190
+ expect(emittedValue).toBeTruthy();
191
+ expect(emittedValue[0][0]).toEqual(false);
192
+ });
193
+ });
194
+
195
+ describe('Actions and appearance', () => {
196
+ it('should not render the secondary button when hideSecondaryButton is true', async () => {
197
+ await wrapper.setProps({
198
+ hideSecondaryButton: true,
199
+ });
200
+ const secondaryButton = wrapper.find('[data-testid="secondary-button"]');
201
+ expect(secondaryButton.exists()).toBe(false);
202
+ });
203
+
204
+ it('should apply a divider class to the actions section when showActionsDivider is true', async () => {
205
+ await wrapper.setProps({
206
+ showActionsDivider: true,
207
+ });
208
+
209
+ const actionsSection = wrapper.find('[data-testid="actions-section"]');
210
+ expect(actionsSection.classes()).toContain(
211
+ 'unnnic-modal-dialog__container__actions--divider',
212
+ );
213
+ });
214
+ });
215
+
216
+ describe('Body overflow', () => {
217
+ it('should toggle body overflow based on modal visibility', async () => {
218
+ await wrapper.setProps({ modelValue: false });
219
+ const updateBodyOverflowSpy = vi.spyOn(wrapper.vm, 'updateBodyOverflow');
220
+
221
+ await wrapper.setProps({ modelValue: true });
222
+ expect(updateBodyOverflowSpy).toHaveBeenCalledWith(true);
223
+
224
+ await wrapper.setProps({ modelValue: false });
225
+ expect(updateBodyOverflowSpy).toHaveBeenCalledWith(false);
226
+ });
227
+ });
228
+
229
+ describe('Validators', () => {
230
+ describe('type prop validator', () => {
231
+ it('should validate type prop when a valid value is provided', () => {
232
+ const validTypes = ['success', 'warning', 'attention'];
233
+ validTypes.forEach((validType) => {
234
+ expect(ModalDialog.props.type.validate(validType)).toBe(true);
235
+ });
236
+ });
237
+
238
+ it('should invalidate type prop when an invalid value is provided', () => {
239
+ expect(ModalDialog.props.type.validate('invalidType')).toBe(false);
240
+ });
241
+ });
242
+
243
+ describe('size prop validator', () => {
244
+ it('should validate size prop when a valid value is provided', () => {
245
+ const validSizes = ['sm', 'md', 'lg'];
246
+ validSizes.forEach((validSize) => {
247
+ expect(ModalDialog.props.size.validate(validSize)).toBe(true);
248
+ });
249
+ });
250
+
251
+ it('should invalidate size prop when an invalid value is provided', () => {
252
+ expect(ModalDialog.props.size.validate('invalidSize')).toBe(false);
253
+ });
254
+ });
255
+ });
256
+ });
@@ -0,0 +1,24 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ModalDialog.vue > Elements rendering > matches the snapshot 1`] = `
4
+ "<section data-v-68ebadeb="" class="unnnic-modal-dialog" data-testid="modal-dialog">
5
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__overlay" data-testid="modal-overlay"></section>
6
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container unnnic-modal-dialog__container--md" data-testid="modal-container">
7
+ <!--v-if-->
8
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__body">
9
+ <header data-v-68ebadeb="" class="unnnic-modal-dialog__container__header">
10
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__title-container">
11
+ <unnnic-icon-stub data-v-68ebadeb="" filled="false" next="false" icon="test-icon" clickable="false" size="md" scheme="neutral-darkest" data-testid="title-icon" class="unnnic-modal-dialog__container__title-icon"></unnnic-icon-stub>
12
+ <h1 data-v-68ebadeb="" class="unnnic-modal-dialog__container__title-text" data-testid="title-text">Test Title</h1>
13
+ </section>
14
+ <unnnic-icon-stub data-v-68ebadeb="" filled="false" next="false" icon="close" clickable="true" size="md" scheme="neutral-darkest" data-testid="close-icon"></unnnic-icon-stub>
15
+ </header>
16
+ <section data-v-68ebadeb="" class="unnnic-modal-dialog__container__content"></section>
17
+ <section data-v-68ebadeb="" data-testid="actions-section" class="unnnic-modal-dialog__container__actions">
18
+ <unnnic-button-stub data-v-68ebadeb="" size="large" text="Cancel" type="tertiary" float="false" iconleft="" iconright="" iconcenter="" next="false" disabled="false" loading="false" data-testid="secondary-button" class="unnnic-modal-dialog__container__actions__secondary-button"></unnnic-button-stub>
19
+ <unnnic-button-stub data-v-68ebadeb="" size="large" text="Confirm" type="primary" float="false" iconleft="" iconright="" iconcenter="" next="false" disabled="false" loading="false" data-testid="primary-button" class="unnnic-modal-dialog__container__actions__primary-button"></unnnic-button-stub>
20
+ </section>
21
+ </section>
22
+ </section>
23
+ </section>"
24
+ `;
@@ -1,6 +1,10 @@
1
1
  <template>
2
2
  <table class="unnnic-table-next">
3
- <thead class="unnnic-table-next__header">
3
+ <thead
4
+ v-if="!shouldHideHeaders"
5
+ class="unnnic-table-next__header"
6
+ data-testid="header"
7
+ >
4
8
  <tr
5
9
  class="unnnic-table-next__header-row"
6
10
  data-testid="header-row"
@@ -17,7 +21,13 @@
17
21
  </tr>
18
22
  </thead>
19
23
 
20
- <tbody class="unnnic-table-next__body">
24
+ <tbody
25
+ :class="{
26
+ 'unnnic-table-next__body': true,
27
+ 'unnnic-table-next__body--hide-headers': shouldHideHeaders,
28
+ }"
29
+ data-testid="body"
30
+ >
21
31
  <tr
22
32
  v-if="isLoading"
23
33
  class="unnnic-table-next__body-row"
@@ -50,7 +60,10 @@
50
60
  <TableBodyCell
51
61
  v-for="cell of row.content"
52
62
  :key="cell + index"
53
- class="unnnic-table-next__body-cell"
63
+ :class="[
64
+ 'unnnic-table-next__body-cell',
65
+ `unnnic-table-next__body-cell--${size}`,
66
+ ]"
54
67
  data-testid="body-cell"
55
68
  :cell="cell"
56
69
  />
@@ -59,7 +72,10 @@
59
72
  <TableBodyCell
60
73
  v-for="cell of row.content"
61
74
  :key="cell + index"
62
- class="unnnic-table-next__body-cell"
75
+ :class="[
76
+ 'unnnic-table-next__body-cell',
77
+ `unnnic-table-next__body-cell--${size}`,
78
+ ]"
63
79
  data-testid="body-cell"
64
80
  :cell="cell"
65
81
  />
@@ -71,7 +87,10 @@
71
87
  class="unnnic-table-next__body-row"
72
88
  >
73
89
  <td
74
- class="unnnic-table-next__body-cell"
90
+ :class="[
91
+ 'unnnic-table-next__body-cell',
92
+ `unnnic-table-next__body-cell--${size}`,
93
+ ]"
75
94
  data-testid="body-cell"
76
95
  >
77
96
  <p
@@ -112,7 +131,7 @@ export default {
112
131
  /**
113
132
  * @typedef {Array} HeaderItem
114
133
  * @property {string} content - The content of the header cell.
115
- * @property {number} size - The size of the header cell in fractions.
134
+ * @property {number|string} size - The size of the header cell, either as a fraction (number) or 'auto'.
116
135
  * @property {boolean|undefined} isSortable - Indicates if the cell is enabled for sorting.
117
136
  */
118
137
 
@@ -122,7 +141,7 @@ export default {
122
141
  */
123
142
  headers: {
124
143
  type: Array,
125
- required: true,
144
+ default: () => [],
126
145
  validator: validateHeaders,
127
146
  },
128
147
 
@@ -138,10 +157,21 @@ export default {
138
157
  */
139
158
  rows: {
140
159
  type: Array,
141
- required: true,
160
+ default: () => [],
142
161
  validator: validateRows,
143
162
  },
144
163
 
164
+ size: {
165
+ type: String,
166
+ default: 'sm',
167
+ validator: (value) => ['md', 'sm'].includes(value),
168
+ },
169
+
170
+ hideHeaders: {
171
+ type: Boolean,
172
+ default: false,
173
+ },
174
+
145
175
  pagination: {
146
176
  type: Number,
147
177
  default: 1,
@@ -179,7 +209,20 @@ export default {
179
209
  return this.rows.length === 0 ? 0 : this.paginationTotal;
180
210
  },
181
211
  gridTemplateColumns() {
182
- return this.headers.map((header) => `${header.size || 1}fr`).join(' ');
212
+ const defaultSize = '1fr';
213
+ const getHeaderColumnSize = (header) =>
214
+ typeof header.size === 'number'
215
+ ? `${header.size || 1}fr`
216
+ : header.size || defaultSize;
217
+
218
+ const columnSizes = this.headers.length
219
+ ? this.headers.map(getHeaderColumnSize)
220
+ : this.rows[0].content.map(() => defaultSize);
221
+
222
+ return columnSizes.join(' ');
223
+ },
224
+ shouldHideHeaders() {
225
+ return this.hideHeaders || !this.headers.length;
183
226
  },
184
227
  },
185
228
  };
@@ -231,9 +274,18 @@ $tableBorder: $unnnic-border-width-thinner solid $unnnic-color-neutral-soft;
231
274
  }
232
275
 
233
276
  &__body {
277
+ &--hide-headers {
278
+ .unnnic-table-next__body-row:first-of-type {
279
+ border-radius: $unnnic-border-radius-sm $unnnic-border-radius-sm 0 0;
280
+ border-top: $tableBorder;
281
+ }
282
+ }
283
+
234
284
  &-row {
235
285
  @extend %base-row;
236
286
 
287
+ overflow: hidden;
288
+
237
289
  border: $tableBorder;
238
290
  border-collapse: collapse;
239
291
  border-top: none;
@@ -267,6 +319,11 @@ $tableBorder: $unnnic-border-width-thinner solid $unnnic-color-neutral-soft;
267
319
  text-overflow: ellipsis;
268
320
  }
269
321
  }
322
+
323
+ td.unnnic-table-next__body-cell--sm {
324
+ padding: $unnnic-spacing-ant $unnnic-spacing-sm;
325
+ }
326
+
270
327
  &-cell--loading {
271
328
  margin: $unnnic-spacing-xl 0;
272
329
  padding: 0;
@@ -280,7 +337,7 @@ $tableBorder: $unnnic-border-width-thinner solid $unnnic-color-neutral-soft;
280
337
  %base-cell {
281
338
  border-collapse: collapse;
282
339
 
283
- padding: $unnnic-spacing-ant $unnnic-spacing-sm;
340
+ padding: $unnnic-spacing-sm $unnnic-spacing-sm;
284
341
 
285
342
  font-family: $unnnic-font-family-secondary;
286
343
  font-size: $unnnic-font-size-body-gt;
@@ -45,6 +45,47 @@ describe('TableNext.vue', () => {
45
45
  // The first column uses the default size of 1fr,
46
46
  // and the second column is set to 2fr as specified in the header configuration.
47
47
  });
48
+
49
+ it('renders rows with default 1fr when no headers are provided', async () => {
50
+ wrapper = mount(TableNext, {
51
+ props: { rows },
52
+ });
53
+
54
+ const rowElement = wrapper.find('[data-testid="body-row"]');
55
+ const gridTemplateColumns = rowElement.attributes('style');
56
+ expect(gridTemplateColumns).toContain('1fr 1fr');
57
+ // Since headers are absent, each row column should default to 1fr as per the logic in `gridTemplateColumns`.
58
+ });
59
+
60
+ it('do not render the header if it has the hideHeaders prop', async () => {
61
+ await wrapper.setProps({ headers, hideHeaders: true });
62
+
63
+ const header = wrapper.find('[data-testid="header"]');
64
+ expect(header.exists()).toBe(false);
65
+
66
+ const body = wrapper.find('[data-testid="body"]');
67
+ expect(body.classes()).toContain('unnnic-table-next__body--hide-headers');
68
+ });
69
+
70
+ it('renders headers with mixed sizes (number and string)', () => {
71
+ wrapper = mount(TableNext, {
72
+ props: {
73
+ headers: [
74
+ { content: 'ID', size: 1 },
75
+ { content: 'Name', size: 'auto' },
76
+ { content: 'Age', size: 2 },
77
+ ],
78
+ rows,
79
+ },
80
+ });
81
+
82
+ const headerRow = wrapper.find('[data-testid="header-row"]');
83
+ const gridTemplateColumns = headerRow.attributes('style');
84
+
85
+ expect(gridTemplateColumns).toContain(
86
+ 'grid-template-columns: 1fr auto 2fr',
87
+ );
88
+ });
48
89
  });
49
90
 
50
91
  describe('Row rendering and behaviors', () => {
@@ -77,8 +118,10 @@ describe('TableNext.vue', () => {
77
118
  expect(secondLink.attributes('target')).toBe('_self');
78
119
  });
79
120
 
80
- it('renders "no matching results" message when there are no rows', async () => {
81
- await wrapper.setProps({ headers, rows: [] });
121
+ it('renders "no matching results" message when there are no rows', () => {
122
+ wrapper = mount(TableNext, {
123
+ props: { headers },
124
+ });
82
125
 
83
126
  const noResultsMessage = wrapper.find('[data-testid="body-cell-text"]');
84
127
  expect(noResultsMessage.text()).toBe('No matching results');
@@ -2,34 +2,34 @@
2
2
 
3
3
  exports[`TableNext.vue > matches the snapshot 1`] = `
4
4
  "<table data-v-2143c794="" class="unnnic-table-next">
5
- <thead data-v-2143c794="" class="unnnic-table-next__header">
5
+ <thead data-v-2143c794="" class="unnnic-table-next__header" data-testid="header">
6
6
  <tr data-v-2143c794="" class="unnnic-table-next__header-row" data-testid="header-row" style="grid-template-columns: 1fr 2fr;">
7
7
  <th data-v-2143c794="" class="unnnic-table-next__header-cell" data-testid="header-cell">Header 1</th>
8
8
  <th data-v-2143c794="" class="unnnic-table-next__header-cell" data-testid="header-cell">Header 2</th>
9
9
  </tr>
10
10
  </thead>
11
- <tbody data-v-2143c794="" class="unnnic-table-next__body">
11
+ <tbody data-v-2143c794="" class="unnnic-table-next__body" data-testid="body">
12
12
  <tr data-v-2143c794="" class="unnnic-table-next__body-row" data-testid="body-row" style="grid-template-columns: 1fr 2fr;">
13
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
13
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
14
14
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 1 Col 1</p>
15
15
  </td>
16
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
16
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
17
17
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 1 Col 2</p>
18
18
  </td>
19
19
  </tr>
20
20
  <tr data-v-2143c794="" class="unnnic-table-next__body-row" data-testid="body-row" style="grid-template-columns: auto;"><a data-v-2143c794="" class="unnnic-table-next__body-row--redirect" data-testid="body-row-redirect" style="grid-template-columns: 1fr 2fr;" href="#" target="_blank">
21
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
21
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
22
22
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 2 Col 1</p>
23
23
  </td>
24
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
24
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
25
25
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 2 Col 2</p>
26
26
  </td>
27
27
  </a></tr>
28
28
  <tr data-v-2143c794="" class="unnnic-table-next__body-row" data-testid="body-row" style="grid-template-columns: auto;"><a data-v-2143c794="" class="unnnic-table-next__body-row--redirect" data-testid="body-row-redirect" style="grid-template-columns: 1fr 2fr;" href="#" target="_self">
29
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
29
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
30
30
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 3 Col 1</p>
31
31
  </td>
32
- <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell" data-testid="body-cell">
32
+ <td data-v-fd58013b="" data-v-2143c794="" class="unnnic-table-next__body-cell unnnic-table-next__body-cell unnnic-table-next__body-cell--sm" data-testid="body-cell">
33
33
  <p data-v-fd58013b="" class="unnnic-table-next__body-cell-text" data-testid="body-cell-text">Row 3 Col 2</p>
34
34
  </td>
35
35
  </a></tr>
@@ -9,12 +9,6 @@ describe('TableNext props validations', () => {
9
9
  );
10
10
  });
11
11
 
12
- it('should throw an error if headers is an empty array', () => {
13
- expect(() => validateHeaders([])).toThrow(
14
- 'Property headers must not to be an empty array.',
15
- );
16
- });
17
-
18
12
  it('should throw an error if a header does not have "content" as a string', () => {
19
13
  const invalidHeaders = [{ content: 123 }];
20
14
  expect(() => validateHeaders(invalidHeaders)).toThrow(
@@ -25,7 +19,14 @@ describe('TableNext props validations', () => {
25
19
  it('should throw an error if a header has "size" that is not a positive number', () => {
26
20
  const invalidHeaders = [{ content: 'Header 1', size: -1 }];
27
21
  expect(() => validateHeaders(invalidHeaders)).toThrow(
28
- 'Each item in "headers" that contains "size" must assign it as positive number',
22
+ 'Each item in "headers" that contains "size" must assign it as positive number or equals to "auto"',
23
+ );
24
+ });
25
+
26
+ it('should throw an error if a header has "size" that is a string not equal to "auto"', () => {
27
+ const invalidHeaders = [{ content: 'Header 1', size: 'invalid' }];
28
+ expect(() => validateHeaders(invalidHeaders)).toThrow(
29
+ 'Each item in "headers" that contains "size" must assign it as positive number or equals to "auto"',
29
30
  );
30
31
  });
31
32
 
@@ -4,11 +4,13 @@ const validateHeader = (header) => {
4
4
  throw new Error('Each item in "headers" must have "content" as a string.');
5
5
  }
6
6
 
7
- const isSizePositiveNumber =
8
- 'size' in header && (typeof header.size !== 'number' || header.size < 0);
9
- if (isSizePositiveNumber) {
7
+ const isSizeInvalid =
8
+ 'size' in header &&
9
+ ((header.size !== 'auto' && typeof header.size !== 'number') ||
10
+ header.size < 0);
11
+ if (isSizeInvalid) {
10
12
  throw new Error(
11
- 'Each item in "headers" that contains "size" must assign it as positive number',
13
+ 'Each item in "headers" that contains "size" must assign it as positive number or equals to "auto"',
12
14
  );
13
15
  }
14
16
 
@@ -26,10 +28,6 @@ export const validateHeaders = (headers) => {
26
28
  throw new Error('Property headers needs to be an array.');
27
29
  }
28
30
 
29
- if (headers.length === 0) {
30
- throw new Error('Property headers must not to be an empty array.');
31
- }
32
-
33
31
  headers.forEach(validateHeader);
34
32
 
35
33
  return true;
@@ -37,10 +37,6 @@ export default {
37
37
  type: Boolean,
38
38
  default: false,
39
39
  },
40
- icon: {
41
- type: String,
42
- default: null,
43
- },
44
40
  },
45
41
  methods: {
46
42
  closeClicked() {