Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 810b2d2

Browse files
author
G r e y
authored
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
1 parent 95160d0 commit 810b2d2

File tree

4 files changed

+160
-37
lines changed

4 files changed

+160
-37
lines changed

site/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
"storybook": "start-storybook -p 6006 -s ./static",
1818
"storybook:build": "build-storybook",
1919
"test": "jest --selectProjects test",
20-
"test:coverage": "jest --selectProjects test --collectCoverage"
20+
"test:coverage": "jest --selectProjects test --collectCoverage",
21+
"test:watch": "jest --selectProjects test --watch"
2122
},
2223
"dependencies": {
2324
"@material-ui/core": "4.9.4",
2425
"@material-ui/icons": "4.5.1",
2526
"@material-ui/lab": "4.0.0-alpha.42",
27+
"axios": "0.26.1",
2628
"formik": "2.2.9",
2729
"history": "5.3.0",
2830
"react": "17.0.2",

site/src/api.test.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import axios from "axios"
2+
import { APIKeyResponse, getApiKey, login, LoginResponse, logout } from "./api"
3+
4+
// Mock the axios module so that no real network requests are made, but rather
5+
// we swap in a resolved or rejected value
6+
//
7+
// See: https://jestjs.io/docs/mock-functions#mocking-modules
8+
jest.mock("axios")
9+
10+
describe("api.ts", () => {
11+
describe("login", () => {
12+
it("should return LoginResponse", async () => {
13+
// given
14+
const loginResponse: LoginResponse = {
15+
session_token: "abc_123_test",
16+
}
17+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
18+
return Promise.resolve({ data: loginResponse })
19+
})
20+
axios.post = axiosMockPost
21+
22+
// when
23+
const result = await login("test", "123")
24+
25+
// then
26+
expect(axiosMockPost).toHaveBeenCalled()
27+
expect(result).toStrictEqual(loginResponse)
28+
})
29+
30+
it("should throw an error on 401", async () => {
31+
// given
32+
// ..ensure that we await our expect assertion in async/await test
33+
expect.assertions(1)
34+
const expectedError = {
35+
message: "Validation failed",
36+
errors: [{ field: "email", code: "email" }],
37+
}
38+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
39+
return Promise.reject(expectedError)
40+
})
41+
axios.post = axiosMockPost
42+
43+
try {
44+
await login("test", "123")
45+
} catch (error) {
46+
expect(error).toStrictEqual(expectedError)
47+
}
48+
})
49+
})
50+
51+
describe("logout", () => {
52+
it("should return without erroring", async () => {
53+
// given
54+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
55+
return Promise.resolve()
56+
})
57+
axios.post = axiosMockPost
58+
59+
// when
60+
await logout()
61+
62+
// then
63+
expect(axiosMockPost).toHaveBeenCalled()
64+
})
65+
66+
it("should throw an error on 500", async () => {
67+
// given
68+
// ..ensure that we await our expect assertion in async/await test
69+
expect.assertions(1)
70+
const expectedError = {
71+
message: "Failed to logout.",
72+
}
73+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
74+
return Promise.reject(expectedError)
75+
})
76+
axios.post = axiosMockPost
77+
78+
try {
79+
await logout()
80+
} catch (error) {
81+
expect(error).toStrictEqual(expectedError)
82+
}
83+
})
84+
})
85+
86+
describe("getApiKey", () => {
87+
it("should return APIKeyResponse", async () => {
88+
// given
89+
const apiKeyResponse: APIKeyResponse = {
90+
key: "abc_123_test",
91+
}
92+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
93+
return Promise.resolve({ data: apiKeyResponse })
94+
})
95+
axios.post = axiosMockPost
96+
97+
// when
98+
const result = await getApiKey()
99+
100+
// then
101+
expect(axiosMockPost).toHaveBeenCalled()
102+
expect(result).toStrictEqual(apiKeyResponse)
103+
})
104+
105+
it("should throw an error on 401", async () => {
106+
// given
107+
// ..ensure that we await our expect assertion in async/await test
108+
expect.assertions(1)
109+
const expectedError = {
110+
message: "No Cookie!",
111+
}
112+
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
113+
return Promise.reject(expectedError)
114+
})
115+
axios.post = axiosMockPost
116+
117+
try {
118+
await getApiKey()
119+
} catch (error) {
120+
expect(error).toStrictEqual(expectedError)
121+
}
122+
})
123+
})
124+
})

site/src/api.ts

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import axios, { AxiosRequestHeaders } from "axios"
12
import { mutate } from "swr"
23

3-
interface LoginResponse {
4-
session_token: string
4+
const CONTENT_TYPE_JSON: AxiosRequestHeaders = {
5+
"Content-Type": "application/json",
56
}
67

78
/**
@@ -107,48 +108,32 @@ export namespace Workspace {
107108
}
108109
}
109110

111+
export interface LoginResponse {
112+
session_token: string
113+
}
114+
110115
export const login = async (email: string, password: string): Promise<LoginResponse> => {
111-
const response = await fetch("/api/v2/users/login", {
112-
method: "POST",
113-
headers: {
114-
"Content-Type": "application/json",
115-
},
116-
body: JSON.stringify({
117-
email,
118-
password,
119-
}),
116+
const payload = JSON.stringify({
117+
email,
118+
password,
120119
})
121120

122-
const body = await response.json()
123-
if (!response.ok) {
124-
throw new Error(body.message)
125-
}
121+
const response = await axios.post<LoginResponse>("/api/v2/users/login", payload, {
122+
headers: { ...CONTENT_TYPE_JSON },
123+
})
126124

127-
return body
125+
return response.data
128126
}
129127

130128
export const logout = async (): Promise<void> => {
131-
const response = await fetch("/api/v2/users/logout", {
132-
method: "POST",
133-
})
134-
135-
if (!response.ok) {
136-
const body = await response.json()
137-
throw new Error(body.message)
138-
}
139-
140-
return
129+
await axios.post("/api/v2/users/logout")
141130
}
142131

143-
export const getApiKey = async (): Promise<{ key: string }> => {
144-
const response = await fetch("/api/v2/users/me/keys", {
145-
method: "POST",
146-
})
147-
148-
if (!response.ok) {
149-
const body = await response.json()
150-
throw new Error(body.message)
151-
}
132+
export interface APIKeyResponse {
133+
key: string
134+
}
152135

153-
return await response.json()
136+
export const getApiKey = async (): Promise<APIKeyResponse> => {
137+
const response = await axios.post<APIKeyResponse>("/api/v2/users/me/keys")
138+
return response.data
154139
}

site/yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,6 +4085,13 @@ axe-core@^4.3.5:
40854085
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.0.tgz#f93be7f81017eb8bedeb1859cc8092cc918d2dc8"
40864086
integrity sha512-btWy2rze3NnxSSxb7LtNhPYYFrRoFBfjiGzmSc/5Hu47wApO2KNXjP/w7Nv2Uz/Fyr/pfEiwOkcXhDxu0jz5FA==
40874087

4088+
4089+
version "0.26.1"
4090+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
4091+
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
4092+
dependencies:
4093+
follow-redirects "^1.14.8"
4094+
40884095
axobject-query@^2.2.0:
40894096
version "2.2.0"
40904097
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -6773,6 +6780,11 @@ follow-redirects@^1.0.0:
67736780
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
67746781
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
67756782

6783+
follow-redirects@^1.14.8:
6784+
version "1.14.9"
6785+
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
6786+
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
6787+
67766788
for-in@^1.0.2:
67776789
version "1.0.2"
67786790
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"

0 commit comments

Comments
 (0)