feat(auth): create login api call with basic test coverage and msw mock
This commit is contained in:
1
src/features/auth/api/calls/index.ts
Normal file
1
src/features/auth/api/calls/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./login";
|
||||||
6
src/features/auth/api/calls/login/constants.ts
Normal file
6
src/features/auth/api/calls/login/constants.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export const LOGIN_API_ROUTE = "auth/login";
|
||||||
|
|
||||||
|
// MOCKS
|
||||||
|
export const MOCK_EMAIL = "test@test.com";
|
||||||
|
export const MOCK_PASSWORD = "password";
|
||||||
|
export const MOCK_TOKEN = "mock.access.token";
|
||||||
2
src/features/auth/api/calls/login/index.ts
Normal file
2
src/features/auth/api/calls/login/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { login } from './login';
|
||||||
|
export { LOGIN_API_ROUTE } from './constants';
|
||||||
27
src/features/auth/api/calls/login/login.mock.ts
Normal file
27
src/features/auth/api/calls/login/login.mock.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { http, HttpResponse } from "msw";
|
||||||
|
import type { AuthData } from "../../../model/types/service";
|
||||||
|
import { BASE_URL } from "shared/config";
|
||||||
|
import {
|
||||||
|
LOGIN_API_ROUTE,
|
||||||
|
MOCK_EMAIL,
|
||||||
|
MOCK_PASSWORD,
|
||||||
|
MOCK_TOKEN,
|
||||||
|
} from "./constants";
|
||||||
|
|
||||||
|
const LOGIN_URL = `${BASE_URL}/${LOGIN_API_ROUTE}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Msw interceptor. Mocks the login endpoint response.
|
||||||
|
*/
|
||||||
|
export const loginMock = http.post(LOGIN_URL, async ({ request }) => {
|
||||||
|
const { email, password } = (await request.json()) as AuthData;
|
||||||
|
|
||||||
|
if (email === MOCK_EMAIL && password === MOCK_PASSWORD) {
|
||||||
|
return HttpResponse.json({
|
||||||
|
accessToken: MOCK_TOKEN,
|
||||||
|
user: { id: "1", email },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return HttpResponse.json({ message: "Invalid credentials" }, { status: 401 });
|
||||||
|
});
|
||||||
29
src/features/auth/api/calls/login/login.spec.ts
Normal file
29
src/features/auth/api/calls/login/login.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { setupServer } from "msw/node";
|
||||||
|
import { login } from "./login";
|
||||||
|
import { loginMock } from "./login.mock";
|
||||||
|
import { MOCK_EMAIL, MOCK_PASSWORD } from "./constants";
|
||||||
|
|
||||||
|
const server = setupServer(loginMock);
|
||||||
|
|
||||||
|
describe("login", () => {
|
||||||
|
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
||||||
|
afterEach(() => server.resetHandlers());
|
||||||
|
afterAll(() => server.close());
|
||||||
|
|
||||||
|
describe("happy path", () => {
|
||||||
|
it("returns access token and user on valid credentials", async () => {
|
||||||
|
const result = await login({ email: MOCK_EMAIL, password: MOCK_PASSWORD });
|
||||||
|
|
||||||
|
expect(result.accessToken).toBe("mock.access.token");
|
||||||
|
expect(result.user).toEqual({ id: "1", email: MOCK_EMAIL });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("error cases", () => {
|
||||||
|
it("throws on invalid credentials", async () => {
|
||||||
|
await expect(
|
||||||
|
login({ email: "wrong@test.com", password: "wrong" }),
|
||||||
|
).rejects.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
13
src/features/auth/api/calls/login/login.ts
Normal file
13
src/features/auth/api/calls/login/login.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { api } from "../../../api";
|
||||||
|
import type { AuthData, AuthResponse } from "../../../model/types/service";
|
||||||
|
import { LOGIN_API_ROUTE } from "./constants";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs in a user with the given email and password.
|
||||||
|
*
|
||||||
|
* @param loginData - The user's login data (email and password).
|
||||||
|
* @returns A promise that resolves to the authentication response.
|
||||||
|
*/
|
||||||
|
export function login(loginData: AuthData) {
|
||||||
|
return api.post(LOGIN_API_ROUTE, { json: loginData }).json<AuthResponse>();
|
||||||
|
}
|
||||||
@@ -1,5 +1,16 @@
|
|||||||
import type { User } from "entities/User";
|
import type { User } from "entities/User";
|
||||||
|
|
||||||
|
export interface AuthData {
|
||||||
|
/**
|
||||||
|
* User's email address.
|
||||||
|
*/
|
||||||
|
email: string;
|
||||||
|
/**
|
||||||
|
* User's password.
|
||||||
|
*/
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AuthResponse {
|
export interface AuthResponse {
|
||||||
/**
|
/**
|
||||||
* Access token for the authenticated user.
|
* Access token for the authenticated user.
|
||||||
|
|||||||
Reference in New Issue
Block a user