Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: bump planx-core (multiple schemas support) #4206

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
149 changes: 149 additions & 0 deletions api.planx.uk/modules/flows/validate/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import type { FlowGraph } from "@opensystemslab/planx-core/types";
import { ComponentType as TYPES } from "@opensystemslab/planx-core/types";

import { hasComponentType, numberOfComponentType } from "./helpers.js";

describe("hasComponentType", () => {
test("it returns true for a component type that is present", () => {
expect(hasComponentType(flow, TYPES.Question)).toEqual(true);
});

test("it returns false for a component type that is not present", () => {
expect(hasComponentType(flow, TYPES.DrawBoundary)).toEqual(false);
});

test("it returns true for a component type that is present and has the specified data field as a `val` prop", () => {
expect(hasComponentType(flow, TYPES.Answer, "residential.flat")).toEqual(
true,
);
});

test("it returns true for a component type that is present and has the specified data field as a `fn` prop", () => {
expect(hasComponentType(flow, TYPES.Question, "property.type")).toEqual(
true,
);
});

test("it returns false for a component type that is present but does not have the specified data field", () => {
expect(hasComponentType(flow, TYPES.Question, "application.type")).toEqual(
false,
);
});
});

describe("numberOfComponentType", () => {
test("it returns the correct count of nested component types", () => {
expect(numberOfComponentType(flow, TYPES.Answer)).toEqual(5);
});

test("it returns the correct count of component types with a specified data field as a `fn` prop", () => {
expect(
numberOfComponentType(flow, TYPES.Question, "property.type"),
).toEqual(2);
});

test("it returns the correct count of component types with a specified data field as a `val` prop", () => {
expect(numberOfComponentType(flow, TYPES.Answer, "residential")).toEqual(1);
});

test("it returns 0 for a component type that is not present", () => {
expect(numberOfComponentType(flow, TYPES.Calculate)).toEqual(0);
});

test("it returns 0 for a component type that is present but does not have the specified data field", () => {
expect(
numberOfComponentType(flow, TYPES.Question, "application.type"),
).toEqual(0);
});
});

const flow: FlowGraph = {
_root: {
edges: ["FindProperty", "QuestionOne", "Result", "Notice"],
},
"4jSYMB7hBJ": {
data: {
val: "residential.house",
text: "House",
flags: ["flag.pp.permittedDevelopment"],
},
type: TYPES.Answer,
},
FindProperty: {
data: {
title: "Find the property",
newAddressTitle:
"Click or tap at where the property is on the map and name it below",
allowNewAddresses: false,
newAddressDescription:
"You will need to select a location and provide a name to continue",
newAddressDescriptionLabel: "Name the site",
},
type: TYPES.FindProperty,
},
Notice: {
data: {
color: "#EFEFEF",
title: "End of test",
resetButton: true,
},
type: TYPES.Notice,
},
QJeTHUDzfz: {
data: {
text: "Something else",
flags: ["flag.pp.missingInfo"],
},
type: TYPES.Answer,
},
QuestionTwo: {
data: {
fn: "property.type",
tags: [],
text: "What type of residence is it?",
neverAutoAnswer: false,
},
type: TYPES.Question,
edges: ["4jSYMB7hBJ", "xHpGvCpm0y", "QJeTHUDzfz"],
},
oaF6TgEGZO: {
data: {
val: "residential",
text: "Residential",
flags: ["flag.pp.permittedDevelopment"],
},
type: TYPES.Answer,
edges: ["QuestionTwo"],
},
QuestionOne: {
data: {
fn: "property.type",
tags: [],
text: "What type of property is it?",
neverAutoAnswer: false,
},
type: TYPES.Question,
edges: ["oaF6TgEGZO", "tgP6NiYImY"],
},
tgP6NiYImY: {
data: {
text: "Something else",
flags: ["flag.pp.missingInfo"],
},
type: TYPES.Answer,
},
xHpGvCpm0y: {
data: {
val: "residential.flat",
text: "Flat",
flags: ["flag.pp.permissionNeeded"],
},
type: TYPES.Answer,
},
Result: {
data: {
flagSet: "Planning permission",
},
type: TYPES.Result,
},
};
27 changes: 18 additions & 9 deletions api.planx.uk/modules/flows/validate/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {
import {
ComponentType,
FlowGraph,
Node,
type FlowGraph,
type Node,
} from "@opensystemslab/planx-core/types";
import type { Entry } from "type-fest";

Expand All @@ -24,7 +24,11 @@ export const hasComponentType = (
);

if (fn) {
return nodeIds.some(([, nodeData]) => nodeData?.data?.fn === fn);
if (type === ComponentType.Answer) {
return nodeIds.some(([, nodeData]) => nodeData?.data?.val === fn);
} else {
return nodeIds.some(([, nodeData]) => nodeData?.data?.fn === fn);
}
}

return Boolean(nodeIds.length);
Expand All @@ -39,11 +43,16 @@ export const numberOfComponentType = (
(entry): entry is [string, Node] => isComponentType(entry, type),
);
if (fn) {
nodeIds
?.filter(([_nodeId, nodeData]) => nodeData?.data?.fn === fn)
?.map(([nodeId, _nodeData]) => nodeId);
if (type === ComponentType.Answer) {
return nodeIds
?.filter(([_nodeId, nodeData]) => nodeData?.data?.val === fn)
?.map(([nodeId, _nodeData]) => nodeId)?.length;
} else {
return nodeIds
?.filter(([_nodeId, nodeData]) => nodeData?.data?.fn === fn)
?.map(([nodeId, _nodeData]) => nodeId)?.length;
}
} else {
nodeIds?.map(([nodeId, _nodeData]) => nodeId);
return nodeIds?.map(([nodeId, _nodeData]) => nodeId)?.length;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

These changes are unrelated to the most recent planx-core change, but came across them when investigating why the validate.test.ts tests were still passing without a mock in this module - spotted a data field issue & additionally added test coverage ! (Data field issue does not impact current live usage of these helper functions, but likely would have cropped up next time we try to use elsewhere!)

return nodeIds?.length;
};
3 changes: 3 additions & 0 deletions api.planx.uk/modules/send/utils/exportZip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ vi.mock("@opensystemslab/planx-core", () => {
.fn()
.mockImplementation(() => "<p>application</p>"),
generateMapHTML: vi.fn().mockImplementation(() => "<p>map</p>"),
getValidSchemaValues: vi
.fn()
.mockImplementation(() => ["ldc", "ldc.p", "ldc.e", "pp", "pa"]),
};
});
const mockGenerateOneAppXML = vi
Expand Down
39 changes: 39 additions & 0 deletions api.planx.uk/modules/send/utils/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Passport } from "@opensystemslab/planx-core/types";

import { isApplicationTypeSupported } from "./helpers.js";

vi.mock("@opensystemslab/planx-core", () => {
return {
getValidSchemaValues: vi
.fn()
.mockImplementation(() => ["ldc", "ldc.p", "ldc.e", "pp", "pa"]),
};
});
Copy link
Member Author

@jessicamcinchak jessicamcinchak Jan 28, 2025

Choose a reason for hiding this comment

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

These mocks resolve questions raised earlier here: https://opensystemslab.slack.com/archives/C01E3AC0C03/p1737996349338569

When testing the route via supertest, then getValidSchemaValues and planx-core will be called "for real" and not require a mock (eg see modules/flows/validate/validate.test.ts >> describe("ODP Schema file type validation on diff"), but when simply unit testing like here we need to mock & include partial, realistic mockImplementation return values.


describe("isApplicationTypeSupported", () => {
beforeEach(() => {
vi.clearAllMocks();
});

test("returns true for statutory application types", () => {
const mockPassport: Passport = { data: { "application.type": ["ldc.p"] } };
expect(isApplicationTypeSupported(mockPassport)).toEqual(true);
});

test("return true for pre-applications", () => {
const mockPassport: Passport = { data: { "application.type": ["preApp"] } };
expect(isApplicationTypeSupported(mockPassport)).toEqual(true);
});

test("returns false for discretionary types", () => {
const mockPassport: Passport = { data: { "application.type": ["breach"] } };
expect(isApplicationTypeSupported(mockPassport)).toEqual(false);
});

test("returns false if passport does not have application.type key", () => {
const mockPassport: Passport = {
data: { "property.type": ["residential"] },
};
expect(isApplicationTypeSupported(mockPassport)).toEqual(false);
});
});
15 changes: 9 additions & 6 deletions api.planx.uk/modules/send/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getValidSchemaValues } from "@opensystemslab/planx-core";
import type { Passport } from "../../../types.js";

/**
Expand All @@ -6,12 +7,14 @@ import type { Passport } from "../../../types.js";
* @returns boolean
*/
export function isApplicationTypeSupported(passport: Passport): boolean {
// Prefixes of application types that are supported by the ODP Schema
// TODO in future look up via schema type definitions
const supportedAppTypes = ["ldc", "listed", "pa", "pp"];
const userApplicationType = passport.data?.["application.type"]?.[0];
if (!userApplicationType) return false;

const appType = passport.data?.["application.type"]?.[0];
const appTypePrefix = appType?.split(".")?.[0];
const statutoryApplicationTypes = getValidSchemaValues("ApplicationType");
const preApplicationType = "preApp";
const supportedApplicationTypes = (statutoryApplicationTypes || []).concat(
preApplicationType,
);

return supportedAppTypes.includes(appTypePrefix);
return supportedApplicationTypes.includes(userApplicationType);
}
2 changes: 1 addition & 1 deletion api.planx.uk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@airbrake/node": "^2.1.8",
"@aws-sdk/client-s3": "^3.696.0",
"@aws-sdk/s3-request-presigner": "^3.701.0",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#01d3dc6",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#6f16516",
"@types/isomorphic-fetch": "^0.0.36",
"adm-zip": "^0.5.10",
"axios": "^1.7.4",
Expand Down
10 changes: 5 additions & 5 deletions api.planx.uk/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/tests/api-driven/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"packageManager": "[email protected]",
"dependencies": {
"@cucumber/cucumber": "^11.1.1",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#01d3dc6",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#6f16516",
"axios": "^1.7.4",
"dotenv": "^16.3.1",
"dotenv-expand": "^10.0.0",
Expand Down
12 changes: 6 additions & 6 deletions e2e/tests/api-driven/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/tests/ui-driven/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"type": "module",
"dependencies": {
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#01d3dc6",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#6f16516",
"axios": "^1.7.4",
"dotenv": "^16.3.1",
"eslint": "^8.56.0",
Expand Down
10 changes: 5 additions & 5 deletions e2e/tests/ui-driven/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion editor.planx.uk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@mui/material": "^5.15.10",
"@mui/utils": "^5.15.11",
"@opensystemslab/map": "1.0.0-alpha.4",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#01d3dc6",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#6f16516",
"@tiptap/core": "^2.4.0",
"@tiptap/extension-bold": "^2.0.3",
"@tiptap/extension-bubble-menu": "^2.1.13",
Expand Down
Loading
Loading