-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from ucsb-cs156-s24/Sreeganesh-SchoolsCRUD-Create
Schools Create and Index Page and Fixed Backend Issues
- Loading branch information
Showing
7 changed files
with
246 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
GITHUB_CLIENT_ID=see-instructions-in-readme | ||
GITHUB_CLIENT_SECRET=see-instructions-in-readme | ||
ADMIN_GITHUB_LOGINS=pconrad,phtcon | ||
ADMIN_GITHUB_LOGINS=pconrad,phtcon |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import BasicLayout from "main/layouts/BasicLayout/BasicLayout"; | ||
import SchoolForm from "main/components/School/SchoolForm"; | ||
import { Navigate } from 'react-router-dom' | ||
import { useBackendMutation } from "main/utils/useBackend"; | ||
import { toast } from "react-toastify"; | ||
|
||
export default function SchoolCreatePage({storybook=false}) { | ||
|
||
|
||
const objectToAxiosParams = (school) => ({ | ||
url: "/api/schools/post", | ||
method: "POST", | ||
data: school | ||
}); | ||
|
||
const onSuccess = (school) => { | ||
toast(`New school created - id: ${school.abbrev}`); | ||
} | ||
|
||
const mutation = useBackendMutation( | ||
objectToAxiosParams, | ||
{ onSuccess }, | ||
// Stryker disable next-line all : hard to set up test for caching | ||
["/api/schools/all"] // mutation makes this key stale so that pages relying on it reload | ||
); | ||
|
||
const { isSuccess } = mutation | ||
|
||
const onSubmit = async (data) => { | ||
mutation.mutate(data); | ||
} | ||
|
||
if (isSuccess && !storybook) { | ||
return <Navigate to="/schools" /> | ||
} | ||
|
||
return ( | ||
<BasicLayout> | ||
<div className="pt-2"> | ||
<h1>Create New School</h1> | ||
|
||
<SchoolForm submitAction={onSubmit} /> | ||
|
||
</div> | ||
</BasicLayout> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React from 'react'; | ||
import { apiCurrentUserFixtures } from "fixtures/currentUserFixtures"; | ||
import { systemInfoFixtures } from "fixtures/systemInfoFixtures"; | ||
import { rest } from "msw"; | ||
|
||
import SchoolCreatePage from "main/pages/SchoolCreatePage"; | ||
|
||
export default { | ||
title: 'pages/SchoolCreatePage', | ||
component: SchoolCreatePage | ||
}; | ||
|
||
const Template = () => <SchoolCreatePage storybook={true} />; | ||
|
||
export const Default = Template.bind({}); | ||
Default.parameters = { | ||
msw: [ | ||
rest.get('/api/currentUser', (_req, res, ctx) => { | ||
return res(ctx.json(apiCurrentUserFixtures.userOnly)); | ||
}), | ||
rest.get('/api/systemInfo', (_req, res, ctx) => { | ||
return res(ctx.json(systemInfoFixtures.showingNeither)); | ||
}), | ||
rest.post('/api/schools/post', (req, res, ctx) => { | ||
window.alert("POST: " + JSON.stringify(req.url)); | ||
return res(ctx.status(200),ctx.json({})); | ||
}), | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | ||
import { QueryClient, QueryClientProvider } from "react-query"; | ||
import { MemoryRouter } from "react-router-dom"; | ||
import SchoolCreatePage from "main/pages/SchoolCreatePage"; | ||
|
||
import { apiCurrentUserFixtures } from "fixtures/currentUserFixtures"; | ||
import { systemInfoFixtures } from "fixtures/systemInfoFixtures"; | ||
|
||
import axios from "axios"; | ||
import AxiosMockAdapter from "axios-mock-adapter"; | ||
|
||
const mockToast = jest.fn(); | ||
jest.mock('react-toastify', () => { | ||
const originalModule = jest.requireActual('react-toastify'); | ||
return { | ||
__esModule: true, | ||
...originalModule, | ||
toast: (x) => mockToast(x) | ||
}; | ||
}); | ||
|
||
const mockNavigate = jest.fn(); | ||
jest.mock('react-router-dom', () => { | ||
const originalModule = jest.requireActual('react-router-dom'); | ||
return { | ||
__esModule: true, | ||
...originalModule, | ||
Navigate: (x) => { mockNavigate(x); return null; } | ||
}; | ||
}); | ||
|
||
describe("SchoolCreatePage tests", () => { | ||
|
||
const axiosMock =new AxiosMockAdapter(axios); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
axiosMock.reset(); | ||
axiosMock.resetHistory(); | ||
axiosMock.onGet("/api/currentUser").reply(200, apiCurrentUserFixtures.userOnly); | ||
axiosMock.onGet("/api/systemInfo").reply(200, systemInfoFixtures.showingNeither); | ||
}); | ||
|
||
|
||
|
||
const queryClient = new QueryClient(); | ||
test("renders without crashing", () => { | ||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<MemoryRouter> | ||
<SchoolCreatePage /> | ||
</MemoryRouter> | ||
</QueryClientProvider> | ||
); | ||
}); | ||
|
||
test("on submit, makes request to backend", async () => { | ||
|
||
const queryClient = new QueryClient(); | ||
const school = { | ||
abbrev: "ucsb", | ||
name: "UC Santa Barbara", | ||
termRegex: "[WSMF]\\d\\d", | ||
termDescription: "quarter", | ||
termError: "test" | ||
}; | ||
|
||
axiosMock.onPost("/api/schools/post").reply(200, school); | ||
|
||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<MemoryRouter> | ||
<SchoolCreatePage /> | ||
</MemoryRouter> | ||
</QueryClientProvider> | ||
); | ||
|
||
|
||
expect(await screen.findByText("Create New School")).toBeInTheDocument(); | ||
|
||
const abbrevField = screen.getByTestId("SchoolForm-abbrev"); | ||
const nameField = screen.getByTestId("SchoolForm-name"); | ||
const termRegexField = screen.getByTestId("SchoolForm-termRegex"); | ||
const termDescriptionField = screen.getByTestId("SchoolForm-termDescription"); | ||
const termErrorField = screen.getByTestId("SchoolForm-termError"); | ||
const submitButton = screen.getByTestId("SchoolForm-submit"); | ||
|
||
|
||
fireEvent.change(abbrevField, { target: { value: 'ucsb' } }); | ||
fireEvent.change(nameField, { target: { value: 'UC Santa Barbara' } }); | ||
fireEvent.change(termRegexField, { target: { value: '[WSMF]\\d\\d' } }); | ||
fireEvent.change(termDescriptionField, { target: { value: 'quarter' } }); | ||
fireEvent.change(termErrorField, { target: { value: 'test' } }); | ||
|
||
|
||
fireEvent.click(submitButton); | ||
|
||
await waitFor(() => expect(axiosMock.history.post.length).toBe(1)); | ||
|
||
expect(axiosMock.history.post[0].data).toEqual( | ||
JSON.stringify({ | ||
"abbrev": "ucsb", | ||
"name": "UC Santa Barbara", | ||
"termRegex": "[WSMF]\\d\\d", | ||
"termDescription": "quarter", | ||
"termError": "test" | ||
})); | ||
|
||
expect(mockToast).toBeCalledWith("New school created - id: ucsb"); | ||
expect(mockNavigate).toBeCalledWith({ "to": "/schools" }); | ||
}); | ||
|
||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.