Skip to content

Commit

Permalink
Merge pull request #2103 from anth-volk/feat/2095-infinity-input
Browse files Browse the repository at this point in the history
Infinity inputs
  • Loading branch information
anth-volk authored Oct 17, 2024
2 parents 7f49e72 + d2f0a10 commit 30910d9
Show file tree
Hide file tree
Showing 25 changed files with 301 additions and 103 deletions.
41 changes: 36 additions & 5 deletions metadata_fetch.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import fetch from "node-fetch";
import fs from "fs";
import path from "path";

// const fetch = require('node-fetch')
// const fs = require('fs');
// const path = require('path');

let metadataUS = null;
let metadataUK = null;
let metadataCA = null;
Expand All @@ -18,9 +14,42 @@ const filePath = path.join(
"data.json",
);

/**
* Replaces Response.json(), which unfortunately has no
* native way of passing a reviver
*
* This function is copied, instead of imported, due to
* limitations of Jest within ES6+ module environment
* @param {Response} response The response object
* @returns {Promise} The JSON object, parsed with custom reviver
*/
function wrappedResponseJson(response) {
return new Promise((resolve, reject) => {
response.text().then((text) => {
resolve(wrappedJsonParse(text));
});
});
}

function wrappedJsonParse() {
return JSON.parse(...arguments, JsonReviver);
}

function JsonReviver(key, value) {
if (value === "Infinity") {
return Infinity;
}
if (value === "-Infinity") {
return -Infinity;
}
return value;
}

async function fetchMetadata(countryId) {
const res = await fetch(`https://api.policyengine.org/${countryId}/metadata`);
const metadataRaw = await res.json();
// For the time being, this is being kept as res.json(), unlike
// the rest of the repo, due to Jest's challenges with ES6 modules
const metadataRaw = await wrappedResponseJson(res);
const metadata = metadataRaw.result;
return metadata;
}
Expand All @@ -34,6 +63,8 @@ let jsonData = {
metadataUK: metadataUK,
metadataCA: metadataCA,
};
// For the time being, this is being kept as res.json(), unlike
// the rest of the repo, due to Jest's challenges with ES6 modules
jsonData = JSON.stringify(jsonData);

fs.writeFile(filePath, jsonData, (err) => {
Expand Down
7 changes: 4 additions & 3 deletions src/PolicyEngine.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import RedirectBlogPost from "./routing/RedirectBlogPost";
import { StatusPage } from "./pages/StatusPage";
import ManifestosComparison from "./applets/ManifestosComparison";
import CTCComparison from "./applets/CTCComparison";
import { wrappedResponseJson } from "./data/wrappedJson";

const PolicyPage = lazy(() => import("./pages/PolicyPage"));
const HouseholdPage = lazy(() => import("./pages/HouseholdPage"));
Expand Down Expand Up @@ -133,7 +134,7 @@ export default function PolicyEngine() {
useEffect(() => {
if (metadata) {
countryApiCall(countryId, `/policy/${baselinePolicyId}`)
.then((res) => res.json())
.then((res) => wrappedResponseJson(res))
.then((dataHolder) => {
if (dataHolder.result.label === "None") {
dataHolder.result.label = null;
Expand All @@ -151,7 +152,7 @@ export default function PolicyEngine() {
useEffect(() => {
if (metadata) {
countryApiCall(countryId, `/policy/${reformPolicyId}`)
.then((res) => res.json())
.then((res) => wrappedResponseJson(res))
.then((dataHolder) => {
if (dataHolder.result.label === "None") {
dataHolder.result.label = null;
Expand All @@ -168,7 +169,7 @@ export default function PolicyEngine() {
useEffect(() => {
if (searchParams.get("renamed") && reformPolicyId) {
countryApiCall(countryId, `/policy/${reformPolicyId}`)
.then((res) => res.json())
.then((res) => wrappedResponseJson(res))
.then((dataHolder) => {
setReformPolicy({
data: dataHolder.result.policy_json,
Expand Down
3 changes: 3 additions & 0 deletions src/__tests__/pages/APIDocumentationPage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ describe("APIDocumentationPage", () => {
Promise.resolve({
message: "successfully resolved",
}),
text: () => Promise.resolve('{"message": "successfully resolved"}'),
}),
);

Expand Down Expand Up @@ -134,6 +135,7 @@ describe("APIDocumentationPage", () => {
Promise.resolve({
message: "successfully resolved",
}),
text: () => Promise.resolve('{"message": "successfully resolved"}'),
}),
);

Expand Down Expand Up @@ -173,6 +175,7 @@ describe("APIDocumentationPage", () => {
Promise.resolve({
message: "successfully resolved",
}),
text: () => Promise.resolve('{"message": "successfully resolved"}'),
}),
);

Expand Down
35 changes: 10 additions & 25 deletions src/__tests__/pages/policy/PolicyRightSidebar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ describe("SinglePolicyChange", () => {
const testCountryId = "us";
const testValue = 3;
const testParamLabel = "maxwell";
// Test against changes to IRS income tax bracket 1
const testParamName = "gov.irs.income.bracket.rates.1";

test("Should display simple, single-year policies correctly", () => {
// This must be declared here, and not in describe
Expand All @@ -249,15 +251,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-01";
const testEndDate = "2024-12-31";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];

const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -272,14 +271,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-01";
const testEndDate = "2025-12-31";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -294,14 +291,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-01";
const testEndDate = defaultForeverYear.concat("-12-31");

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -316,14 +311,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-02";
const testEndDate = defaultForeverYear.concat("-12-31");

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -340,14 +333,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-02";
const testEndDate = "2025-12-30";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -365,14 +356,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-02";
const testEndDate = "2025-12-31";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -390,14 +379,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-01";
const testEndDate = "2025-12-30";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand All @@ -415,14 +402,12 @@ describe("SinglePolicyChange", () => {
const testStartDate = "2024-01-01";
const testEndDate = "2024-01-01";

const index = Math.floor(Object.keys(allParams).length / 2);
const desiredParamName = Object.keys(allParams)[index];
const { getByText } = render(
<BrowserRouter>
<SinglePolicyChange
startDateStr={testStartDate}
endDateStr={testEndDate}
parameterMetadata={allParams[desiredParamName]}
parameterMetadata={allParams[testParamName]}
value={testValue}
paramLabel={testParamLabel}
countryId={testCountryId}
Expand Down
12 changes: 12 additions & 0 deletions src/__tests__/pages/policy/PolicySearch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ const testSearchResults = {
],
};

// Note that any fetch will return text, which is then passed
// to wrappedJsonParse, hence the need to stringify, only for the
// app to then custom parse
const testSearchResultsWrapper = {
json: () => Promise.resolve(testSearchResults),
text: () => Promise.resolve(JSON.stringify(testSearchResults)),
};

const testStackingPolicy = {
Expand All @@ -36,6 +40,14 @@ const testStackingPolicyWrapper = {
policy_json: testStackingPolicy,
},
}),
text: () =>
Promise.resolve(
JSON.stringify({
result: {
policy_json: testStackingPolicy,
},
}),
),
};

const mockCountryApiCall = jest.fn();
Expand Down
5 changes: 3 additions & 2 deletions src/api/call.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { buildParameterTree } from "./parameters";
import { buildVariableTree, getTreeLeavesInOrder } from "./variables";
import { wrappedJsonStringify, wrappedResponseJson } from "../data/wrappedJson";

const POLICYENGINE_API = "https://api.policyengine.org";

Expand All @@ -19,7 +20,7 @@ export function apiCall(path, body, method, secondAttempt = false) {
headers: {
"Content-Type": "application/json",
},
body: body ? JSON.stringify(body) : null,
body: body ? wrappedJsonStringify(body) : null,
}).then((response) => {
// If the response is a 500, try again once.
if (response.status === 500 && !secondAttempt) {
Expand Down Expand Up @@ -87,7 +88,7 @@ export async function updateMetadata(countryId) {
return null;
}

const dataHolder = await res.json();
const dataHolder = await wrappedResponseJson(res);

let data = dataHolder.result;
const variableTree = buildVariableTree(
Expand Down
3 changes: 2 additions & 1 deletion src/api/parameters.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IntervalMap } from "algorithms/IntervalMap";
import { countryApiCall } from "./call";
import { cmpDates } from "lang/stringDates";
import { wrappedResponseJson } from "../data/wrappedJson";

export function buildParameterTree(parameters) {
let tree = {};
Expand Down Expand Up @@ -86,7 +87,7 @@ export function getNewPolicyId(countryId, newPolicyData, newPolicyLabel) {
submission.label = newPolicyLabel;
}
return countryApiCall(countryId, "/policy", submission, "POST")
.then((response) => response.json())
.then((response) => wrappedResponseJson(response))
.then((data) => {
let result = {};
if (data.status === "ok") {
Expand Down
5 changes: 3 additions & 2 deletions src/api/userPolicies.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { wrappedResponseJson } from "../data/wrappedJson";
import { apiCall } from "./call";

const USER_POLICY_ENDPOINT = "/user_policy";
Expand All @@ -17,7 +18,7 @@ export async function postUserPolicy(countryId, policyToAdd) {
policyToAdd,
"POST",
);
const resJson = await res.json();
const resJson = await wrappedResponseJson(res);
// If the record already exists...
if (res.status === 200 && resJson.status === "ok") {
// Update the API version and updated_date fields
Expand Down Expand Up @@ -49,7 +50,7 @@ export async function updateUserPolicy(countryId, policyToAdd) {
policyToAdd,
"PUT",
);
const resJson = await res.json();
const resJson = await wrappedResponseJson(res);
if (resJson.status !== "ok") {
console.error("Error while POSTing user policy:");
console.error(resJson.message);
Expand Down
3 changes: 2 additions & 1 deletion src/api/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { countryApiCall } from "./call";
import { capitalize } from "../lang/format";
import { defaultHouseholds } from "../data/defaultHouseholds";
import { defaultYear } from "data/constants";
import { wrappedResponseJson } from "../data/wrappedJson";

export function removePerson(situation, name) {
// Remove a person from the situation
Expand Down Expand Up @@ -401,7 +402,7 @@ export function getDefaultHouseholdId(metadata) {
{ data: defaultHousehold },
"POST",
)
.then((res) => res.json())
.then((res) => wrappedResponseJson(res))
.then((dataHolder) => {
return dataHolder.result.household_id;
});
Expand Down
7 changes: 2 additions & 5 deletions src/controls/StableInputNumber.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { InputNumber } from "antd";
import { useState } from "react";

/**
*
Expand Down Expand Up @@ -35,13 +34,11 @@ import { useState } from "react";
* @returns a StableInputNumber component
*/
export default function StableInputNumber(props) {
const { defaultValue, onPressEnter, onBlur, ...others } = props;
const [value, setValue] = useState(defaultValue);
delete others.onChange;
const { defaultValue, onPressEnter, onBlur, value, ...others } = props;
return (
<InputNumber
defaultValue={defaultValue}
onChange={setValue}
value={value}
onPressEnter={(e) => onPressEnter?.(e, value)}
onBlur={(e) => onBlur?.(e, value)}
{...others}
Expand Down
Loading

0 comments on commit 30910d9

Please sign in to comment.