Skip to main content
Glama
user-routes.test.ts7.51 kB
import t from "tap"; import _ from "lodash"; import { DateTime } from "luxon"; import { expect } from "chai"; import { TosVersion } from "@si/ts-lib/src/terms-of-service"; import { request } from "./helpers/supertest-agents"; import { testSuiteAfter, testSuiteBefore } from "./helpers/test-suite-hooks"; import { createDummyUser } from "./helpers/dummy-factory"; t.before(testSuiteBefore); t.teardown(testSuiteAfter); t.test("User routes", async () => { const { user } = await createDummyUser(); const { user: anotherUser } = await createDummyUser(); const { user: userNeedsTos } = await createDummyUser({ tos: false }); t.test("GET /whoami - check auth and load current user", async (t) => { t.test("fails if user is not logged in", async () => { await request.get("/whoami") .expectError("Unauthorized"); }); t.test("fetches user info", async () => { await request.get("/whoami") .set("spoof-auth", user.id) .expectOk() .expectBody({ user: { // not checking everything here... id: user.id, email: user.email, }, }); }); }); t.test("PATCH /users/:userId - update user info", async (t) => { const GOOD_PARAMS = { firstName: "newfirst", lastName: "newlast", nickname: "newnickname", email: `newemail${+new Date()}@systeminit.dev`, pictureUrl: "https://placekitten.com/100/100", discordUsername: "newdiscord#9999", githubUsername: "newgithubusername", }; t.test("cannot update user data without auth", async () => { await request.patch(`/users/${user.id}`) .send(GOOD_PARAMS) .expectError("Unauthorized"); }); t.test("cannot update user data of other users", async () => { await request.patch(`/users/${user.id}`) .set("spoof-auth", anotherUser.id) .send(GOOD_PARAMS) .expectError("Forbidden"); }); t.test("can update your own user info", async () => { await request.patch(`/users/${user.id}`) .set("spoof-auth", user.id) .send(GOOD_PARAMS) .expectOk() .expectBody({ user: GOOD_PARAMS }); }); // check bad params _.each({ "non-string firstName": { firstName: 1 }, "non-string lastName": { lastName: true }, "non-string nickname": { nickname: {} }, "null nickname": { nickname: null }, // all other fields are nullable currently "non-string email": { email: 1 }, "invalid email": { email: "bad-email@systeminit" }, "non-string pictureUrl": { pictureUrl: 1 }, "invalid pictureUrl": { pictureUrl: "not-a-url" }, "non-string discordUsername": { discordUsername: false }, "non-string githubUsername": { githubUsername: {} }, }, (bodyOverride, description) => { t.test(`bad params - ${description}`, async () => { await request.patch(`/users/${user.id}`) .set("spoof-auth", user.id) .send({ GOOD_PARAMS, ...bodyOverride, }) .expectError("BadRequest"); }); }); }); t.test("POST /users/:userId/complete-tutorial-step - record tutorial progress", async (t) => { const STEP_NAME_1 = "fakeStep1"; const STEP_NAME_2 = "fakeStep2"; const GOOD_PARAMS = { step: STEP_NAME_1, }; t.test("cannot access without auth", async () => { await request.post(`/users/${user.id}/complete-tutorial-step`) .send(GOOD_PARAMS) .expectError("Unauthorized"); }); t.test("cannot access for other users", async () => { await request.post(`/users/${user.id}/complete-tutorial-step`) .set("spoof-auth", anotherUser.id) .send(GOOD_PARAMS) .expectError("Forbidden"); }); t.test("can record tutorial progress for yourself", async () => { await request.post(`/users/${user.id}/complete-tutorial-step`) .set("spoof-auth", user.id) .send(GOOD_PARAMS) .expectOk() .expect((res) => { const completedStepsData = res.body.user.onboardingDetails.vroStepsCompletedAt; expect(completedStepsData).to.have.all.keys(STEP_NAME_1); expect(DateTime.fromISO(completedStepsData[STEP_NAME_1]).isValid).to.be.true; }); }); t.test("can record multiple tutorial steps", async () => { await request.post(`/users/${user.id}/complete-tutorial-step`) .set("spoof-auth", user.id) .send({ step: STEP_NAME_2 }) .expectOk() .expect((res) => { const completedStepsData = res.body.user.onboardingDetails.vroStepsCompletedAt; expect(completedStepsData).to.have.all.keys(STEP_NAME_1, STEP_NAME_2); expect(DateTime.fromISO(completedStepsData[STEP_NAME_2]).isValid).to.be.true; expect(completedStepsData[STEP_NAME_2] > completedStepsData[STEP_NAME_1]).to.be.true; }); }); }); t.test("POST /tos-agreement - record agreement to TOS", async (t) => { // version IDs are currently just a sortable string // and a single "latest version" is managed in the code // this will probably move to something in the db or env vars eventually... const VERSION_1 = TosVersion.v20230330; const VERSION_2 = VERSION_1.replace("2023", "2024"); const GOOD_PARAMS = { tosVersionId: VERSION_1, }; t.test("cannot access without auth", async () => { await request.post(`/tos-agreement`) .send(GOOD_PARAMS) .expectError("Unauthorized"); }); t.test("(confirm user needs TOS update)", async () => { await request.get("/whoami") .set("spoof-auth", userNeedsTos.id) .expectBody({ user: { needsTosUpdate: true } }); }); t.test("success - record agreement", async () => { await request.post(`/tos-agreement`) .set("spoof-auth", userNeedsTos.id) .set("X-Forwarded-For", "9.8.7.6") .send({ tosVersionId: VERSION_1 }) .expectOk() .expectBody({ userId: userNeedsTos.id, tosVersionId: VERSION_1, ipAddress: "9.8.7.6", }); }); t.test("confirm user no longer needs TOS update", async () => { await request.get("/whoami") .set("spoof-auth", userNeedsTos.id) .expectBody({ user: { needsTosUpdate: false } }); }); t.test("can record agreement to a newer version", async () => { await request.post(`/tos-agreement`) .set("spoof-auth", userNeedsTos.id) .send({ tosVersionId: VERSION_2 }) .expectOk(); }); t.test("cannot record agreement to an earlier version", async () => { await request.post(`/tos-agreement`) .set("spoof-auth", userNeedsTos.id) .send({ tosVersionId: VERSION_1 }) .expectError("Conflict"); }); // check bad params _.each({ "no version": {}, "null version": { tosVersionId: null }, "non-string version": { tosVersionId: 123 }, }, (bodyOverride, description) => { t.test(`bad params - ${description}`, async () => { await request.post("/tos-agreement") .set("spoof-auth", userNeedsTos.id) .send({ ...bodyOverride, }) .expectError("BadRequest"); }); }); t.test("success - record agreement", async () => { await request.post(`/tos-agreement`) .set("spoof-auth", anotherUser.id) .send(GOOD_PARAMS) .expectOk(); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server