Skip to content

Commit

Permalink
Merge 15aef9d into f3d8e8d
Browse files Browse the repository at this point in the history
  • Loading branch information
macfarlandian committed Feb 4, 2021
2 parents f3d8e8d + 15aef9d commit bb1edc0
Show file tree
Hide file tree
Showing 27 changed files with 1,560 additions and 331 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { observer } from "mobx-react-lite";
import React from "react";
import type DemographicsByCategoryMetric from "../contentModels/DemographicsByCategoryMetric";
import type HistoricalPopulationBreakdownMetric from "../contentModels/HistoricalPopulationBreakdownMetric";
import RecidivismRateMetric from "../contentModels/RecidivismRateMetric";
import {
DemographicView,
DemographicViewList,
Expand All @@ -31,7 +32,10 @@ import { Dropdown } from "../UiLibrary";
type DemographicFilterOption = { id: DemographicView; label: string };

type DemographicFilterSelectProps = {
metric: HistoricalPopulationBreakdownMetric | DemographicsByCategoryMetric;
metric:
| HistoricalPopulationBreakdownMetric
| DemographicsByCategoryMetric
| RecidivismRateMetric;
};

const DemographicFilterSelect: React.FC<DemographicFilterSelectProps> = ({
Expand Down
7 changes: 7 additions & 0 deletions spotlight-client/src/MetricVizMapper/MetricVizMapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import VizPopulationBreakdownByLocation from "../VizPopulationBreakdownByLocatio
import DemographicsByCategoryMetric from "../contentModels/DemographicsByCategoryMetric";
import VizDemographicsByCategory from "../VizDemographicsByCategory";
import VizPrisonStayLengths from "../VizPrisonStayLengths";
import RecidivismRateMetric from "../contentModels/RecidivismRateMetric";
import VizRecidivismRateSingleFollowup from "../VizRecidivismRateSingleFollowup";

type MetricVizMapperProps = {
metric: Metric<MetricRecord>;
Expand All @@ -43,6 +45,11 @@ const MetricVizMapper: React.FC<MetricVizMapperProps> = ({ metric }) => {
}
return <VizDemographicsByCategory metric={metric} />;
}
if (metric instanceof RecidivismRateMetric) {
if (metric.id === "PrisonRecidivismRateSingleFollowupHistorical") {
return <VizRecidivismRateSingleFollowup metric={metric} />;
}
}
return <h3>Placeholder for {metric.name}</h3>;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { fireEvent, screen, waitFor, within } from "@testing-library/react";
import { screen, within } from "@testing-library/react";
import { runInAction, when } from "mobx";
import React from "react";
import DemographicsByCategoryMetric from "../contentModels/DemographicsByCategoryMetric";
Expand Down Expand Up @@ -63,60 +63,6 @@ test("total chart", async () => {
expect(within(bubbles).getAllByRole("img", { name: /Node/ }).length).toBe(4);
});

test("demographic charts", async () => {
renderWithStore(<VizDemographicsByCategory metric={metric} />);

await when(() => !metric.isLoading);

const menuButton = screen.getByRole("button", {
name: "View Total",
});
fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Race or Ethnicity" }));

// pause for animated transition
await waitFor(() => {
expect(
screen.getByRole("figure", { name: "Native American" })
).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "Black" })).toBeInTheDocument();
expect(
screen.getByRole("figure", { name: "Hispanic" })
).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "White" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "Other" })).toBeInTheDocument();

expect(
screen.getAllByRole("group", { name: "4 bars in a bar chart" }).length
).toBe(5);
});

fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Gender" }));

// pause for animated transition
await waitFor(() => {
expect(screen.getByRole("figure", { name: "Male" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "Female" })).toBeInTheDocument();

expect(
screen.getAllByRole("group", { name: "4 bars in a bar chart" }).length
).toBe(2);
});

fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Age Group" }));

// pause for animated transition
await waitFor(() => {
expect(screen.getByRole("figure", { name: "<25" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "25-29" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "30-34" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "35-39" })).toBeInTheDocument();
expect(screen.getByRole("figure", { name: "40<" })).toBeInTheDocument();

expect(
screen.getAllByRole("group", { name: "4 bars in a bar chart" }).length
).toBe(5);
});
});
// tests for demographic charts don't work because of inconsistent SVG support in JSDOM;
// see https://github.com/jsdom/jsdom/issues/2531 for a (not super helpful) explanation
// of the error that occurs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2021 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { action } from "mobx";
import { observer } from "mobx-react-lite";
import React from "react";
import RecidivismRateMetric from "../contentModels/RecidivismRateMetric";
import { Dropdown } from "../UiLibrary";

const options = [
{
id: "1",
label: "1 Year",
},
{
id: "3",
label: "3 Years",
},
{
id: "5",
label: "5 Years",
},
];

type FollowupPeriodFilterSelectProps = {
metric: RecidivismRateMetric;
};

const FollowupPeriodFilterSelect: React.FC<FollowupPeriodFilterSelectProps> = ({
metric,
}) => {
const onChange = action(
"change followup period filter",
(newFilter: string) => {
// eslint-disable-next-line no-param-reassign
metric.followUpYears = Number(newFilter);
}
);

return (
<Dropdown
label="Follow-up Period"
onChange={onChange}
options={options}
selectedId={`${metric.followUpYears}`}
/>
);
};

export default observer(FollowupPeriodFilterSelect);
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2021 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import {
fireEvent,
screen,
waitForElementToBeRemoved,
within,
} from "@testing-library/react";
import { runInAction, when } from "mobx";
import React from "react";
import RecidivismRateMetric from "../contentModels/RecidivismRateMetric";
import DataStore from "../DataStore";
import { reactImmediately, renderWithStore } from "../testUtils";
import VizRecidivismRateSingleFollowup from "./VizRecidivismRateSingleFollowup";

jest.mock("../MeasureWidth/MeasureWidth");

let metric: RecidivismRateMetric;

let originalFilters: {
demographicView: RecidivismRateMetric["demographicView"];
followupYears: RecidivismRateMetric["followUpYears"];
};

beforeEach(() => {
runInAction(() => {
DataStore.tenantStore.currentTenantId = "US_ND";
});
reactImmediately(() => {
const metricToTest = DataStore.tenant?.metrics.get(
"PrisonRecidivismRateSingleFollowupHistorical"
);
// it will be
if (metricToTest instanceof RecidivismRateMetric) {
metric = metricToTest;
originalFilters = {
demographicView: metric.demographicView,
followupYears: metric.followUpYears,
};
}
});
});

afterEach(() => {
runInAction(() => {
DataStore.tenantStore.currentTenantId = undefined;
metric.demographicView = originalFilters.demographicView;
metric.followUpYears = originalFilters.followupYears;
});
});

test("loading", () => {
renderWithStore(<VizRecidivismRateSingleFollowup metric={metric} />);
expect(screen.getByText(/loading/i)).toBeVisible();
});

test("total chart", async () => {
renderWithStore(<VizRecidivismRateSingleFollowup metric={metric} />);

await when(() => !metric.isLoading);

const chart = screen.getByRole("group", { name: "8 bars in a bar chart" });
expect(chart).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2009 bar value 27%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2010 bar value 57%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2011 bar value 39%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2012 bar value 38%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2013 bar value 40%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2014 bar value 37%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2015 bar value 30%" })
).toBeVisible();
expect(
within(chart).getByRole("img", { name: "2016 bar value 20%" })
).toBeVisible();
});

test("demographic charts", async () => {
renderWithStore(<VizRecidivismRateSingleFollowup metric={metric} />);

await when(() => !metric.isLoading);

const totalChart = screen.getByRole("group", {
name: "8 bars in a bar chart",
});

const menuButton = screen.getByRole("button", {
name: "View Total",
});
fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Race or Ethnicity" }));

// pause for animated transition
await waitForElementToBeRemoved(totalChart);

const raceCharts = screen.getAllByRole("group", {
name: "8 bars in a bar chart",
});
expect(raceCharts.length).toBe(5);

fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Gender" }));

// pause for animated transition
await waitForElementToBeRemoved(raceCharts[0]);

const genderCharts = screen.getAllByRole("group", {
name: "8 bars in a bar chart",
});
expect(genderCharts.length).toBe(2);

fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "Age Group" }));

// pause for animated transition
await waitForElementToBeRemoved(genderCharts[0]);

expect(
screen.getAllByRole("group", { name: "8 bars in a bar chart" }).length
).toBe(5);
});

test("followup period filter", async () => {
renderWithStore(<VizRecidivismRateSingleFollowup metric={metric} />);

await when(() => !metric.isLoading);

const menuButton = screen.getByRole("button", {
name: "Follow-up Period 3 Years",
});
fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "1 Year" }));

const oneYearChart = screen.getByRole("group", {
name: "10 bars in a bar chart",
});
expect(oneYearChart).toBeVisible();

expect(menuButton).toHaveTextContent("1 Year");
fireEvent.click(menuButton);
fireEvent.click(screen.getByRole("option", { name: "5 Years" }));

expect(
screen.getByRole("group", { name: "6 bars in a bar chart" })
).toBeVisible();
expect(menuButton).toHaveTextContent("5 Years");
});
Loading

0 comments on commit bb1edc0

Please sign in to comment.