mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
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:
@ -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
124
site/src/api.test.ts
Normal 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)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user