Skip to content

Commit

Permalink
Merge pull request #755 from sebgroup/develop
Browse files Browse the repository at this point in the history
New release - removed css-style-inject and fixed unit tests
  • Loading branch information
mario-subo authored Aug 9, 2022
2 parents e02ecac + c35ab7e commit 9581f65
Show file tree
Hide file tree
Showing 31 changed files with 16,672 additions and 73,352 deletions.
31,784 changes: 0 additions & 31,784 deletions docs/package-lock.json

This file was deleted.

14,816 changes: 0 additions & 14,816 deletions lib/package-lock.json

This file was deleted.

1 change: 0 additions & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"@types/body-scroll-lock": "^3.1.0",
"body-scroll-lock": "^4.0.0-beta.0",
"classnames": "^2.3.1",
"css-style-inject": "^1.1.1",
"pupa": "^2.1.1"
},
"devDependencies": {
Expand Down
28 changes: 26 additions & 2 deletions lib/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ import pkg from "./package.json";
import commonPkg from "../package.json";

const components = require("./src/index.json");

function injectCSS(css, uniqueId, isPrepend) {
if (!css || !document) {
return;
}

const exists = !!document.querySelector(`style[id="${uniqueId}"]`)
if (exists) {
return;
}

const cssElement = document.createElement("style");
cssElement.id = uniqueId;
cssElement.setAttribute("type", "text/css");

cssElement.innerHTML = css;
if (isPrepend && document.head.firstChild) {
document.head.insertBefore(cssElement, document.head.firstChild);
} else {
document.head.appendChild(cssElement);
}
return cssElement;
}

const globals = {
react: "React",
"react-dom": "ReactDOM",
Expand All @@ -30,7 +54,7 @@ export default [
(varname, id) => {
const filePathArray = id.split("\\");
const file = filePathArray[filePathArray.length - 1].split(".");
return `const inject = require("css-style-inject");\n${varname} = inject.injectCSS(${varname}, "rc-${file[0]}");`;
return `${varname} = injectCSS(${varname}, "rc-${file[0]}");`;
},
],
}),
Expand Down Expand Up @@ -58,7 +82,7 @@ export default [
(varname, id) => {
const filePathArray = id.split("\\");
const file = filePathArray[filePathArray.length - 1].split(".");
return `const inject = require("css-style-inject");\n${varname} = inject.injectCSS(${varname}, "rc-${file[0]}");`;
return `${varname} = injectCSS(${varname}, "rc-${file[0]}");`;
},
],
}),
Expand Down
245 changes: 100 additions & 145 deletions lib/src/Accordion/Accordion.test.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
import { render, RenderResult, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import { act, Simulate } from "react-dom/test-utils";
import { unmountComponentAtNode, render } from "react-dom";
import { Accordion, AccordionItem } from ".";

describe("Component: Accordion", () => {
let container: HTMLDivElement = null;
function getAccordionButtons(): Array<HTMLButtonElement> {
return screen.getAllByRole<HTMLButtonElement>("button");
}

/** To disable Collapse setTimeout calls */
beforeAll(() => jest.useFakeTimers());

beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
});

afterEach(() => {
unmountComponentAtNode(container);
container.remove();
container = null;
});
function getButtonExpansion(button: HTMLButtonElement): boolean {
return JSON.parse(button.getAttribute("aria-expanded"));
}

it("Should render correctly", () => {
act(() => {
render(<Accordion />, container);
});
const { container }: RenderResult = render(<Accordion />);
expect(container.firstElementChild.classList.contains("rc")).toBeTruthy();
expect(container.firstElementChild.classList.contains("accordion")).toBeTruthy();
expect(container.firstElementChild.id).toBeDefined();
Expand All @@ -32,188 +22,153 @@ describe("Component: Accordion", () => {
it("Should render with id, custom class and alternative style", () => {
const id: string = "myId";
const className: string = "myClassname";
act(() => {
render(<Accordion id={id} className={className} alternative />, container);
});
const { container }: RenderResult = render(<Accordion id={id} className={className} alternative />);
expect(container.firstElementChild.id).toEqual(id);
expect(container.firstElementChild.classList.contains("alternative")).toBeTruthy();
expect(container.firstElementChild.classList.contains(className)).toBeTruthy();
});

it("Should toggle on and off an accordion item", () => {
act(() => {
render(
<Accordion>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
);
});
const firstButton: HTMLButtonElement = container.querySelectorAll<HTMLButtonElement>("button.btn-link").item(0);
act(() => {
firstButton.click();
});
expect(JSON.parse(firstButton.getAttribute("aria-expanded"))).toBeTruthy();
act(() => {
firstButton.click();
});
expect(JSON.parse(firstButton.getAttribute("aria-expanded"))).toBeFalsy();
it("Should toggle on and off an accordion item", async () => {
render(
<Accordion>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>
);
const firstButton: HTMLButtonElement = getAccordionButtons()[0];
await userEvent.click(firstButton);
expect(getButtonExpansion(firstButton)).toBeTruthy();
await userEvent.click(firstButton);
expect(getButtonExpansion(firstButton)).toBeFalsy();
});

it("Should allow rendering none elements", () => {
const text: string = "Some text";
act(() => {
render(<Accordion>{text}</Accordion>, container);
});
expect(container.firstElementChild.innerHTML).toEqual(text);
render(<Accordion>{text}</Accordion>);
expect(screen.getByText(text)).toBeInTheDocument();
});

describe("Should forward the following props to children accordion items", () => {
const id: string = "myId";
let container: HTMLElement;
let firstButton: HTMLButtonElement;

beforeEach(() => {
act(() => {
render(
<Accordion id={id} defaultValue={0}>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
);
});
firstButton = container.querySelectorAll<HTMLButtonElement>("button").item(0);
const result: RenderResult = render(
<Accordion id={id} defaultValue={0}>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>
);
container = result.container;
firstButton = getAccordionButtons()[0];
});

test("paretnId", () => expect(container.querySelectorAll<HTMLDivElement>(".collapse").item(0).dataset.parent).toEqual(`#${id}`));
test("parentId", () => expect(container.querySelectorAll<HTMLDivElement>(".collapse").item(0).dataset.parent).toEqual(`#${id}`));

test("value", () => expect(firstButton.dataset.indexNumber).toEqual("0"));
test("active", () => expect(firstButton.getAttribute("aria-expanded")).toEqual("true"));
test("onToggle", () => {
act(() => {
firstButton.click();
});
expect(firstButton.getAttribute("aria-expanded")).toEqual("false");

test("active", () => expect(getButtonExpansion(firstButton)).toBeTruthy());

test("onToggle", async () => {
await userEvent.click(firstButton);
expect(getButtonExpansion(firstButton)).toBeFalsy();
});
});

describe("Should set default expanded using default value and default checked", () => {
test("defaultValue from parent", () => {
act(() => {
render(
<Accordion defaultValue={0}>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
);
});
expect(container.querySelector<HTMLButtonElement>("button").getAttribute("aria-expanded")).toEqual("true");
});
test("defaultValue from children", () => {
act(() => {
render(
<Accordion>
<AccordionItem defaultChecked header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
);
});
expect(container.querySelector<HTMLButtonElement>("button").getAttribute("aria-expanded")).toEqual("true");
});
});

it("Should fire on toggle", () => {
const mockFn: jest.Mock = jest.fn();
act(() => {
render(
<Accordion onToggle={mockFn}>
<Accordion defaultValue={0}>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
</Accordion>
);
expect(getButtonExpansion(getAccordionButtons()[0])).toBeTruthy();
});
const firstButton: HTMLButtonElement = container.querySelectorAll<HTMLButtonElement>("button.btn-link").item(0);
act(() => {
firstButton.click();
});
expect(mockFn).toBeCalled();
});

it("Should fire accordion item callback on toggle", () => {
const mockFn: jest.Mock = jest.fn();
act(() => {
test("defaultValue from children", () => {
render(
<Accordion>
<AccordionItem header="First" onToggle={mockFn} />
<AccordionItem defaultChecked header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
</Accordion>
);
expect(getButtonExpansion(getAccordionButtons()[0])).toBeTruthy();
});
const firstButton: HTMLButtonElement = container.querySelectorAll<HTMLButtonElement>("button.btn-link").item(0);
act(() => {
firstButton.click();
});
});

it("Should fire on toggle", async () => {
const mockFn: jest.Mock = jest.fn();
render(
<Accordion onToggle={mockFn}>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>
);
await userEvent.click(getAccordionButtons()[0]);
expect(mockFn).toBeCalled();
});

it("Should fire accordion item callback on toggle", async () => {
const mockFn: jest.Mock = jest.fn();
render(
<Accordion>
<AccordionItem header="First" onToggle={mockFn} />
<AccordionItem header="Second" />
</Accordion>
);
await userEvent.click(getAccordionButtons()[0]);
expect(mockFn).toBeCalled();
});

describe("Keyboard support", () => {
function renderAccordion(): void {
act(() => {
render(
<Accordion>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>,
container
);
});
container.querySelector<HTMLButtonElement>("button").focus();
}

function pressKey(key: string): void {
act(() => Simulate.keyDown(document.activeElement, { key }));
render(
<Accordion>
<AccordionItem header="First" />
<AccordionItem header="Second" />
</Accordion>
);
getAccordionButtons()[0].focus();
}

function assertFocusedElement(element: HTMLElement): void {
expect(document.activeElement).toEqual(element);
}

it("Should focus on next header when down arrow button is pressed", () => {
it("Should focus on next header when down arrow button is pressed", async () => {
renderAccordion();
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
pressKey("ArrowDown");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[1]);
pressKey("ArrowDown");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
assertFocusedElement(getAccordionButtons()[0]);
await userEvent.keyboard("[ArrowDown]");
assertFocusedElement(getAccordionButtons()[1]);
await userEvent.keyboard("[ArrowDown]");
assertFocusedElement(getAccordionButtons()[0]);
});

it("Should focus on previous header when up arrow button is pressed", () => {
it("Should focus on previous header when up arrow button is pressed", async () => {
renderAccordion();
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
pressKey("ArrowUp");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[1]);
pressKey("ArrowUp");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
assertFocusedElement(getAccordionButtons()[0]);
await userEvent.keyboard("[ArrowUp]");
assertFocusedElement(getAccordionButtons()[1]);
await userEvent.keyboard("[ArrowUp]");
assertFocusedElement(getAccordionButtons()[0]);
});

it("Should focus on first header when home button is pressed", () => {
it("Should focus on first header when home button is pressed", async () => {
renderAccordion();
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
pressKey("ArrowDown");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[1]);
pressKey("Home");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
assertFocusedElement(getAccordionButtons()[0]);
await userEvent.keyboard("[ArrowDown]");
assertFocusedElement(getAccordionButtons()[1]);
await userEvent.keyboard("[Home]");
assertFocusedElement(getAccordionButtons()[0]);
});

it("Should focus on last header when end button is pressed", () => {
it("Should focus on last header when end button is pressed", async () => {
renderAccordion();
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[0]);
pressKey("End");
assertFocusedElement(container.querySelectorAll<HTMLButtonElement>("button")[1]);
assertFocusedElement(getAccordionButtons()[0]);
await userEvent.keyboard("[End]");
assertFocusedElement(getAccordionButtons()[1]);
});

it("Should not handle button event when button is pressed on element aside from accordion header", () => {
Expand Down
Loading

0 comments on commit 9581f65

Please sign in to comment.