@instructure/ui-options 10.19.2-snapshot-2 → 10.19.2-snapshot-4
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.
- package/CHANGELOG.md +1 -1
- package/package.json +14 -14
- package/tsconfig.build.tsbuildinfo +1 -1
- package/es/Options/Item/__new-tests__/Item.test.js +0 -197
- package/es/Options/__new-tests__/Options.test.js +0 -201
- package/lib/Options/Item/__new-tests__/Item.test.js +0 -199
- package/lib/Options/__new-tests__/Options.test.js +0 -202
- package/src/Options/Item/__new-tests__/Item.test.tsx +0 -212
- package/src/Options/__new-tests__/Options.test.tsx +0 -203
- package/types/Options/Item/__new-tests__/Item.test.d.ts +0 -2
- package/types/Options/Item/__new-tests__/Item.test.d.ts.map +0 -1
- package/types/Options/__new-tests__/Options.test.d.ts +0 -2
- package/types/Options/__new-tests__/Options.test.d.ts.map +0 -1
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
var _react = require("@testing-library/react");
|
|
5
|
-
var _vitest = require("vitest");
|
|
6
|
-
var _uiAxeCheck = require("@instructure/ui-axe-check");
|
|
7
|
-
var _generateA11yTests = require("@instructure/ui-scripts/lib/test/generateA11yTests");
|
|
8
|
-
require("@testing-library/jest-dom");
|
|
9
|
-
var _index = require("../index");
|
|
10
|
-
var _Options10 = _interopRequireDefault(require("../__examples__/Options.examples"));
|
|
11
|
-
var _jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
12
|
-
var _Options, _Options2, _Options$Item, _Options$Item2, _Options3, _Options4, _Options5, _Options6, _Options7, _Options8, _Options9;
|
|
13
|
-
/*
|
|
14
|
-
* The MIT License (MIT)
|
|
15
|
-
*
|
|
16
|
-
* Copyright (c) 2015 - present Instructure, Inc.
|
|
17
|
-
*
|
|
18
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
20
|
-
* in the Software without restriction, including without limitation the rights
|
|
21
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
22
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
23
|
-
* furnished to do so, subject to the following conditions:
|
|
24
|
-
*
|
|
25
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
26
|
-
* copies or substantial portions of the Software.
|
|
27
|
-
*
|
|
28
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
29
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
30
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
31
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
32
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
33
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
34
|
-
* SOFTWARE.
|
|
35
|
-
*/
|
|
36
|
-
// eslint-disable-next-line no-restricted-imports
|
|
37
|
-
describe('<Options />', () => {
|
|
38
|
-
it('should render', async () => {
|
|
39
|
-
const _render = (0, _react.render)(_Options || (_Options = (0, _jsxRuntime.jsx)(_index.Options, {}))),
|
|
40
|
-
container = _render.container;
|
|
41
|
-
const options = container.querySelector('div[class*="-options"]');
|
|
42
|
-
(0, _vitest.expect)(options).toBeInTheDocument();
|
|
43
|
-
});
|
|
44
|
-
it('should render items', async () => {
|
|
45
|
-
(0, _react.render)(_Options2 || (_Options2 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
46
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
47
|
-
children: "Option one"
|
|
48
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
49
|
-
children: "Option two"
|
|
50
|
-
})]
|
|
51
|
-
})));
|
|
52
|
-
const items = _react.screen.getAllByRole('listitem');
|
|
53
|
-
(0, _vitest.expect)(items.length).toBe(2);
|
|
54
|
-
});
|
|
55
|
-
it('should provide elementRef', async () => {
|
|
56
|
-
const elementRef = _vitest.vi.fn();
|
|
57
|
-
(0, _react.render)((0, _jsxRuntime.jsxs)(_index.Options, {
|
|
58
|
-
elementRef: elementRef,
|
|
59
|
-
as: "ul",
|
|
60
|
-
children: [_Options$Item || (_Options$Item = (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
61
|
-
children: "Option one"
|
|
62
|
-
})), _Options$Item2 || (_Options$Item2 = (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
63
|
-
children: "Option two"
|
|
64
|
-
}))]
|
|
65
|
-
}));
|
|
66
|
-
const optionList = _react.screen.getByRole('list');
|
|
67
|
-
(0, _vitest.expect)(elementRef).toHaveBeenCalledWith(optionList);
|
|
68
|
-
});
|
|
69
|
-
it('should render designated tag if `as` prop is specified', async () => {
|
|
70
|
-
(0, _react.render)(_Options3 || (_Options3 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
71
|
-
as: "ol",
|
|
72
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
73
|
-
children: "Option one"
|
|
74
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
75
|
-
children: "Option two"
|
|
76
|
-
})]
|
|
77
|
-
})));
|
|
78
|
-
const optionList = _react.screen.getByRole('list');
|
|
79
|
-
(0, _vitest.expect)(optionList.tagName).toBe('OL');
|
|
80
|
-
});
|
|
81
|
-
it('should render children as listitems when appropriate', async () => {
|
|
82
|
-
const _render2 = (0, _react.render)(_Options4 || (_Options4 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
83
|
-
as: "ul",
|
|
84
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
85
|
-
children: "Option one"
|
|
86
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
87
|
-
children: "Option two"
|
|
88
|
-
})]
|
|
89
|
-
}))),
|
|
90
|
-
container = _render2.container;
|
|
91
|
-
const list = container.querySelector('ul');
|
|
92
|
-
const items = container.querySelectorAll('li');
|
|
93
|
-
(0, _vitest.expect)(list).toBeInTheDocument();
|
|
94
|
-
(0, _vitest.expect)(items.length).toBe(2);
|
|
95
|
-
});
|
|
96
|
-
it('should pass props through to list', async () => {
|
|
97
|
-
const _render3 = (0, _react.render)(_Options5 || (_Options5 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
98
|
-
as: "ul",
|
|
99
|
-
role: "listbox",
|
|
100
|
-
"data-custom-attr": "true",
|
|
101
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
102
|
-
children: "Option one"
|
|
103
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
104
|
-
children: "Option two"
|
|
105
|
-
})]
|
|
106
|
-
}))),
|
|
107
|
-
container = _render3.container;
|
|
108
|
-
const options = container.querySelector('[class*="-options__list"]');
|
|
109
|
-
(0, _vitest.expect)(options).toHaveRole('listbox');
|
|
110
|
-
(0, _vitest.expect)(options).toHaveAttribute('data-custom-attr', 'true');
|
|
111
|
-
});
|
|
112
|
-
it('should render root with appropriate role', async () => {
|
|
113
|
-
const _render4 = (0, _react.render)(_Options6 || (_Options6 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
114
|
-
role: "listbox",
|
|
115
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
116
|
-
children: "Option one"
|
|
117
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
118
|
-
children: "Option two"
|
|
119
|
-
})]
|
|
120
|
-
}))),
|
|
121
|
-
container = _render4.container;
|
|
122
|
-
const options = container.querySelector('div[class*="-options"]');
|
|
123
|
-
(0, _vitest.expect)(options).toHaveAttribute('role', 'presentation');
|
|
124
|
-
});
|
|
125
|
-
it('should allow null children', async () => {
|
|
126
|
-
(0, _react.render)(_Options7 || (_Options7 = (0, _jsxRuntime.jsx)(_index.Options, {})));
|
|
127
|
-
const options = _react.screen.getByRole('list');
|
|
128
|
-
(0, _vitest.expect)(options).toBeInTheDocument();
|
|
129
|
-
});
|
|
130
|
-
it('should render nested options properly', async () => {
|
|
131
|
-
const _render5 = (0, _react.render)(_Options8 || (_Options8 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
132
|
-
"data-testId": "outer-list",
|
|
133
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
134
|
-
children: "Option one "
|
|
135
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
136
|
-
children: "Option two "
|
|
137
|
-
}), (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
138
|
-
renderLabel: 'Nested list',
|
|
139
|
-
"data-testId": "nested-list",
|
|
140
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
141
|
-
children: "Nested option one "
|
|
142
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
143
|
-
children: "Nested option two "
|
|
144
|
-
})]
|
|
145
|
-
})]
|
|
146
|
-
}))),
|
|
147
|
-
container = _render5.container;
|
|
148
|
-
const allLists = container.querySelectorAll('[class*="-options__list"]');
|
|
149
|
-
const allItems = container.querySelectorAll('[class$="-optionItem"]');
|
|
150
|
-
(0, _vitest.expect)(allLists.length).toBe(2);
|
|
151
|
-
(0, _vitest.expect)(allItems.length).toBe(5);
|
|
152
|
-
const outerList = _react.screen.getByTestId('outer-list');
|
|
153
|
-
(0, _vitest.expect)(outerList).toHaveTextContent('Option one Option two');
|
|
154
|
-
const nestedLabel = outerList.querySelector('[class*=-options__label]');
|
|
155
|
-
(0, _vitest.expect)(nestedLabel).toBeInTheDocument();
|
|
156
|
-
(0, _vitest.expect)(nestedLabel).toHaveTextContent('Nested list');
|
|
157
|
-
const nestedList = _react.screen.getByTestId('nested-list');
|
|
158
|
-
(0, _vitest.expect)(nestedList).toHaveTextContent('Nested option one Nested option two');
|
|
159
|
-
const nestedListItems = nestedList.querySelectorAll('[class$=-optionItem]');
|
|
160
|
-
(0, _vitest.expect)(nestedListItems.length).toBe(2);
|
|
161
|
-
(0, _vitest.expect)(outerList).toContainElement(nestedLabel);
|
|
162
|
-
(0, _vitest.expect)(outerList).toContainElement(nestedList);
|
|
163
|
-
});
|
|
164
|
-
describe('with generated examples', () => {
|
|
165
|
-
const generatedComponents = (0, _generateA11yTests.generateA11yTests)(_index.Options, _Options10.default);
|
|
166
|
-
for (const component of generatedComponents) {
|
|
167
|
-
it(component.description, async () => {
|
|
168
|
-
const _render6 = (0, _react.render)(component.content),
|
|
169
|
-
container = _render6.container;
|
|
170
|
-
|
|
171
|
-
// axe-check is more strict now, and expects "list" role to have "listitem" children, but we use "role='none'" children. After discussing it with the A11y team, we agreed to ignore this error because the screen readers can read the component perfectly.
|
|
172
|
-
// TODO: try to remove this ignore if axe-check is updated and isn't this strict anymore
|
|
173
|
-
// https://dequeuniversity.com/rules/axe/4.6/aria-required-children?application=axeAPI
|
|
174
|
-
const axeCheck = await (0, _uiAxeCheck.runAxeCheck)(container, {
|
|
175
|
-
ignores: ['aria-required-children']
|
|
176
|
-
});
|
|
177
|
-
(0, _vitest.expect)(axeCheck).toBe(true);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
describe('for a11y', () => {
|
|
182
|
-
it('should be accessible with links', async () => {
|
|
183
|
-
const _render7 = (0, _react.render)(_Options9 || (_Options9 = (0, _jsxRuntime.jsxs)(_index.Options, {
|
|
184
|
-
children: [(0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
185
|
-
children: "Option"
|
|
186
|
-
}), (0, _jsxRuntime.jsx)(_index.Options.Item, {
|
|
187
|
-
href: "/",
|
|
188
|
-
children: "Option link"
|
|
189
|
-
})]
|
|
190
|
-
}))),
|
|
191
|
-
container = _render7.container;
|
|
192
|
-
|
|
193
|
-
// axe-check is more strict now, and expects "list" role to have "listitem" children, but we use "role='none'" children. After discussing it with the A11y team, we agreed to ignore this error because the screen readers can read the component perfectly.
|
|
194
|
-
// TODO: try to remove this ignore if axe-check is updated and isn't this strict anymore
|
|
195
|
-
// https://dequeuniversity.com/rules/axe/4.6/aria-required-children?application=axeAPI
|
|
196
|
-
const axeCheck = await (0, _uiAxeCheck.runAxeCheck)(container, {
|
|
197
|
-
ignores: ['aria-required-children']
|
|
198
|
-
});
|
|
199
|
-
(0, _vitest.expect)(axeCheck).toBe(true);
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
});
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The MIT License (MIT)
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) 2015 - present Instructure, Inc.
|
|
5
|
-
*
|
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
-
* in the Software without restriction, including without limitation the rights
|
|
9
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
* furnished to do so, subject to the following conditions:
|
|
12
|
-
*
|
|
13
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
* copies or substantial portions of the Software.
|
|
15
|
-
*
|
|
16
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
* SOFTWARE.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { render, screen, waitFor } from '@testing-library/react'
|
|
26
|
-
import { vi, expect } from 'vitest'
|
|
27
|
-
import userEvent from '@testing-library/user-event'
|
|
28
|
-
|
|
29
|
-
import '@testing-library/jest-dom'
|
|
30
|
-
import { IconCheckSolid } from '@instructure/ui-icons'
|
|
31
|
-
import { Options } from '../../index'
|
|
32
|
-
import { Item } from '../index'
|
|
33
|
-
|
|
34
|
-
describe('<Item />', () => {
|
|
35
|
-
it('should render', async () => {
|
|
36
|
-
const { container } = render(<Item />)
|
|
37
|
-
|
|
38
|
-
const optionItem = container.querySelector('[class$="-optionItem"]')
|
|
39
|
-
expect(optionItem).toBeInTheDocument()
|
|
40
|
-
|
|
41
|
-
const optionItemContainer = optionItem!.querySelector(
|
|
42
|
-
'[class$="-optionItem__container"]'
|
|
43
|
-
)
|
|
44
|
-
expect(optionItemContainer).toBeInTheDocument()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should not render as a list item by default', async () => {
|
|
48
|
-
const { container } = render(<Item>Hello World</Item>)
|
|
49
|
-
|
|
50
|
-
const item = container.querySelector('[class$="-optionItem"]')
|
|
51
|
-
|
|
52
|
-
expect(item).toBeInTheDocument()
|
|
53
|
-
expect(item!.tagName).not.toBe('LI')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should render designated tag if `as` prop is specified', async () => {
|
|
57
|
-
const { container } = render(<Item as="li">Hello World</Item>)
|
|
58
|
-
|
|
59
|
-
const item = container.querySelector('[class$="-optionItem"]')
|
|
60
|
-
|
|
61
|
-
expect(item).toBeInTheDocument()
|
|
62
|
-
expect(item!.tagName).toBe('LI')
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should render children properly', async () => {
|
|
66
|
-
const { container } = render(
|
|
67
|
-
<Item>
|
|
68
|
-
<span id="customContent">Hello World</span>
|
|
69
|
-
</Item>
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
const item = container.querySelector('[class$="-optionItem"]')
|
|
73
|
-
const customContent = item!.querySelector('#customContent')
|
|
74
|
-
|
|
75
|
-
expect(customContent).toHaveTextContent('Hello World')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('should render role attributes appropriately when given a role', async () => {
|
|
79
|
-
const { container } = render(<Item role="option">Hello World</Item>)
|
|
80
|
-
|
|
81
|
-
const item = container.querySelector('[class$="-optionItem"]')
|
|
82
|
-
const child = screen.getByRole('option')
|
|
83
|
-
|
|
84
|
-
expect(item).toHaveAttribute('role', 'none')
|
|
85
|
-
expect(child).toBeInTheDocument()
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should render description properly', async () => {
|
|
89
|
-
const { container } = render(
|
|
90
|
-
<Item description="Some text as description">
|
|
91
|
-
<span id="customContent">Hello World</span>
|
|
92
|
-
</Item>
|
|
93
|
-
)
|
|
94
|
-
const item = container.querySelector('[class$="-optionItem"]')
|
|
95
|
-
|
|
96
|
-
const customContent = item!.querySelector('#customContent')
|
|
97
|
-
const description = item!.querySelector('[class$="__description"]')
|
|
98
|
-
|
|
99
|
-
expect(customContent).toHaveTextContent('Hello World')
|
|
100
|
-
expect(description).toHaveTextContent('Some text as description')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should render role attributes for description', async () => {
|
|
104
|
-
render(
|
|
105
|
-
<Item description="Some text as description" descriptionRole="comment">
|
|
106
|
-
Hello World
|
|
107
|
-
</Item>
|
|
108
|
-
)
|
|
109
|
-
const description = screen.getByRole('comment')
|
|
110
|
-
|
|
111
|
-
expect(description).toBeInTheDocument()
|
|
112
|
-
expect(description).toHaveTextContent('Some text as description')
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should pass props through to label', async () => {
|
|
116
|
-
const { container } = render(
|
|
117
|
-
<Item role="option" tabIndex={-1} data-custom-attr="true">
|
|
118
|
-
Hello World
|
|
119
|
-
</Item>
|
|
120
|
-
)
|
|
121
|
-
const optionItem = container.querySelector('[class$="-optionItem"]')
|
|
122
|
-
const optionItemContainer = optionItem!.querySelector(
|
|
123
|
-
'[class$="-optionItem__container"]'
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
expect(optionItem).toHaveRole('none')
|
|
127
|
-
expect(optionItemContainer).toHaveRole('option')
|
|
128
|
-
expect(optionItemContainer).toHaveAttribute('tabindex', '-1')
|
|
129
|
-
expect(optionItemContainer).toHaveAttribute('data-custom-attr', 'true')
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('should pass event handlers through to label', async () => {
|
|
133
|
-
const onClick = vi.fn()
|
|
134
|
-
const { container } = render(<Item onClick={onClick}>Hello World</Item>)
|
|
135
|
-
|
|
136
|
-
const optionItem = container.querySelector('[class$="-optionItem"]')
|
|
137
|
-
const optionItemContainer = container.querySelector(
|
|
138
|
-
'[class$="-optionItem__container"]'
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
userEvent.click(optionItem!)
|
|
142
|
-
await waitFor(() => {
|
|
143
|
-
expect(onClick).not.toHaveBeenCalled()
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
userEvent.click(optionItemContainer!)
|
|
147
|
-
await waitFor(() => {
|
|
148
|
-
expect(onClick).toHaveBeenCalledTimes(1)
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('should render content before label', async () => {
|
|
153
|
-
const { container } = render(
|
|
154
|
-
<Item renderBeforeLabel={<IconCheckSolid />}>Hello World</Item>
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
const content = container.querySelector(
|
|
158
|
-
'[class$=-optionItem__content--before]'
|
|
159
|
-
)
|
|
160
|
-
expect(content).toBeInTheDocument()
|
|
161
|
-
|
|
162
|
-
const icon = content!.querySelector('svg[name="IconCheck"]')
|
|
163
|
-
expect(icon).toBeInTheDocument()
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('should render content after label', async () => {
|
|
167
|
-
const { container } = render(
|
|
168
|
-
<Item renderAfterLabel={<IconCheckSolid />}>Hello World</Item>
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
const content = container.querySelector(
|
|
172
|
-
'[class$=-optionItem__content--after]'
|
|
173
|
-
)
|
|
174
|
-
expect(content).toBeInTheDocument()
|
|
175
|
-
|
|
176
|
-
const icon = content!.querySelector('svg[name="IconCheck"]')
|
|
177
|
-
expect(icon).toBeInTheDocument()
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('should render nested lists', async () => {
|
|
181
|
-
const { container } = render(
|
|
182
|
-
<Item>
|
|
183
|
-
<Options as="ul" renderLabel={'Nested list'}>
|
|
184
|
-
<Item>Sub item</Item>
|
|
185
|
-
</Options>
|
|
186
|
-
</Item>
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
const item = container.querySelector('span[class$="-optionItem"]')
|
|
190
|
-
expect(item).toBeInTheDocument()
|
|
191
|
-
|
|
192
|
-
const options = item!.querySelector('div[class$="-options"]')
|
|
193
|
-
expect(options).toBeInTheDocument()
|
|
194
|
-
|
|
195
|
-
const nestedList = options!.querySelector('ul')
|
|
196
|
-
const nestedItem = options!.querySelector('li[class$="-optionItem"]')
|
|
197
|
-
|
|
198
|
-
expect(nestedList).toBeInTheDocument()
|
|
199
|
-
expect(nestedItem).toBeInTheDocument()
|
|
200
|
-
expect(nestedItem).toHaveTextContent('Sub item')
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
it('should render as link with href prop', async () => {
|
|
204
|
-
const { container } = render(<Item href="/helloWorld">Hello World</Item>)
|
|
205
|
-
|
|
206
|
-
const link = container.querySelector('[class$="-optionItem__container"]')
|
|
207
|
-
|
|
208
|
-
expect(link).toBeInTheDocument()
|
|
209
|
-
expect(link).toHaveAttribute('href', '/helloWorld')
|
|
210
|
-
expect(link?.tagName).toBe('A')
|
|
211
|
-
})
|
|
212
|
-
})
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The MIT License (MIT)
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) 2015 - present Instructure, Inc.
|
|
5
|
-
*
|
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
-
* in the Software without restriction, including without limitation the rights
|
|
9
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
* furnished to do so, subject to the following conditions:
|
|
12
|
-
*
|
|
13
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
* copies or substantial portions of the Software.
|
|
15
|
-
*
|
|
16
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
* SOFTWARE.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { render, screen } from '@testing-library/react'
|
|
26
|
-
import { vi, expect } from 'vitest'
|
|
27
|
-
import { runAxeCheck } from '@instructure/ui-axe-check'
|
|
28
|
-
|
|
29
|
-
// eslint-disable-next-line no-restricted-imports
|
|
30
|
-
import { generateA11yTests } from '@instructure/ui-scripts/lib/test/generateA11yTests'
|
|
31
|
-
import '@testing-library/jest-dom'
|
|
32
|
-
import { Options } from '../index'
|
|
33
|
-
import OptionsExamples from '../__examples__/Options.examples'
|
|
34
|
-
|
|
35
|
-
describe('<Options />', () => {
|
|
36
|
-
it('should render', async () => {
|
|
37
|
-
const { container } = render(<Options />)
|
|
38
|
-
|
|
39
|
-
const options = container.querySelector('div[class*="-options"]')
|
|
40
|
-
|
|
41
|
-
expect(options).toBeInTheDocument()
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('should render items', async () => {
|
|
45
|
-
render(
|
|
46
|
-
<Options>
|
|
47
|
-
<Options.Item>Option one</Options.Item>
|
|
48
|
-
<Options.Item>Option two</Options.Item>
|
|
49
|
-
</Options>
|
|
50
|
-
)
|
|
51
|
-
const items = screen.getAllByRole('listitem')
|
|
52
|
-
|
|
53
|
-
expect(items.length).toBe(2)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should provide elementRef', async () => {
|
|
57
|
-
const elementRef = vi.fn()
|
|
58
|
-
|
|
59
|
-
render(
|
|
60
|
-
<Options elementRef={elementRef} as="ul">
|
|
61
|
-
<Options.Item>Option one</Options.Item>
|
|
62
|
-
<Options.Item>Option two</Options.Item>
|
|
63
|
-
</Options>
|
|
64
|
-
)
|
|
65
|
-
const optionList = screen.getByRole('list')
|
|
66
|
-
|
|
67
|
-
expect(elementRef).toHaveBeenCalledWith(optionList)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should render designated tag if `as` prop is specified', async () => {
|
|
71
|
-
render(
|
|
72
|
-
<Options as="ol">
|
|
73
|
-
<Options.Item>Option one</Options.Item>
|
|
74
|
-
<Options.Item>Option two</Options.Item>
|
|
75
|
-
</Options>
|
|
76
|
-
)
|
|
77
|
-
const optionList = screen.getByRole('list')
|
|
78
|
-
|
|
79
|
-
expect(optionList.tagName).toBe('OL')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('should render children as listitems when appropriate', async () => {
|
|
83
|
-
const { container } = render(
|
|
84
|
-
<Options as="ul">
|
|
85
|
-
<Options.Item>Option one</Options.Item>
|
|
86
|
-
<Options.Item>Option two</Options.Item>
|
|
87
|
-
</Options>
|
|
88
|
-
)
|
|
89
|
-
const list = container.querySelector('ul')
|
|
90
|
-
const items = container.querySelectorAll('li')
|
|
91
|
-
|
|
92
|
-
expect(list).toBeInTheDocument()
|
|
93
|
-
expect(items.length).toBe(2)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('should pass props through to list', async () => {
|
|
97
|
-
const { container } = render(
|
|
98
|
-
<Options as="ul" role="listbox" data-custom-attr="true">
|
|
99
|
-
<Options.Item>Option one</Options.Item>
|
|
100
|
-
<Options.Item>Option two</Options.Item>
|
|
101
|
-
</Options>
|
|
102
|
-
)
|
|
103
|
-
const options = container.querySelector('[class*="-options__list"]')
|
|
104
|
-
|
|
105
|
-
expect(options).toHaveRole('listbox')
|
|
106
|
-
expect(options).toHaveAttribute('data-custom-attr', 'true')
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('should render root with appropriate role', async () => {
|
|
110
|
-
const { container } = render(
|
|
111
|
-
<Options role="listbox">
|
|
112
|
-
<Options.Item>Option one</Options.Item>
|
|
113
|
-
<Options.Item>Option two</Options.Item>
|
|
114
|
-
</Options>
|
|
115
|
-
)
|
|
116
|
-
const options = container.querySelector('div[class*="-options"]')
|
|
117
|
-
|
|
118
|
-
expect(options).toHaveAttribute('role', 'presentation')
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('should allow null children', async () => {
|
|
122
|
-
render(<Options />)
|
|
123
|
-
|
|
124
|
-
const options = screen.getByRole('list')
|
|
125
|
-
|
|
126
|
-
expect(options).toBeInTheDocument()
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('should render nested options properly', async () => {
|
|
130
|
-
const { container } = render(
|
|
131
|
-
<Options data-testId="outer-list">
|
|
132
|
-
<Options.Item>Option one </Options.Item>
|
|
133
|
-
<Options.Item>Option two </Options.Item>
|
|
134
|
-
<Options renderLabel={'Nested list'} data-testId="nested-list">
|
|
135
|
-
<Options.Item>Nested option one </Options.Item>
|
|
136
|
-
<Options.Item>Nested option two </Options.Item>
|
|
137
|
-
</Options>
|
|
138
|
-
</Options>
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
const allLists = container.querySelectorAll('[class*="-options__list"]')
|
|
142
|
-
const allItems = container.querySelectorAll('[class$="-optionItem"]')
|
|
143
|
-
expect(allLists.length).toBe(2)
|
|
144
|
-
expect(allItems.length).toBe(5)
|
|
145
|
-
|
|
146
|
-
const outerList = screen.getByTestId('outer-list')
|
|
147
|
-
expect(outerList).toHaveTextContent('Option one Option two')
|
|
148
|
-
|
|
149
|
-
const nestedLabel = outerList.querySelector(
|
|
150
|
-
'[class*=-options__label]'
|
|
151
|
-
) as HTMLElement
|
|
152
|
-
expect(nestedLabel).toBeInTheDocument()
|
|
153
|
-
expect(nestedLabel).toHaveTextContent('Nested list')
|
|
154
|
-
|
|
155
|
-
const nestedList = screen.getByTestId('nested-list')
|
|
156
|
-
expect(nestedList).toHaveTextContent('Nested option one Nested option two')
|
|
157
|
-
|
|
158
|
-
const nestedListItems = nestedList!.querySelectorAll('[class$=-optionItem]')
|
|
159
|
-
expect(nestedListItems.length).toBe(2)
|
|
160
|
-
|
|
161
|
-
expect(outerList).toContainElement(nestedLabel)
|
|
162
|
-
expect(outerList).toContainElement(nestedList)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
describe('with generated examples', () => {
|
|
166
|
-
const generatedComponents = generateA11yTests(Options, OptionsExamples)
|
|
167
|
-
|
|
168
|
-
for (const component of generatedComponents) {
|
|
169
|
-
it(component.description, async () => {
|
|
170
|
-
const { container } = render(component.content)
|
|
171
|
-
|
|
172
|
-
// axe-check is more strict now, and expects "list" role to have "listitem" children, but we use "role='none'" children. After discussing it with the A11y team, we agreed to ignore this error because the screen readers can read the component perfectly.
|
|
173
|
-
// TODO: try to remove this ignore if axe-check is updated and isn't this strict anymore
|
|
174
|
-
// https://dequeuniversity.com/rules/axe/4.6/aria-required-children?application=axeAPI
|
|
175
|
-
const axeCheck = await runAxeCheck(container, {
|
|
176
|
-
ignores: ['aria-required-children']
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
expect(axeCheck).toBe(true)
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
describe('for a11y', () => {
|
|
185
|
-
it('should be accessible with links', async () => {
|
|
186
|
-
const { container } = render(
|
|
187
|
-
<Options>
|
|
188
|
-
<Options.Item>Option</Options.Item>
|
|
189
|
-
<Options.Item href="/">Option link</Options.Item>
|
|
190
|
-
</Options>
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
// axe-check is more strict now, and expects "list" role to have "listitem" children, but we use "role='none'" children. After discussing it with the A11y team, we agreed to ignore this error because the screen readers can read the component perfectly.
|
|
194
|
-
// TODO: try to remove this ignore if axe-check is updated and isn't this strict anymore
|
|
195
|
-
// https://dequeuniversity.com/rules/axe/4.6/aria-required-children?application=axeAPI
|
|
196
|
-
const axeCheck = await runAxeCheck(container, {
|
|
197
|
-
ignores: ['aria-required-children']
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
expect(axeCheck).toBe(true)
|
|
201
|
-
})
|
|
202
|
-
})
|
|
203
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Item.test.d.ts","sourceRoot":"","sources":["../../../../src/Options/Item/__new-tests__/Item.test.tsx"],"names":[],"mappings":"AA4BA,OAAO,2BAA2B,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Options.test.d.ts","sourceRoot":"","sources":["../../../src/Options/__new-tests__/Options.test.tsx"],"names":[],"mappings":"AA8BA,OAAO,2BAA2B,CAAA"}
|