-
Notifications
You must be signed in to change notification settings - Fork 2
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
[api] migrate testing framework (Jest > Vitest) #3555
Changes from all commits
a741b75
b05151b
7b7b41c
5702e3f
c870585
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,40 @@ | ||
import { createScheduledEvent, RequiredScheduledEventArgs } from "./index.js"; | ||
import Axios, { AxiosError } from "axios"; | ||
import axios from "axios"; | ||
import type { Mocked } from "vitest"; | ||
|
||
jest.mock("axios", () => ({ | ||
...jest.requireActual("axios"), | ||
post: jest.fn(), | ||
})); | ||
const mockAxios = Axios as jest.Mocked<typeof Axios>; | ||
describe("Creation of scheduled event", () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrapped tests which I adapted in a |
||
vi.mock("axios", async (importOriginal) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. vitest has this Could also have used |
||
const actualAxios = await importOriginal<typeof import("axios")>(); | ||
return { | ||
default: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Vitest does not assume, like jest, that a returned object is the |
||
...actualAxios, | ||
post: vi.fn(), | ||
}, | ||
}; | ||
}); | ||
const mockAxios = axios as Mocked<typeof axios>; | ||
|
||
const mockScheduledEvent: RequiredScheduledEventArgs = { | ||
webhook: "test url", | ||
schedule_at: new Date(), | ||
comment: "test comment", | ||
payload: {}, | ||
}; | ||
const mockScheduledEvent: RequiredScheduledEventArgs = { | ||
webhook: "test url", | ||
schedule_at: new Date(), | ||
comment: "test comment", | ||
payload: {}, | ||
}; | ||
|
||
test("createScheduledEvent returns an error if request fails", async () => { | ||
mockAxios.post.mockRejectedValue(new Error()); | ||
await expect(createScheduledEvent(mockScheduledEvent)).rejects.toThrow(); | ||
}); | ||
test("returns an error if request fails", async () => { | ||
mockAxios.post.mockRejectedValue(new Error()); | ||
await expect(createScheduledEvent(mockScheduledEvent)).rejects.toThrow(); | ||
}); | ||
|
||
test("createScheduledEvent returns an error if Axios errors", async () => { | ||
mockAxios.post.mockRejectedValue(new AxiosError()); | ||
await expect(createScheduledEvent(mockScheduledEvent)).rejects.toThrow(); | ||
}); | ||
test("returns an error if axios errors", async () => { | ||
mockAxios.post.mockRejectedValue(new axios.AxiosError()); | ||
await expect(createScheduledEvent(mockScheduledEvent)).rejects.toThrow(); | ||
}); | ||
|
||
test("createScheduledEvent returns response data on success", async () => { | ||
mockAxios.post.mockResolvedValue({ data: "test data" }); | ||
await expect(createScheduledEvent(mockScheduledEvent)).resolves.toBe( | ||
"test data", | ||
); | ||
test("returns response data on success", async () => { | ||
mockAxios.post.mockResolvedValue({ data: "test data" }); | ||
await expect(createScheduledEvent(mockScheduledEvent)).resolves.toBe( | ||
"test data", | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,33 @@ | ||
import { runSQL } from "./index.js"; | ||
import Axios, { AxiosError } from "axios"; | ||
import axios from "axios"; | ||
import type { Mocked } from "vitest"; | ||
|
||
jest.mock("axios", () => ({ | ||
...jest.requireActual("axios"), | ||
post: jest.fn(), | ||
})); | ||
const mockAxios = Axios as jest.Mocked<typeof Axios>; | ||
describe("runSQL", () => { | ||
vi.mock("axios", async (importOriginal) => { | ||
const actualAxios = await importOriginal<typeof import("axios")>(); | ||
return { | ||
default: { | ||
...actualAxios, | ||
post: vi.fn(), | ||
}, | ||
}; | ||
}); | ||
const mockAxios = axios as Mocked<typeof axios>; | ||
|
||
const sql = "SELECT * FROM TEST"; | ||
const sql = "SELECT * FROM TEST"; | ||
|
||
test("runSQL returns an error if request fails", async () => { | ||
mockAxios.post.mockRejectedValue(new Error()); | ||
await expect(runSQL(sql)).rejects.toThrow(); | ||
}); | ||
test("returns an error if request fails", async () => { | ||
mockAxios.post.mockRejectedValue(new Error()); | ||
await expect(runSQL(sql)).rejects.toThrow(); | ||
}); | ||
|
||
test("runSQL returns an error if Axios errors", async () => { | ||
mockAxios.post.mockRejectedValue(new AxiosError()); | ||
await expect(runSQL(sql)).rejects.toThrow(); | ||
}); | ||
test("returns an error if Axios errors", async () => { | ||
mockAxios.post.mockRejectedValue(new axios.AxiosError()); | ||
await expect(runSQL(sql)).rejects.toThrow(); | ||
}); | ||
|
||
test("runSQL returns response data on success", async () => { | ||
mockAxios.post.mockResolvedValue({ data: "test data" }); | ||
await expect(runSQL(sql)).resolves.toBe("test data"); | ||
test("returns response data on success", async () => { | ||
mockAxios.post.mockResolvedValue({ data: "test data" }); | ||
await expect(runSQL(sql)).resolves.toBe("test data"); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ import { sendEmail } from "./index.js"; | |
import { NotifyClient } from "notifications-node-client"; | ||
import { NotifyConfig } from "../../types.js"; | ||
|
||
jest.mock("notifications-node-client"); | ||
vi.mock("notifications-node-client"); | ||
|
||
const TEST_EMAIL = "[email protected]"; | ||
const mockConfig: NotifyConfig = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,16 +5,16 @@ import { authHeader } from "../../../tests/mockJWT.js"; | |
const endpoint = (strings: TemplateStringsArray) => | ||
`/admin/session/${strings[0]}/csv`; | ||
|
||
const mockGenerateCSVData = jest.fn().mockResolvedValue([ | ||
const mockGenerateCSVData = vi.fn().mockResolvedValue([ | ||
{ | ||
question: "Is this a test?", | ||
responses: [{ value: "Yes" }], | ||
metadata: {}, | ||
}, | ||
]); | ||
jest.mock("@opensystemslab/planx-core", () => { | ||
vi.mock("@opensystemslab/planx-core", () => { | ||
return { | ||
CoreDomainClient: jest.fn().mockImplementation(() => ({ | ||
CoreDomainClient: vi.fn().mockImplementation(() => ({ | ||
export: { | ||
csvData: () => mockGenerateCSVData(), | ||
}, | ||
|
@@ -23,7 +23,9 @@ jest.mock("@opensystemslab/planx-core", () => { | |
}); | ||
|
||
describe("CSV data admin endpoint", () => { | ||
afterEach(() => jest.clearAllMocks()); | ||
afterEach(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hooks like |
||
vi.clearAllMocks(); | ||
}); | ||
const auth = authHeader({ role: "platformAdmin" }); | ||
|
||
it("requires a user to be logged in", async () => { | ||
|
Unchanged files with check annotations Beta
if (template === "save") | ||
returnValue.expiryDate = config.personalisation.expiryDate; | ||
return returnValue; | ||
} catch (error: any) { | ||
const notifyError = error?.response?.data?.errors?.length | ||
? JSON.stringify(error?.response?.data?.errors?.[0]) | ||
: error?.message; |
return done({ | ||
status: 404, | ||
message: `User (${email}) not found. Do you need to log in to a different Google Account?`, | ||
} as any); | ||
} | ||
done(null, { jwt }); |
const uploadAndLabelFileTypes = uploadAndLabelNodes | ||
.map(([_nodeId, node]: [string, Node]) => node.data?.fileTypes) | ||
.flat(); | ||
return uploadAndLabelFileTypes?.map((file: any) => file?.fn as string); | ||
}; | ||
export { validateFileTypes }; |
fn: PASSPORT_FN, | ||
value: true, | ||
text: `is on a Classified Road`, | ||
data: features.map((feature: any) => ({ | ||
name: `${feature.properties["RoadName1"]} - ${feature.properties["RoadClassification"]}`, | ||
entity: feature.properties["GmlID"], // match Planning Data "entity" identifier for convenience when reporting inaccurate constraints | ||
properties: feature.properties, | ||
}, | ||
} as GISResponse); | ||
} | ||
} catch (error: any) { | ||
return next({ | ||
message: "Failed to fetch classified roads: " + error?.message, | ||
}); |
options, | ||
)}${datasets}`; | ||
const res = await fetch(url) | ||
.then((response: { json: () => any }) => response.json()) | ||
.catch((error: any) => console.log(error)); | ||
// if analytics are "on", store an audit record of the raw response | ||
if (extras?.analytics !== "false") { | ||
// check for & add any 'positive' constraints to the formattedResult | ||
let formattedResult: Record<string, Constraint> = {}; | ||
if (res && res.count > 0 && res.entities) { | ||
res.entities.forEach((entity: { dataset: any }) => { | ||
// get the planx variable that corresponds to this entity's 'dataset', should never be null because our initial request is filtered on 'dataset' | ||
const key = Object.keys(baseSchema).find((key) => | ||
baseSchema[key]["digital-land-datasets"]?.includes(entity.dataset), | ||
formattedResult["designated.nationalPark"] && | ||
formattedResult["designated.nationalPark"].value | ||
) { | ||
formattedResult["designated.nationalPark"]?.data?.forEach((entity: any) => { | ||
if ( | ||
baseSchema[broads]["digital-land-entities"]?.includes(entity.entity) | ||
) { | ||
// loop through any intersecting a4 data entities and set granular planx values based on this local authority's schema | ||
if (a4s && formattedResult["article4"].value) { | ||
formattedResult["article4"]?.data?.forEach((entity: any) => { | ||
Object.keys(a4s)?.forEach((key) => { | ||
if ( | ||
// these are various ways we link source data to granular planx values (see local_authorities/metadata for specifics) |
await page.getByText("Continue").click(); | ||
await page.getByLabel("email").fill(context.user.email); | ||
await page.getByText("Continue").click(); | ||
await page.waitForLoadState("networkidle"); | ||
await expect(toggleInviteToPayButton).toBeDisabled(); | ||
}); |
const invalidPaymentRequestURL = `/${context.team!.slug!}/${context.flow! | ||
.slug!}/pay?analytics=false&paymentRequestId=INVALID-ID`; | ||
await page.goto(invalidPaymentRequestURL); | ||
await page.waitForLoadState("networkidle"); | ||
await expect(page.getByText(PAYMENT_NOT_FOUND_TEXT)).toBeVisible(); | ||
}); | ||
const invalidPaymentRequestURL = `/${context.team!.slug!}/${context.flow! | ||
.slug!}/pay?analytics=false`; | ||
await page.goto(invalidPaymentRequestURL); | ||
await page.waitForLoadState("networkidle"); | ||
await expect(page.getByText(PAYMENT_NOT_FOUND_TEXT)).toBeVisible(); | ||
}); | ||
const paymentRequestURL = `/${context.team!.slug!}/${context.flow! | ||
.slug!}/pay?analytics=false&paymentRequestId=${paymentRequest.id}`; | ||
await page.goto(paymentRequestURL); | ||
await page.waitForLoadState("networkidle"); | ||
} | ||
async function setupPaymentRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super happy for this to be a follow up PR - it might be worth looking at something like https://www.npmjs.com/package/eslint-plugin-vitest to replace this?