Skip to content

Commit

Permalink
Refactor and make some messages more consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
calebeby committed Nov 21, 2021
1 parent c932639 commit 61a4142
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 108 deletions.
158 changes: 60 additions & 98 deletions src/user-util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,6 @@ ${el}`;
}
};

// Why is this hardcoded?
// So that the snapshots do not fail when a new version is released and all the error messages change
// Why is this not pointing to `main`?
// So that if the docs are moved around or renamed in the future, the links in previous PT versions still work
// Does this need to be updated before every release?
// No, only when the docs are changed
const docsVersion = 'v2.0.0';
const customizeDocsMessage = `You can customize this check by setting the targetSize option, more details at https://github.com/cloudfour/pleasantest/blob/${docsVersion}/docs/errors/target-size.md`;
const errorMessage = 'Cannot click element that is too small.';

type TargetSize = number | true | undefined;

export const assertTargetSize = (el: Element, targetSize: TargetSize) => {
Expand All @@ -65,16 +55,38 @@ export const assertTargetSize = (el: Element, targetSize: TargetSize) => {
}

const { width, height } = el.getBoundingClientRect();
const size = getTargetSize(targetSize);
const minSize = typeof targetSize === 'number' ? targetSize : 44;

const elDescriptor =
el instanceof HTMLInputElement ? `${el.type} input` : 'element';

// Why is this hardcoded?
// So that the snapshots do not fail when a new version is released and all the error messages change
// Why is this not pointing to `main`?
// So that if the docs are moved around or renamed in the future, the links in previous PT versions still work
// Does this need to be updated before every release?
// No, only when the docs are changed
const docsVersion = 'v2.0.0';

const targetSizeError = (suggestion: string | InterpolableIntoError[] = '') =>
error`Cannot click element that is too small.
Target size of ${elDescriptor} is smaller than ${
typeof targetSize === 'number'
? `configured minimum of ${minSize}px × ${minSize}px`
: 'W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html'
}
${capitalizeText(elDescriptor)} was ${width}px × ${height}px
${el}${suggestion}
You can customize this check by setting the targetSize option, more details at https://github.com/cloudfour/pleasantest/blob/${docsVersion}/docs/errors/target-size.md`;

if (width < size || height < size) {
if (width < minSize || height < minSize) {
// Custom messaging for inputs that should have labels (e.g. type="radio").
//
// Inputs that aren't expected to have labels (e.g. type="submit") are
// checked by the general element check.
// Inputs that aren't expected to have labels (e.g. type="submit")
// arechecked by the general element check.
//
// MDN <input> docs were referenced and the following were assumed
// to not have labels:
// MDN <input> docs were referenced
// and the following were assumed to not have labels:
// - type="submit"
// - type="button"
// - type="reset"
Expand All @@ -86,60 +98,37 @@ export const assertTargetSize = (el: Element, targetSize: TargetSize) => {
el.type !== 'button' &&
el.type !== 'reset'
) {
return checkInputEl({ el, targetSize });
const labelSize = el.labels?.[0]?.getBoundingClientRect();

// Element did not have label
if (!labelSize) {
throw targetSizeError(`
You can increase the target size of the ${elDescriptor} by adding a label that is larger than ${minSize}px × ${minSize}px`);
}

// If label is valid
if (labelSize.width >= minSize && labelSize.height >= minSize) return;

// Element and label was too small
throw targetSizeError(
// The error template tag is used here
// so that the interpolated element (label name) does not get stringified.
error`
Label associated with the ${elDescriptor} was ${labelSize.width}px × ${
labelSize.height
}px
${el.labels![0]}
You can increase the target size by making the label or ${elDescriptor} larger than ${minSize}px × ${minSize}px.`
.error,
);
}

// General element messaging
throw error`${errorMessage}
${getTargetSizeMessage({ el, targetSize })}
${getDimensionsMessage(el)}
${el}
${customizeDocsMessage}`;
throw targetSizeError();
}
};

/** Handles inputs that should have labels */
const checkInputEl = ({
el,
targetSize,
}: {
el: HTMLInputElement;
targetSize: TargetSize;
}) => {
const labelSize = el.labels?.[0]?.getBoundingClientRect();
const size = getTargetSize(targetSize);

// Element did not have label
if (!labelSize) {
throw error`${errorMessage}
${getTargetSizeMessage({ el, targetSize })}
${getDimensionsMessage(el)}
${el}
You can increase the target size of the ${getElementDescriptor(
el,
)} by adding a label that is larger than ${size}px × ${size}px
${customizeDocsMessage}`;
}

// If label is valid
if (labelSize.width >= size && labelSize.height >= size) {
return;
}

// Element and label was too small
throw error`${errorMessage}
${getTargetSizeMessage({ el, targetSize })}
${getDimensionsMessage(el)}
${el}
Label associated with the ${getElementDescriptor(el)} was ${
labelSize.width
}px × ${labelSize.height}px
${el.labels![0]}
You can increase the target size by making the label or ${getElementDescriptor(
el,
)} larger than ${size}px × ${size}px.
${customizeDocsMessage}`;
};
type InterpolableIntoError = Element | string | number | boolean;

// This is used to generate the arrays that are used
// to produce messages with live elements in the browser,
Expand All @@ -149,44 +138,17 @@ ${customizeDocsMessage}`;
// returns { error: ['something bad happened', el]}
export const error = (
literals: TemplateStringsArray,
...placeholders: (Element | string | number | boolean)[]
...placeholders: (InterpolableIntoError | InterpolableIntoError[])[]
) => ({
error: literals.reduce((acc, val, i) => {
if (i !== 0) acc.push(placeholders[i - 1]);
if (i !== 0) {
const item = placeholders[i - 1];
if (Array.isArray(item)) acc.push(...item);
else acc.push(item);
}
if (val !== '') acc.push(val);
return acc;
}, [] as (string | Element | number | boolean)[]),
});

const getTargetSizeMessage = ({
el,
targetSize,
}: {
el: Element;
targetSize: TargetSize;
}) => {
const size = getTargetSize(targetSize);
return typeof targetSize === 'number'
? `Target size of ${getElementDescriptor(
el,
)} is smaller than ${size}px × ${size}px`
: `${capitalizeText(
getElementDescriptor(el),
)} target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html`;
};

const getDimensionsMessage = (el: Element) => {
const { width, height } = el.getBoundingClientRect();
return `${capitalizeText(
getElementDescriptor(el),
)} was ${width}px × ${height}px`;
};

const getTargetSize = (targetSize: TargetSize) =>
typeof targetSize === 'number' ? targetSize : 44;

const getElementDescriptor = (el: Element) =>
el instanceof HTMLInputElement ? `${el.type} input` : 'element';

const capitalizeText = (text: string) =>
text.charAt(0).toUpperCase() + text.slice(1);
const capitalizeText = (text: string) => text[0].toUpperCase() + text.slice(1);
20 changes: 10 additions & 10 deletions tests/user/click.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ test(
await expect(user.click(button)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Element target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of element is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Element was 2px × 2px
<button style=\\"width: 2px; height: 2px; border: none; padding: 0;\\">hi</button>
You can customize this check by setting the targetSize option, more details at https://github.com/cloudfour/pleasantest/blob/v2.0.0/docs/errors/target-size.md"
Expand All @@ -227,7 +227,7 @@ test(
await expect(user.click(button, { targetSize: 46 })).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Target size of element is smaller than 46px × 46px
Target size of element is smaller than configured minimum of 46px × 46px
Element was 45px × 45px
<button style=\\"width: 45px; height: 45px; border: none; padding: 0px;\\">hi</button>
You can customize this check by setting the targetSize option, more details at https://github.com/cloudfour/pleasantest/blob/v2.0.0/docs/errors/target-size.md"
Expand Down Expand Up @@ -265,7 +265,7 @@ test(
await expect(user.click(button)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Button input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of button input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Button input was 90px × 25px
<input
style=\\"display: block; width: 90px; height: 25px;\\"
Expand All @@ -283,7 +283,7 @@ test(
await expect(user.click(submit)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Submit input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of submit input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Submit input was 90px × 25px
<input
style=\\"display: block; width: 90px; height: 25px;\\"
Expand All @@ -301,7 +301,7 @@ test(
await expect(user.click(reset)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Reset input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of reset input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Reset input was 90px × 25px
<input
style=\\"display: block; width: 90px; height: 25px;\\"
Expand Down Expand Up @@ -333,7 +333,7 @@ test(
await expect(user.click(checkbox)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Checkbox input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of checkbox input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Checkbox input was 13px × 13px
<input type=\\"checkbox\\" name=\\"test-checkbox\\" />
Label associated with the checkbox input was 120px × 20px
Expand All @@ -355,7 +355,7 @@ test(
await expect(user.click(radio)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Radio input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of radio input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Radio input was 13px × 13px
<input
type=\\"radio\\"
Expand Down Expand Up @@ -386,7 +386,7 @@ test(
await expect(user.click(checkbox)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Checkbox input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of checkbox input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Checkbox input was 13px × 13px
<input type=\\"checkbox\\" name=\\"test-checkbox\\" />
You can increase the target size of the checkbox input by adding a label that is larger than 44px × 44px
Expand All @@ -400,7 +400,7 @@ test(
await expect(user.click(radio)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Radio input target size does not meet W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Target size of radio input is smaller than W3C recommendation of 44px × 44px: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
Radio input was 13px × 13px
<input type=\\"radio\\" name=\\"test-radio\\" />
You can increase the target size of the radio input by adding a label that is larger than 44px × 44px
Expand All @@ -422,7 +422,7 @@ test(
await expect(user.click(button)).rejects
.toThrowErrorMatchingInlineSnapshot(`
"Cannot click element that is too small.
Target size of element is smaller than 46px × 46px
Target size of element is smaller than configured minimum of 46px × 46px
Element was 2px × 2px
<button style=\\"width: 2px; height: 2px; border: none; padding: 0;\\">hi</button>
You can customize this check by setting the targetSize option, more details at https://github.com/cloudfour/pleasantest/blob/v2.0.0/docs/errors/target-size.md"
Expand Down

0 comments on commit 61a4142

Please sign in to comment.