Skip to content

Commit

Permalink
Use JSON data for request bodies instead of FormData
Browse files Browse the repository at this point in the history
  • Loading branch information
david-mears-2 committed Sep 12, 2024
1 parent fbb2a05 commit 2a03920
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 38 deletions.
11 changes: 3 additions & 8 deletions components/ParameterForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@
color="primary"
:size="appStore.largeScreen ? 'lg' : undefined"
type="submit"
:disabled="formSubmitting"
:disabled="formSubmitting || props.metadataFetchStatus === 'error'"
@click="submitForm"
>
Run
<CSpinner v-if="formSubmitting" size="sm" class="ms-1" />
<CSpinner v-if="formSubmitting && props.metadataFetchStatus !== 'error'" size="sm" class="ms-1" />
<CIcon v-else icon="cilArrowRight" />
</CButton>
</CForm>
Expand Down Expand Up @@ -134,15 +134,10 @@ const submitForm = async () => {
return;
};
const formDataObject = new FormData();
Object.entries(formData.value).forEach(([key, value]) => {
formDataObject.append(key, value.toString());
});
formSubmitting.value = true;
const response = await $fetch<NewScenarioData>("/api/scenarios", {
method: "POST",
body: formDataObject,
body: { parameters: formData.value },
}).catch((error: FetchError) => {
console.error(error);
});
Expand Down
6 changes: 3 additions & 3 deletions server/api/scenarios.post.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { runScenario } from "@/server/handlers/scenarios";
import { defineRApiEventHandler } from "@/server/utils/defineRApiEventHandler";

Check warning on line 2 in server/api/scenarios.post.ts

View check run for this annotation

Codecov / codecov/patch

server/api/scenarios.post.ts#L2

Added line #L2 was not covered by tests
import { formDataToObject } from "@/server/utils/helpers";
import type { NewScenarioResponse } from "@/types/apiResponseTypes";

export default defineRApiEventHandler(
async (event): Promise<NewScenarioResponse> => {
const formDataBody = await readFormData(event);
const newScenarioResponse = await runScenario(formDataToObject(formDataBody), event);
const body = await readBody(event);
const parameters = typeof body === "object" ? body.parameters : JSON.parse(body).parameters; // Comes through as a string in the integration tests.
const newScenarioResponse = await runScenario(parameters, event);
return newScenarioResponse;
},
);

Check warning on line 12 in server/api/scenarios.post.ts

View check run for this annotation

Codecov / codecov/patch

server/api/scenarios.post.ts#L5-L12

Added lines #L5 - L12 were not covered by tests
36 changes: 14 additions & 22 deletions tests/integration/rApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,11 @@ describe("endpoints which consume the R API", { sequential: true }, async () =>
// instead use the mockoonResponse parameter to tell Mockoon which type of response to send.
describe("post api/scenarios", async () => {
it("returns a successful response when the mock server responds successfully", async () => {
const formData = new FormData();
formData.append("mockoonResponse", "successful");
formData.append("country", "Thailand");
formData.append("pathogen", "sars-cov-1");
formData.append("response", "no_closure");
formData.append("vaccine", "none");
const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body: formData });
const body = JSON.stringify(
{ parameters: { mockoonResponse: "successful", country: "Thailand", pathogen: "sars-cov-1", response: "no_closure", vaccine: "none" } },
);

const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body });

expect(response.ok).toBe(true);
expect(response.status).toBe(200);
Expand All @@ -144,14 +142,11 @@ describe("endpoints which consume the R API", { sequential: true }, async () =>
});

it("returns a response with informative errors when the mock server responds with an error", async () => {
const formData = new FormData();
formData.append("mockoonResponse", "notFound");
formData.append("country", "Thailand");
formData.append("pathogen", "sars-cov-1");
formData.append("response", "no_closure");
formData.append("vaccine", "none");
const body = JSON.stringify(
{ parameters: { mockoonResponse: "notFound", country: "Thailand", pathogen: "sars-cov-1", response: "no_closure", vaccine: "none" } },
);

const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body: formData });
const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body });

expect(response.ok).toBe(false);
expect(response.status).toBe(404);
Expand All @@ -163,14 +158,11 @@ describe("endpoints which consume the R API", { sequential: true }, async () =>
});

it("returns a response with informative errors when the mock server doesn't respond in time", async () => {
const formData = new FormData();
formData.append("mockoonResponse", "delayed");
formData.append("country", "Thailand");
formData.append("pathogen", "sars-cov-1");
formData.append("response", "no_closure");
formData.append("vaccine", "none");

const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body: formData });
const body = JSON.stringify(
{ parameters: { mockoonResponse: "delayed", country: "Thailand", pathogen: "sars-cov-1", response: "no_closure", vaccine: "none" } },
);

const response = await nuxtTestUtilsFetch(`/api/scenarios`, { method: "POST", body });

expect(response.ok).toBe(false);
expect(response.status).toBe(500);
Expand Down
13 changes: 8 additions & 5 deletions tests/unit/components/ParameterForm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { describe, expect, it } from "vitest";
import { mountSuspended, registerEndpoint } from "@nuxt/test-utils/runtime";
import { FetchError } from "ofetch";
import { readBody } from "h3";
import { flushPromises } from "@vue/test-utils";
import { waitFor } from "@testing-library/vue";

import { formDataToObject } from "@/server/utils/helpers";
import type { Metadata } from "@/types/apiResponseTypes";
import ParameterForm from "@/components/ParameterForm.vue";

Expand Down Expand Up @@ -110,7 +111,7 @@ describe("parameter form", () => {
registerEndpoint("/api/scenarios", {
method: "POST",
async handler(event) {
const parameters = formDataToObject(event.node.req.body) as Record<string, string>;
const { parameters } = await readBody(event);

if (parameters.long_list === "1" && parameters.region === "HVN" && parameters.short_list === "no") {
return { runId: "randomId" };
Expand All @@ -134,9 +135,11 @@ describe("parameter form", () => {
// I couldn't find a way to spy on the navigateTo function, so this is a second-best test that we
// at least construct the correct path to navigate to.
const cForm = component.findComponent({ name: "CForm" });
expect(
cForm.element.attributes.getNamedItem("data-test-navigate-to")!.value,
).toBe("/scenarios/randomId");
await waitFor(() => {
expect(
cForm.element.attributes.getNamedItem("data-test-navigate-to")!.value,
).toBe("/scenarios/randomId");
});
});

it("displays CAlert with error message when metadataFetchStatus is 'error'", async () => {
Expand Down

0 comments on commit 2a03920

Please sign in to comment.