Skip to content

Commit 1c2f272

Browse files
authored
fix: Add tests for various activities (#5)
1 parent 81d7367 commit 1c2f272

4 files changed

Lines changed: 255 additions & 3 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { AuthenticateApp, AuthenticateAppInputs } from "../AuthenticateApp";
2+
3+
// Restore global fetch
4+
const originalFetch = global.fetch;
5+
afterEach(() => {
6+
global.fetch = originalFetch;
7+
});
8+
9+
const mockFetch = jest.fn();
10+
11+
function mockResponseOnce(
12+
response: Record<string, unknown>,
13+
callback?: (input: RequestInfo, init: RequestInit) => void
14+
) {
15+
global.fetch = mockFetch;
16+
mockFetch.mockImplementationOnce((input, init) => {
17+
callback?.(input, init);
18+
return Promise.resolve({
19+
ok: true,
20+
json: () => Promise.resolve(response),
21+
status: 200,
22+
statusText: "OK",
23+
});
24+
});
25+
}
26+
27+
describe("AuthenticateApp", () => {
28+
describe("execute", () => {
29+
it("requires url input", async () => {
30+
const activity = new AuthenticateApp();
31+
const inputs: AuthenticateAppInputs = {
32+
url: "",
33+
companyAccount: "c",
34+
appName: "a",
35+
secret: "s"
36+
};
37+
38+
await expect(() => activity.execute(inputs)).rejects.toThrow("url is required");
39+
});
40+
it("requires companyAccount input", async () => {
41+
const activity = new AuthenticateApp();
42+
const inputs: AuthenticateAppInputs = {
43+
url: "https://test",
44+
companyAccount: "",
45+
appName: "a",
46+
secret: "s"
47+
};
48+
49+
await expect(() => activity.execute(inputs)).rejects.toThrow("companyAccount is required");
50+
});
51+
it("requires appName input", async () => {
52+
const activity = new AuthenticateApp();
53+
const inputs: AuthenticateAppInputs = {
54+
url: "https://test",
55+
companyAccount: "a",
56+
appName: "",
57+
secret: "s"
58+
};
59+
60+
await expect(() => activity.execute(inputs)).rejects.toThrow("appName is required");
61+
});
62+
it("requires secret input", async () => {
63+
const activity = new AuthenticateApp();
64+
const inputs: AuthenticateAppInputs = {
65+
url: "https://test",
66+
companyAccount: "c",
67+
appName: "a",
68+
secret: ""
69+
};
70+
71+
await expect(() => activity.execute(inputs)).rejects.toThrow("secret is required");
72+
});
73+
it("calls the API using POST", async () => {
74+
const activity = new AuthenticateApp();
75+
const inputs: AuthenticateAppInputs = {
76+
url: "https://test",
77+
companyAccount: "c",
78+
appName: "a",
79+
secret: "s"
80+
};
81+
const authResponse = { foo: "bar" };
82+
83+
mockResponseOnce(authResponse, (input, init) => {
84+
expect(input).toBe(`https://test/api/token/app`);
85+
expect(init.method).toBe("post");
86+
expect(init.headers?.["content-type"]).toBe("application/json");
87+
if (typeof init.body === "string") {
88+
expect(JSON.parse(init.body)).toStrictEqual({
89+
appName: "a",
90+
companyAccount: "c",
91+
secret: "s"
92+
});
93+
} else {
94+
fail("body was not a string")
95+
}
96+
});
97+
98+
const result = await activity.execute(inputs);
99+
expect(result).toStrictEqual({
100+
service: {
101+
url: inputs.url,
102+
...authResponse,
103+
}
104+
})
105+
});
106+
});
107+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { AuthenticateUser, AuthenticateUserInputs } from "../AuthenticateUser";
2+
3+
// Restore global fetch
4+
const originalFetch = global.fetch;
5+
afterEach(() => {
6+
global.fetch = originalFetch;
7+
});
8+
9+
const mockFetch = jest.fn();
10+
11+
function mockResponseOnce(
12+
response: Record<string, unknown>,
13+
callback?: (input: RequestInfo, init: RequestInit) => void
14+
) {
15+
global.fetch = mockFetch;
16+
mockFetch.mockImplementationOnce((input, init) => {
17+
callback?.(input, init);
18+
return Promise.resolve({
19+
ok: true,
20+
json: () => Promise.resolve(response),
21+
status: 200,
22+
statusText: "OK",
23+
});
24+
});
25+
}
26+
27+
describe("AuthenticateUser", () => {
28+
describe("execute", () => {
29+
it("requires url input", async () => {
30+
const activity = new AuthenticateUser();
31+
const inputs: AuthenticateUserInputs = {
32+
url: "",
33+
username: "u",
34+
password: "p",
35+
};
36+
37+
await expect(() => activity.execute(inputs)).rejects.toThrow("url is required");
38+
});
39+
it("requires username input", async () => {
40+
const activity = new AuthenticateUser();
41+
const inputs: AuthenticateUserInputs = {
42+
url: "https://test",
43+
username: "",
44+
password: "p",
45+
};
46+
47+
await expect(() => activity.execute(inputs)).rejects.toThrow("username is required");
48+
});
49+
it("requires password input", async () => {
50+
const activity = new AuthenticateUser();
51+
const inputs: AuthenticateUserInputs = {
52+
url: "https://test",
53+
username: "u",
54+
password: "",
55+
};
56+
57+
await expect(() => activity.execute(inputs)).rejects.toThrow("password is required");
58+
});
59+
it("calls the API using POST", async () => {
60+
const activity = new AuthenticateUser();
61+
const inputs: AuthenticateUserInputs = {
62+
url: "https://test",
63+
username: "u",
64+
password: "p",
65+
};
66+
const authResponse = { foo: "bar" };
67+
68+
mockResponseOnce(authResponse, (input, init) => {
69+
expect(input).toBe(`https://test/api/token/user`);
70+
expect(init.method).toBe("post");
71+
expect(init.headers?.["content-type"]).toBe("application/json");
72+
if (typeof init.body === "string") {
73+
expect(JSON.parse(init.body)).toStrictEqual({
74+
username: "u",
75+
password: "p",
76+
});
77+
} else {
78+
fail("body was not a string")
79+
}
80+
});
81+
82+
const result = await activity.execute(inputs);
83+
expect(result).toStrictEqual({
84+
service: {
85+
url: inputs.url,
86+
...authResponse,
87+
}
88+
})
89+
});
90+
});
91+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { CreateServiceOrder, CreateServiceOrderInputs } from "../CreateServiceOrder";
2+
import { ApiService } from "../../ApiService";
3+
import { post } from "../../request";
4+
5+
jest.mock("../../request");
6+
const mockPost = post as jest.MockedFunction<typeof post>;
7+
8+
describe("CreateServiceOrder", () => {
9+
describe("execute", () => {
10+
it("requires service input", async () => {
11+
const activity = new CreateServiceOrder();
12+
await expect(() => activity.execute({
13+
service: undefined as any,
14+
templateId: 1,
15+
userId: 1,
16+
divisionId: 1,
17+
coreObjectKey: "1"
18+
})).rejects.toThrow("service is required");
19+
});
20+
it("requires templateId input", async () => {
21+
const activity = new CreateServiceOrder();
22+
await expect(() => activity.execute({
23+
service: {} as any,
24+
templateId: undefined as any,
25+
userId: 1,
26+
divisionId: 1,
27+
coreObjectKey: "1"
28+
})).rejects.toThrow("templateId is required");
29+
});
30+
it("calls the API using POST", async () => {
31+
const inputs: CreateServiceOrderInputs = {
32+
service: {} as any,
33+
templateId: 1,
34+
userId: 1,
35+
divisionId: 1,
36+
coreObjectKey: "1"
37+
};
38+
const result = { foo: "bar" };
39+
mockPost.mockImplementationOnce((service: ApiService, path: string, data?: Record<string, any>) => {
40+
expect(service).toBe(inputs.service);
41+
expect(path).toBe("workmanagement/serviceorders/templates/generate");
42+
expect(data).toMatchObject({
43+
coreObjectKey: inputs.coreObjectKey,
44+
divisionID: inputs.divisionId,
45+
templateID: inputs.templateId,
46+
userID: inputs.userId,
47+
})
48+
return Promise.resolve(result);
49+
})
50+
const activity = new CreateServiceOrder();
51+
expect(await activity.execute(inputs)).toStrictEqual({ result });
52+
});
53+
});
54+
});

src/request.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ApiService } from "./ApiService";
33
export async function get<T = any>(
44
service: ApiService,
55
path: string,
6-
params?: { [key: string]: any }
6+
params?: Record<string, string | number | boolean | null | undefined>
77
): Promise<T> {
88
if (!service.url) {
99
throw new Error("url is required");
@@ -23,7 +23,7 @@ export async function get<T = any>(
2323
export async function post<T = any>(
2424
service: ApiService,
2525
path: string,
26-
data?: { [key: string]: any }
26+
data?: Record<string, any>
2727
): Promise<T> {
2828
if (!service.url) {
2929
throw new Error("url is required");
@@ -42,7 +42,7 @@ export async function post<T = any>(
4242
return response;
4343
}
4444

45-
function objectToQueryString(data?: Record<string, string | number | boolean>): string {
45+
function objectToQueryString(data?: Record<string, string | number | boolean | null | undefined>): string {
4646
if (!data) {
4747
return "";
4848
}

0 commit comments

Comments
 (0)