Skip to content

Commit

Permalink
test: added common test utils (#29)
Browse files Browse the repository at this point in the history
* test: added a11y test util

* chore: test naming change

* test: improved & extracted out mockImage
  • Loading branch information
anuraghazra authored Dec 29, 2020
1 parent 811490f commit fb2ad25
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 81 deletions.
91 changes: 35 additions & 56 deletions src/avatar/test/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,11 @@
import * as React from "react";
import { Avatar, AvatarBadge } from "../Avatar";

import { configureAxe } from "jest-axe";
import { render, waitFor, screen } from "@testing-library/react";

const axe = configureAxe({
rules: {
region: { enabled: false },
},
});
import { render, screen } from "@testing-library/react";

const DELAY = 0;
const LOAD_IMAGE = "load.png";
const ERROR_IMAGE = "error.png";
const orignalImage = window.Image;

const mockImage = (loadState: string) => {
jest.useFakeTimers();

(window.Image as unknown) = class MockImage {
onload: () => void = () => {};
onerror: () => void = () => {};
src: string = "";
constructor() {
if (loadState === LOAD_IMAGE) {
setTimeout(() => {
this.onload();
}, DELAY);
}
if (loadState === ERROR_IMAGE) {
setTimeout(() => {
this.onerror();
}, DELAY);
}
return this;
}
};
};
import { Avatar, AvatarBadge } from "../Avatar";
import { testA11y, mockImage } from "../../utils/testUtils";

afterAll(() => {
window.Image = orignalImage;
mockImage.restoreMock();
});

describe("<Avatar />", () => {
Expand Down Expand Up @@ -89,7 +55,7 @@ describe("<Avatar />", () => {
expect(getByLabelText("fallback")).toHaveTextContent(fallbackContent);
});

it("renders name if fallback & name both are provided", () => {
it("prioritize name between fallback & name", () => {
const fallbackContent = "I'm a fallback";
const name = "Anurag Hazra";
const { queryByLabelText } = render(
Expand All @@ -104,33 +70,46 @@ describe("<Avatar />", () => {
expect(queryByLabelText("fallback")).not.toBeInTheDocument();
});

it("Avatar onError", async () => {
mockImage(ERROR_IMAGE);
const onErrorFn = jest.fn();
it("prioritize src between fallback, name & src", async () => {
mockImage.load();
const fallbackContent = "I'm a fallback";
const name = "Anurag Hazra";
const src = "demo.png";
render(
<Avatar
src={src}
name={name}
fallback={<div aria-label="fallback">{fallbackContent}</div>}
/>,
);

render(<Avatar src={"demo.png"} onError={onErrorFn}></Avatar>);
await mockImage.advanceTimer();

await waitFor(() => {
jest.advanceTimersByTime(DELAY);
});
expect(onErrorFn).toBeCalledTimes(1);
expect(screen.getByTestId("testid-avatarimg")).toBeInTheDocument();
});

it("Avatar Image loads", async () => {
mockImage(LOAD_IMAGE);
mockImage.load();
await testA11y(<Avatar>Ally</Avatar>);
render(<Avatar src={"demo.png"}></Avatar>);

await waitFor(() => {
jest.advanceTimersByTime(DELAY);
});
await mockImage.advanceTimer();

expect(screen.getByTestId("testid-avatarimg")).toBeInTheDocument();
});

it("should not have axe violations", async () => {
jest.useRealTimers();
const { container } = render(<Avatar>Ally</Avatar>);
const results = await axe(container);
it("Avatar onError", async () => {
mockImage.error();
const onErrorFn = jest.fn();

render(<Avatar src={"demo.png"} onError={onErrorFn}></Avatar>);

await mockImage.advanceTimer();

expect(onErrorFn).toBeCalledTimes(1);
});

expect(results).toHaveNoViolations();
it("should not have a11y violations", async () => {
await testA11y(<Avatar>Ally</Avatar>);
});
});
16 changes: 3 additions & 13 deletions src/avatar/test/AvatarGroup.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import * as React from "react";
import { Avatar } from "../Avatar";
import { configureAxe } from "jest-axe";
import { render, screen } from "@testing-library/react";
import { AvatarGroup } from "../AvatarGroup";

const axe = configureAxe({
rules: {
// disabled landmark rules when testing isolated components.
region: { enabled: false },
},
});
import { testA11y } from "../../utils/testUtils";

describe("<AvatarGroup />", () => {
expect.assertions(1);
Expand Down Expand Up @@ -103,15 +96,12 @@ describe("<AvatarGroup />", () => {
expect(group.childElementCount).toEqual(2);
});

it("should not have axe violations", async () => {
const { container } = render(
it("should not have a11y violations", async () => {
await testA11y(
<AvatarGroup>
<Avatar />
<Avatar />
</AvatarGroup>,
);
const results = await axe(container);

expect(results).toHaveNoViolations();
});
});
14 changes: 2 additions & 12 deletions src/button/__tests__/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import * as React from "react";
import { Button } from "../Button";

import { configureAxe } from "jest-axe";
import { render, screen } from "@testing-library/react";

const axe = configureAxe({
rules: {
// disabled landmark rules when testing isolated components.
region: { enabled: false },
},
});
import { testA11y } from "../../utils/testUtils";

describe("Testing Button", () => {
it("should render properly", () => {
Expand All @@ -19,9 +12,6 @@ describe("Testing Button", () => {
});

it("should not have axe violations", async () => {
const { container } = render(<Button>Ally</Button>);
const results = await axe(container);

expect(results).toHaveNoViolations();
testA11y(<Button>Ally</Button>);
});
});
72 changes: 72 additions & 0 deletions src/utils/testUtils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from "react";
import { configureAxe } from "jest-axe";
import { RunOptions } from "axe-core";
import { render, RenderOptions, waitFor } from "@testing-library/react";

export const axe = configureAxe({
rules: {
// disabled landmark rules when testing isolated components.
region: { enabled: false },
},
});

type UI = Parameters<typeof render>[0] | Element;
type TestA11YOptions = RenderOptions & {
axeOptions?: RunOptions;
};

export const testA11y = async (
ui: UI,
{ axeOptions, ...options }: TestA11YOptions = {},
) => {
jest.useRealTimers();

const container = React.isValidElement(ui)
? render(ui, options).container
: ui;

const results = await axe(container, axeOptions);

expect(results).toHaveNoViolations();
};

const DELAY = 0;
const LOAD_IMAGE = "load.png";
const ERROR_IMAGE = "error.png";
const orignalImage = window.Image;

export const mockImage = (loadState: string) => {
jest.useFakeTimers();

(window.Image as unknown) = class MockImage {
onload: () => void = () => {};
onerror: () => void = () => {};
src: string = "";
constructor() {
if (loadState === LOAD_IMAGE) {
setTimeout(() => {
this.onload();
}, DELAY);
}
if (loadState === ERROR_IMAGE) {
setTimeout(() => {
this.onerror();
}, DELAY);
}
return this;
}
};
};

mockImage.DELAY = DELAY;
mockImage.LOAD_IMAGE = LOAD_IMAGE;
mockImage.ERROR_IMAGE = ERROR_IMAGE;
mockImage.ERROR_IMAGE = ERROR_IMAGE;
mockImage.load = () => mockImage(LOAD_IMAGE);
mockImage.error = () => mockImage(ERROR_IMAGE);
mockImage.restoreMock = () => (window.Image = orignalImage);
mockImage.advanceTimer = async () => {
return await waitFor(() => {
jest.advanceTimersByTime(mockImage.DELAY);
});
};

1 comment on commit fb2ad25

@vercel
Copy link

@vercel vercel bot commented on fb2ad25 Dec 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.