feat: Test utils API audit, additional feature coverage (RTL, grid nav, etc) in prep for RC/1.0#9998
feat: Test utils API audit, additional feature coverage (RTL, grid nav, etc) in prep for RC/1.0#9998
Conversation
also gives us the option of adding args in the future
this is a lower level than using react testing library of which we wernt really using anything unique from that library. trade off is that we need to wrap act so it works for other react versions, still not 100% sure if we wanna do this
…essages more descriptive
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
| } | ||
|
|
||
| if (!this.checkboxgroup.contains(document.activeElement)) { | ||
| if (!this.checkboxgroup().contains(document.activeElement)) { |
There was a problem hiding this comment.
if it's a function, then I think I'd prefer the naming scheme getCheckboxGroup
| @@ -59,33 +60,50 @@ export async function triggerLongPress(opts: {element: HTMLElement, advanceTimer | |||
| // util before first render. Will need to document it well | |||
| let {element, advanceTimer, pointerOpts = {}} = opts; | |||
| let pointerType = pointerOpts.pointerType ?? 'mouse'; | |||
| let shouldFireCompatibilityEvents = fireEvent.pointerDown(element, {pointerType, ...pointerOpts}); | |||
There was a problem hiding this comment.
instead of this, we should do what react testing library does and configure the dom testing library to wrap events https://github.com/testing-library/react-testing-library/blob/be9d81d91314c9f0bafaa363f70b409b4b31989c/src/pure.js#L60
However, there's a bigger issue I'm worried about, react testing library actually modifies fireEvent pretty substantially with React specific things, so we'd need to probably copy this as well
https://github.com/testing-library/react-testing-library/blob/main/src/fire-event.js
There was a problem hiding this comment.
I imagine we need the other things in that configuration as well
There was a problem hiding this comment.
just realised this is in our testing tools, not a test
I'm not sure we need to include the act wrapper, the users environment should handle it
how did you determine you needed these?
There was a problem hiding this comment.
the long press tests started failing without these after I switched to testing-library/dom, I believe react testing library does some auto wrapping
There was a problem hiding this comment.
i think the right thing is going to be for people to pass in their fireEvent implementation themselves, that way we don't need to worry about if it should be wrapped in an act or not.
|
|
||
| export function formatTargetNode(value: number | string | HTMLElement): string { | ||
| if (typeof HTMLElement !== 'undefined' && value instanceof HTMLElement) { | ||
| return value.outerHTML; |
There was a problem hiding this comment.
could be very large, how would you feel about something like
value.cloneNode(false).outerHTML
this will remove all the children and just give you the tag + attributes
| } | ||
| let menu = this.menu(); | ||
| if (!menu) { | ||
| throw new Error('Cannot open submenu, parent menu didn\'t open on trigger "${formatTargetNode(trigger)}" press.'); |
There was a problem hiding this comment.
missing the interpolation backticks
| expect(within(row).getByRole('checkbox')).toBeDisabled(); | ||
|
|
||
| let gridListTester = testUtilUser.createTester('GridList', {root: getByRole('grid')}); | ||
| await expect(gridListTester.toggleRowSelection({row: 0})).rejects.toThrow(); |
There was a problem hiding this comment.
something to remember, expect.toThrow is extremely slow
| } | ||
|
|
||
| export const act = actImpl; | ||
| export const act: typeof actImpl = ((fn: any) => { |
There was a problem hiding this comment.
I don't think so since we are just either passing the provided fn to the act wrapper from react or returning the fn call as is, shouldn't matter if the fn provided is async or not since they can await it if need be
There was a problem hiding this comment.
hmmm why do you need the as then? or the any? that should be fn: () => void | Promise no?
| let curr = (document.activeElement as HTMLElement).getBoundingClientRect(); | ||
| let target = option.getBoundingClientRect(); | ||
| let key: string; | ||
| // basically compare current position with desired position to determine if we need to go up/down/left/right |
There was a problem hiding this comment.
basically compare current position with desired position to determine if we need to go up/down/left/right
There was a problem hiding this comment.
this should accept a rowGroup to look within i think since we now support tables with multiple bodies/row groups
There was a problem hiding this comment.
oh good point, I forgot that existed since it wasn't in the docs haha. I'll update
| * Returns the footer rows within the table if any. | ||
| */ | ||
| footerRows(): HTMLElement[] { | ||
| let footerRowGroup = this.rowGroups()[2]; |
…Node, fix missing menu tests from bad merge
|
Build successful! 🎉 |
## API Changes
@react-aria/test-utils/@react-aria/test-utils:CheckboxGroupTester CheckboxGroupTester {
- checkboxes: Array<HTMLElement>
- checkboxgroup: HTMLElement
constructor: (CheckboxGroupTesterOpts) => void
findCheckbox: ({
- checkboxIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- selectedCheckboxes: Array<HTMLElement>
+ getCheckboxGroup: () => HTMLElement
+ getCheckboxes: () => Array<HTMLElement>
+ getSelectedCheckboxes: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleCheckbox: (TriggerCheckboxOptions) => Promise<void>
}/@react-aria/test-utils:ComboBoxTester ComboBoxTester {
close: () => Promise<void>
- combobox: HTMLElement
constructor: (ComboBoxTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- focusedOption: HTMLElement | null
- listbox: HTMLElement | null
- open: (ComboBoxOpenOpts) => Promise<void>
- options: ({
+ getCombobox: () => HTMLElement
+ getFocusedOption: () => HTMLElement | null
+ getListbox: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (ComboBoxSelectOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (ComboBoxOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
+ toggleOptionSelection: (ComboBoxSelectOpts) => Promise<void>
}/@react-aria/test-utils:DialogTester DialogTester {
close: () => Promise<void>
constructor: (DialogTesterOpts) => void
- dialog: HTMLElement | null
+ getDialog: () => HTMLElement | null
+ getTrigger: () => HTMLElement
open: (DialogOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
}/@react-aria/test-utils:GridListTester GridListTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
constructor: (GridListTesterOpts) => void
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- gridlist: HTMLElement
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getGridlist: () => HTMLElement
+ getRows: () => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleRowSelection: (GridListToggleRowOpts) => Promise<void>
triggerRowAction: (GridListRowActionOpts) => Promise<void>
}/@react-aria/test-utils:ListBoxTester ListBoxTester {
constructor: (ListBoxTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- listbox: HTMLElement
- options: ({
+ getListbox: () => HTMLElement
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectedOptions: Array<HTMLElement>
+ getSections: () => Array<HTMLElement>
+ getSelectedOptions: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleOptionSelection: (ListBoxToggleOptionOpts) => Promise<void>
triggerOptionAction: (ListBoxOptionActionOpts) => Promise<void>
}/@react-aria/test-utils:MenuTester MenuTester {
close: () => Promise<void>
constructor: (MenuTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- menu: HTMLElement | null
- open: (MenuOpenOpts) => Promise<void>
- openSubmenu: (MenuOpenSubmenuOpts) => Promise<MenuTester | null>
- options: ({
+ getMenu: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (MenuSelectOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getSubmenuTriggers: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (MenuOpenOpts) => Promise<void>
+ openSubmenu: (MenuOpenSubmenuOpts) => Promise<MenuTester>
setInteractionType: (UserOpts['interactionType']) => void
- submenuTriggers: Array<HTMLElement>
- trigger: HTMLElement
+ toggleOptionSelection: (MenuSelectOpts) => Promise<void>
}/@react-aria/test-utils:RadioGroupTester RadioGroupTester {
constructor: (RadioGroupTesterOpts) => void
findRadio: ({
- radioIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- radiogroup: HTMLElement
- radios: Array<HTMLElement>
- selectedRadio: HTMLElement | null
+ getRadioGroup: () => HTMLElement
+ getRadios: () => Array<HTMLElement>
+ getSelectedRadio: () => HTMLElement | null
setInteractionType: (UserOpts['interactionType']) => void
triggerRadio: (TriggerRadioOptions) => Promise<void>
}/@react-aria/test-utils:SelectTester SelectTester {
close: () => Promise<void>
constructor: (SelectTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- listbox: HTMLElement | null
- open: (SelectOpenOpts) => Promise<void>
- options: ({
+ getListbox: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (SelectTriggerOptionOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (SelectOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
+ toggleOptionSelection: (SelectTriggerOptionOpts) => Promise<void>
}/@react-aria/test-utils:TableTester TableTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
- columns: Array<HTMLElement>
constructor: (TableTesterOpts) => void
findCell: ({
text: string
}) => HTMLElement
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- rowGroups: Array<HTMLElement>
- rowHeaders: Array<HTMLElement>
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getColumns: () => Array<HTMLElement>
+ getFooterRows: () => Array<HTMLElement>
+ getRowGroups: () => Array<HTMLElement>
+ getRowHeaders: () => Array<HTMLElement>
+ getRows: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
+ getTable: () => HTMLElement
setInteractionType: (UserOpts['interactionType']) => void
- table: HTMLElement
toggleRowExpansion: (TableToggleExpansionOpts) => Promise<void>
toggleRowSelection: (TableToggleRowOpts) => Promise<void>
toggleSelectAll: ({
interactionType?: UserOpts['interactionType']
toggleSort: (TableToggleSortOpts) => Promise<void>
triggerColumnHeaderAction: (TableColumnHeaderActionOpts) => Promise<void>
triggerRowAction: (TableRowActionOpts) => Promise<void>
}/@react-aria/test-utils:TabsTester TabsTester {
- activeTabpanel: HTMLElement | null
constructor: (TabsTesterOpts) => void
findTab: ({
- tabIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- selectedTab: HTMLElement | null
+ getActiveTabpanel: () => HTMLElement | null
+ getSelectedTab: () => HTMLElement | null
+ getTablist: () => HTMLElement
+ getTabpanels: () => Array<HTMLElement>
+ getTabs: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
- tablist: HTMLElement
- tabpanels: Array<HTMLElement>
- tabs: Array<HTMLElement>
triggerTab: (TriggerTabOptions) => Promise<void>
}/@react-aria/test-utils:TreeTester TreeTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
constructor: (TreeTesterOpts) => void
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getRows: () => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
+ getTree: () => HTMLElement
setInteractionType: (UserOpts['interactionType']) => void
toggleRowExpansion: (TreeToggleExpansionOpts) => Promise<void>
toggleRowSelection: (TreeToggleRowOpts) => Promise<void>
- tree: HTMLElement
triggerRowAction: (TreeRowActionOpts) => Promise<void>
}@react-spectrum/test-utils/@react-spectrum/test-utils:CheckboxGroupTester CheckboxGroupTester {
- checkboxes: Array<HTMLElement>
- checkboxgroup: HTMLElement
constructor: (CheckboxGroupTesterOpts) => void
findCheckbox: ({
- checkboxIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- selectedCheckboxes: Array<HTMLElement>
+ getCheckboxGroup: () => HTMLElement
+ getCheckboxes: () => Array<HTMLElement>
+ getSelectedCheckboxes: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleCheckbox: (TriggerCheckboxOptions) => Promise<void>
}/@react-spectrum/test-utils:ComboBoxTester ComboBoxTester {
close: () => Promise<void>
- combobox: HTMLElement
constructor: (ComboBoxTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- focusedOption: HTMLElement | null
- listbox: HTMLElement | null
- open: (ComboBoxOpenOpts) => Promise<void>
- options: ({
+ getCombobox: () => HTMLElement
+ getFocusedOption: () => HTMLElement | null
+ getListbox: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (ComboBoxSelectOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (ComboBoxOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
+ toggleOptionSelection: (ComboBoxSelectOpts) => Promise<void>
}/@react-spectrum/test-utils:DialogTester DialogTester {
close: () => Promise<void>
constructor: (DialogTesterOpts) => void
- dialog: HTMLElement | null
+ getDialog: () => HTMLElement | null
+ getTrigger: () => HTMLElement
open: (DialogOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
}/@react-spectrum/test-utils:GridListTester GridListTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
constructor: (GridListTesterOpts) => void
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- gridlist: HTMLElement
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getGridlist: () => HTMLElement
+ getRows: () => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleRowSelection: (GridListToggleRowOpts) => Promise<void>
triggerRowAction: (GridListRowActionOpts) => Promise<void>
}/@react-spectrum/test-utils:ListBoxTester ListBoxTester {
constructor: (ListBoxTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- listbox: HTMLElement
- options: ({
+ getListbox: () => HTMLElement
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectedOptions: Array<HTMLElement>
+ getSections: () => Array<HTMLElement>
+ getSelectedOptions: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
toggleOptionSelection: (ListBoxToggleOptionOpts) => Promise<void>
triggerOptionAction: (ListBoxOptionActionOpts) => Promise<void>
}/@react-spectrum/test-utils:MenuTester MenuTester {
close: () => Promise<void>
constructor: (MenuTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- menu: HTMLElement | null
- open: (MenuOpenOpts) => Promise<void>
- openSubmenu: (MenuOpenSubmenuOpts) => Promise<MenuTester | null>
- options: ({
+ getMenu: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (MenuSelectOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getSubmenuTriggers: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (MenuOpenOpts) => Promise<void>
+ openSubmenu: (MenuOpenSubmenuOpts) => Promise<MenuTester>
setInteractionType: (UserOpts['interactionType']) => void
- submenuTriggers: Array<HTMLElement>
- trigger: HTMLElement
+ toggleOptionSelection: (MenuSelectOpts) => Promise<void>
}/@react-spectrum/test-utils:RadioGroupTester RadioGroupTester {
constructor: (RadioGroupTesterOpts) => void
findRadio: ({
- radioIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- radiogroup: HTMLElement
- radios: Array<HTMLElement>
- selectedRadio: HTMLElement | null
+ getRadioGroup: () => HTMLElement
+ getRadios: () => Array<HTMLElement>
+ getSelectedRadio: () => HTMLElement | null
setInteractionType: (UserOpts['interactionType']) => void
triggerRadio: (TriggerRadioOptions) => Promise<void>
}/@react-spectrum/test-utils:SelectTester SelectTester {
close: () => Promise<void>
constructor: (SelectTesterOpts) => void
findOption: ({
- optionIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- listbox: HTMLElement | null
- open: (SelectOpenOpts) => Promise<void>
- options: ({
+ getListbox: () => HTMLElement | null
+ getOptions: ({
element?: HTMLElement
}) => Array<HTMLElement>
- sections: Array<HTMLElement>
- selectOption: (SelectTriggerOptionOpts) => Promise<void>
+ getSections: () => Array<HTMLElement>
+ getTrigger: () => HTMLElement
+ open: (SelectOpenOpts) => Promise<void>
setInteractionType: (UserOpts['interactionType']) => void
- trigger: HTMLElement
+ toggleOptionSelection: (SelectTriggerOptionOpts) => Promise<void>
}/@react-spectrum/test-utils:TableTester TableTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
- columns: Array<HTMLElement>
constructor: (TableTesterOpts) => void
findCell: ({
text: string
}) => HTMLElement
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- rowGroups: Array<HTMLElement>
- rowHeaders: Array<HTMLElement>
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getColumns: () => Array<HTMLElement>
+ getFooterRows: () => Array<HTMLElement>
+ getRowGroups: () => Array<HTMLElement>
+ getRowHeaders: () => Array<HTMLElement>
+ getRows: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
+ getTable: () => HTMLElement
setInteractionType: (UserOpts['interactionType']) => void
- table: HTMLElement
toggleRowExpansion: (TableToggleExpansionOpts) => Promise<void>
toggleRowSelection: (TableToggleRowOpts) => Promise<void>
toggleSelectAll: ({
interactionType?: UserOpts['interactionType']
toggleSort: (TableToggleSortOpts) => Promise<void>
triggerColumnHeaderAction: (TableColumnHeaderActionOpts) => Promise<void>
triggerRowAction: (TableRowActionOpts) => Promise<void>
}/@react-spectrum/test-utils:TabsTester TabsTester {
- activeTabpanel: HTMLElement | null
constructor: (TabsTesterOpts) => void
findTab: ({
- tabIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- selectedTab: HTMLElement | null
+ getActiveTabpanel: () => HTMLElement | null
+ getSelectedTab: () => HTMLElement | null
+ getTablist: () => HTMLElement
+ getTabpanels: () => Array<HTMLElement>
+ getTabs: () => Array<HTMLElement>
setInteractionType: (UserOpts['interactionType']) => void
- tablist: HTMLElement
- tabpanels: Array<HTMLElement>
- tabs: Array<HTMLElement>
triggerTab: (TriggerTabOptions) => Promise<void>
}/@react-spectrum/test-utils:TreeTester TreeTester {
- cells: ({
- element?: HTMLElement
-}) => Array<HTMLElement>
constructor: (TreeTesterOpts) => void
findRow: ({
- rowIndexOrText: number | string
+ indexOrText: number | string
}) => HTMLElement
- rows: Array<HTMLElement>
- selectedRows: Array<HTMLElement>
+ getCells: ({
+ element?: HTMLElement
+}) => Array<HTMLElement>
+ getRows: () => Array<HTMLElement>
+ getSelectedRows: () => Array<HTMLElement>
+ getTree: () => HTMLElement
setInteractionType: (UserOpts['interactionType']) => void
toggleRowExpansion: (TreeToggleExpansionOpts) => Promise<void>
toggleRowSelection: (TreeToggleRowOpts) => Promise<void>
- tree: HTMLElement
triggerRowAction: (TreeRowActionOpts) => Promise<void>
} |
See commits for what changed
Some additional pattern support to be opened in a different PR maybe, to discuss if we think they are worth it or not.
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project:
RSP