@kiva/kv-components 1.4.4 → 3.0.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 (52) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +1 -1
  2. package/CHANGELOG.md +75 -0
  3. package/README.md +2 -2
  4. package/__mocks__/ResizeObserver.js +13 -0
  5. package/package.json +34 -20
  6. package/{postcss.config.js → postcss.config.cjs} +2 -2
  7. package/{tailwind.config.js → tailwind.config.cjs} +10 -13
  8. package/tests/unit/jest-setup.js +5 -0
  9. package/tests/unit/specs/components/KvButton.spec.js +14 -25
  10. package/tests/unit/specs/components/KvCarousel.spec.js +11 -0
  11. package/tests/unit/specs/components/KvCheckbox.spec.js +73 -14
  12. package/tests/unit/specs/components/KvLightbox.spec.js +14 -0
  13. package/tests/unit/specs/components/KvProgressBar.spec.js +11 -0
  14. package/tests/unit/specs/components/KvRadio.spec.js +94 -5
  15. package/tests/unit/specs/components/KvSelect.spec.js +113 -0
  16. package/tests/unit/specs/components/KvSwitch.spec.js +92 -33
  17. package/tests/unit/specs/components/KvTabPanel.spec.js +11 -0
  18. package/tests/unit/specs/components/KvTabs.spec.js +99 -0
  19. package/tests/unit/specs/components/KvTextInput.spec.js +86 -9
  20. package/tests/unit/specs/components/KvTextLink.spec.js +16 -24
  21. package/tests/unit/specs/components/KvToast.spec.js +11 -0
  22. package/tests/unit/utils/addVueRouter.js +24 -0
  23. package/utils/attrs.js +62 -0
  24. package/utils/{themeUtils.js → themeUtils.cjs} +0 -0
  25. package/vue/.storybook/main.cjs +33 -0
  26. package/vue/.storybook/preview.js +6 -1
  27. package/vue/KvButton.vue +80 -53
  28. package/vue/KvCarousel.vue +142 -106
  29. package/vue/KvCheckbox.vue +86 -60
  30. package/vue/KvContentfulImg.vue +45 -34
  31. package/vue/KvLightbox.vue +108 -69
  32. package/vue/KvProgressBar.vue +33 -19
  33. package/vue/KvRadio.vue +72 -41
  34. package/vue/KvSelect.vue +46 -20
  35. package/vue/KvSwitch.vue +55 -33
  36. package/vue/KvTab.vue +49 -21
  37. package/vue/KvTabPanel.vue +26 -6
  38. package/vue/KvTabs.vue +70 -53
  39. package/vue/KvTextInput.vue +71 -48
  40. package/vue/KvTextLink.vue +42 -20
  41. package/vue/KvThemeProvider.vue +1 -1
  42. package/vue/KvToast.vue +53 -37
  43. package/vue/stories/KvCheckbox.stories.js +5 -5
  44. package/vue/stories/KvSwitch.stories.js +2 -2
  45. package/vue/stories/KvTabs.stories.js +8 -8
  46. package/vue/stories/KvTextInput.stories.js +1 -1
  47. package/vue/stories/KvThemeProvider.stories.js +1 -1
  48. package/vue/stories/KvToast.stories.js +3 -2
  49. package/vue/stories/StyleguidePrimitives.stories.js +10 -10
  50. package/.babelrc +0 -16
  51. package/jest.config.js +0 -36
  52. package/vue/.storybook/main.js +0 -36
@@ -0,0 +1,113 @@
1
+ import { render, fireEvent } from '@testing-library/vue';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { axe } from 'jest-axe';
4
+ import KvSelect from '../../../../vue/KvSelect.vue';
5
+
6
+ describe('KvSelect', () => {
7
+ it('renders with a role of "select"', () => {
8
+ const { getByRole } = render(KvSelect, {
9
+ slots: { default: 'Test Select' },
10
+ props: { id: 'test' },
11
+ });
12
+ const selectEl = getByRole('combobox');
13
+
14
+ expect(selectEl).toBeDefined();
15
+ });
16
+
17
+ it('works with v-model', async () => {
18
+ const TestComponent = {
19
+ template:
20
+ `<div>
21
+ <label for="test-select">Test select</label>
22
+ <KvSelect id="test-select" v-model="selectValue">
23
+ <option value="a">A</option>
24
+ <option value="b">B</option>
25
+ <option value="c">C</option>
26
+ </KvSelect>
27
+ <button @click="selectValue = 'b'">reset</button>
28
+ <span>The select value is {{ selectValue }}</span>
29
+ </div>`,
30
+ components: { KvSelect },
31
+ data: () => ({ selectValue: 'b' }),
32
+ };
33
+ const { getByRole, getByText } = render(TestComponent);
34
+ const selectEl = getByRole('combobox');
35
+
36
+ // Check that the value is 'b' initially
37
+ expect(getByText('The select value is b')).toBeDefined();
38
+ expect(selectEl.value).toEqual('b');
39
+
40
+ // Click the switch and expect the value to be `true` now
41
+ await userEvent.selectOptions(selectEl, 'C');
42
+ expect(getByText('The select value is c')).toBeDefined();
43
+ expect(selectEl.value).toEqual('c');
44
+
45
+ // Click the reset button and expect the value to be `false` again
46
+ await fireEvent.click(getByText('reset'));
47
+ expect(getByText('The select value is b')).toBeDefined();
48
+ expect(selectEl.value).toEqual('b');
49
+ });
50
+
51
+ it('applies parent event listeners to the input element', async () => {
52
+ const onChange = jest.fn();
53
+ const TestComponent = {
54
+ template:
55
+ `<KvSelect id="test" @change="onChange">
56
+ <option>A</option>
57
+ <option>B</option>
58
+ </KvSelect>`,
59
+ components: { KvSelect },
60
+ methods: { onChange },
61
+ };
62
+ const { getByRole } = render(TestComponent);
63
+
64
+ const selectEl = getByRole('combobox');
65
+ await userEvent.selectOptions(selectEl, 'B');
66
+ expect(onChange.mock.calls.length).toBe(1);
67
+ });
68
+
69
+ it('applies parent attributes to the input element', async () => {
70
+ const TestComponent = {
71
+ template: '<KvSelect id="test" name="test-select"></KvSelect>',
72
+ components: { KvSelect },
73
+ };
74
+ const { getByRole } = render(TestComponent);
75
+
76
+ const selectEl = getByRole('combobox');
77
+ expect(selectEl.name).toBe('test-select');
78
+ });
79
+
80
+ it('applies parent styles to the root element', async () => {
81
+ const TestComponent = {
82
+ template: '<KvSelect id="test" style="padding-top:1234px"></KvSelect>',
83
+ components: { KvSelect },
84
+ };
85
+ const { container } = render(TestComponent);
86
+
87
+ expect(container.firstChild.style.paddingTop).toEqual('1234px');
88
+ });
89
+
90
+ it('applies parent classes to the root element', async () => {
91
+ const TestComponent = {
92
+ template: '<KvSelect id="test" class="test-class"></KvSelect>',
93
+ components: { KvSelect },
94
+ };
95
+ const { container } = render(TestComponent);
96
+
97
+ expect(container.firstChild.classList).toContain('test-class');
98
+ });
99
+
100
+ it('has no automated accessibility violations', async () => {
101
+ const TestComponent = {
102
+ template:
103
+ `<div>
104
+ <label for="test-select">Test select</label>
105
+ <KvSelect id="test-select">options</KvSelect>
106
+ </div>`,
107
+ components: { KvSelect },
108
+ };
109
+ const { container } = render(TestComponent);
110
+ const results = await axe(container);
111
+ expect(results).toHaveNoViolations();
112
+ });
113
+ });
@@ -1,60 +1,119 @@
1
- import { render } from '@testing-library/vue';
2
- import { axe, toHaveNoViolations } from 'jest-axe';
1
+ import { render, fireEvent } from '@testing-library/vue';
2
+ import { axe } from 'jest-axe';
3
3
  import KvSwitch from '../../../../vue/KvSwitch.vue';
4
4
 
5
- expect.extend(toHaveNoViolations);
6
-
7
5
  describe('KvSwitch', () => {
6
+ const renderTestSwitch = (options) => render(KvSwitch, {
7
+ slots: { default: 'Test Switch' },
8
+ ...options,
9
+ });
10
+
8
11
  it('renders with a role of "switch"', () => {
9
- const { getByRole } = render(KvSwitch, {
10
- slots: { default: 'Test Switch' },
11
- });
12
+ const { getByRole } = renderTestSwitch();
12
13
  const switchEl = getByRole('switch');
13
14
 
14
15
  expect(switchEl).toBeDefined();
15
16
  });
16
17
 
17
18
  it('toggles the switch when the label is clicked', async () => {
18
- const { getByLabelText } = render(KvSwitch, {
19
- slots: { default: 'Test Switch' },
20
- });
21
- const switchEl = getByLabelText('Test Switch');
19
+ const { getByText, getByLabelText } = renderTestSwitch();
20
+ const switchEl = getByText('Test Switch');
21
+ const switchInput = getByLabelText('Test Switch');
22
22
 
23
- expect(switchEl.checked).toEqual(false);
24
- await switchEl.click();
25
- expect(switchEl.checked).toEqual(true);
23
+ expect(switchInput.checked).toEqual(false);
24
+ await fireEvent.click(switchEl);
25
+ expect(switchInput.checked).toEqual(true);
26
26
  });
27
27
 
28
28
  it('can\'t be toggled when the disabled prop is true', async () => {
29
- const { getByLabelText } = render(KvSwitch, {
29
+ const { getByText, getByLabelText } = renderTestSwitch({
30
30
  props: { disabled: true },
31
- slots: { default: 'Test Switch' },
32
31
  });
33
- const switchEl = getByLabelText('Test Switch');
32
+ const switchEl = getByText('Test Switch');
33
+ const switchInput = getByLabelText('Test Switch');
34
34
 
35
- expect(switchEl.checked).toEqual(false);
36
- await switchEl.click();
37
- expect(switchEl.checked).toEqual(false);
35
+ expect(switchInput.checked).toEqual(false);
36
+ await fireEvent.click(switchEl);
37
+ expect(switchInput.checked).toEqual(false);
38
38
  });
39
39
 
40
- it('emits a change event when toggled', async () => {
41
- const { getByLabelText, emitted } = render(KvSwitch, {
42
- slots: { default: 'Test Switch' },
43
- });
44
- const switchEl = getByLabelText('Test Switch');
40
+ it('works with v-model', async () => {
41
+ const TestComponent = {
42
+ template:
43
+ `<div>
44
+ <KvSwitch v-model="switchValue">Test Switch</KvSwitch>
45
+ <button @click="switchValue = false">reset</button>
46
+ <span>The switch value is {{ switchValue }}</span>
47
+ </div>`,
48
+ components: { KvSwitch },
49
+ data: () => ({ switchValue: false }),
50
+ };
51
+ const { getByLabelText, getByText } = render(TestComponent);
52
+ const switchEl = getByText('Test Switch');
53
+ const switchInput = getByLabelText('Test Switch');
45
54
 
46
- await switchEl.click();
47
- expect(emitted().change[0]).toEqual([true]);
55
+ // Check that the value is `false` initially
56
+ expect(getByText('The switch value is false')).toBeDefined();
57
+ expect(switchInput.checked).toEqual(false);
48
58
 
49
- await switchEl.click();
50
- expect(emitted().change[1]).toEqual([false]);
51
- expect(emitted().change.length).toBe(2);
59
+ // Click the switch and expect the value to be `true` now
60
+ await fireEvent.click(switchEl);
61
+ expect(getByText('The switch value is true')).toBeDefined();
62
+ expect(switchInput.checked).toEqual(true);
63
+
64
+ // Click the reset button and expect the value to be `false` again
65
+ await fireEvent.click(getByText('reset'));
66
+ expect(getByText('The switch value is false')).toBeDefined();
67
+ expect(switchInput.checked).toEqual(false);
68
+ });
69
+
70
+ it('applies parent event listeners to the input element', async () => {
71
+ const onInput = jest.fn();
72
+ const TestComponent = {
73
+ template: '<KvSwitch @input="onInput">Test Switch</KvSwitch>',
74
+ components: { KvSwitch },
75
+ methods: { onInput },
76
+ };
77
+ const { getByText } = render(TestComponent);
78
+
79
+ const switchEl = getByText('Test Switch');
80
+ await fireEvent.click(switchEl);
81
+ expect(onInput.mock.calls.length).toBe(1);
82
+ });
83
+
84
+ it('applies parent attributes to the input element', async () => {
85
+ const TestComponent = {
86
+ template: '<KvSwitch name="test-switch">Test Switch</KvSwitch>',
87
+ components: { KvSwitch },
88
+ };
89
+ const { getByRole } = render(TestComponent);
90
+
91
+ const switchEl = getByRole('switch');
92
+ expect(switchEl.name).toBe('test-switch');
93
+ });
94
+
95
+ it('applies parent styles to the root element', async () => {
96
+ const TestComponent = {
97
+ template: '<KvSwitch style="padding-top:1234px">Test Switch</KvSwitch>',
98
+ components: { KvSwitch },
99
+ };
100
+ const { container } = render(TestComponent);
101
+
102
+ expect(container.firstChild.style.paddingTop).toEqual('1234px');
103
+ });
104
+
105
+ it('applies parent classes to the root element', async () => {
106
+ const TestComponent = {
107
+ template: '<KvSwitch class="test-class">Test Switch</KvSwitch>',
108
+ components: { KvSwitch },
109
+ };
110
+ const { container } = render(TestComponent);
111
+
112
+ expect(container.firstChild.classList).toContain('test-class');
52
113
  });
53
114
 
54
115
  it('has no automated accessibility violations', async () => {
55
- const { container } = render(KvSwitch, {
56
- slots: { default: 'Test Switch' },
57
- });
116
+ const { container } = renderTestSwitch();
58
117
  const results = await axe(container);
59
118
  expect(results).toHaveNoViolations();
60
119
  });
@@ -0,0 +1,11 @@
1
+ import { render } from '@testing-library/vue';
2
+ import { axe } from 'jest-axe';
3
+ import KvTabPanel from '../../../../vue/KvTabPanel.vue';
4
+
5
+ describe('KvTabPanel', () => {
6
+ it('has no automated accessibility violations', async () => {
7
+ const { container } = render(KvTabPanel);
8
+ const results = await axe(container);
9
+ expect(results).toHaveNoViolations();
10
+ });
11
+ });
@@ -0,0 +1,99 @@
1
+ import { render, fireEvent } from '@testing-library/vue';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { axe } from 'jest-axe';
4
+ import '../../../../__mocks__/ResizeObserver';
5
+ import KvTab from '../../../../vue/KvTab.vue';
6
+ import KvTabPanel from '../../../../vue/KvTabPanel.vue';
7
+ import KvTabs from '../../../../vue/KvTabs.vue';
8
+
9
+ // jsdom does not include scrollIntoView, so define it to avoid errors when switching tabs
10
+ window.HTMLElement.prototype.scrollIntoView = () => {};
11
+
12
+ function renderOneTabSet() {
13
+ return render({
14
+ components: { KvTabs, KvTab, KvTabPanel },
15
+ template: `
16
+ <kv-tabs>
17
+ <template #tabNav>
18
+ <kv-tab forPanel="demo-1-first">First</kv-tab>
19
+ <kv-tab forPanel="demo-1-second">Second</kv-tab>
20
+ <kv-tab forPanel="demo-1-third">Third</kv-tab>
21
+ <kv-tab forPanel="demo-1-forth">Fourth is longer</kv-tab>
22
+ </template>
23
+ <template #tabPanels>
24
+ <kv-tab-panel id="demo-1-first"><p>First Panel</p></kv-tab-panel>
25
+ <kv-tab-panel id="demo-1-second"><p>Second Panel has <br>longer<br>content</p></kv-tab-panel>
26
+ <kv-tab-panel id="demo-1-third"><p>Third Panel</p></kv-tab-panel>
27
+ <kv-tab-panel id="demo-1-forth"><p>Fourth Panel</p></kv-tab-panel>
28
+ </template>
29
+ </kv-tabs>
30
+ `,
31
+ });
32
+ }
33
+
34
+ describe('KvTabs', () => {
35
+ it('has no automated accessibility violations', async () => {
36
+ const { container } = renderOneTabSet();
37
+ const results = await axe(container);
38
+ expect(results).toHaveNoViolations();
39
+ });
40
+
41
+ it('renders with a role of "tablist", "tab", & "tabpanel"', async () => {
42
+ const { getByRole, getAllByRole } = renderOneTabSet();
43
+ expect(getByRole('tablist')).toBeDefined();
44
+ expect(getAllByRole('tab').length).toBe(4);
45
+ // expect(getByRole('tabpanel')).toBeDefined(); // TODO: make sure first panel reveals itself
46
+ });
47
+
48
+ // TODO: it renders with the first slide active by default
49
+
50
+ it('switches between tab panels when tabs are clicked', async () => {
51
+ const { getByText } = renderOneTabSet();
52
+
53
+ // Click third tab and expect the third panel to be visible
54
+ await fireEvent.click(getByText('Third'));
55
+ expect(getByText('First Panel')).not.toBeVisible();
56
+ expect(getByText('Third Panel')).toBeVisible();
57
+
58
+ // Click first tab and expect the first panel to be visible
59
+ await fireEvent.click(getByText('First'));
60
+ expect(getByText('First Panel')).toBeVisible();
61
+ expect(getByText('Third Panel')).not.toBeVisible();
62
+ });
63
+
64
+ it('switches between tab panels when the left and right arrows are pressed', async () => {
65
+ const { findByText } = renderOneTabSet();
66
+
67
+ // Focus on the first tab
68
+ const firstTab = await findByText('First');
69
+ firstTab.focus();
70
+
71
+ // Press arrow right twice and expect the third tab panel to be visible
72
+ userEvent.keyboard('{ArrowRight}{ArrowRight}');
73
+ expect(await findByText('Third Panel')).toBeVisible();
74
+
75
+ // Press arrow left once and expect the second tab panel to be visible
76
+ userEvent.keyboard('{ArrowLeft}');
77
+ expect(await findByText('Second Panel', { exact: false })).toBeVisible();
78
+ });
79
+
80
+ it('goes to first panel when home key is pressed and last panel when end key is pressed', async () => {
81
+ const { findByText } = renderOneTabSet();
82
+
83
+ // Focus on the first tab
84
+ const firstTab = await findByText('First');
85
+ firstTab.focus();
86
+
87
+ // Press arrow right once and expect the second tab panel to be visible
88
+ userEvent.keyboard('{ArrowRight}');
89
+ expect(await findByText('Second Panel', { exact: false })).toBeVisible();
90
+
91
+ // Press end key and expect the fourth panel to be visible
92
+ userEvent.keyboard('{End}');
93
+ expect(await findByText('Fourth Panel')).toBeVisible();
94
+
95
+ // Press home key and expect the first panel to be visible
96
+ userEvent.keyboard('{Home}');
97
+ expect(await findByText('First Panel')).toBeVisible();
98
+ });
99
+ });
@@ -1,10 +1,8 @@
1
1
  import { render, fireEvent } from '@testing-library/vue';
2
2
  import userEvent from '@testing-library/user-event';
3
- import { axe, toHaveNoViolations } from 'jest-axe';
3
+ import { axe } from 'jest-axe';
4
4
  import KvTextInput from '../../../../vue/KvTextInput.vue';
5
5
 
6
- expect.extend(toHaveNoViolations);
7
-
8
6
  const KvTextInputTemplate = {
9
7
  components: { KvTextInput },
10
8
  template: `
@@ -28,7 +26,7 @@ describe('KvTextInput', () => {
28
26
  const textInputEl = getByRole('textbox');
29
27
 
30
28
  expect(textInputEl.value).toEqual('');
31
- await userEvent.type(textInputEl, 'abc 123');
29
+ userEvent.type(textInputEl, 'abc 123');
32
30
  expect(textInputEl.value).toEqual('abc 123');
33
31
  });
34
32
 
@@ -47,6 +45,81 @@ describe('KvTextInput', () => {
47
45
  expect(textInputEl.value).toEqual('');
48
46
  });
49
47
 
48
+ it('works with v-model', async () => {
49
+ const TestComponent = {
50
+ template:
51
+ `<div>
52
+ <label for="text-input">Text input</label>
53
+ <KvTextInput v-model="textValue" id="text-input" />
54
+ <button @click="textValue = 'abc'">reset</button>
55
+ <span>The text value is {{ textValue }}</span>
56
+ </div>`,
57
+ components: { KvTextInput },
58
+ data: () => ({ textValue: 'abc' }),
59
+ };
60
+ const { getByRole, getByText } = render(TestComponent);
61
+ const textInputEl = getByRole('textbox');
62
+
63
+ // Check that the value is 'abc' initially
64
+ expect(getByText('The text value is abc')).toBeDefined();
65
+ expect(textInputEl.value).toEqual('abc');
66
+
67
+ // Type 'def' in the text input and expect the value to be 'abcdef' now
68
+ await userEvent.type(textInputEl, 'def');
69
+ expect(getByText('The text value is abcdef')).toBeDefined();
70
+ expect(textInputEl.value).toEqual('abcdef');
71
+
72
+ // Click the reset button and expect the value to be 'abc' again
73
+ await fireEvent.click(getByText('reset'));
74
+ expect(getByText('The text value is abc')).toBeDefined();
75
+ expect(textInputEl.value).toEqual('abc');
76
+ });
77
+
78
+ it('applies parent event listeners to the input element', async () => {
79
+ const onInput = jest.fn();
80
+ const TestComponent = {
81
+ template: '<KvTextInput id="test" @input="onInput" />',
82
+ components: { KvTextInput },
83
+ methods: { onInput },
84
+ };
85
+ const { getByRole } = render(TestComponent);
86
+
87
+ const textInputEl = getByRole('textbox');
88
+ await userEvent.type(textInputEl, 'a');
89
+ expect(onInput.mock.calls.length).toBe(1);
90
+ });
91
+
92
+ it('applies parent attributes to the input element', async () => {
93
+ const TestComponent = {
94
+ template: '<KvTextInput id="test" name="test-text-input" />',
95
+ components: { KvTextInput },
96
+ };
97
+ const { getByRole } = render(TestComponent);
98
+
99
+ const textInputEl = getByRole('textbox');
100
+ expect(textInputEl.name).toBe('test-text-input');
101
+ });
102
+
103
+ it('applies parent styles to the root element', async () => {
104
+ const TestComponent = {
105
+ template: '<KvTextInput id="test" style="padding-top:1234px" />',
106
+ components: { KvTextInput },
107
+ };
108
+ const { container } = render(TestComponent);
109
+
110
+ expect(container.firstChild.style.paddingTop).toEqual('1234px');
111
+ });
112
+
113
+ it('applies parent classes to the root element', async () => {
114
+ const TestComponent = {
115
+ template: '<KvTextInput id="test" class="test-class" />',
116
+ components: { KvTextInput },
117
+ };
118
+ const { container } = render(TestComponent);
119
+
120
+ expect(container.firstChild.classList).toContain('test-class');
121
+ });
122
+
50
123
  it('has no automated accessibility violations', async () => {
51
124
  const { container } = render(KvTextInputTemplate);
52
125
  const results = await axe(container);
@@ -55,7 +128,7 @@ describe('KvTextInput', () => {
55
128
  });
56
129
 
57
130
  it('clear button cleans the input value', async () => {
58
- const { getByRole } = render(KvTextInput, {
131
+ const { getByRole, findByRole, queryByRole } = render(KvTextInput, {
59
132
  props: {
60
133
  canClear: true,
61
134
  valid: true,
@@ -63,12 +136,16 @@ describe('KvTextInput', () => {
63
136
  },
64
137
  });
65
138
  const textInputEl = getByRole('textbox');
139
+
66
140
  expect(textInputEl.value).toEqual('');
67
- await userEvent.type(textInputEl, 'abc 123');
141
+ expect(queryByRole('button')).toBeNull();
142
+
143
+ userEvent.type(textInputEl, 'abc 123');
68
144
  expect(textInputEl.value).toEqual('abc 123');
69
- const buttonInputEl = getByRole('button');
70
- expect(buttonInputEl).toBeDefined();
71
- await fireEvent.click(buttonInputEl);
145
+ const buttonEl = await findByRole('button');
146
+ expect(buttonEl).toBeDefined();
147
+
148
+ await fireEvent.click(buttonEl);
72
149
  expect(textInputEl.value).toEqual('');
73
150
  });
74
151
  });
@@ -1,41 +1,37 @@
1
1
  import { render } from '@testing-library/vue';
2
- import { axe, toHaveNoViolations } from 'jest-axe';
3
- import VueRouter from 'vue-router';
2
+ import { axe } from 'jest-axe';
3
+ import addVueRouter from '../../utils/addVueRouter';
4
4
  import KvTextLink from '../../../../vue/KvTextLink.vue';
5
5
 
6
- const router = new VueRouter();
7
-
8
- expect.extend(toHaveNoViolations);
9
-
10
6
  describe('Default Button', () => {
7
+ const renderTestTextLink = (options) => render(KvTextLink, addVueRouter({
8
+ slots: { default: 'Test Text Link' },
9
+ ...options,
10
+ }));
11
+
11
12
  it('renders as a button tag by default', () => {
12
- const { getByRole } = render(KvTextLink, {
13
- slots: { default: 'Test Button' },
14
- });
15
- getByRole('button', { name: 'Test Button' });
13
+ const { getByRole } = renderTestTextLink();
14
+ getByRole('button', { name: 'Test Text Link' });
16
15
  });
17
16
 
18
17
  it('renders as an anchor tag when passed an href prop', () => {
19
- const { getByRole } = render(KvTextLink, {
18
+ const { getByRole } = renderTestTextLink({
20
19
  props: { href: 'https://www.example.com/' },
21
- slots: { default: 'Test Button' },
22
20
  });
23
- const anchorEl = getByRole('link', { name: 'Test Button' });
21
+ const anchorEl = getByRole('link', { name: 'Test Text Link' });
24
22
  expect(anchorEl.href).toEqual('https://www.example.com/');
25
23
  });
26
24
 
27
25
  it('renders as an anchor tag when passed a route string', () => {
28
- const { getByRole } = render(KvTextLink, {
26
+ const { getByRole } = renderTestTextLink({
29
27
  props: { to: '/home' },
30
- slots: { default: 'Test Button' },
31
- routes: router,
32
28
  });
33
- const anchorEl = getByRole('link', { name: 'Test Button' });
29
+ const anchorEl = getByRole('link', { name: 'Test Text Link' });
34
30
  expect(anchorEl.href).toEqual('http://localhost/#/home');
35
31
  });
36
32
 
37
33
  it('renders as an anchor tag when passed a route object', () => {
38
- const { getByRole } = render(KvTextLink, {
34
+ const { getByRole } = renderTestTextLink({
39
35
  props: {
40
36
  to: {
41
37
  path: 'test-route-with-query',
@@ -44,17 +40,13 @@ describe('Default Button', () => {
44
40
  },
45
41
  },
46
42
  },
47
- slots: { default: 'Test Button' },
48
- routes: router,
49
43
  });
50
- const anchorEl = getByRole('link', { name: 'Test Button' });
44
+ const anchorEl = getByRole('link', { name: 'Test Text Link' });
51
45
  expect(anchorEl.href).toEqual('http://localhost/#/test-route-with-query?param1=a');
52
46
  });
53
47
 
54
48
  it('has no automated accessibility violations', async () => {
55
- const { container } = render(KvTextLink, {
56
- slots: { default: 'Test Button' },
57
- });
49
+ const { container } = renderTestTextLink();
58
50
  const results = await axe(container);
59
51
  expect(results).toHaveNoViolations();
60
52
  });
@@ -0,0 +1,11 @@
1
+ import { render } from '@testing-library/vue';
2
+ import { axe } from 'jest-axe';
3
+ import KvToast from '../../../../vue/KvToast.vue';
4
+
5
+ describe('KvToast', () => {
6
+ it('has no automated accessibility violations', async () => {
7
+ const { container } = render(KvToast);
8
+ const results = await axe(container);
9
+ expect(results).toHaveNoViolations();
10
+ });
11
+ });
@@ -0,0 +1,24 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import { isVue3 } from 'vue-demi';
3
+ import * as VueRouter from 'vue-router';
4
+
5
+ export default function addVueRouter(testingLibraryOptions, vueRouterOptions) {
6
+ const opts = { ...testingLibraryOptions };
7
+
8
+ if (isVue3) {
9
+ // create opts.global.plugins array if it does not exist
10
+ opts.global = opts.global ?? {};
11
+ opts.global.plugins = opts.global.plugins ?? [];
12
+
13
+ // add Vue Router to plugins array
14
+ opts.global.plugins.push(VueRouter.createRouter(vueRouterOptions ?? {
15
+ history: VueRouter.createWebHashHistory(),
16
+ routes: [{ path: '/:path(.*)', component: {} }],
17
+ }));
18
+ } else {
19
+ const VueRouterDefault = VueRouter.default;
20
+ opts.routes = new VueRouterDefault(vueRouterOptions);
21
+ }
22
+
23
+ return opts;
24
+ }