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

test: write test for required inputs to read messages #2906

Merged
merged 32 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bc9d33b
test: write test for required inputs to read messages
nmerget Jul 24, 2024
6510a60
chore: add windows snapshot
nmerget Jul 25, 2024
db44d3b
Merge branch 'main' of github.com:db-ui/mono into test-input-required…
nmerget Jul 25, 2024
07904d4
chore: update from main
nmerget Jul 25, 2024
6ecbba2
fix: add span only for voiceover to inform users about valid/invalid …
nmerget Jul 25, 2024
f3eec77
chore: update snapshots
nmerget Jul 25, 2024
f611d1c
chore: update snapshots
nmerget Jul 25, 2024
710c9e2
Merge branch 'main' into test-input-required-messages
nmerget Jul 26, 2024
16fa741
Merge branch 'main' into test-input-required-messages
nmerget Jul 26, 2024
46a9978
refactor: using an attribute instead of a class
mfranzke Jul 26, 2024
24977cc
Revert "refactor: using an attribute instead of a class"
mfranzke Jul 26, 2024
2d93464
refactor: using an attribute instead of a class
mfranzke Jul 26, 2024
cfe23ee
Update textarea.lite.tsx
mfranzke Jul 26, 2024
c4f4e10
Update select.lite.tsx
mfranzke Jul 26, 2024
78d36ff
Update checkbox.lite.tsx
mfranzke Jul 26, 2024
13d8369
Update input.lite.tsx
mfranzke Jul 26, 2024
58b18eb
Update textarea.lite.tsx
mfranzke Jul 26, 2024
b669db9
Update select.lite.tsx
mfranzke Jul 26, 2024
a6f6b37
Update input.lite.tsx
mfranzke Jul 26, 2024
e024f31
Update checkbox.lite.tsx
mfranzke Jul 26, 2024
6854aad
refactor: cool dude comment
mfranzke Jul 26, 2024
8f83ed7
fix: issues with _voiceOverFallback not clearing
nmerget Jul 26, 2024
2ab0e43
fix: someone broke typescript
nmerget Jul 26, 2024
a5fbcc1
fix: issue with double valid message by adding delay fn
nmerget Jul 29, 2024
4079fc6
Merge branch 'main' into test-input-required-messages
nmerget Jul 29, 2024
ba3b88a
Merge branch 'main' into test-input-required-messages
nmerget Jul 29, 2024
d09cc10
Merge branch 'main' into test-input-required-messages
mfranzke Aug 14, 2024
705f537
chore: update sr tests
nmerget Aug 14, 2024
98b59f1
Merge branch 'main' into test-input-required-messages
nmerget Aug 14, 2024
1042df3
Merge branch 'main' into test-input-required-messages
nmerget Aug 14, 2024
6e91961
fix: issue with input typing sr test
nmerget Aug 14, 2024
888f6fa
Merge branch 'main' into test-input-required-messages
nmerget Aug 14, 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
22 changes: 21 additions & 1 deletion packages/components/src/components/checkbox/checkbox.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useStore
} from '@builder.io/mitosis';
import { DBCheckboxProps, DBCheckboxState } from './model';
import { cls, uuid } from '../../utils';
import { cls, delay, hasVoiceOver, uuid } from '../../utils';
import {
DEFAULT_INVALID_MESSAGE,
DEFAULT_INVALID_MESSAGE_ID_SUFFIX,
Expand All @@ -33,6 +33,7 @@ export default function DBCheckbox(props: DBCheckboxProps) {
_validMessageId: this._id + DEFAULT_VALID_MESSAGE_ID_SUFFIX,
_invalidMessageId: this._id + DEFAULT_INVALID_MESSAGE_ID_SUFFIX,
_descByIds: '',
_voiceOverFallback: '',
handleChange: (event: ChangeEvent<HTMLInputElement>) => {
if (props.onChange) {
props.onChange(event);
Expand All @@ -46,11 +47,23 @@ export default function DBCheckbox(props: DBCheckboxProps) {
/* For a11y reasons we need to map the correct message with the checkbox */
if (!ref?.validity.valid || props.customValidity === 'invalid') {
state._descByIds = state._invalidMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.invalidMessage ??
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (
props.customValidity === 'valid' ||
(ref?.validity.valid && props.required)
) {
state._descByIds = state._validMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.validMessage ?? DEFAULT_VALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (props.message) {
state._descByIds = state._messageId;
} else {
Expand Down Expand Up @@ -179,6 +192,13 @@ export default function DBCheckbox(props: DBCheckboxProps) {
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE}
</DBInfotext>

{/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html
* Currently VoiceOver isn't supporting changes from aria-describedby.
* This is an internal Fallback */}
<span data-visually-hidden="true" role="status">
{state._voiceOverFallback}
</span>
</div>
);
}
4 changes: 2 additions & 2 deletions packages/components/src/components/drawer/drawer.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { DBDrawerProps, DBDrawerState } from './model';
import { DBButton } from '../button';
import { DEFAULT_CLOSE_BUTTON } from '../../shared/constants';
import { cls } from '../../utils';
import { cls, delay } from '../../utils';

useMetadata({
isAttachedToShadowDom: true
Expand Down Expand Up @@ -54,7 +54,7 @@ export default function DBDrawer(props: DBDrawerProps) {
if (dialogContainerRef) {
dialogContainerRef.hidden = true;
}
setTimeout(() => {
delay(() => {
if (dialogContainerRef) {
dialogContainerRef.hidden = false;
}
Expand Down
22 changes: 21 additions & 1 deletion packages/components/src/components/input/input.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useRef,
useStore
} from '@builder.io/mitosis';
import { cls, isArrayOfStrings, uuid } from '../../utils';
import { cls, delay, hasVoiceOver, isArrayOfStrings, uuid } from '../../utils';
import { DBInputProps, DBInputState } from './model';
import {
DEFAULT_DATALIST_ID_SUFFIX,
Expand Down Expand Up @@ -42,6 +42,7 @@ export default function DBInput(props: DBInputProps) {
_dataListId: this._id + DEFAULT_DATALIST_ID_SUFFIX,
_descByIds: '',
_value: '',
_voiceOverFallback: '',
defaultValues: {
label: DEFAULT_LABEL,
placeholder: ' '
Expand Down Expand Up @@ -69,6 +70,13 @@ export default function DBInput(props: DBInputProps) {
/* For a11y reasons we need to map the correct message with the input */
if (!ref?.validity.valid || props.customValidity === 'invalid') {
state._descByIds = state._invalidMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.invalidMessage ??
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (
props.customValidity === 'valid' ||
(ref?.validity.valid &&
Expand All @@ -78,6 +86,11 @@ export default function DBInput(props: DBInputProps) {
props.pattern))
) {
state._descByIds = state._validMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.validMessage ?? DEFAULT_VALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (props.message) {
state._descByIds = state._messageId;
} else {
Expand Down Expand Up @@ -230,6 +243,13 @@ export default function DBInput(props: DBInputProps) {
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE}
</DBInfotext>

{/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html
* Currently VoiceOver isn't supporting changes from aria-describedby.
* This is an internal Fallback */}
<span data-visually-hidden="true" role="status">
{state._voiceOverFallback}
</span>
</div>
);
// jscpd:ignore-end
Expand Down
24 changes: 22 additions & 2 deletions packages/components/src/components/select/select.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useStore
} from '@builder.io/mitosis';
import { DBSelectOptionType, DBSelectProps, DBSelectState } from './model';
import { cls, uuid } from '../../utils';
import { cls, delay, hasVoiceOver, uuid } from '../../utils';
import {
DEFAULT_INVALID_MESSAGE,
DEFAULT_INVALID_MESSAGE_ID_SUFFIX,
Expand Down Expand Up @@ -47,6 +47,7 @@ export default function DBSelect(props: DBSelectProps) {
_descByIds: '',
_value: '',
initialized: false,
_voiceOverFallback: '',
handleClick: (event: ClickEvent<HTMLSelectElement>) => {
if (props.onClick) {
props.onClick(event);
Expand Down Expand Up @@ -75,11 +76,23 @@ export default function DBSelect(props: DBSelectProps) {
/* For a11y reasons we need to map the correct message with the select */
if (!ref?.validity.valid || props.customValidity === 'invalid') {
state._descByIds = state._invalidMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.invalidMessage ??
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (
props.customValidity === 'valid' ||
(ref?.validity.valid && props.required)
) {
state._descByIds = state._validMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.validMessage ?? DEFAULT_VALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (props.message) {
state._descByIds = state._messageId;
} else {
Expand Down Expand Up @@ -156,7 +169,7 @@ export default function DBSelect(props: DBSelectProps) {
name={props.name}
value={props.value ?? state._value}
autocomplete={props.autocomplete}
onInput={(event: ChangeEvent<HTMLInputElement>) =>
onInput={(event: ChangeEvent<HTMLSelectElement>) =>
state.handleInput(event)
}
onClick={(event: ClickEvent<HTMLSelectElement>) =>
Expand Down Expand Up @@ -243,6 +256,13 @@ export default function DBSelect(props: DBSelectProps) {
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE}
</DBInfotext>

{/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html
* Currently VoiceOver isn't supporting changes from aria-describedby.
* This is an internal Fallback */}
<span data-visually-hidden="true" role="status">
{state._voiceOverFallback}
</span>
</div>
);
// jscpd:ignore-end
Expand Down
24 changes: 22 additions & 2 deletions packages/components/src/components/textarea/textarea.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@builder.io/mitosis';
import { DBTextareaProps, DBTextareaState } from './model';
import { DBInfotext } from '../infotext';
import { cls, uuid } from '../../utils';
import { cls, delay, hasVoiceOver, uuid } from '../../utils';
import {
DEFAULT_INVALID_MESSAGE,
DEFAULT_INVALID_MESSAGE_ID_SUFFIX,
Expand Down Expand Up @@ -40,6 +40,7 @@ export default function DBTextarea(props: DBTextareaProps) {
placeholder: ' ',
rows: '4'
},
_voiceOverFallback: '',
handleInput: (event: InputEvent<HTMLTextAreaElement>) => {
if (props.onInput) {
props.onInput(event);
Expand All @@ -63,12 +64,24 @@ export default function DBTextarea(props: DBTextareaProps) {
/* For a11y reasons we need to map the correct message with the textarea */
if (!ref?.validity.valid || props.customValidity === 'invalid') {
state._descByIds = state._invalidMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.invalidMessage ??
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (
props.customValidity === 'valid' ||
(ref?.validity.valid &&
(props.required || props.minLength || props.maxLength))
) {
state._descByIds = state._validMessageId;
if (hasVoiceOver()) {
state._voiceOverFallback =
props.validMessage ?? DEFAULT_VALID_MESSAGE;
delay(() => (state._voiceOverFallback = ''), 1000);
}
} else if (props.message) {
state._descByIds = state._messageId;
} else {
Expand Down Expand Up @@ -143,7 +156,7 @@ export default function DBTextarea(props: DBTextareaProps) {
wrap={props.wrap}
spellcheck={props.spellCheck}
autocomplete={props.autocomplete}
onInput={(event: ChangeEvent<HTMLInputElement>) =>
onInput={(event: ChangeEvent<HTMLTextAreaElement>) =>
state.handleInput(event)
}
onChange={(event: ChangeEvent<HTMLTextAreaElement>) =>
Expand Down Expand Up @@ -188,6 +201,13 @@ export default function DBTextarea(props: DBTextareaProps) {
ref?.validationMessage ??
DEFAULT_INVALID_MESSAGE}
</DBInfotext>

{/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html
* Currently VoiceOver isn't supporting changes from aria-describedby.
* This is an internal Fallback */}
<span data-visually-hidden="true" role="status">
{state._voiceOverFallback}
</span>
</div>
);
// jscpd:ignore-end
Expand Down
7 changes: 7 additions & 0 deletions packages/components/src/shared/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ export type FormState = {
_invalidMessageId?: string;
_descByIds?: string;
_value?: string;

/**
* https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html
* Currently VoiceOver isn't supporting changes from aria-describedby.
* This is an internal Fallback
*/
_voiceOverFallback?: string;
};

export type InitializedState = {
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/styles/_form-components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@use "@db-ui/foundations/build/scss/helpers";
@use "component";

@forward "visually-hidden";

$dropdown-icon-transition: transform variables.$db-transition-straight-emotional;
$dropdown-icon-transform: rotate(-180deg);

Expand Down
6 changes: 6 additions & 0 deletions packages/components/src/styles/visually-hidden.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@use "@db-ui/foundations/build/scss/helpers";

.db-visually-hidden,
[data-visually-hidden="true"] {
@extend %a11y-visually-hidden;
}
12 changes: 11 additions & 1 deletion packages/components/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ export const handleDataOutside = (el: Element): DBDataOutsidePair => {
export const isArrayOfStrings = (value: unknown): value is string[] =>
Array.isArray(value) && value.every((item) => typeof item === 'string');

const appleOs = ['Mac', 'iPhone', 'iPad', 'iPod'];
export const hasVoiceOver = (): boolean =>
typeof window !== 'undefined' &&
appleOs.some((os) => window.navigator.userAgent.includes(os));

export const delay = (fn: () => void, ms: number) =>
new Promise(() => setTimeout(fn, ms));

export default {
filterPassingProps,
cls,
Expand All @@ -203,5 +211,7 @@ export default {
visibleInVY,
isInView,
handleDataOutside,
isArrayOfStrings
isArrayOfStrings,
hasVoiceOver,
delay
};
19 changes: 14 additions & 5 deletions packages/foundations/scss/helpers/_a11y.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
%a11y-visually-hidden {
clip: rect(0, 0, 0, 0);
block-size: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0) !important;
overflow: hidden !important;
white-space: nowrap !important;
font-size: 0 !important;
all: initial;
inset-block-start: 0 !important;
block-size: 1px !important;
position: absolute !important;
white-space: nowrap;
inline-size: 1px;
inline-size: 1px !important;
border-width: 0 !important;
border-style: initial !important;
border-color: initial !important;
border-image: initial !important;
padding: 0 !important;
pointer-events: none !important;
nmerget marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["Label * Label* Required required edit text","TODO: Add a validMessage. Test","Test selected","Test. Fill out this field","TODO: Add a validMessage. Test"]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["Label star, edit, required, Required, blank","T. e. s. t. TODO: Add a valid Message","Test selected","blank. Please fill out this field.. unselected","T. e. s. t. TODO: Add a valid Message"]
15 changes: 1 addition & 14 deletions showcases/screen-reader/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,7 @@ import {
type RunTestType,
type ScreenReaderTestType
} from './data';

const translations: Record<string, string[]> = {
button: ['Schalter'],
edit: ['Eingabefeld'],
'radio button': ['Auswahlschalter'],
blank: ['Leer'],
checked: ['aktiviert'],
' of ': [' von '],
clickable: ['anklickbar'],
'has auto complete': ['mit Auto Vervollständigung'],
unknown: ['Unbekannt'],
dialog: ['Dialogfeld'],
document: ['Dokument']
};
import { translations } from './translations';

const standardPhrases = [
'You are currently',
Expand Down
Loading
Loading