@okta/odyssey-react-mui 1.22.0 → 1.23.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 (230) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/@types/i18next.d.js.map +1 -1
  3. package/dist/Autocomplete.js +30 -0
  4. package/dist/Autocomplete.js.map +1 -1
  5. package/dist/Callout.js +12 -24
  6. package/dist/Callout.js.map +1 -1
  7. package/dist/DataTable/useScrollIndication.js +7 -3
  8. package/dist/DataTable/useScrollIndication.js.map +1 -1
  9. package/dist/FileUploader/FileUploadIllustration.js.map +1 -0
  10. package/dist/FileUploader/FileUploadPreview.js.map +1 -0
  11. package/dist/{labs/FileUpload.js → FileUploader/FileUploader.js} +6 -5
  12. package/dist/FileUploader/FileUploader.js.map +1 -0
  13. package/dist/FileUploader/index.js +13 -0
  14. package/dist/FileUploader/index.js.map +1 -0
  15. package/dist/OdysseyProvider.js +4 -0
  16. package/dist/OdysseyProvider.js.map +1 -1
  17. package/dist/Radio.js +2 -2
  18. package/dist/Radio.js.map +1 -1
  19. package/dist/Select.js +36 -0
  20. package/dist/Select.js.map +1 -1
  21. package/dist/{labs/Switch.js → Switch.js} +7 -7
  22. package/dist/Switch.js.map +1 -0
  23. package/dist/Tabs.js +7 -9
  24. package/dist/Tabs.js.map +1 -1
  25. package/dist/Tag.js +102 -4
  26. package/dist/Tag.js.map +1 -1
  27. package/dist/TextField.js +16 -39
  28. package/dist/TextField.js.map +1 -1
  29. package/dist/Toast.js +2 -2
  30. package/dist/Toast.js.map +1 -1
  31. package/dist/createShadowDomElements.js +1 -0
  32. package/dist/createShadowDomElements.js.map +1 -1
  33. package/dist/i18n.js +1 -1
  34. package/dist/i18n.js.map +1 -1
  35. package/dist/index.js +2 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.scss +92 -4
  38. package/dist/labs/DataView/DataView.js +64 -25
  39. package/dist/labs/DataView/DataView.js.map +1 -1
  40. package/dist/labs/DataView/TableLayoutContent.js +17 -3
  41. package/dist/labs/DataView/TableLayoutContent.js.map +1 -1
  42. package/dist/labs/DataView/componentTypes.js.map +1 -1
  43. package/dist/labs/DateField.js +2 -0
  44. package/dist/labs/DateField.js.map +1 -1
  45. package/dist/labs/DatePicker.js +5 -1
  46. package/dist/labs/DatePicker.js.map +1 -1
  47. package/dist/labs/SideNav/OktaLogo.js +36 -0
  48. package/dist/labs/SideNav/OktaLogo.js.map +1 -0
  49. package/dist/labs/SideNav/SideNav.js +125 -36
  50. package/dist/labs/SideNav/SideNav.js.map +1 -1
  51. package/dist/labs/SideNav/SideNavHeader.js +33 -10
  52. package/dist/labs/SideNav/SideNavHeader.js.map +1 -1
  53. package/dist/labs/SideNav/types.js.map +1 -1
  54. package/dist/labs/TopNav.js +2 -1
  55. package/dist/labs/TopNav.js.map +1 -1
  56. package/dist/labs/index.js +0 -2
  57. package/dist/labs/index.js.map +1 -1
  58. package/dist/labs/useDateFieldsTranslations.js +1 -1
  59. package/dist/labs/useDateFieldsTranslations.js.map +1 -1
  60. package/dist/properties/ts/odyssey-react-mui.js +3 -1
  61. package/dist/properties/ts/odyssey-react-mui.js.map +1 -1
  62. package/dist/src/Autocomplete.d.ts +30 -0
  63. package/dist/src/Autocomplete.d.ts.map +1 -1
  64. package/dist/src/Callout.d.ts +11 -23
  65. package/dist/src/Callout.d.ts.map +1 -1
  66. package/dist/src/DataTable/useScrollIndication.d.ts.map +1 -1
  67. package/dist/src/FileUploader/FileUploadIllustration.d.ts.map +1 -0
  68. package/dist/src/{labs → FileUploader}/FileUploadPreview.d.ts +2 -2
  69. package/dist/src/FileUploader/FileUploadPreview.d.ts.map +1 -0
  70. package/dist/src/{labs/FileUpload.d.ts → FileUploader/FileUploader.d.ts} +5 -4
  71. package/dist/src/FileUploader/FileUploader.d.ts.map +1 -0
  72. package/dist/src/FileUploader/index.d.ts +13 -0
  73. package/dist/src/FileUploader/index.d.ts.map +1 -0
  74. package/dist/src/NativeSelect.d.ts +1 -1
  75. package/dist/src/OdysseyProvider.d.ts.map +1 -1
  76. package/dist/src/OdysseyTranslationProvider.d.ts +1 -1
  77. package/dist/src/OdysseyTranslationProvider.d.ts.map +1 -1
  78. package/dist/src/PasswordField.d.ts +1 -1
  79. package/dist/src/SearchField.d.ts +1 -1
  80. package/dist/src/Select.d.ts +36 -0
  81. package/dist/src/Select.d.ts.map +1 -1
  82. package/dist/src/{labs/Switch.d.ts → Switch.d.ts} +3 -3
  83. package/dist/src/Switch.d.ts.map +1 -0
  84. package/dist/src/Tabs.d.ts +6 -8
  85. package/dist/src/Tabs.d.ts.map +1 -1
  86. package/dist/src/Tag.d.ts +7 -1
  87. package/dist/src/Tag.d.ts.map +1 -1
  88. package/dist/src/TextField.d.ts +17 -40
  89. package/dist/src/TextField.d.ts.map +1 -1
  90. package/dist/src/createShadowDomElements.d.ts.map +1 -1
  91. package/dist/src/i18n.d.ts +2 -2
  92. package/dist/src/i18n.d.ts.map +1 -1
  93. package/dist/src/index.d.ts +2 -1
  94. package/dist/src/index.d.ts.map +1 -1
  95. package/dist/src/labs/DataView/DataView.d.ts +1 -1
  96. package/dist/src/labs/DataView/DataView.d.ts.map +1 -1
  97. package/dist/src/labs/DataView/TableLayoutContent.d.ts +2 -1
  98. package/dist/src/labs/DataView/TableLayoutContent.d.ts.map +1 -1
  99. package/dist/src/labs/DataView/componentTypes.d.ts +10 -0
  100. package/dist/src/labs/DataView/componentTypes.d.ts.map +1 -1
  101. package/dist/src/labs/DateField.d.ts +2 -2
  102. package/dist/src/labs/DateField.d.ts.map +1 -1
  103. package/dist/src/labs/DatePicker.d.ts +2 -2
  104. package/dist/src/labs/DatePicker.d.ts.map +1 -1
  105. package/dist/{test-selectors/odysseyTestSelectors.js → src/labs/SideNav/OktaLogo.d.ts} +3 -9
  106. package/dist/src/labs/SideNav/OktaLogo.d.ts.map +1 -0
  107. package/dist/src/labs/SideNav/SideNav.d.ts +2 -1
  108. package/dist/src/labs/SideNav/SideNav.d.ts.map +1 -1
  109. package/dist/src/labs/SideNav/SideNavHeader.d.ts +1 -1
  110. package/dist/src/labs/SideNav/SideNavHeader.d.ts.map +1 -1
  111. package/dist/src/labs/SideNav/types.d.ts +28 -5
  112. package/dist/src/labs/SideNav/types.d.ts.map +1 -1
  113. package/dist/src/labs/TopNav.d.ts +1 -0
  114. package/dist/src/labs/TopNav.d.ts.map +1 -1
  115. package/dist/src/labs/index.d.ts +0 -2
  116. package/dist/src/labs/index.d.ts.map +1 -1
  117. package/dist/src/properties/ts/odyssey-react-mui.d.ts +2 -0
  118. package/dist/src/properties/ts/odyssey-react-mui.d.ts.map +1 -1
  119. package/dist/src/test-selectors/getByQuerySelector.d.ts +148 -0
  120. package/dist/src/test-selectors/getByQuerySelector.d.ts.map +1 -0
  121. package/{src/test-selectors/odysseyTestSelectors.ts → dist/src/test-selectors/getComputedAccessibleErrorMessageText.d.ts} +3 -11
  122. package/dist/src/test-selectors/getComputedAccessibleErrorMessageText.d.ts.map +1 -0
  123. package/dist/src/test-selectors/{featureTestSelector.d.ts → getComputedAccessibleText.d.ts} +11 -19
  124. package/dist/src/test-selectors/getComputedAccessibleText.d.ts.map +1 -0
  125. package/dist/src/test-selectors/index.d.ts +2 -2
  126. package/dist/src/test-selectors/index.d.ts.map +1 -1
  127. package/dist/src/test-selectors/interpolateString.d.ts +15 -0
  128. package/dist/src/test-selectors/interpolateString.d.ts.map +1 -0
  129. package/dist/src/test-selectors/linkedHtmlSelectors.d.ts +24 -0
  130. package/dist/src/test-selectors/linkedHtmlSelectors.d.ts.map +1 -0
  131. package/dist/src/test-selectors/queryOdysseySelector.d.ts +5755 -0
  132. package/dist/src/test-selectors/queryOdysseySelector.d.ts.map +1 -0
  133. package/dist/src/test-selectors/querySelector.d.ts +59 -3613
  134. package/dist/src/test-selectors/querySelector.d.ts.map +1 -1
  135. package/dist/src/test-selectors/sanityChecks.d.ts +18 -0
  136. package/dist/src/test-selectors/sanityChecks.d.ts.map +1 -0
  137. package/dist/src/test-selectors/testSelector.d.ts +46 -0
  138. package/dist/src/test-selectors/testSelector.d.ts.map +1 -0
  139. package/dist/src/theme/components.d.ts.map +1 -1
  140. package/dist/test-selectors/getByQuerySelector.js +64 -0
  141. package/dist/test-selectors/getByQuerySelector.js.map +1 -0
  142. package/dist/test-selectors/getComputedAccessibleErrorMessageText.js +25 -0
  143. package/dist/test-selectors/getComputedAccessibleErrorMessageText.js.map +1 -0
  144. package/dist/test-selectors/getComputedAccessibleText.js +24 -0
  145. package/dist/test-selectors/getComputedAccessibleText.js.map +1 -0
  146. package/dist/test-selectors/index.js +2 -2
  147. package/dist/test-selectors/index.js.map +1 -1
  148. package/{src/test-selectors/featureTestSelector.ts → dist/test-selectors/interpolateString.js} +11 -27
  149. package/dist/test-selectors/interpolateString.js.map +1 -0
  150. package/dist/test-selectors/linkedHtmlSelectors.js +34 -0
  151. package/dist/test-selectors/linkedHtmlSelectors.js.map +1 -0
  152. package/dist/test-selectors/queryOdysseySelector.js +26 -0
  153. package/dist/test-selectors/queryOdysseySelector.js.map +1 -0
  154. package/dist/test-selectors/querySelector.js +82 -58
  155. package/dist/test-selectors/querySelector.js.map +1 -1
  156. package/dist/test-selectors/sanityChecks.js +33 -0
  157. package/dist/test-selectors/sanityChecks.js.map +1 -0
  158. package/dist/test-selectors/testSelector.js +2 -0
  159. package/dist/test-selectors/testSelector.js.map +1 -0
  160. package/dist/test-selectors/testSelectors.json +1 -1
  161. package/dist/theme/components.js +0 -1
  162. package/dist/theme/components.js.map +1 -1
  163. package/dist/tsconfig.production.tsbuildinfo +1 -1
  164. package/dist/tsconfig.tsbuildinfo +1 -1
  165. package/jest.setup.js +3 -0
  166. package/package.json +5 -4
  167. package/scripts/generateTestSelectorsJson.ts +1 -1
  168. package/src/@types/i18next.d.ts +1 -1
  169. package/src/Autocomplete.tsx +32 -0
  170. package/src/Callout.tsx +13 -25
  171. package/src/DataTable/useScrollIndication.tsx +9 -2
  172. package/src/{labs → FileUploader}/FileUploadPreview.tsx +3 -3
  173. package/src/{labs/FileUpload.tsx → FileUploader/FileUploader.tsx} +7 -6
  174. package/src/FileUploader/index.ts +13 -0
  175. package/src/OdysseyCacheProvider.test.tsx +1 -0
  176. package/src/OdysseyProvider.tsx +6 -1
  177. package/src/Radio.tsx +2 -2
  178. package/src/Select.tsx +38 -0
  179. package/src/{labs/Switch.tsx → Switch.tsx} +10 -10
  180. package/src/Tabs.tsx +8 -10
  181. package/src/Tag.tsx +134 -3
  182. package/src/TextField.tsx +18 -41
  183. package/src/Toast.tsx +1 -1
  184. package/src/createShadowDomElements.ts +3 -0
  185. package/src/i18n.ts +3 -3
  186. package/src/index.ts +6 -1
  187. package/src/labs/DataView/DataView.test.tsx +158 -0
  188. package/src/labs/DataView/DataView.tsx +98 -50
  189. package/src/labs/DataView/TableLayoutContent.tsx +28 -1
  190. package/src/labs/DataView/componentTypes.ts +13 -0
  191. package/src/labs/DateField.tsx +3 -0
  192. package/src/labs/DatePicker.tsx +12 -1
  193. package/src/labs/SideNav/OktaLogo.tsx +39 -0
  194. package/src/labs/SideNav/SideNav.tsx +187 -51
  195. package/src/labs/SideNav/SideNavHeader.tsx +30 -7
  196. package/src/labs/SideNav/types.ts +32 -5
  197. package/src/labs/TopNav.tsx +3 -1
  198. package/src/labs/index.ts +0 -3
  199. package/src/labs/useDateFieldsTranslations.ts +1 -1
  200. package/src/properties/odyssey-react-mui.properties +2 -1
  201. package/src/properties/ts/odyssey-react-mui.ts +1 -1
  202. package/src/test-selectors/getByQuerySelector.ts +176 -0
  203. package/src/test-selectors/getComputedAccessibleErrorMessageText.ts +52 -0
  204. package/src/test-selectors/getComputedAccessibleText.ts +36 -0
  205. package/src/test-selectors/index.ts +2 -2
  206. package/src/test-selectors/interpolateString.ts +41 -0
  207. package/src/test-selectors/linkedHtmlSelectors.ts +73 -0
  208. package/src/test-selectors/queryOdysseySelector.ts +36 -0
  209. package/src/test-selectors/querySelector.ts +221 -170
  210. package/src/test-selectors/sanityChecks.ts +53 -0
  211. package/src/test-selectors/testSelector.ts +143 -0
  212. package/src/theme/components.tsx +0 -2
  213. package/dist/labs/FileUpload.js.map +0 -1
  214. package/dist/labs/FileUploadIllustration.js.map +0 -1
  215. package/dist/labs/FileUploadPreview.js.map +0 -1
  216. package/dist/labs/Switch.js.map +0 -1
  217. package/dist/src/labs/FileUpload.d.ts.map +0 -1
  218. package/dist/src/labs/FileUploadIllustration.d.ts.map +0 -1
  219. package/dist/src/labs/FileUploadPreview.d.ts.map +0 -1
  220. package/dist/src/labs/Switch.d.ts.map +0 -1
  221. package/dist/src/test-selectors/featureTestSelector.d.ts.map +0 -1
  222. package/dist/src/test-selectors/odysseyTestSelectors.d.ts +0 -120
  223. package/dist/src/test-selectors/odysseyTestSelectors.d.ts.map +0 -1
  224. package/dist/test-selectors/featureTestSelector.js +0 -2
  225. package/dist/test-selectors/featureTestSelector.js.map +0 -1
  226. package/dist/test-selectors/odysseyTestSelectors.js.map +0 -1
  227. /package/dist/{labs → FileUploader}/FileUploadIllustration.js +0 -0
  228. /package/dist/{labs → FileUploader}/FileUploadPreview.js +0 -0
  229. /package/dist/src/{labs → FileUploader}/FileUploadIllustration.d.ts +0 -0
  230. /package/src/{labs → FileUploader}/FileUploadIllustration.tsx +0 -0
@@ -0,0 +1,176 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import {
14
+ queries,
15
+ within,
16
+ type BoundFunctions,
17
+ type ByRoleMatcher,
18
+ type ByRoleOptions,
19
+ type Matcher,
20
+ type SelectorMatcherOptions,
21
+ } from "@testing-library/dom";
22
+
23
+ export type RoleSelectorMethod = "ByRole";
24
+
25
+ export type TextSelectorMethod =
26
+ | "ByLabelText"
27
+ | "ByPlaceholderText"
28
+ | "ByText"
29
+ | "ByAltText"
30
+ | "ByTitle";
31
+
32
+ export type QueryMethod = "find" | "get" | "query";
33
+
34
+ export type ByRoleMethods =
35
+ | "getByRole"
36
+ // | "getAllByRole"
37
+ | "queryByRole";
38
+ // | "queryAllByRole"
39
+ // | "findByRole"
40
+ // | "findAllByRole"
41
+
42
+ export type ByTextMethods =
43
+ | "getByLabelText"
44
+ // | "getAllByLabelText"
45
+ | "queryByLabelText"
46
+ // | "queryAllByLabelText"
47
+ // | "findByLabelText"
48
+ // | "findAllByLabelText"
49
+ | "getByPlaceholderText"
50
+ // | "getAllByPlaceholderText"
51
+ | "queryByPlaceholderText"
52
+ // | "queryAllByPlaceholderText"
53
+ // | "findByPlaceholderText"
54
+ // | "findAllByPlaceholderText"
55
+ | "getByText"
56
+ // | "getAllByText"
57
+ | "queryByText"
58
+ // | "queryAllByText"
59
+ // | "findByText"
60
+ // | "findAllByText"
61
+ | "getByAltText"
62
+ // | "getAllByAltText"
63
+ | "queryByAltText"
64
+ // | "queryAllByAltText"
65
+ // | "findByAltText"
66
+ // | "findAllByAltText"
67
+ | "getByTitle"
68
+ // | "getAllByTitle"
69
+ | "queryByTitle";
70
+ // | "queryAllByTitle"
71
+ // | "findByTitle"
72
+ // | "findAllByTitle"
73
+
74
+ export const executeTestingLibraryMethod = <
75
+ CanvasMethods extends keyof BoundFunctions<typeof queries>,
76
+ >({
77
+ canvas,
78
+ queryMethod,
79
+ selectionMethod,
80
+ }: {
81
+ canvas: Pick<BoundFunctions<typeof queries>, CanvasMethods>;
82
+ queryMethod: QueryMethod;
83
+ selectionMethod: RoleSelectorMethod | TextSelectorMethod;
84
+ }) =>
85
+ canvas[
86
+ queryMethod.concat(selectionMethod) as keyof Pick<
87
+ BoundFunctions<typeof queries>,
88
+ CanvasMethods
89
+ >
90
+ ];
91
+
92
+ export const getByQuerySelector = <
93
+ LocalQueryMethod extends QueryMethod = "get",
94
+ >({
95
+ element,
96
+ queryMethod,
97
+ queryOptions,
98
+ role,
99
+ selectionMethod,
100
+ text,
101
+ }: {
102
+ element: HTMLElement;
103
+ queryMethod: LocalQueryMethod;
104
+ } & (
105
+ | {
106
+ queryOptions?: ByRoleOptions;
107
+ role: ByRoleMatcher;
108
+ selectionMethod: RoleSelectorMethod;
109
+ text?: never;
110
+ }
111
+ | {
112
+ queryOptions?: SelectorMatcherOptions;
113
+ role?: never;
114
+ selectionMethod: TextSelectorMethod;
115
+ text: Matcher;
116
+ }
117
+ )) => {
118
+ const canvas = within(element);
119
+
120
+ const capturedElement =
121
+ selectionMethod === "ByRole"
122
+ ? executeTestingLibraryMethod<ByRoleMethods>({
123
+ canvas,
124
+ queryMethod,
125
+ selectionMethod,
126
+ })(role, queryOptions)
127
+ : executeTestingLibraryMethod<ByTextMethods>({
128
+ canvas,
129
+ queryMethod,
130
+ selectionMethod,
131
+ })(text, queryOptions);
132
+
133
+ return capturedElement as LocalQueryMethod extends "get"
134
+ ? HTMLElement
135
+ : HTMLElement | null;
136
+ };
137
+
138
+ export const getByRoleQuerySelector = <LocalQueryMethod extends QueryMethod>({
139
+ element,
140
+ queryMethod,
141
+ queryOptions,
142
+ role,
143
+ }: {
144
+ element: HTMLElement;
145
+ queryMethod: LocalQueryMethod;
146
+ queryOptions?: ByRoleOptions;
147
+ role: ByRoleMatcher;
148
+ }) =>
149
+ getByQuerySelector({
150
+ element,
151
+ queryMethod,
152
+ queryOptions,
153
+ role,
154
+ selectionMethod: "ByRole",
155
+ });
156
+
157
+ export const getByTextQuerySelector = <LocalQueryMethod extends QueryMethod>({
158
+ element,
159
+ queryMethod,
160
+ queryOptions,
161
+ selectionMethod,
162
+ text,
163
+ }: {
164
+ element: HTMLElement;
165
+ queryMethod: LocalQueryMethod;
166
+ queryOptions?: SelectorMatcherOptions;
167
+ selectionMethod: TextSelectorMethod;
168
+ text: Matcher;
169
+ }) =>
170
+ getByQuerySelector({
171
+ element,
172
+ queryMethod,
173
+ queryOptions,
174
+ selectionMethod,
175
+ text,
176
+ });
@@ -0,0 +1,52 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { normalizeText, validateHtmlElement } from "./sanityChecks";
14
+
15
+ // Code modified from: https://github.com/testing-library/jest-dom/blob/main/src/to-have-accessible-errormessage.js
16
+
17
+ /** @see https://www.w3.org/TR/wai-aria-1.2/#aria-errormessage */
18
+ export const getComputedAccessibleErrorMessageText = (
19
+ htmlElement: HTMLElement,
20
+ ) => {
21
+ validateHtmlElement(htmlElement);
22
+
23
+ const ariaErrorMessageId = htmlElement.getAttribute("aria-errormessage");
24
+
25
+ // `aria-errormessage` only supports a single `id`.
26
+ if (Boolean(ariaErrorMessageId) && /\s+/.test(ariaErrorMessageId || "")) {
27
+ throw new Error(
28
+ "`aria-errormessage` needs to have a single `id`.".concat(
29
+ "\n",
30
+ `Received: ${ariaErrorMessageId}`,
31
+ ),
32
+ );
33
+ }
34
+
35
+ /** @see https://www.w3.org/TR/wai-aria-1.2/#aria-invalid */
36
+ const ariaInvalid = htmlElement.getAttribute("aria-invalid");
37
+
38
+ // `aria-invalid` only supports `true` when getting an error message.
39
+ if (!htmlElement.hasAttribute("aria-invalid") || ariaInvalid === "false") {
40
+ throw new Error(
41
+ "`aria-invalid` must be `true` when getting an accessible error message.".concat(
42
+ "\n",
43
+ `Received: ${ariaInvalid}`,
44
+ ),
45
+ );
46
+ }
47
+
48
+ return normalizeText(
49
+ htmlElement.ownerDocument.getElementById(ariaErrorMessageId || "")
50
+ ?.textContent ?? "",
51
+ );
52
+ };
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import {
14
+ computeAccessibleName,
15
+ computeAccessibleDescription,
16
+ } from "dom-accessibility-api";
17
+
18
+ import { type AccessibleTextSelectorValue } from "./testSelector";
19
+ import { getComputedAccessibleErrorMessageText } from "./getComputedAccessibleErrorMessageText";
20
+
21
+ export const accessibleTextSelector = {
22
+ description: computeAccessibleDescription,
23
+ errorMessage: getComputedAccessibleErrorMessageText,
24
+ label: computeAccessibleName,
25
+ } as const satisfies Record<
26
+ AccessibleTextSelectorValue,
27
+ (element: HTMLElement) => string
28
+ >;
29
+
30
+ export const getComputedAccessibleText = ({
31
+ element,
32
+ type,
33
+ }: {
34
+ element: HTMLElement;
35
+ type: AccessibleTextSelectorValue;
36
+ }) => accessibleTextSelector[type](element);
@@ -10,6 +10,6 @@
10
10
  * See the License for the specific language governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- export * from "./featureTestSelector";
13
+ export * from "./queryOdysseySelector";
14
14
  export * from "./querySelector";
15
- export * from "./odysseyTestSelectors";
15
+ export * from "./testSelector";
@@ -0,0 +1,41 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ export const isRegExpString = (string: string) => /^\/*(.+)\/$/.test(string);
14
+
15
+ /** @deprecated This function is only to be used to interpolate strings in unit tests. It uses `eval` internally which could be unsafe if it wasn't done explicitly in our testing environment. */
16
+ export const interpolateString = (
17
+ string: string,
18
+ replacements: Record<string, string | RegExp>,
19
+ ) => {
20
+ // Writes out all replacement pairs as "const variableName = value" because we don't know which we want. Then at the end, we `return` the value we want by simply adding it as the last thing in eval'd code.
21
+ const interpolatedString = eval(`
22
+ ${Object.entries(replacements)
23
+ .map(
24
+ ([variableName, value]) =>
25
+ `const ${variableName} = ${
26
+ typeof value === "string" ? JSON.stringify(value) : value
27
+ };`,
28
+ )
29
+ .join("")}
30
+
31
+ \`${string}\`
32
+ `) as string;
33
+
34
+ if (isRegExpString(interpolatedString)) {
35
+ // If this string matches the RegExp format, we know that it's a RegExp, and we'll evaluate it to one. TypeScript has no way of knowing the resulting type, so we have to set that ourselves.
36
+ return eval(interpolatedString) as RegExp;
37
+ }
38
+
39
+ // This interpolated string is just a string.
40
+ return interpolatedString;
41
+ };
@@ -0,0 +1,73 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { type AriaRole } from "react";
14
+ import { ElementError } from "./sanityChecks";
15
+ import { getRole } from "dom-accessibility-api";
16
+
17
+ /**
18
+ * For `aria-haspopup`:
19
+ * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-haspopup
20
+ * For `datalist`:
21
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
22
+ */
23
+ export const getControlledElement = ({
24
+ element,
25
+ role,
26
+ }: {
27
+ element: HTMLElement;
28
+ /** If this element controls multiple items, it might be valuable to help narrow down the specific item's `role`. */
29
+ role?: AriaRole;
30
+ }) => {
31
+ if (element instanceof HTMLInputElement && element.list) {
32
+ return element.list;
33
+ }
34
+
35
+ if (element.getAttribute("aria-expanded") === "false") {
36
+ throw new ElementError(
37
+ "Popup isn't open in ARIA; therefore, it cannot be captured.",
38
+ element,
39
+ );
40
+ }
41
+
42
+ const linkedElementIds =
43
+ element.getAttribute("aria-controls") || element.getAttribute("aria-owns");
44
+
45
+ if (!linkedElementIds) {
46
+ throw new ElementError(
47
+ "Popup isn't linked; therefore, it cannot be captured.",
48
+ element,
49
+ );
50
+ }
51
+
52
+ const linkedElement = linkedElementIds
53
+ .split(" ")
54
+ .map((linkedElementId) =>
55
+ element.ownerDocument.getElementById(linkedElementId),
56
+ )
57
+ // This can be `.filter(Boolean)` when Inferred Type Predicates is in TypeScript (which should be part of the version we're using): https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#:~:text=Inferred%20Type%20Predicates,Thanks%20Dan!
58
+ .filter((linkedElement): linkedElement is HTMLElement =>
59
+ Boolean(linkedElement),
60
+ )
61
+ .find((linkedElement) =>
62
+ role ? getRole(linkedElement) === role : Boolean(linkedElement),
63
+ );
64
+
65
+ if (!linkedElement) {
66
+ throw new ElementError(
67
+ "Controlled element isn't available; therefore, it cannot be captured.",
68
+ element,
69
+ );
70
+ }
71
+
72
+ return linkedElement;
73
+ };
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * Copyright (c) 2024-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { querySelector } from "./querySelector";
14
+ import { type TestSelector } from "./testSelector";
15
+ import { AutocompleteTestSelector } from "../Autocomplete";
16
+ import { CalloutTestSelector } from "../Callout";
17
+ import { SelectTestSelector } from "../Select";
18
+ import { TabsTestSelector } from "../Tabs";
19
+ import { TextFieldTestSelector } from "../TextField";
20
+
21
+ export const odysseyTestSelector = {
22
+ Autocomplete: AutocompleteTestSelector,
23
+ Callout: CalloutTestSelector,
24
+ Select: SelectTestSelector,
25
+ Tabs: TabsTestSelector,
26
+ TextField: TextFieldTestSelector,
27
+ } as const satisfies Record<string, TestSelector>;
28
+
29
+ export const queryOdysseySelector = <
30
+ ComponentName extends keyof typeof odysseyTestSelector,
31
+ >(
32
+ /**
33
+ * Name of the component you want to select within.
34
+ */
35
+ componentName: ComponentName,
36
+ ) => querySelector(odysseyTestSelector[componentName]);