Skip to content

Commit

Permalink
Implement ISelectionProvider and ISelectionItemProvider (microsoft#14019
Browse files Browse the repository at this point in the history
)

Adds support for ISelectionProvider interface
Adds support for ISelectionItemProvider interface
Adds support for accessibilityState:selected
Adjusts AccessibilityState native type on Windows to be std::optional instead of bool
Adjusts AccessibilityState native type on Windows to include multiselectable and required fields of type std::optional
Adds multiselectable and required fields to AccessibilityState type in JS with type boolean | undefined
Adds support for aria-multiselectable and aria-required.
Adds support for the following accessibilityActions: addToSelection, removeFromSelection, select
Fixes crash in AccessibilityInsights.
  • Loading branch information
chiaramooney authored and acoates-ms committed Jan 10, 2025
1 parent 0f9d266 commit d429f4f
Show file tree
Hide file tree
Showing 28 changed files with 49,658 additions and 32,853 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement ISelectionProvider and ISelectionItemProvider",
"packageName": "react-native-windows",
"email": "34109996+chiaramooney@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -312,33 +312,40 @@ class AccessibilityStateExamples extends React.Component {
The following list of TouchableHighlights toggles
accessibilityState.selected when touched:
</Text>
<FlatList
accessibilityLabel="List of selectable items"
data={selectableItems}
renderItem={item => (
<TouchableHighlight
style={{
width: 100,
height: 50,
backgroundColor: this.state.itemsSelected[item.index]
? 'gray'
: 'lightskyblue',
}}
accessibilityRole="button"
accessibilityLabel={'Selectable item ' + (item.index + 1)}
accessibilityState={{
selected: this.state.itemsSelected[item.index],
}}
onPress={() => this.selectPress(item.index)}>
<Text>
{this.state.itemsSelected[item.index]
? 'Selected'
: 'Unselected'}
</Text>
</TouchableHighlight>
)}
keyExtractor={(item, index) => index.toString()}
/>
<View
accessible
accessibilityLabel="Selection Container"
accessibilityState={{multiselectable: true, required: true}}
testID="selection-container">
<FlatList
accessibilityLabel="List of selectable items"
data={selectableItems}
renderItem={item => (
<TouchableHighlight
style={{
width: 100,
height: 50,
backgroundColor: this.state.itemsSelected[item.index]
? 'gray'
: 'lightskyblue',
}}
accessibilityRole="button"
accessibilityLabel={'Selectable item ' + (item.index + 1)}
testID={'Selectable item ' + (item.index + 1)}
accessibilityState={{
selected: this.state.itemsSelected[item.index],
}}
onPress={() => this.selectPress(item.index)}>
<Text>
{this.state.itemsSelected[item.index]
? 'Selected'
: 'Unselected'}
</Text>
</TouchableHighlight>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
<Text>
The following TouchableHighlight cycles accessibilityState.checked
through unchecked/checked/mixed for the View under it:
Expand Down
62 changes: 62 additions & 0 deletions packages/e2e-test-app-fabric/test/AccessibilityTest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
* @format
*/

import {dumpVisualTree} from '@react-native-windows/automation-commands';
import {goToApiExample} from './RNTesterNavigation';
import {app} from '@react-native-windows/automation';
import {verifyNoErrorLogs} from './Helpers';

beforeAll(async () => {
// If window is partially offscreen, tests will fail to click on certain elements
await app.setWindowPosition(0, 0);
await app.setWindowSize(1000, 1250);
await goToApiExample('Accessibility Windows');
});

afterEach(async () => {
await verifyNoErrorLogs();
});

const searchBox = async (input: string) => {
const searchBox = await app.findElementByTestID('example_search');
await app.waitUntil(
async () => {
await searchBox.setValue(input);
return (await searchBox.getText()) === input;
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct search text into test searchbox.`,
},
);
};

describe('Accessibility Tests', () => {
test('Elements can set accessibilityState:selected to false', async () => {
await searchBox('Sta');
const component = await app.findElementByTestID('Selectable item 1');
await component.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('Selectable item 1');
expect(dump).toMatchSnapshot();
});
test('Elements can set accessibilityState:selected to true', async () => {
await searchBox('Sta');
const component = await app.findElementByTestID('Selectable item 1');
await component.waitForDisplayed({timeout: 5000});
await component.click();
const dump = await dumpVisualTree('Selectable item 1');
expect(dump).toMatchSnapshot();
});
test('Selectable items must have a Selection Container. Elements can set accessibilityState:multiselectable and accessibilityState:required to true', async () => {
await searchBox('Sta');
const componentsTab = await app.findElementByTestID('selection-container');
await componentsTab.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('selection-container');
expect(dump).toMatchSnapshot();
});
});
Loading

0 comments on commit d429f4f

Please sign in to comment.