Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Update Test Selector types and improve functionality #2333

Merged
merged 29 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
58f7e36
fix: selecting controlled elements
KevinGhadyani-Okta Aug 19, 2024
eebaa9f
feat: adds ability to have type-safe roles in queries
KevinGhadyani-Okta Aug 19, 2024
df88130
fix: updates Callout test selectors
KevinGhadyani-Okta Aug 21, 2024
47d0244
test
KevinGhadyani-Okta Aug 21, 2024
00804e2
test 2
KevinGhadyani-Okta Aug 21, 2024
724f013
test 3
KevinGhadyani-Okta Aug 21, 2024
ae71a24
test 4
KevinGhadyani-Okta Aug 22, 2024
aa71cc1
test 5
KevinGhadyani-Okta Aug 23, 2024
b53ae5a
fix: reconfigured querySelector with correct types
KevinGhadyani-Okta Aug 23, 2024
2b1fb72
fix: improved test selectors API
KevinGhadyani-Okta Aug 23, 2024
8af669f
fix: adds typing for getAccessibleText
KevinGhadyani-Okta Aug 23, 2024
04df4e5
fix: cleanup test selectors code
KevinGhadyani-Okta Aug 23, 2024
d88b7a0
fix: removes rxjs
KevinGhadyani-Okta Aug 27, 2024
71549c2
fix: prettify code
KevinGhadyani-Okta Aug 27, 2024
025d48a
fix: fixed test error in Callout stories
KevinGhadyani-Okta Aug 27, 2024
183ecf5
fix: removes explicit odysseyTestSelectors file
KevinGhadyani-Okta Aug 27, 2024
b72ac41
fix: updates ElementError logging with message denoting ElementError
KevinGhadyani-Okta Aug 27, 2024
40fb286
fix: defaults `ChildQueryMethod` as `"get"` to match other instances
KevinGhadyani-Okta Aug 27, 2024
101c196
fix: minor fix to change Options key to never where it wouldn't exist…
KevinGhadyani-Okta Aug 27, 2024
d2a1965
fix: adds comment around `interpolateString` to make it clear how dan…
KevinGhadyani-Okta Aug 27, 2024
b51e8e3
fix: marks interpolateString as @deprecated as it will probably be re…
KevinGhadyani-Okta Aug 27, 2024
4f10bd4
fix: removes unused type in querySelector
KevinGhadyani-Okta Aug 27, 2024
b5b4289
fix: massively renamed TestSelector types to be easily understood
KevinGhadyani-Okta Aug 27, 2024
fba00ac
fix: moves element selection outside of querySelector
KevinGhadyani-Okta Aug 29, 2024
801ed83
fix: adds missing accessibleText to Select
KevinGhadyani-Okta Aug 29, 2024
d449bda
fix: renames testSelectors to testSelector in all supported components
KevinGhadyani-Okta Aug 29, 2024
9c30029
Merge branch 'main' into OKTA-794668-test-selectors-functionality
KevinGhadyani-Okta Sep 11, 2024
7af68be
fix: fixes small type issues and Autocomplete merge issue
KevinGhadyani-Okta Sep 11, 2024
97b1c22
fix: fixes broken Select interaction test
KevinGhadyani-Okta Sep 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/odyssey-react-mui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"@okta/odyssey-design-tokens": "workspace:^",
"@types/luxon": "^3.4.2",
"date-fns": "^2.30.0",
"dom-accessibility-api": "^0.7.0",
"i18next": "^23.8.2",
"luxon": "^3.4.4",
"material-react-table": "^2.11.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { join } from "node:path";
const distDirectory = join(__dirname, "../dist/test-selectors");

import("../src/test-selectors/index").then(
({ odysseyTestSelectors: testSelector }) =>
({ odysseyTestSelector: testSelector }) =>
mkdir(distDirectory)
.catch(() => null)
.then(() =>
Expand Down
40 changes: 36 additions & 4 deletions packages/odyssey-react-mui/src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ import _AutoSizer, {
} from "react-virtualized-auto-sizer";
import { useTranslation } from "react-i18next";

// This is required to get around a react-types issue for "AutoSizer is not a valid JSX element."
// @see https://github.com/bvaughn/react-virtualized/issues/1739#issuecomment-1291444246
const AutoSizer = _AutoSizer as unknown as FC<AutoSizerProps>;

import { Field } from "./Field";
import { FieldComponentProps } from "./FieldComponentProps";
import type { HtmlProps } from "./HtmlProps";
Expand All @@ -51,6 +47,42 @@ import {
useInputValues,
getControlState,
} from "./inputUtils";
import { FeatureTestSelector } from "./test-selectors";

// This is required to get around a react-types issue for "AutoSizer is not a valid JSX element."
// @see https://github.com/bvaughn/react-virtualized/issues/1739#issuecomment-1291444246
const AutoSizer = _AutoSizer as unknown as FC<AutoSizerProps>;

export const AutocompleteTestSelectors = {
accessibleText: {
errorMessage: "errorMessage",
hint: "description",
label: "label",
},
feature: {
list: {
feature: {
listItem: {
selector: {
method: "ByRole",
options: {
label: "name",
},
role: "option",
},
},
},
isControlledElement: true,
},
},
selector: {
method: "ByRole",
options: {
label: "name",
},
role: "combobox",
},
} as const satisfies FeatureTestSelector;

export type AutocompleteProps<
OptionType,
Expand Down
26 changes: 7 additions & 19 deletions packages/odyssey-react-mui/src/Callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,27 @@ import { Paragraph } from "./Typography";
import { useUniqueId } from "./useUniqueId";

export const CalloutTestSelectors = {
accessibleText: {
text: "description",
title: "label",
},
feature: {
link: {
selector: {
method: "ByRole",
options: {
name: "${linkText}",
linkText: "name",
},
role: "link",
templateVariableNames: ["linkText"],
},
},
text: {
selector: {
method: "ByText",
templateVariableNames: ["text"],
text: "${text}",
},
},
title: {
selector: {
method: "ByText",
templateVariableNames: ["title"],
text: "${title}",
},
},
},
selector: {
method: "ByRole",
options: {
name: "${title}",
title: "name",
},
role: "${role}",
templateVariableNames: ["role", "title"],
role: ["alert", "status"],
},
} as const satisfies FeatureTestSelector;

Expand Down
32 changes: 32 additions & 0 deletions packages/odyssey-react-mui/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ import {
useOdysseyDesignTokens,
DesignTokens,
} from "./OdysseyDesignTokensContext";
import { FeatureTestSelector } from "./test-selectors";

export const SelectTestSelectors = {
accessibleText: {
errorMessage: "errorMessage",
hint: "description",
label: "label",
},
feature: {
list: {
feature: {
listItem: {
selector: {
method: "ByRole",
options: {
label: "name",
},
role: "option",
},
},
},
isControlledElement: true,
},
},
selector: {
method: "ByRole",
options: {
label: "name",
},
role: "combobox",
},
} as const satisfies FeatureTestSelector;

export type SelectOption = {
text: string;
Expand Down
6 changes: 2 additions & 4 deletions packages/odyssey-react-mui/src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,18 @@ export const TabsTestSelectors = {
selector: {
method: "ByRole",
options: {
name: "${label}",
label: "name",
},
templateVariableNames: ["label"],
role: "tab",
},
},
},
selector: {
method: "ByRole",
options: {
name: "${ariaLabel}",
label: "name",
},
role: "tablist",
templateVariableNames: ["ariaLabel"],
},
} as const satisfies FeatureTestSelector;

Expand Down
49 changes: 13 additions & 36 deletions packages/odyssey-react-mui/src/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,52 +33,29 @@ import { FocusHandle, useInputValues, getControlState } from "./inputUtils";
import { type FeatureTestSelector } from "./test-selectors";

export const TextFieldTestSelectors = {
accessibleText: {
errorMessage: "errorMessage",
hint: "description",
label: "label",
},
feature: {
description: {
selector: {
method: "ByText",
templateVariableNames: ["hint"],
text: "${hint}",
},
},
errorMessage: {
selector: {
method: "ByText",
templateVariableNames: ["errorMessage"],
text: "${errorMessage}",
},
},
input: {
selector: {
method: "ByRole",
options: {
name: "${label}",
},
role: "textbox",
templateVariableNames: ["label"],
},
},
label: {
selector: {
method: "ByRole",
options: {
name: "${label}",
},
role: "LabelText",
templateVariableNames: ["label"],
},
},
link: {
selector: {
method: "ByRole",
options: {
name: "${label}",
label: "name",
},
templateVariableNames: ["label"],
role: "link",
},
},
},
selector: {
method: "ByRole",
options: {
label: "name",
},
role: "textbox",
},
} as const satisfies FeatureTestSelector;

export const textFieldTypeValues = [
Expand Down
138 changes: 119 additions & 19 deletions packages/odyssey-react-mui/src/test-selectors/featureTestSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,132 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import { ByRoleOptions } from "@testing-library/dom";
import { AriaRole } from "react";

export type Selector = {
options?: ByRoleOptions;
templateVariableNames: string[];
} & (
| {
method: "ByRole";
role: AriaRole;
}
| {
method: "ByLabelText" | "ByPlaceholderText" | "ByText";
text: string;
}
);
import {
type ByRoleOptions,
type SelectorMatcherOptions,
} from "@testing-library/dom";

import {
type RoleSelectorMethod,
type TextSelectorMethod,
} from "./getByQuerySelector";

/**
* We can't use React's `AriaRole` because it allows any string value. We want to be very specific. This is otherwise copied straight from React's code.
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L2815
*/
export type AriaRole =
| "alert"
| "alertdialog"
| "application"
| "article"
| "banner"
| "button"
| "cell"
| "checkbox"
| "columnheader"
| "combobox"
| "complementary"
| "contentinfo"
| "definition"
| "dialog"
| "directory"
| "document"
| "feed"
| "figure"
| "form"
| "grid"
| "gridcell"
| "group"
| "heading"
| "img"
| "link"
| "list"
| "listbox"
| "listitem"
| "log"
| "main"
| "marquee"
| "math"
| "menu"
| "menubar"
| "menuitem"
| "menuitemcheckbox"
| "menuitemradio"
| "navigation"
| "none"
| "note"
| "option"
| "presentation"
| "progressbar"
| "radio"
| "radiogroup"
| "region"
| "row"
| "rowgroup"
| "rowheader"
| "scrollbar"
| "search"
| "searchbox"
| "separator"
| "slider"
| "spinbutton"
| "status"
| "switch"
| "tab"
| "table"
| "tablist"
| "tabpanel"
| "term"
| "textbox"
| "timer"
| "toolbar"
| "tooltip"
| "tree"
| "treegrid"
| "treeitem";

export type RoleSelector = {
method: RoleSelectorMethod;
options: Record<string, keyof ByRoleOptions>;
role: AriaRole | AriaRole[];
// | "UNKNOWN" // This should be a `Symbol`, but it can't because this is ultimately going to be JSON stringified.
};

export type TextSelector = {
method: TextSelectorMethod;
options: Record<string, keyof SelectorMatcherOptions>;
text: string;
};

export type Selector = RoleSelector | TextSelector;

export type TestSelector = {
selector: Selector;
};

export type Feature = Record<
string,
FeatureTestSelector & { isControlledElement?: true }
>;

export type FeatureSelector = {
feature: Record<string, FeatureTestSelector>;
feature: Feature;
};

export type AccessibleLabelSelectorType =
| "description"
| "errorMessage"
| "label";

export type AccessibleLabelSelector = {
/** An "accessible -> semantic" name mapping such as "`description` -> `hint`". */
accessibleText: Record<string, AccessibleLabelSelectorType>;
};

export type FeatureTestSelector =
| TestSelector
| FeatureSelector
| (FeatureSelector & TestSelector);
| TestSelector
| (FeatureSelector & TestSelector)
| (AccessibleLabelSelector & TestSelector)
| (FeatureSelector & AccessibleLabelSelector & TestSelector);
Loading