Skip to content

Commit

Permalink
Merge pull request #9 from DTS-STN/kris-experiment-filter
Browse files Browse the repository at this point in the history
Added Experiment and Filter components
  • Loading branch information
var-kyle authored Sep 8, 2021
2 parents 40edc15 + 6bd3ad2 commit 6814a23
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"pre-commit": "lint-staged",
"lint": "prettier --write \"*.{js,md}\" --write \".storybook/**/*.{js,jsx,ts,tsx,json,md,css}\" --write \"playground/**/*.{js,jsx,ts,tsx,json,md,css}\" --write \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"prepare": "husky install",
"storybook": "start-storybook -p 6006",
"storybook": "start-storybook -s ./public -p 6006",
"build-storybook": "build-storybook"
},
"lint-staged": {
Expand Down
3 changes: 3 additions & 0 deletions public/external-link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 85 additions & 0 deletions src/components/Experiment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import PropTypes from "prop-types";

/**
* Displays an experiment card on the page
*/

export const Experiment = (props) => {
const tagColours = {
current_projects: "custom-blue-experiment-blue",
past_projects: "gray-experiment",
upcoming_projects: "custom-blue-experiment-blue",
};
return (
<div
className={`shadow-experiment-shadow p-6 border-b-4 xl:min-h-250px ${
"border-" + (tagColours[props.tag] || "gray-experiment")
}`}
data-testid={props.dataTestId}
data-cy={props.dataCy}
>
<a
className="flex block text-p text-custom-blue-projects-link underline hover:opacity-70"
tabIndex="0"
href={props.href}
>
{props.title}
{props.href.substring(0, 8) === "https://" ? (
<img
alt="external link"
src="/external-link.svg"
className="px-1 py-2"
/>
) : undefined}
</a>
<span
className={`my-4 block w-max py-2 px-2 uppercase font-body text-xxs text-white font-bold rounded ${
"bg-" + (tagColours[props.tag] || "gray-experiment")
}`}
>
{props.tagLabel}
</span>
<p className="mt-2 leading-30px text-lg">{props.description}</p>
</div>
);
};

Experiment.propTypes = {
/**
* Title of the experiment card.
*/
title: PropTypes.string.isRequired,

/**
* tag of the experiment card
*/
tag: PropTypes.string.isRequired,

/**
* Link of the card
*/
href: PropTypes.string,

/**
* the label of the tag card
*/
tagLabel: PropTypes.string.isRequired,

/**
* Description of the experiment card.
*/
description: PropTypes.string.isRequired,

/**
* the test id for unit tests
*/
dataTestId: PropTypes.string,

/**
* the test id for cypress test
*/
dataCy: PropTypes.string,
};

export default Experiment;
27 changes: 27 additions & 0 deletions src/components/Experiment.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import Experiment from "./Experiment";

export default {
title: "Components/Redirect components/Experiment",
component: Experiment,
};

const Template = (args) => <Experiment {...args} />;

export const ExternalLink = Template.bind({});
ExternalLink.args = {
title: "Experiment title",
tag: "current_projects",
tagLabel: "Experiment tag",
description: "Experiment description",
href: "https://www.some.link",
};

export const InternalLink = Template.bind({});
InternalLink.args = {
title: "Experiment title",
tag: "current_projects",
tagLabel: "Experiment tag",
description: "Experiment description",
href: "/some/link",
};
28 changes: 28 additions & 0 deletions src/components/Experiment.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @jest-environment jsdom
*/
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { axe, toHaveNoViolations } from "jest-axe";
import { ExternalLink } from "./Experiment.stories";

expect.extend(toHaveNoViolations);

describe("Experiment tests", () => {
it("renders Experiment in its primary state", () => {
render(<ExternalLink {...ExternalLink.args} />);
const titleElement = screen.getByText("Experiment title");
const tagElement = screen.getByText("Experiment tag");
const descriptionElement = screen.getByText("Experiment description");
expect(titleElement).toBeTruthy();
expect(tagElement).toBeTruthy();
expect(descriptionElement).toBeTruthy();
});

it("has no a11y violations", async () => {
const { container } = render(<ExternalLink {...ExternalLink.args} />);
const results = await axe(container);

expect(results).toHaveNoViolations();
});
});
69 changes: 69 additions & 0 deletions src/components/Filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import PropTypes from "prop-types";
import { RadioButton } from "./RadioButton";

/**
* Filter Experiments component
*/
export function Filter(props) {
return (
<form
className="mt-4 md:flex md:mt-6 mb-6"
data-testid={props.dataTestId}
data-cy={props.dataCy}
>
<fieldset>
<legend className="md:float-left font-body pb-3 pt-2 pr-4 text-sm md:text-base">
{props.label}
</legend>
{props.options.map(({ id, label, checked }, index) => (
<RadioButton
key={id}
label={label}
value={id}
name={id}
id={id}
dataTestId={id}
dataCy={id}
onChange={props.onChange}
checked={checked}
roundedFront={index === 0}
roundedBack={index === props.options.length - 1}
/>
))}
</fieldset>
</form>
);
}

Filter.propTypes = {
/**
* options for the filter
*/
options: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
checked: PropTypes.bool,
})
).isRequired,

/**
* filter label
*/
label: PropTypes.string,

/**
* Action to do on input change
*/
onChange: PropTypes.func,

/**
* Test id for unit tests
*/
dataTestId: PropTypes.string,

/**
* Test id for cypress test
*/
dataCy: PropTypes.string,
};
32 changes: 32 additions & 0 deletions src/components/Filter.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { Filter } from "./Filter";

export default {
title: "Components/Form components/Filter",
component: Filter,
};

const Template = (args) => <Filter {...args} />;

export const Primary = Template.bind({});

Primary.args = {
label: "Filter By",
options: [
{
id: "all",
label: "All",
checked: false,
},
{
id: "coming_soon",
label: "Coming Soon",
checked: false,
},
{
id: "alpha",
label: "Alpha",
checked: true,
},
],
};
41 changes: 41 additions & 0 deletions src/components/Filter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @jest-environment jsdom
*/
import { render, screen, act } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { axe, toHaveNoViolations } from "jest-axe";
import { Primary } from "./Filter.stories";

expect.extend(toHaveNoViolations);

describe("Filter Experiments", () => {
it("renders radio buttons and label correctly", () => {
render(<Primary {...Primary.args} />);
screen.getByText(Primary.args.label);
const optionOne = screen.getByText(Primary.args.options[0].label);
const optionTwo = screen.getByText(Primary.args.options[1].label);
const optionThree = screen.getByText(Primary.args.options[2].label);

expect(optionOne).toHaveClass("rounded-l-lg");
expect(optionTwo).not.toHaveClass("rounded-l-lg");
expect(optionTwo).not.toHaveClass("rounded-r-lg");
expect(optionThree).toHaveClass("rounded-r-lg");
});

it("calls onChange callback correctly", () => {
let mockFn = jest.fn();
render(<Primary {...Primary.args} onChange={mockFn} />);
const allOption = screen.getByText(Primary.args.options[0].label);
act(() => {
allOption.click();
});
expect(mockFn.mock.calls.length).toBe(1);
expect(mockFn.mock.calls[0][0]).toBe(Primary.args.options[0].id);
});

it("has no a11y violations", async () => {
const { container } = render(<Primary {...Primary.args} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
1 change: 1 addition & 0 deletions src/components/SelectField.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Primary.args = {
dataTestId: "select-field-1",
required: true,
requiredText: "(required)",
optionalText: "optional",
options: [
{
id: "option1",
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ module.exports = {
dark: "#26374a",
link: "#0535d2",
"experiment-blue": "#004986",
"projects-link": "#2B4380",
},
"error-border-red": "#D3080C",
"error-background-red": "#F3E9E8",
Expand Down

0 comments on commit 6814a23

Please sign in to comment.