feature/state-and-data-fetching #1
@@ -1,3 +1,4 @@
|
||||
export * from "./login";
|
||||
export * from "./register";
|
||||
export * from "./logout";
|
||||
export * from "./refresh";
|
||||
|
||||
3
src/features/auth/api/calls/refresh/constants.ts
Normal file
3
src/features/auth/api/calls/refresh/constants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const REFRESH_API_ROUTE = "auth/refresh";
|
||||
export const MOCK_TOKEN = "mock.access.token";
|
||||
export const MOCK_FRESH_TOKEN = "mock.fresh.access.token";
|
||||
2
src/features/auth/api/calls/refresh/index.ts
Normal file
2
src/features/auth/api/calls/refresh/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { refresh } from "./refresh";
|
||||
export { REFRESH_API_ROUTE } from "./constants";
|
||||
22
src/features/auth/api/calls/refresh/refresh.mock.ts
Normal file
22
src/features/auth/api/calls/refresh/refresh.mock.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { http, HttpResponse } from "msw";
|
||||
import { BASE_URL } from "shared/config";
|
||||
import { MOCK_FRESH_TOKEN, MOCK_TOKEN, REFRESH_API_ROUTE } from "./constants";
|
||||
|
||||
const REFRESH_URL = `${BASE_URL}/${REFRESH_API_ROUTE}`;
|
||||
|
||||
/**
|
||||
* Msw interceptor. Mocks the refresh endpoint response.
|
||||
* Validates the Authorization header — returns a fresh token on success, 401 on expired/missing session.
|
||||
*/
|
||||
export const refreshMock = http.post(REFRESH_URL, ({ request }) => {
|
||||
const authHeader = request.headers.get("Authorization");
|
||||
|
||||
if (authHeader === `Bearer ${MOCK_TOKEN}`) {
|
||||
return HttpResponse.json({
|
||||
accessToken: MOCK_FRESH_TOKEN,
|
||||
user: { id: "1", email: "test@test.com" },
|
||||
});
|
||||
}
|
||||
|
||||
return HttpResponse.json({ message: "Session expired" }, { status: 401 });
|
||||
});
|
||||
33
src/features/auth/api/calls/refresh/refresh.spec.ts
Normal file
33
src/features/auth/api/calls/refresh/refresh.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { setupServer } from "msw/node";
|
||||
import { useAuthStore } from "../../../model";
|
||||
import { refresh } from "./refresh";
|
||||
import { refreshMock } from "./refresh.mock";
|
||||
import { MOCK_FRESH_TOKEN, MOCK_TOKEN } from "./constants";
|
||||
|
||||
const server = setupServer(refreshMock);
|
||||
|
||||
describe("refresh", () => {
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
||||
afterEach(() => {
|
||||
server.resetHandlers();
|
||||
useAuthStore.setState({ accessToken: undefined });
|
||||
});
|
||||
afterAll(() => server.close());
|
||||
|
||||
describe("happy path", () => {
|
||||
it("returns a fresh access token and user when session is valid", async () => {
|
||||
useAuthStore.setState({ accessToken: MOCK_TOKEN });
|
||||
|
||||
const result = await refresh();
|
||||
|
||||
expect(result.accessToken).toBe(MOCK_FRESH_TOKEN);
|
||||
expect(result.user).toEqual({ id: "1", email: "test@test.com" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("error cases", () => {
|
||||
it("throws when session is expired or missing", async () => {
|
||||
await expect(refresh()).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
7
src/features/auth/api/calls/refresh/refresh.ts
Normal file
7
src/features/auth/api/calls/refresh/refresh.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { api } from "../../../api";
|
||||
import type { AuthResponse } from "../../../model/types/service";
|
||||
import { REFRESH_API_ROUTE } from "./constants";
|
||||
|
||||
export function refresh() {
|
||||
return api.post(REFRESH_API_ROUTE).json<AuthResponse>();
|
||||
}
|
||||
Reference in New Issue
Block a user