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

WB-1780: Refactor combobox to use Announcer [WIP] #2390

Draft
wants to merge 60 commits into
base: announcer-pt1
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
42a2d7b
Initial commit of Announcer
marcysutton Nov 13, 2024
5c67d98
WIP: append messages
marcysutton Nov 15, 2024
3581692
Leverage React for tests
marcysutton Nov 15, 2024
fc86083
Refactor to use dictionary
marcysutton Nov 15, 2024
23f00ef
Cleanup, move types, add comments
marcysutton Nov 15, 2024
859f5e3
Fix outdated param in story
marcysutton Nov 15, 2024
2f3e6b4
Put testing styles in Storybook preview.css
marcysutton Nov 19, 2024
53c9518
Remove console.log
marcysutton Nov 19, 2024
c119abe
Add working test for auto-removal of messages
marcysutton Nov 19, 2024
2428b60
Added changeset
marcysutton Nov 20, 2024
2557a7e
Remove manually created changelog file
marcysutton Nov 22, 2024
3fbf47e
Restructure files based on PR feedback
marcysutton Nov 22, 2024
d6248c4
Rename sendMessage to announceMessage
marcysutton Nov 22, 2024
a01d18d
Rename clear-messages file to match function
marcysutton Nov 22, 2024
1f42473
Move utility functions into separate files
marcysutton Nov 22, 2024
6e1752d
Append regions to end of document.body
marcysutton Nov 22, 2024
8775ba2
Renaming timeouts, adding comments for clarity
marcysutton Nov 22, 2024
5d6e5ca
Reformat files for linter
marcysutton Nov 22, 2024
92beca9
Try kicking the linter one more time
marcysutton Nov 22, 2024
f06ef66
Expand tests
marcysutton Nov 23, 2024
2611248
Make document check more consistent
marcysutton Nov 23, 2024
30edef8
Add comments, types, and a few more tests
marcysutton Nov 23, 2024
48bcf35
Implement debounce / async logic
marcysutton Nov 26, 2024
c36d79a
Implement debounce / async logic
marcysutton Nov 26, 2024
e978123
Get async tests working
marcysutton Nov 26, 2024
147a364
Add missing test utility file
marcysutton Nov 26, 2024
32774c3
Update docs in Storybook for latest API changes
marcysutton Nov 26, 2024
e526e3b
Firm up debounce logic
marcysutton Nov 27, 2024
260b6b1
Clean up stray log and setTimeout testing approach
marcysutton Nov 27, 2024
c95f6f3
Add test file I somehow missed
marcysutton Nov 27, 2024
1ca62d7
Suppress story artifacts from announcements
marcysutton Dec 3, 2024
1dd4106
Add initial timeout back to help Safari/VO
marcysutton Dec 3, 2024
a334d5c
Fix typo in reattachment selector
marcysutton Dec 10, 2024
c7b2162
Rename Announcer filenames to lowercase
marcysutton Dec 10, 2024
698665e
Remove console.log
marcysutton Dec 10, 2024
3bc42da
Remove commented-out test code
marcysutton Dec 10, 2024
36e614f
Update tests from review feedback
marcysutton Dec 10, 2024
06ccdcb
Refactor combobox to use Announcer
jandrade Dec 11, 2024
0cb27cf
Clean up WIP wonder-blocks-style code
marcysutton Dec 12, 2024
cbb4c2d
Refactor debounce logic and tests
marcysutton Dec 12, 2024
7584543
Clean up storybook styling with custom body class
marcysutton Dec 12, 2024
ebe284c
Update jsdoc comments for debounce utility
marcysutton Dec 12, 2024
4957581
Fix incorrect object in debounce test
marcysutton Dec 12, 2024
7492c69
Merge conflicts
jandrade Dec 12, 2024
b5fb657
Merge announcer-pt1 into announcer-combobox
jandrade Dec 12, 2024
b6009b7
[wb1812.1.deprecate] Mark ID stuff as deprecated (#2388)
somewhatabstract Dec 16, 2024
897686b
[wb1812.2.idcomponent] Add the Id component (#2389)
somewhatabstract Dec 16, 2024
56d961f
[wb1812.3.migratewb] Migrate Wonder Blocks off old id providers (#2391)
somewhatabstract Dec 16, 2024
8237972
Version Packages (#2396)
khan-actions-bot Dec 16, 2024
3c1682f
QoL: Turn on automatic commit of changesets (#2394)
jeremywiebe Dec 16, 2024
d23c9c5
[wb1812.4.delete] Delete the custom identifier generation API (#2398)
somewhatabstract Dec 17, 2024
193d8a4
RELEASING: Releasing 27 package(s) (#2402)
khan-actions-bot Dec 17, 2024
e095558
Empty commit to trigger release action
somewhatabstract Dec 17, 2024
361cb52
RadioGroup: Add flexible width to legend element to fill available sp…
jandrade Dec 19, 2024
2cfb36f
Version Packages (#2406)
khan-actions-bot Dec 19, 2024
b2f03d9
Tooling: Move Storybook reusable components to __docs__ to optimize T…
jandrade Dec 20, 2024
1aa4fef
Update changesets' auto-commit feature to not suppress CI on commits …
jeremywiebe Dec 20, 2024
53b4197
Changesets: Bump form package to test release process (#2410)
jandrade Dec 20, 2024
c58e3fa
Version Packages (#2411)
khan-actions-bot Dec 20, 2024
7fc7a6e
Merge announcer-pt1 into announcer-combobox
jandrade Dec 20, 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
Prev Previous commit
Next Next commit
Expand tests
  • Loading branch information
marcysutton committed Nov 23, 2024
commit f06ef6624867f9e6861be1c95c2fe445f7177a31
7 changes: 7 additions & 0 deletions packages/wonder-blocks-announcer/src/Announcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ class Announcer {

return index;
}

reset() {
this.regionFactory.aIndex = 0;
this.regionFactory.pIndex = 0;

this.clear();
}
}

export default Announcer;
Expand Down
97 changes: 97 additions & 0 deletions packages/wonder-blocks-announcer/src/__tests__/Announcer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {screen} from "@testing-library/react";
import Announcer from "../Announcer";

describe("Announcer class", () => {
describe("instantiation", () => {
test("creating one singleton instance", () => {
// Arrange/Act
const announcer = Announcer.getInstance();
const announcer2 = Announcer.getInstance();

// Assert: is this testing anything useful?
expect(announcer).toEqual(announcer2);
});

test("initializing the element structure", () => {
// Arrange/Act
const announcer = Announcer.getInstance();
const wrapperElement = announcer.node;
const regions = announcer.dictionary;

// Assert
expect(wrapperElement).toBeInTheDocument();
expect(wrapperElement?.childElementCount).toBe(2);
expect(regions.size).toBe(4);
});
});

describe("announcing messages", () => {
afterEach(() => {
const announcer = Announcer.getInstance();
announcer.reset();
});

test("appending a message", () => {
// Arrange
const announcer = Announcer.getInstance();
expect(announcer.regionFactory.pIndex).toBe(0);

// Act
announcer.announce("a thing", "polite");

// Assert
expect(announcer.regionFactory.pIndex).toBe(1);
expect(
announcer.dictionary.get("wbARegion-polite1")?.element
.textContent,
).toBe("a thing");
});

test("returning an IDREF", () => {
// Arrange
const announcer = Announcer.getInstance();
expect(announcer.regionFactory.pIndex).toBe(0);

// Act
const idRef = announcer.announce("another thing", "polite");

// Assert
expect(idRef).toBe("wbARegion-polite1");
});
});

describe("clearing messages", () => {
test("clearing by IDREF", () => {
// Arrange
const announcer = Announcer.getInstance();
expect(announcer.regionFactory.pIndex).toBe(0);

// Act
const idRef = announcer.announce("something", "polite");
const firstRegion = announcer.dictionary.get(idRef)?.element;
expect(firstRegion?.textContent).toBe("something");

announcer.clear(idRef);

// Assert
expect(firstRegion?.textContent).not.toBe("something");
});

test("clearing all elements", () => {
// Arrange
const announcer = Announcer.getInstance();

// Act
announcer.announce("One Fish", "polite");
announcer.announce("Loud Fish", "assertive");
expect(screen.getByText("One Fish")).toBeInTheDocument();
expect(screen.getByText("Loud Fish")).toBeInTheDocument();

announcer.clear();

// Assert
expect(screen.queryByText("One Fish")).not.toBeInTheDocument();
expect(screen.queryByText("Loud Fish")).not.toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";
import {render, screen, waitFor} from "@testing-library/react";
import {AnnounceMessageButton} from "./util/announce-message-button";
import {AnnounceMessageButton} from "./components/announce-message-button";
import {announceMessage} from "../announce-message";
import {clearMessages} from "../clear-messages";

Expand Down
133 changes: 133 additions & 0 deletions packages/wonder-blocks-announcer/src/__tests__/util/dom.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import {screen, waitFor} from "@testing-library/react";
import {
createRegionWrapper,
createDuplicateRegions,
createRegion,
removeMessage,
} from "../../util/dom";

jest.useFakeTimers();
jest.spyOn(global, "setTimeout");

describe("Announcer utility functions", () => {
describe("createRegionWrapper", () => {
test("it creates a polite region wrapper element", () => {
const element = createRegionWrapper("polite");

expect(element.tagName).toBe("DIV");
expect(element.id).toEqual("wbAWrap-polite");
});

test("it creates an assertive region wrapper element", () => {
const element = createRegionWrapper("assertive");

expect(element.tagName).toBe("DIV");
expect(element.id).toEqual("wbAWrap-assertive");
});
});

describe("createDuplicateRegions", () => {
test("it creates multiple polite region elements", () => {
const wrapper = document.createElement("div");
const dictionary = new Map();

const regionList = createDuplicateRegions(
wrapper,
"polite",
2,
dictionary,
);

expect(regionList.length).toBe(2);
expect(regionList[0].id).toBe("wbARegion-polite0");
expect(regionList[1].id).toBe("wbARegion-polite1");
expect(dictionary.size).toBe(2);
});

test("it creates multiple assertive region elements", () => {
const wrapper = document.createElement("div");
const dictionary = new Map();

const regionList = createDuplicateRegions(
wrapper,
"assertive",
2,
dictionary,
);

expect(regionList.length).toBe(2);
expect(regionList[0].id).toBe("wbARegion-assertive0");
expect(regionList[1].id).toBe("wbARegion-assertive1");
expect(dictionary.size).toBe(2);
});
});

describe("createRegion", () => {
test("it creates a polite Live Region element", () => {
const dictionary = new Map();
const region = createRegion("polite", 0, dictionary);

expect(region.id).toBe("wbARegion-polite0");
expect(region.getAttribute("aria-live")).toBe("polite");
expect(region.getAttribute("role")).toBe("log");
expect(dictionary.size).toBe(1);
});

test("it creates an assertive Live Region element", () => {
const dictionary = new Map();
const region = createRegion("assertive", 0, dictionary);

expect(region.id).toBe("wbARegion-assertive0");
expect(region.getAttribute("aria-live")).toBe("assertive");
expect(region.getAttribute("role")).toBe("log");
expect(dictionary.size).toBe(1);
});

test("it allows the role to be overridden", () => {
const dictionary = new Map();
const region = createRegion("polite", 0, dictionary, "timer");

expect(region.getAttribute("aria-live")).toBe("polite");
expect(region.getAttribute("role")).toBe("timer");
});
});

describe("removeMessage", () => {
test("it removes an element from the DOM", async () => {
// Arrange
const message = document.createElement("p");
document.body.appendChild(message);
expect(message).toBeInTheDocument();

// Act
removeMessage(message, 0);

// Assert
await waitFor(() => {
expect(message).not.toBeInTheDocument();
});
});

test("it removes an element after a configurable delay", async () => {
// Arrange
const messageText = "Thar she blows";
const message = document.createElement("p");
message.textContent = messageText;
document.body.appendChild(message);

const delay = 300;

// Act
removeMessage(message, delay);

// Assert
expect(setTimeout).toHaveBeenLastCalledWith(
expect.any(Function),
delay,
);
await waitFor(() => {
expect(screen.queryByText(messageText)).not.toBeInTheDocument();
});
});
});
});
2 changes: 1 addition & 1 deletion packages/wonder-blocks-announcer/src/util/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function createDuplicateRegions(
* @param {string} role Role attribute for live regions, defaults to log
* @returns {HTMLElement} DOM element reference for live region
*/
function createRegion(
export function createRegion(
level: PolitenessLevel,
index: number,
dictionary: RegionDictionary,
Expand Down