refactor(site): use axios in non-swr endpoints (#460)

Summary:

Applies axios to login, logout and getApiKey

Impact:

POC of axios (#453) and testing axios

Additional details:

* add test:watch script

resolves: #453
This commit is contained in:
G r e y
2022-03-16 13:01:35 -04:00
committed by GitHub
parent 95160d0ee8
commit 810b2d23a4
4 changed files with 161 additions and 38 deletions

View File

@ -17,12 +17,14 @@
"storybook": "start-storybook -p 6006 -s ./static",
"storybook:build": "build-storybook",
"test": "jest --selectProjects test",
"test:coverage": "jest --selectProjects test --collectCoverage"
"test:coverage": "jest --selectProjects test --collectCoverage",
"test:watch": "jest --selectProjects test --watch"
},
"dependencies": {
"@material-ui/core": "4.9.4",
"@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.42",
"axios": "0.26.1",
"formik": "2.2.9",
"history": "5.3.0",
"react": "17.0.2",

124
site/src/api.test.ts Normal file
View File

@ -0,0 +1,124 @@
import axios from "axios"
import { APIKeyResponse, getApiKey, login, LoginResponse, logout } from "./api"
// Mock the axios module so that no real network requests are made, but rather
// we swap in a resolved or rejected value
//
// See: https://jestjs.io/docs/mock-functions#mocking-modules
jest.mock("axios")
describe("api.ts", () => {
describe("login", () => {
it("should return LoginResponse", async () => {
// given
const loginResponse: LoginResponse = {
session_token: "abc_123_test",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.resolve({ data: loginResponse })
})
axios.post = axiosMockPost
// when
const result = await login("test", "123")
// then
expect(axiosMockPost).toHaveBeenCalled()
expect(result).toStrictEqual(loginResponse)
})
it("should throw an error on 401", async () => {
// given
// ..ensure that we await our expect assertion in async/await test
expect.assertions(1)
const expectedError = {
message: "Validation failed",
errors: [{ field: "email", code: "email" }],
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.reject(expectedError)
})
axios.post = axiosMockPost
try {
await login("test", "123")
} catch (error) {
expect(error).toStrictEqual(expectedError)
}
})
})
describe("logout", () => {
it("should return without erroring", async () => {
// given
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.resolve()
})
axios.post = axiosMockPost
// when
await logout()
// then
expect(axiosMockPost).toHaveBeenCalled()
})
it("should throw an error on 500", async () => {
// given
// ..ensure that we await our expect assertion in async/await test
expect.assertions(1)
const expectedError = {
message: "Failed to logout.",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.reject(expectedError)
})
axios.post = axiosMockPost
try {
await logout()
} catch (error) {
expect(error).toStrictEqual(expectedError)
}
})
})
describe("getApiKey", () => {
it("should return APIKeyResponse", async () => {
// given
const apiKeyResponse: APIKeyResponse = {
key: "abc_123_test",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.resolve({ data: apiKeyResponse })
})
axios.post = axiosMockPost
// when
const result = await getApiKey()
// then
expect(axiosMockPost).toHaveBeenCalled()
expect(result).toStrictEqual(apiKeyResponse)
})
it("should throw an error on 401", async () => {
// given
// ..ensure that we await our expect assertion in async/await test
expect.assertions(1)
const expectedError = {
message: "No Cookie!",
}
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
return Promise.reject(expectedError)
})
axios.post = axiosMockPost
try {
await getApiKey()
} catch (error) {
expect(error).toStrictEqual(expectedError)
}
})
})
})

View File

@ -1,7 +1,8 @@
import axios, { AxiosRequestHeaders } from "axios"
import { mutate } from "swr"
interface LoginResponse {
session_token: string
const CONTENT_TYPE_JSON: AxiosRequestHeaders = {
"Content-Type": "application/json",
}
/**
@ -107,48 +108,32 @@ export namespace Workspace {
}
}
export interface LoginResponse {
session_token: string
}
export const login = async (email: string, password: string): Promise<LoginResponse> => {
const response = await fetch("/api/v2/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
const payload = JSON.stringify({
email,
password,
})
const body = await response.json()
if (!response.ok) {
throw new Error(body.message)
}
const response = await axios.post<LoginResponse>("/api/v2/users/login", payload, {
headers: { ...CONTENT_TYPE_JSON },
})
return body
return response.data
}
export const logout = async (): Promise<void> => {
const response = await fetch("/api/v2/users/logout", {
method: "POST",
})
if (!response.ok) {
const body = await response.json()
throw new Error(body.message)
}
return
await axios.post("/api/v2/users/logout")
}
export const getApiKey = async (): Promise<{ key: string }> => {
const response = await fetch("/api/v2/users/me/keys", {
method: "POST",
})
if (!response.ok) {
const body = await response.json()
throw new Error(body.message)
}
return await response.json()
export interface APIKeyResponse {
key: string
}
export const getApiKey = async (): Promise<APIKeyResponse> => {
const response = await axios.post<APIKeyResponse>("/api/v2/users/me/keys")
return response.data
}

View File

@ -4085,6 +4085,13 @@ axe-core@^4.3.5:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.0.tgz#f93be7f81017eb8bedeb1859cc8092cc918d2dc8"
integrity sha512-btWy2rze3NnxSSxb7LtNhPYYFrRoFBfjiGzmSc/5Hu47wApO2KNXjP/w7Nv2Uz/Fyr/pfEiwOkcXhDxu0jz5FA==
axios@0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
dependencies:
follow-redirects "^1.14.8"
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@ -6773,6 +6780,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
follow-redirects@^1.14.8:
version "1.14.9"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"