From 28dc3d346d6486bd98b8493c66c52494ce8e531d Mon Sep 17 00:00:00 2001 From: James Shiffer Date: Wed, 12 Nov 2025 17:20:02 -0800 Subject: [PATCH] More api tests --- src/lib/api.test.ts | 78 ++++++++++++++++++++++++++++++++++++++++++++- src/lib/models.ts | 2 ++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/lib/api.test.ts b/src/lib/api.test.ts index 39d010b..b720769 100644 --- a/src/lib/api.test.ts +++ b/src/lib/api.test.ts @@ -1,22 +1,65 @@ -import axios from 'axios'; +import axios, { type AxiosRequestConfig } from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { HeaptraderAPI } from './api'; import { expect, jest, test } from '@jest/globals'; +import type { User } from './models'; class HeaptraderAPITest extends HeaptraderAPI { public _mock: MockAdapter; + public _fakeXsrf: string; + public _mockUser: User; constructor() { super(""); this._mock = new MockAdapter(axios); + this._fakeXsrf = "asdfghjkl"; + this._mockUser = { + "id": 1, + "name": "Admin", + "email": "board@ucla.edu", + "email_verified_at": "2025-11-05T20:05:42.000000Z", + "created_at": "2025-11-04T18:57:35.000000Z", + "updated_at": "2025-11-05T20:05:44.000000Z", + "two_factor_confirmed_at": null + }; this.setupMockResponses(); } setupMockResponses(): void { this._mock.onGet("/up").reply(200, {}); + + // TODO: see if there's a way to actually return an xsrf cookie, get mock Axios to use it + this._mock.onGet("/sanctum/csrf-cookie").reply(204); + + this._mock.onPost("/login").reply((config: AxiosRequestConfig) => { + if (config.data.password === 'opensesame') + { + return { + status: 200, + data: {"two_factor": false} + }; + } + else + { + return { + status: 422, + data: { + "message": "These credentials do not match our records.", + "errors": { + "email": [ + "These credentials do not match our records." + ] + } + } + }; + } + // TODO: simulate 419 error from no CSRF cookie + }); + + this._mock.onGet("/api/user").reply(200, this._mockUser); } } @@ -25,3 +68,36 @@ test('check uptime', async () => { const success = await api.heartbeat(); expect(success).toBe(true); }); + +test('requests CSRF cookie before login attempts', async () => { + const api = new HeaptraderAPITest(); + await api.login({ + email: "board@linux.ucla.edu", + password: "password123" + }); + expect(api._mock.history[0].method).toMatch(/GET/i); + expect(api._mock.history[0].url).toBe("/sanctum/csrf-cookie"); +}); + +test('login attempt with correct credentials', async () => { + const api = new HeaptraderAPITest(); + const success = await api.login({ + email: "board@linux.ucla.edu", + password: "opensesame" + }); + expect(success).toBe(true); +}); + +test('login attempt with wrong credentials', async () => { + const api = new HeaptraderAPITest(); + const success = await api.login({ + email: "board@linux.ucla.edu", + password: "sneed" + }); + expect(success).toBe(false); +}); + +test('gets user info', async () => { + const api = new HeaptraderAPITest(); + expect(await api.user()).toEqual(api._mockUser); +}); diff --git a/src/lib/models.ts b/src/lib/models.ts index df191a9..a698b5d 100644 --- a/src/lib/models.ts +++ b/src/lib/models.ts @@ -5,6 +5,8 @@ export interface User email: string email_verified_at: string created_at: string + updated_at: string | null + two_factor_confirmed_at: string | null } export enum ItemCondition