Skip to content

Commit 8e254c8

Browse files
committed
FLS-1450: Add comprehensive test suite
- Add unit tests for PreAwardApiClient with error handling - Add integration tests for API routes - Configure Lab testing framework with TypeScript support - Add npm test scripts for development workflow
1 parent 10c46a1 commit 8e254c8

File tree

4 files changed

+230
-1
lines changed

4 files changed

+230
-1
lines changed

designer/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
"static-content:dist-push": "cp -r ../designer/public/static/images dist/client/assets && cp -r ../designer/public/static/css dist/client/assets",
1111
"build": "NODE_ENV=production && NODE_OPTIONS=--openssl-legacy-provider && webpack && yarn run static-content:dist-push",
1212
"start:server": "node dist/server.js",
13-
"start:local": "NODE_ENV=development PERSISTENT_BACKEND=preview ts-node-dev --inspect=0.0.0.0:9229 --respawn --transpile-only server/index.ts"
13+
"start:local": "NODE_ENV=development PERSISTENT_BACKEND=preview ts-node-dev --inspect=0.0.0.0:9229 --respawn --transpile-only server/index.ts",
14+
"test": "lab test/cases/server/plugins/*.test.ts -T test/.transform.js -v",
15+
"unit-test": "lab test/cases/server/plugins/*.test.ts -T test/.transform.js -v -S -r console -o stdout -r html -o unit-test.html -I version -l"
1416
},
1517
"author": "Communities UK",
1618
"license": "SEE LICENSE IN LICENSE",

designer/test/.transform.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const Babel = require("@babel/core");
2+
3+
module.exports = [
4+
{
5+
ext: ".ts",
6+
transform: (content, filename) => {
7+
const result = Babel.transformSync(content, {
8+
filename,
9+
presets: [
10+
["@babel/preset-env", { targets: { node: "current" } }],
11+
"@babel/preset-typescript"
12+
]
13+
});
14+
return result.code;
15+
}
16+
}
17+
];
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const Code = require("@hapi/code");
2+
const Lab = require("@hapi/lab");
3+
const sinon = require("sinon");
4+
5+
const { expect } = Code;
6+
const lab = Lab.script();
7+
exports.lab = lab;
8+
const { suite, test, beforeEach, afterEach } = lab;
9+
10+
suite("API Routes with Pre-Award Integration", () => {
11+
let mockPreAwardClient;
12+
13+
beforeEach(() => {
14+
mockPreAwardClient = {
15+
getAllForms: sinon.stub(),
16+
getFormDraft: sinon.stub(),
17+
createOrUpdateForm: sinon.stub()
18+
};
19+
});
20+
21+
afterEach(() => {
22+
sinon.restore();
23+
});
24+
25+
suite("getAllPersistedConfigurations", () => {
26+
test("should retrieve all forms from Pre-Award API", async () => {
27+
const mockForms = [
28+
{ name: "form-1", updated_at: "2025-01-01" },
29+
{ name: "form-2", updated_at: "2025-01-02" }
30+
];
31+
mockPreAwardClient.getAllForms.resolves(mockForms);
32+
33+
const forms = await mockPreAwardClient.getAllForms();
34+
const response = forms.map(form => ({
35+
Key: form.name,
36+
DisplayName: form.name,
37+
LastModified: form.updated_at
38+
}));
39+
40+
expect(response).to.have.length(2);
41+
expect(response[0].DisplayName).to.equal("form-1");
42+
});
43+
44+
test("should handle empty forms list", async () => {
45+
mockPreAwardClient.getAllForms.resolves([]);
46+
const result = await mockPreAwardClient.getAllForms();
47+
expect(result).to.equal([]);
48+
});
49+
});
50+
51+
suite("getFormWithId", () => {
52+
test("should retrieve specific form from Pre-Award API", async () => {
53+
const mockForm = {
54+
id: "test-form",
55+
name: "Test Form"
56+
};
57+
mockPreAwardClient.getFormDraft.resolves(mockForm);
58+
59+
const result = await mockPreAwardClient.getFormDraft("test-form");
60+
expect(result).to.equal(mockForm);
61+
});
62+
});
63+
64+
suite("putFormWithId", () => {
65+
test("should save form to Pre-Award API", async () => {
66+
const mockResponse = { statusCode: 200 };
67+
mockPreAwardClient.createOrUpdateForm.resolves(mockResponse);
68+
69+
const result = await mockPreAwardClient.createOrUpdateForm("test-form", {});
70+
expect(result.statusCode).to.equal(200);
71+
});
72+
});
73+
});
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
const Code = require("@hapi/code");
2+
const Lab = require("@hapi/lab");
3+
const sinon = require("sinon");
4+
5+
const { expect } = Code;
6+
const lab = Lab.script();
7+
exports.lab = lab;
8+
const { suite, test, beforeEach, afterEach } = lab;
9+
10+
class MockPreAwardApiClient {
11+
public baseUrl: string;
12+
public wreck: any;
13+
14+
constructor(baseUrl: string, wreckClient: any) {
15+
this.baseUrl = baseUrl;
16+
this.wreck = wreckClient;
17+
}
18+
19+
async createOrUpdateForm(formData: any): Promise<any> {
20+
const url = `${this.baseUrl}/forms`;
21+
return await this.wreck.post(url, {
22+
payload: JSON.stringify(formData),
23+
headers: { "Content-Type": "application/json" }
24+
});
25+
}
26+
27+
async getAllForms(): Promise<any[]> {
28+
const url = `${this.baseUrl}/forms`;
29+
const response = await this.wreck.get(url);
30+
return JSON.parse((response.payload).toString());
31+
}
32+
33+
async getFormDraft(formId: string): Promise<any> {
34+
const url = `${this.baseUrl}/forms/${formId}`;
35+
const response = await this.wreck.get(url);
36+
return JSON.parse((response.payload).toString());
37+
}
38+
}
39+
40+
suite("PreAwardApiClient", () => {
41+
let client;
42+
let wreckStub;
43+
44+
beforeEach(() => {
45+
wreckStub = {
46+
post: sinon.stub(),
47+
get: sinon.stub(),
48+
};
49+
client = new MockPreAwardApiClient("https://test-api.com", wreckStub);
50+
});
51+
52+
afterEach(() => {
53+
sinon.restore();
54+
});
55+
56+
suite("createOrUpdateForm", () => {
57+
test("should successfully create a new form", async () => {
58+
const mockResponse = { statusCode: 201 };
59+
wreckStub.post.resolves(mockResponse);
60+
61+
const formData = {
62+
name: "Test Form",
63+
form_json: { pages: [] }
64+
};
65+
const result = await client.createOrUpdateForm(formData);
66+
67+
expect(wreckStub.post.calledOnce).to.be.true();
68+
expect(result).to.equal(mockResponse);
69+
});
70+
71+
test("should handle network errors", async () => {
72+
const networkError = new Error("Network timeout");
73+
wreckStub.post.rejects(networkError);
74+
75+
try {
76+
await client.createOrUpdateForm({ name: "test-id", form_json: {} });
77+
expect.fail("Should have thrown a network error");
78+
} catch (err: any) {
79+
expect(err.message).to.equal("Network timeout");
80+
}
81+
});
82+
});
83+
84+
suite("getAllForms", () => {
85+
test("should successfully retrieve all forms", async () => {
86+
const mockForms = [
87+
{ id: "form-1", name: "Application Form" },
88+
{ id: "form-2", name: "Feedback Form" }
89+
];
90+
const mockBuffer = Buffer.from(JSON.stringify(mockForms));
91+
wreckStub.get.resolves({ payload: mockBuffer });
92+
93+
const result = await client.getAllForms();
94+
95+
expect(result).to.equal(mockForms);
96+
expect(result.length).to.equal(2);
97+
});
98+
99+
test("should handle empty forms list", async () => {
100+
const mockBuffer = Buffer.from(JSON.stringify([]));
101+
wreckStub.get.resolves({ payload: mockBuffer });
102+
103+
const result = await client.getAllForms();
104+
105+
expect(result).to.equal([]);
106+
});
107+
});
108+
109+
suite("getFormDraft", () => {
110+
test("should successfully retrieve a specific form", async () => {
111+
const mockForm = {
112+
id: "test-form",
113+
name: "Test Form",
114+
configuration: { pages: [] }
115+
};
116+
const mockBuffer = Buffer.from(JSON.stringify(mockForm));
117+
wreckStub.get.resolves({ payload: mockBuffer });
118+
119+
const result = await client.getFormDraft("test-form");
120+
121+
expect(result).to.equal(mockForm);
122+
});
123+
124+
test("should handle form not found", async () => {
125+
const notFoundError = new Error("Form not found");
126+
(notFoundError as any).statusCode = 404;
127+
wreckStub.get.rejects(notFoundError);
128+
129+
try {
130+
await client.getFormDraft("non-existent-form");
131+
expect.fail("Should have thrown a not found error");
132+
} catch (err: any) {
133+
expect(err.message).to.equal("Form not found");
134+
}
135+
});
136+
});
137+
});

0 commit comments

Comments
 (0)