mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-12 09:18:25 +03:00
feat: tests and touchups
This commit is contained in:
+4
-1
@@ -31,4 +31,7 @@ I_HAVE_BOOTSTRAPPED_OK
|
||||
# new bootstrap flag
|
||||
BOOTSTRAP_OK
|
||||
# v3 bootstrap flag (omg)
|
||||
_SETUP_OK
|
||||
_SETUP_OK
|
||||
|
||||
# Local debugging: `just db-schema` (see Justfile-db)
|
||||
db/schema.sql
|
||||
+5
-1
@@ -42,4 +42,8 @@ server-db-test-template-reset:
|
||||
# Load the seeds into the database.
|
||||
db-load-seeds POSTGRES_DB=DEFAULT_DB:
|
||||
cd typescript/server && POSTGRES_URL="{{POSTGRES_URL}}/{{POSTGRES_DB}}" \
|
||||
bun run src/scripts/load-seeds-pg.ts
|
||||
bun run src/scripts/load-seeds-pg.ts
|
||||
|
||||
# Reset templatedb from migrations, then dump schema and indexes for local debugging.
|
||||
db-schema: (db-reset "templatedb")
|
||||
pg_dump "{{POSTGRES_URL}}/templatedb" --schema-only --no-owner --no-acl -f db/schema.sql
|
||||
@@ -0,0 +1,3 @@
|
||||
-- One MYT card integration row per account (upsert target for UPDATE_MYT_CARD_INFO).
|
||||
ALTER TABLE "priv_svc_myt_card_info"
|
||||
ADD CONSTRAINT "priv_svc_myt_card_info_user_id_key" UNIQUE ("user_id");
|
||||
@@ -0,0 +1,160 @@
|
||||
import DB from "#services/pg/db";
|
||||
import { seedUser } from "#test-utils/pg-fixtures";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { ACTION_DeleteMytCardInfo } from "./delete-myt-card-info";
|
||||
import { ACTION_UpdateMytCardInfo } from "./update-myt-card-info";
|
||||
|
||||
const CODE_A = "00000000000000000001";
|
||||
const CODE_B = "00000000000000000002";
|
||||
const CODE_OTHER = "00000000000000009999";
|
||||
|
||||
async function getMytCardRow(userId: number) {
|
||||
return DB.selectFrom("priv_svc_myt_card_info")
|
||||
.selectAll()
|
||||
.where("user_id", "=", userId)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
describe("ACTION_UpdateMytCardInfo", () => {
|
||||
let userId: number;
|
||||
let username: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ id: userId, username } = await seedUser({ username: "test_user" }));
|
||||
});
|
||||
|
||||
it("returns {} on success", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
const result = await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_A });
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it("inserts a row on first call", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_A });
|
||||
|
||||
const row = await getMytCardRow(userId);
|
||||
expect(row).toMatchObject({ user_id: userId, card_access_code: CODE_A });
|
||||
});
|
||||
|
||||
it("updates card_access_code on second call for the same user", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_A });
|
||||
await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_B });
|
||||
|
||||
const row = await getMytCardRow(userId);
|
||||
expect(row?.card_access_code).toBe(CODE_B);
|
||||
|
||||
const { count } = await DB.selectFrom("priv_svc_myt_card_info")
|
||||
.select(DB.fn.countAll().as("count"))
|
||||
.where("user_id", "=", userId)
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
expect(Number(count)).toBe(1);
|
||||
});
|
||||
|
||||
it("does not modify another user's row", async () => {
|
||||
const other = await seedUser({ username: "other_user", email: "other@example.com" });
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await DB.insertInto("priv_svc_myt_card_info")
|
||||
.values({ user_id: other.id, card_access_code: CODE_OTHER })
|
||||
.execute();
|
||||
|
||||
await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_A });
|
||||
|
||||
const otherRow = await getMytCardRow(other.id);
|
||||
expect(otherRow?.card_access_code).toBe(CODE_OTHER);
|
||||
});
|
||||
|
||||
it("writes a GOOD action row on success", async () => {
|
||||
const taker = { ip: "10.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateMytCardInfo(taker, { cardAccessCode: CODE_A });
|
||||
|
||||
const action = await DB.selectFrom("action")
|
||||
.selectAll()
|
||||
.where("kind", "=", "UPDATE_MYT_CARD_INFO")
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
expect(action).toMatchObject({
|
||||
kind: "UPDATE_MYT_CARD_INFO",
|
||||
result: "GOOD",
|
||||
ip: "10.0.0.1",
|
||||
user_id: userId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ACTION_DeleteMytCardInfo", () => {
|
||||
let userId: number;
|
||||
let username: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ id: userId, username } = await seedUser({ username: "test_user" }));
|
||||
});
|
||||
|
||||
it("returns {} when no row exists", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
const result = await ACTION_DeleteMytCardInfo(taker, {});
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it("deletes the user's row when present", async () => {
|
||||
await DB.insertInto("priv_svc_myt_card_info")
|
||||
.values({ user_id: userId, card_access_code: CODE_A })
|
||||
.execute();
|
||||
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_DeleteMytCardInfo(taker, {});
|
||||
|
||||
expect(await getMytCardRow(userId)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not delete another user's row", async () => {
|
||||
const other = await seedUser({ username: "other_user", email: "other@example.com" });
|
||||
await DB.insertInto("priv_svc_myt_card_info")
|
||||
.values({ user_id: userId, card_access_code: CODE_A })
|
||||
.execute();
|
||||
await DB.insertInto("priv_svc_myt_card_info")
|
||||
.values({ user_id: other.id, card_access_code: CODE_OTHER })
|
||||
.execute();
|
||||
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_DeleteMytCardInfo(taker, {});
|
||||
|
||||
const otherRow = await getMytCardRow(other.id);
|
||||
expect(otherRow?.card_access_code).toBe(CODE_OTHER);
|
||||
});
|
||||
|
||||
it("writes a GOOD action row on success when a row was deleted", async () => {
|
||||
await DB.insertInto("priv_svc_myt_card_info")
|
||||
.values({ user_id: userId, card_access_code: CODE_A })
|
||||
.execute();
|
||||
|
||||
const taker = { ip: "10.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_DeleteMytCardInfo(taker, {});
|
||||
|
||||
const action = await DB.selectFrom("action")
|
||||
.selectAll()
|
||||
.where("kind", "=", "DELETE_MYT_CARD_INFO")
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
expect(action).toMatchObject({
|
||||
kind: "DELETE_MYT_CARD_INFO",
|
||||
result: "GOOD",
|
||||
ip: "10.0.0.1",
|
||||
user_id: userId,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,149 @@
|
||||
import DB from "#services/pg/db";
|
||||
import { seedUser } from "#test-utils/pg-fixtures";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { ACTION_UpdateUserSettings } from "./update-user-settings";
|
||||
|
||||
async function getSettings(userId: number) {
|
||||
return DB.selectFrom("account_settings")
|
||||
.selectAll()
|
||||
.where("user_id", "=", userId)
|
||||
.executeTakeFirstOrThrow();
|
||||
}
|
||||
|
||||
describe("ACTION_UpdateUserSettings", () => {
|
||||
let userId: number;
|
||||
let username: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ id: userId, username } = await seedUser({
|
||||
username: "test_user",
|
||||
withSettings: true,
|
||||
}));
|
||||
});
|
||||
|
||||
it("throws 400 when no fields are provided", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await expect(ACTION_UpdateUserSettings(taker, {})).rejects.toMatchObject({ code: 400 });
|
||||
});
|
||||
|
||||
it("writes a BAD action row when no fields are provided", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await expect(ACTION_UpdateUserSettings(taker, {})).rejects.toThrow();
|
||||
|
||||
const action = await DB.selectFrom("action")
|
||||
.select("result")
|
||||
.where("kind", "=", "UPDATE_USER_SETTINGS")
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
expect(action.result).toBe("BAD");
|
||||
});
|
||||
|
||||
it("returns {} on success", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
const result = await ACTION_UpdateUserSettings(taker, { invisible: true });
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it("persists invisible to pf_invisible", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { invisible: true });
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_invisible).toBe(true);
|
||||
expect(row.pf_developer_mode).toBe(false);
|
||||
expect(row.pf_advanced_mode).toBe(false);
|
||||
expect(row.pf_contentious_content).toBe(false);
|
||||
expect(row.pf_deletable_scores).toBe(false);
|
||||
});
|
||||
|
||||
it("persists developerMode to pf_developer_mode", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { developerMode: true });
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_developer_mode).toBe(true);
|
||||
expect(row.pf_invisible).toBe(false);
|
||||
});
|
||||
|
||||
it("persists contentiousContent to pf_contentious_content", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { contentiousContent: true });
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_contentious_content).toBe(true);
|
||||
});
|
||||
|
||||
it("persists advancedMode to pf_advanced_mode", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { advancedMode: true });
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_advanced_mode).toBe(true);
|
||||
});
|
||||
|
||||
it("persists deletableScores to pf_deletable_scores", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { deletableScores: true });
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_deletable_scores).toBe(true);
|
||||
});
|
||||
|
||||
it("updates multiple fields in one call and leaves others unchanged", async () => {
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, {
|
||||
invisible: true,
|
||||
developerMode: true,
|
||||
});
|
||||
|
||||
const row = await getSettings(userId);
|
||||
expect(row.pf_invisible).toBe(true);
|
||||
expect(row.pf_developer_mode).toBe(true);
|
||||
expect(row.pf_advanced_mode).toBe(false);
|
||||
expect(row.pf_contentious_content).toBe(false);
|
||||
expect(row.pf_deletable_scores).toBe(false);
|
||||
});
|
||||
|
||||
it("does not modify another user's account_settings", async () => {
|
||||
const other = await seedUser({
|
||||
username: "other_user",
|
||||
email: "other@example.com",
|
||||
withSettings: true,
|
||||
});
|
||||
const taker = { ip: "127.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { invisible: true });
|
||||
|
||||
const otherRow = await getSettings(other.id);
|
||||
expect(otherRow.pf_invisible).toBe(false);
|
||||
});
|
||||
|
||||
it("writes a GOOD action row on success", async () => {
|
||||
const taker = { ip: "10.0.0.1", acct: { id: userId, username } };
|
||||
|
||||
await ACTION_UpdateUserSettings(taker, { invisible: true });
|
||||
|
||||
const action = await DB.selectFrom("action")
|
||||
.selectAll()
|
||||
.where("kind", "=", "UPDATE_USER_SETTINGS")
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
expect(action).toMatchObject({
|
||||
kind: "UPDATE_USER_SETTINGS",
|
||||
result: "GOOD",
|
||||
ip: "10.0.0.1",
|
||||
user_id: userId,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user