Skip to content

Commit ed48cfe

Browse files
committed
more details and tests
1 parent 8175736 commit ed48cfe

File tree

4 files changed

+83
-13
lines changed

4 files changed

+83
-13
lines changed

src/helpers/__tests__/accessiblity.test.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,4 +522,73 @@ describe('computeAccessibleName', () => {
522522
);
523523
expect(computeAccessibleName(screen.getByTestId('text-content'))).toBe('Text Content');
524524
});
525+
526+
test('concatenates children accessible names', async () => {
527+
await render(
528+
<>
529+
<View testID="multiple-text">
530+
<Text>Hello</Text>
531+
<Text>World</Text>
532+
</View>
533+
<View testID="nested-views">
534+
<View>
535+
<Text>Hello</Text>
536+
</View>
537+
<View>
538+
<Text>World</Text>
539+
</View>
540+
</View>
541+
<View testID="child-with-label">
542+
<View aria-label="Hello" />
543+
<Text>World</Text>
544+
</View>
545+
<View testID="deeply-nested">
546+
<View>
547+
<View>
548+
<Text>Hello</Text>
549+
</View>
550+
</View>
551+
<Text>World</Text>
552+
</View>
553+
<View testID="child-label-over-text">
554+
<View aria-label="Hello">
555+
<Text>Ignored</Text>
556+
</View>
557+
<Text>World</Text>
558+
</View>
559+
<View testID="child-accessibility-label-over-text">
560+
<View accessibilityLabel="Hello">
561+
<Text>Ignored</Text>
562+
</View>
563+
<Text>World</Text>
564+
</View>
565+
</>,
566+
);
567+
expect(computeAccessibleName(screen.getByTestId('multiple-text'))).toBe('Hello World');
568+
expect(computeAccessibleName(screen.getByTestId('nested-views'))).toBe('Hello World');
569+
expect(computeAccessibleName(screen.getByTestId('child-with-label'))).toBe('Hello World');
570+
expect(computeAccessibleName(screen.getByTestId('deeply-nested'))).toBe('Hello World');
571+
expect(computeAccessibleName(screen.getByTestId('child-label-over-text'))).toBe('Hello World');
572+
expect(computeAccessibleName(screen.getByTestId('child-accessibility-label-over-text'))).toBe(
573+
'Hello World',
574+
);
575+
});
576+
577+
test('TextInput placeholder is used only for the element itself', async () => {
578+
await render(
579+
<>
580+
<TextInput testID="text-input" placeholder="Placeholder" />
581+
<View testID="parent">
582+
<TextInput placeholder="Placeholder" />
583+
<Text>Hello</Text>
584+
</View>
585+
<View testID="parent-no-text">
586+
<TextInput placeholder="Placeholder" />
587+
</View>
588+
</>,
589+
);
590+
expect(computeAccessibleName(screen.getByTestId('text-input'))).toBe('Placeholder');
591+
expect(computeAccessibleName(screen.getByTestId('parent'))).toBe('Hello');
592+
expect(computeAccessibleName(screen.getByTestId('parent-no-text'))).toBe('');
593+
});
525594
});

src/helpers/accessibility.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,20 @@ export function computeAriaValue(element: HostElement): AccessibilityValue {
244244
};
245245
}
246246

247-
export function computeAccessibleName(element: HostElement): string | undefined {
247+
type ComputeAccessibleNameOptions = {
248+
root?: boolean;
249+
};
250+
251+
export function computeAccessibleName(
252+
element: HostElement,
253+
options?: ComputeAccessibleNameOptions,
254+
): string | undefined {
248255
const label = computeAriaLabel(element);
249256
if (label) {
250257
return label;
251258
}
252259

253-
if (isHostTextInput(element) && element.props.placeholder) {
260+
if (isHostTextInput(element) && element.props.placeholder && options?.root !== false) {
254261
return element.props.placeholder;
255262
}
256263

@@ -261,7 +268,7 @@ export function computeAccessibleName(element: HostElement): string | undefined
261268
parts.push(child);
262269
}
263270
} else {
264-
const childLabel = computeAccessibleName(child);
271+
const childLabel = computeAccessibleName(child, { root: false });
265272
if (childLabel) {
266273
parts.push(childLabel);
267274
}

src/queries/__tests__/role.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,16 @@ describe('supports name option', () => {
135135
expect(screen.getByRole('button', { name: 'Save' }).props.testID).toBe('target-button');
136136
});
137137

138-
test('returns an element that has the corresponding role when several children include the name', async () => {
138+
test('returns an element that has the corresponding role when several children provide the name', async () => {
139139
await render(
140140
<TouchableOpacity accessibilityRole="button" testID="target-button">
141141
<Text>Save</Text>
142-
<Text>Save</Text>
142+
<Text>As</Text>
143143
</TouchableOpacity>,
144144
);
145145

146146
// assert on the testId to be sure that the returned element is the one with the accessibilityRole
147-
expect(screen.getByRole('button', { name: 'Save' }).props.testID).toBe('target-button');
147+
expect(screen.getByRole('button', { name: 'Save As' }).props.testID).toBe('target-button');
148148
});
149149

150150
test('returns an element that has the corresponding role and a children with a matching accessibilityLabel', async () => {

src/queries/role.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,8 @@ export type ByRoleOptions = CommonQueryOptions &
4040
const matchAccessibleNameIfNeeded = (node: HostElement, name?: TextMatch) => {
4141
if (name == null) return true;
4242

43-
// TODO: rewrite computeAccessibleName for real world a11y compliance
4443
const accessibleName = computeAccessibleName(node);
45-
if (matches(name, accessibleName)) {
46-
return true;
47-
}
48-
49-
const { queryAllByText, queryAllByLabelText } = getQueriesForElement(node);
50-
return queryAllByText(name).length > 0 || queryAllByLabelText(name).length > 0;
44+
return matches(name, accessibleName);
5145
};
5246

5347
const matchAccessibleStateIfNeeded = (node: HostElement, options?: ByRoleOptions) => {

0 commit comments

Comments
 (0)