Skip to content

Commit

Permalink
update fn for checking stat app and adjust files
Browse files Browse the repository at this point in the history
  • Loading branch information
RODO94 committed Jan 29, 2025
1 parent 1e507b6 commit b682d58
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 265 deletions.
95 changes: 95 additions & 0 deletions api.planx.uk/modules/flows/publish/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
ComponentType as TYPES,
type FlowGraph,
} from "@opensystemslab/planx-core/types";
import { hasStatutoryApplicationType } from "./helpers.js";

const mockStatutoryFlow: FlowGraph = {
_root: {
edges: ["QuestionOne", "Send"],
},
QuestionTwo: {
data: {
fn: "application.type",
text: "What type of application is it?",
neverAutoAnswer: false,
},
type: TYPES.Question,
edges: [
"AnswerWithDiscretionaryApplicationValue",
"AnswerWithStatutoryApplicationValue",
"VeeQdrkcef",
],
},
AnswerWithDiscretionaryApplicationValue: {
data: {
val: "findOut",
text: "Find out if",
},
type: TYPES.Answer,
},
VeeQdrkcef: {
data: {
text: "Something else",
},
type: TYPES.Answer,
},
AnswerWithStatutoryApplicationValue: {
data: {
val: "ldc",
text: "LDC",
},
type: TYPES.Answer,
},
QuestionOne: {
type: TYPES.Question,
data: {
text: "Branching question",
neverAutoAnswer: false,
},
edges: ["7lDopQVOjk", "V5ZV8milBj"],
},
"7lDopQVOjk": {
type: TYPES.Answer,
data: {
text: "Left",
},
edges: ["QuestionTwo"],
},
V5ZV8milBj: {
type: TYPES.Answer,
data: {
text: "Right",
},
},
Send: {
type: TYPES.Send,
data: {
title: "Send to email",
destinations: ["email"],
},
},
};

const mockStatutoryFlowWithoutSend = { ...mockStatutoryFlow };
delete mockStatutoryFlowWithoutSend["Send"];

describe("hasStatutoryApplicationPath", () => {
test("returns false for a flow that doesn't have a Send", () => {
expect(hasStatutoryApplicationType(mockStatutoryFlowWithoutSend)).toEqual(
false,
);
});

test.todo("returns false for a flow with Send but not any application.type");

test.todo(
"returns false for a flow with Send but only discretionary application.type values",
);

test("returns true for a flow with Send and at least one statutory application.type value", () => {
expect(hasStatutoryApplicationType(mockStatutoryFlow)).toEqual(true);
});
});

// TODO also add mocks which use SetValue, etc
45 changes: 45 additions & 0 deletions api.planx.uk/modules/flows/publish/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
ComponentType,
type FlowGraph,
} from "@opensystemslab/planx-core/types";
import { hasComponentType } from "../validate/helpers.js";
import { getValidSchemaValues } from "@opensystemslab/planx-core";

export const hasStatutoryApplicationType = (flattenedFlow: FlowGraph) => {
const hasSendComponent = hasComponentType(flattenedFlow, ComponentType.Send);
if (!hasSendComponent) return false;

const statutoryApplicationTypes = getValidSchemaValues("ApplicationType");
if (!statutoryApplicationTypes) return false;

let isStatutoryApplication = false;
Object.entries(flattenedFlow).some(([nodeId, _nodeData]) => {
const nodeToCheck = flattenedFlow[nodeId];

// Only continue if application.type exists in a Node
if (nodeToCheck?.data?.fn === "application.type") {
// Check SetValue as data.val will be in node, not edge
if (typeof nodeToCheck.data?.val === "string") {
isStatutoryApplication = statutoryApplicationTypes.includes(
nodeToCheck.data?.val,
);
return isStatutoryApplication;
}

// Check other Nodes which have Edges
if (nodeToCheck.edges) {
// Loop through each edge and check the value
nodeToCheck.edges.some((edge) => {
const edgeData = flattenedFlow[edge].data;
if (typeof edgeData?.val === "string") {
isStatutoryApplication = statutoryApplicationTypes.includes(
edgeData.val,
);
return isStatutoryApplication;
}
});
}
}
});
return isStatutoryApplication;
};
212 changes: 4 additions & 208 deletions api.planx.uk/modules/flows/publish/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import { authHeader, getTestJWT } from "../../../tests/mockJWT.js";
import app from "../../../server.js";
import { userContext } from "../../auth/middleware.js";
import { mockFlowData } from "../../../tests/mocks/validateAndPublishMocks.js";
import {
applicationTypeFail,
checklistApplicationTypePass,
questionApplicationTypePass,
setValueApplicationTypePass,
} from "../../../tests/mocks/applicationTypeCheckMocks.js";
import * as applicationTypes from "./service/applicationTypes.js";

beforeAll(() => {
const getStoreMock = vi.spyOn(userContext, "getStore");
Expand Down Expand Up @@ -89,7 +82,10 @@ describe("publish", () => {
},
},
});
await supertest(app).post("/flows/1/publish").set(auth).expect(200);
await supertest(app)
.post("/flows/1/publish")
.set(authHeader({ role: "platformAdmin" }))
.expect(200);
});

it("does not update if there are no new changes", async () => {
Expand Down Expand Up @@ -185,203 +181,3 @@ describe("publish", () => {
});
});
});

describe("how 'is_statutory_application_Type' is updated when a service is published", () => {
beforeEach(() => {
const getStoreMock = vi.spyOn(userContext, "getStore");
getStoreMock.mockReturnValue({
user: {
sub: "123",
jwt: getTestJWT({ role: "teamEditor" }),
},
});
});
it("checks that is_statutory_application_type is true for SetValue component", async () => {
const checkStatutoryApplicationMock = vi.spyOn(
applicationTypes,
"checkStatutoryApplicationTypes",
);

const alteredFlow = {
...mockFlowData,
...setValueApplicationTypePass,
};

queryMock.mockQuery({
name: "GetFlowData",
matchOnVariables: false,
data: {
flow: {
data: alteredFlow,
slug: "stat-app-set-value",
team_id: 1,
team: {
slug: "testing",
},
publishedFlows: [{ data: alteredFlow }],
},
},
});

queryMock.mockQuery({
name: "PublishFlow",
matchOnVariables: false,
data: {
publishedFlow: {
data: alteredFlow,
},
},
});

await supertest(app)
.post("/flows/1/publish")
.set(auth)
.expect(200)
.then(() => {
const [isStatutoryApplicationType] =
checkStatutoryApplicationMock.mock.results;
expect(isStatutoryApplicationType.value).toEqual(true);
});
});
it("checks whether is_statutory_application_type is true for Checklist component", async () => {
const checkStatutoryApplicationMock = vi.spyOn(
applicationTypes,
"checkStatutoryApplicationTypes",
);

const alteredFlow = {
...mockFlowData,
...checklistApplicationTypePass,
};

queryMock.mockQuery({
name: "GetFlowData",
matchOnVariables: false,
data: {
flow: {
data: alteredFlow,
slug: "stat-app-checklist",
team_id: 1,
team: {
slug: "testing",
},
publishedFlows: [{ data: alteredFlow }],
},
},
});

queryMock.mockQuery({
name: "PublishFlow",
matchOnVariables: false,
data: {
publishedFlow: {
data: alteredFlow,
},
},
});

await supertest(app)
.post("/flows/1/publish")
.set(auth)
.expect(200)
.then(() => {
const [isStatutoryApplicationType] =
checkStatutoryApplicationMock.mock.results;
expect(isStatutoryApplicationType.value).toEqual(true);
});
});
it("checks is_statutory_application_type is true for Question component", async () => {
const checkStatutoryApplicationMock = vi.spyOn(
applicationTypes,
"checkStatutoryApplicationTypes",
);

const alteredFlow = {
...mockFlowData,
...questionApplicationTypePass,
};

queryMock.mockQuery({
name: "GetFlowData",
matchOnVariables: false,
data: {
flow: {
data: alteredFlow,
slug: "stat-app-question",
team_id: 1,
team: {
slug: "testing",
},
publishedFlows: [{ data: alteredFlow }],
},
},
});

queryMock.mockQuery({
name: "PublishFlow",
matchOnVariables: false,
data: {
publishedFlow: {
data: alteredFlow,
},
},
});

await supertest(app)
.post("/flows/1/publish")
.set(auth)
.expect(200)
.then(() => {
const [isStatutoryApplicationType] =
checkStatutoryApplicationMock.mock.results;
expect(isStatutoryApplicationType.value).toEqual(true);
});
});
it("checks is_statutory_application_type is false when no application type matches schema", async () => {
const checkStatutoryApplicationMock = vi.spyOn(
applicationTypes,
"checkStatutoryApplicationTypes",
);

const alteredFlow = {
...mockFlowData,
...applicationTypeFail,
};

queryMock.mockQuery({
name: "GetFlowData",
matchOnVariables: false,
data: {
flow: {
data: alteredFlow,
slug: "stat-app-fail",
team_id: 1,
team: {
slug: "testing",
},
publishedFlows: [{ data: alteredFlow }],
},
},
});

queryMock.mockQuery({
name: "PublishFlow",
matchOnVariables: false,
data: {
publishedFlow: {
data: alteredFlow,
},
},
});

await supertest(app)
.post("/flows/1/publish")
.set(auth)
.expect(200)
.then(() => {
const [isStatutoryApplicationType] =
checkStatutoryApplicationMock.mock.results;
expect(isStatutoryApplicationType.value).toEqual(false);
});
});
});
Loading

0 comments on commit b682d58

Please sign in to comment.