Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kendallgassner committed Jul 14, 2022
1 parent 94bc45b commit 7557e0f
Show file tree
Hide file tree
Showing 8 changed files with 9,435 additions and 491 deletions.
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: [["@babel/preset-env", { targets: { node: "current" } }]],
};
7 changes: 6 additions & 1 deletion devtools-feedback/panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ ul {
list-style: none;
padding: 0;
}
li {

.divider {
border-top: 1px solid var(--github-a11y-border-color);
}

.feedbackGroup {
background-color: var(--github-a11y-background-accent);
padding: 16px;
border-radius: 4px;
Expand Down
98 changes: 58 additions & 40 deletions devtools-feedback/panel.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,76 @@
const LEVEL_1_HEADING_REGEX = /\#\s/g;
const HELPER_LINKS = {
headings: "https://www.markdownguide.org/basic-syntax/#headings",
};
import {
LEVEL_1_HEADING_REGEX,
LINK_REGEX,
HELPER_LINKS,
disableButton,
enableButton,
invalidLinks,
createErrorListItem,
createFeedbackGroup,
} from "./utils";

const replaceMainContent = (element) => {
document.getElementById("main").innerHTML = "";
return document.getElementById("main").append(element);
};

const disableButton = (button) => {
button.ariaDisabled = "true";
button.disabled = true;
};

const enableButton = (button) => {
button.ariaDisabled = "false";
button.disabled = false;
};
/**
* Given the content of a textArea
* return a list of accessibility errors found
*
* WORKING RULES:
* - checks for a heading
* - ensures that there is no h1
* - ensures that links are descriptive
*
*
* TODO:
* - validate image alt text
* - Report bugs individually. For example we report the "Non Descriptive Links" error once ... even if multiple links are not descriptive
* but it would be nice to report each link individually to provide more descriptive feedback.
*/
const provideFeedback = (textContent, type, id) => {
const list = document.createElement("ul");
list.ariaLabel = `Errors found in textArea with id: ${id}`;

const provideFeedback = (textContent, type) => {
const hasHeading = textContent && textContent.includes("#");

if (!hasHeading) {
return {
title: "Missing Heading",
message: `Looks like you haven\'t added any headings to your ${type} body. <a href="${HELPER_LINKS.headings}">Learn how to use Markdown Headings</a>`,
};
list.append(
createErrorListItem(
"Missing Heading",
`Looks like you haven\'t added any headings to your ${type} body. <a href="${HELPER_LINKS.headings}">Learn how to use Markdown Headings</a>`
)
);
}

const usesLevel1Heading = LEVEL_1_HEADING_REGEX.test(textContent);
const usesLevel1Heading = textContent.match(LEVEL_1_HEADING_REGEX);
if (usesLevel1Heading) {
return {
title: "Uses Level 1 Heading",
message: `Looks like you\'re using a level 1 heading. That\'s already been set on this page. Try using a level two heading or <a href="${HELPER_LINKS.headings}">Learn how to use Markdown Headings</a>`,
};
list.append(
createErrorListItem(
"Uses Level 1 Heading",
`Looks like you\'re using a level 1 heading. That\'s already been set on this page. Try using a level two heading or <a href="${HELPER_LINKS.headings}">Learn how to use Markdown Headings</a>`
)
);
}

const usesNonDescriptiveLinks = false;
if (usesNonDescriptiveLinks) {
return {};
const links = textContent.match(LINK_REGEX) || [];

if (invalidLinks(links).length) {
list.append(
createErrorListItem(
"Non Descriptive Links",
`Looks like your link text could be more descriptive. Avoid using words such as 'click here' or 'learn more' -- link text should provide context of where it will take a user. For more information <a href="${HELPER_LINKS.linkText}">Learn how to write descriptive links</a>`
)
);
}

// TODO
const usesBadAltText = false;
if (usesBadAltText) {
return {};
// return {};
}
return list;
};

const focus = (id) => {
Expand All @@ -69,6 +96,8 @@ const validateMarkdown = () => {
const port = chrome.tabs.connect(tabs[0].id);
const list = document.createElement("ul");

list.ariaLabel = "edited textAreas";

port.postMessage({ request: "getTextAreas" });

port.onMessage.addListener((msg) => {
Expand All @@ -77,22 +106,11 @@ const validateMarkdown = () => {
const feedback = provideFeedback(textAreaOutput, type);

if (feedback) {
const listItem = document.createElement("li");
const heading = document.createElement("h2");
const paragraph = document.createElement("p");
const highlightButton = document.createElement("button");

heading.innerHTML = feedback.title;
paragraph.innerHTML = feedback.message;
highlightButton.innerText = "Find Component";
highlightButton.addEventListener("click", () => focus(id));

listItem.append(heading);
listItem.append(paragraph);
listItem.append(highlightButton);
listItem = createFeedbackGroup(id, () => focus(id));
list.append(listItem);
}
});

if (msg.results.length === 0 || list.innerHTML === "") {
const heading = document.createElement("h2");
heading.innerText = "Everything looks good!";
Expand Down
108 changes: 108 additions & 0 deletions devtools-feedback/tests/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {
LEVEL_1_HEADING_REGEX,
LINK_REGEX,
INNER_LINK_REGEX,
disableButton,
enableButton,
invalidLinks,
} from "../utils";

describe("Regex", () => {
test("LEVEL_1_HEADING_REGEX", () => {
const testCase1 = "# h1".match(LEVEL_1_HEADING_REGEX);
expect(testCase1).toEqual(["# "]);

const testCase2 = "## h2".match(LEVEL_1_HEADING_REGEX);
expect(testCase2).toEqual(null);

const testCase3 = "#something thats not a heading".match(
LEVEL_1_HEADING_REGEX
);
expect(testCase3).toEqual(null);

const testCase4 = " # space in front".match(LEVEL_1_HEADING_REGEX);
expect(testCase4).toEqual([" # "]);

const testCase5 = "something else thats not a heading#lalal".match(
LEVEL_1_HEADING_REGEX
);
expect(testCase5).toEqual(null);
});

test("LINK_REGEX", () => {
const testCase1 = "<a>A link</a>".match(LINK_REGEX);
expect(testCase1).toEqual(["<a>A link</a>"]);

const testCase2 = "<div>not a link</div>".match(LINK_REGEX);
expect(testCase2).toEqual(null);

const testCase3 = "<a class='link' href='google.com'>A link</a>".match(
LINK_REGEX
);
expect(testCase3).toEqual(["<a class='link' href='google.com'>A link</a>"]);

const testCase4 = "<a class='link'>A link</a>".match(LINK_REGEX);
expect(testCase4).toEqual(["<a class='link'>A link</a>"]);

const testCase5 = "<a class='link'>A link</a".match(LINK_REGEX);
expect(testCase5).toEqual(null);
});

test("INNER_LINK_REGEX", () => {
const testCase1 = "<a>A link</a>".match(INNER_LINK_REGEX);
expect(testCase1).toEqual(["A link"]);

const testCase2 = "<div>not a link</div>".match(INNER_LINK_REGEX);
expect(testCase2).toEqual(null);

const testCase3 =
"<a class='link' href='google.com'>descriptive link</a>".match(
INNER_LINK_REGEX
);
expect(testCase3).toEqual(["descriptive link"]);

const testCase4 = "<a class='link'>a link</a>".match(INNER_LINK_REGEX);
expect(testCase4).toEqual(["a link"]);
});
});

describe("Button Helpers", () => {
test("disableButton", () => {
const button = { ariaDisabled: false, disabled: false };
disableButton(button);

expect(button.ariaDisabled).toBe(true);
expect(button.disabled).toBe(true);
});

test("enableButton", () => {
const button = { ariaDisabled: true, disabled: true };
enableButton(button);

expect(button.ariaDisabled).toBe(false);
expect(button.disabled).toBe(false);
});
});

describe("invalidLinks", () => {
test("all links are valid", () => {
const links = ["<a>A very descriptive link</a>"];
const results = invalidLinks(links);

expect(results).toStrictEqual([]);
});

test("Upper case strings are converted to lower case", () => {
const links = ["<a>Learn more</a>"];
const results = invalidLinks(links);

expect(results).toStrictEqual(["<a>Learn more</a>"]);
});

test("all links are invalid", () => {
const links = ["<a>Learn more</a>", "<a>learn more</a>"];
const results = invalidLinks(links);

expect(results).toStrictEqual(["<a>Learn more</a>", "<a>learn more</a>"]);
});
});
75 changes: 75 additions & 0 deletions devtools-feedback/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export const LEVEL_1_HEADING_REGEX = /(\n|\s|^)\#\s/g;
export const LINK_REGEX = /<a(.*?)>(.*?)<\/a>/g;
export const INNER_LINK_REGEX = /(?<=>).+?(?=<\/a)/g;

// TODO: internationalization
const NON_DESCRIPTIVE_LINK_TEXT = [
"click here",
"click this",
"go",
"here",
"this",
"start",
"right here",
"more",
"learn more",
];

export const HELPER_LINKS = {
headings: "https://www.markdownguide.org/basic-syntax/#headings",
linkText: "https://webaim.org/techniques/hypertext/link_text",
};

export const disableButton = (button) => {
button.ariaDisabled = true;
button.disabled = true;
};

export const enableButton = (button) => {
button.ariaDisabled = false;
button.disabled = false;
};

/** Given a list of links check if the link text is descriptive enough */
export const invalidLinks = (links) => {
return links.filter((link) => {
const description = link.match(INNER_LINK_REGEX) || [];
return NON_DESCRIPTIVE_LINK_TEXT.includes(description[0].toLowerCase());
});
};

/** Create an error message <li> */
export const createErrorListItem = (title, message) => {
const listItem = document.createElement("li");
const heading = document.createElement("h3");
const paragraph = document.createElement("p");

heading.innerHTML = title;
paragraph.innerHTML = message;

listItem.append(heading);
listItem.append(paragraph);

return listItem;
};

/** Create a <li> for each textArea */
export const createFeedbackGroup = (id, highlightEvent) => {
const listItem = document.createElement("li");
const heading = document.createElement("h2");
const divider = document.createElement("hr");
const highlightButton = document.createElement("button");

listItem.classList.add("feedbackGroup");
divider.classList.add("divider");
heading.innerText = `Markdown textArea with id: "${id}"`;
highlightButton.innerText = "Find TextArea";
highlightButton.addEventListener("click", highlightEvent);

listItem.append(heading);
listItem.append(divider);
listItem.append(feedback);
listItem.append(highlightButton);

return listItem;
};
Loading

0 comments on commit 7557e0f

Please sign in to comment.