sendou.ink/app/features/vods/VodRepository.server.test.ts
2026-07-28 17:13:02 +03:00

390 lines
9.2 KiB
TypeScript

import { beforeEach, describe, expect, test } from "vitest";
import * as UserFactory from "~/db/seed/factories/UserFactory";
import * as VodFactory from "~/db/seed/factories/VodFactory";
import * as VodRepository from "./VodRepository.server";
const users = UserFactory.pool();
describe("findByUserId", () => {
beforeEach(async () => {
await users.create(5);
});
test("returns vods for a specific user", async () => {
await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(1) },
});
await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(2) },
});
await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(3) },
});
const result = await VodRepository.findByUserId(users.id(2));
expect(result).toHaveLength(1);
});
test("returns empty array when user has no vods", async () => {
await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(1) },
});
const result = await VodRepository.findByUserId(users.id(2));
expect(result).toHaveLength(0);
});
test("respects the limit parameter", async () => {
await VodFactory.createMany(3, {
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(1) },
});
const result = await VodRepository.findByUserId(users.id(1), 2);
expect(result).toHaveLength(2);
});
});
describe("findVods", () => {
beforeEach(async () => {
await users.create(5);
});
test("filters by weapon", async () => {
const vod = await VodFactory.create({
submitterUserId: users.id(1),
matches: [{ mode: "TW", stageId: 0, startsAt: "0:00", weapons: [1000] }],
});
await VodFactory.create({
submitterUserId: users.id(1),
matches: [{ mode: "TW", stageId: 0, startsAt: "0:00", weapons: [2000] }],
});
const result = await VodRepository.findVods({ weapon: 1000 });
expect(result.length).toBeGreaterThan(0);
expect(result.some((otherVod) => otherVod.id === vod.id)).toBe(true);
});
test("filters by mode", async () => {
for (const mode of ["TW", "SZ", "TC"] as const) {
await VodFactory.create({
submitterUserId: users.id(1),
matches: [{ mode, stageId: 0, startsAt: "0:00", weapons: [0] }],
});
}
const result = await VodRepository.findVods({ mode: "SZ" });
expect(result).toHaveLength(1);
});
test("filters by stageId", async () => {
for (const stageId of [0, 1, 2] as const) {
await VodFactory.create({
submitterUserId: users.id(1),
matches: [{ mode: "TW", stageId, startsAt: "0:00", weapons: [0] }],
});
}
const result = await VodRepository.findVods({ stageId: 1 });
expect(result).toHaveLength(1);
});
test("filters by type", async () => {
for (const type of ["TOURNAMENT", "CAST", "SCRIM"] as const) {
await VodFactory.create({ submitterUserId: users.id(1), type });
}
const result = await VodRepository.findVods({ type: "CAST" });
expect(result).toHaveLength(1);
});
test("returns all vods when no filters provided", async () => {
await VodFactory.createMany(3, { submitterUserId: users.id(1) });
const result = await VodRepository.findVods({});
expect(result).toHaveLength(3);
});
test("respects limit parameter", async () => {
await VodFactory.createMany(3, { submitterUserId: users.id(1) });
const result = await VodRepository.findVods({ limit: 2 });
expect(result).toHaveLength(2);
});
});
describe("findVodById", () => {
beforeEach(async () => {
await users.create(5);
});
test("returns null when vod doesn't exist", async () => {
const result = await VodRepository.findVodById(999);
expect(result).toBeNull();
});
test("correctly resolves pov from user", async () => {
const vod = await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(1) },
});
const result = await VodRepository.findVodById(vod.id);
expect(result).not.toBeNull();
expect(result?.pov).toBeDefined();
expect(typeof result?.pov).not.toBe("string");
});
test("correctly resolves pov from player name", async () => {
const vod = await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "NAME", name: "PlayerName" },
});
const result = await VodRepository.findVodById(vod.id);
expect(result).not.toBeNull();
expect(result?.pov).toBe("PlayerName");
});
});
describe("insert", () => {
beforeEach(async () => {
await users.create(5);
});
test("inserts vod with all metadata", async () => {
const result = await VodRepository.insert({
title: "Complete VOD",
youtubeUrl: "https://www.youtube.com/watch?v=abc123",
date: {
day: 15,
month: 5,
year: 2024,
},
matches: [
{
mode: "TW",
stageId: 0,
startsAt: "0:00",
weapons: [0, 10, 20],
},
],
type: "TOURNAMENT",
pov: { type: "USER", userId: users.id(1) },
submitterUserId: users.id(1),
isValidated: true,
});
const vod = await VodRepository.findVodById(result.id);
expect(vod).not.toBeNull();
expect(vod?.title).toBe("Complete VOD");
expect(vod?.youtubeId).toBe("abc123");
expect(vod?.type).toBe("TOURNAMENT");
expect(vod?.matches).toHaveLength(1);
expect(vod?.matches[0].weapons).toHaveLength(3);
});
test("extracts YouTube ID from URL correctly", async () => {
const { id } = await VodRepository.insert({
title: "Test VOD",
youtubeUrl: "https://www.youtube.com/watch?v=test1",
date: {
day: 1,
month: 0,
year: 2024,
},
matches: [],
type: "TOURNAMENT",
submitterUserId: users.id(1),
isValidated: true,
});
const result = await VodRepository.findVodById(id);
expect(result?.youtubeId).toBe("test1");
});
test("handles NAME type pov", async () => {
const result = await VodRepository.insert({
title: "Test VOD",
youtubeUrl: "https://www.youtube.com/watch?v=test123",
date: {
day: 1,
month: 0,
year: 2024,
},
matches: [
{
mode: "TW",
stageId: 0,
startsAt: "0:00",
weapons: [0],
},
],
type: "TOURNAMENT",
pov: { type: "NAME", name: "TestPlayer" },
submitterUserId: users.id(1),
isValidated: true,
});
const vod = await VodRepository.findVodById(result.id);
expect(vod?.pov).toBe("TestPlayer");
});
test("handles USER type pov", async () => {
const result = await VodRepository.insert({
title: "Test VOD",
youtubeUrl: "https://www.youtube.com/watch?v=test123",
date: {
day: 1,
month: 0,
year: 2024,
},
matches: [
{
mode: "TW",
stageId: 0,
startsAt: "0:00",
weapons: [0],
},
],
type: "TOURNAMENT",
pov: { type: "USER", userId: users.id(1) },
submitterUserId: users.id(1),
isValidated: true,
});
const vod = await VodRepository.findVodById(result.id);
expect(vod?.pov).toBeDefined();
expect(typeof vod?.pov).not.toBe("string");
});
});
describe("update", () => {
beforeEach(async () => {
await users.create(5);
});
test("updates vod metadata", async () => {
const vod = await VodFactory.create({
submitterUserId: users.id(1),
pov: { type: "USER", userId: users.id(1) },
});
await VodRepository.update({
id: vod.id,
title: "Updated Title",
youtubeUrl: "https://www.youtube.com/watch?v=updated123",
date: {
day: 1,
month: 0,
year: 2024,
},
matches: [
{
mode: "SZ",
stageId: 5,
startsAt: "0:00",
weapons: [50],
},
],
type: "CAST",
pov: { type: "USER", userId: users.id(2) },
submitterUserId: users.id(1),
isValidated: true,
});
const result = await VodRepository.findVodById(vod.id);
expect(result?.title).toBe("Updated Title");
expect(result?.youtubeId).toBe("updated123");
expect(result?.type).toBe("CAST");
});
test("deletes and recreates matches", async () => {
const vod = await VodFactory.create({
submitterUserId: users.id(1),
matches: [
{ mode: "TW", stageId: 0, startsAt: "0:00", weapons: [0] },
{ mode: "SZ", stageId: 1, startsAt: "5:00", weapons: [10] },
],
});
await VodRepository.update({
id: vod.id,
title: "Test VOD",
youtubeUrl: "https://www.youtube.com/watch?v=test123",
date: {
day: 1,
month: 0,
year: 2024,
},
matches: [
{
mode: "TC",
stageId: 2,
startsAt: "0:00",
weapons: [20],
},
],
type: "TOURNAMENT",
pov: { type: "USER", userId: users.id(1) },
submitterUserId: users.id(1),
isValidated: true,
});
const result = await VodRepository.findVodById(vod.id);
expect(result?.matches).toHaveLength(1);
expect(result?.matches[0].mode).toBe("TC");
});
});
describe("deleteById", () => {
beforeEach(async () => {
await users.create(5);
});
test("deletes vod by id", async () => {
const vod = await VodFactory.create({ submitterUserId: users.id(1) });
await VodRepository.deleteById(vod.id);
const result = await VodRepository.findVodById(vod.id);
expect(result).toBeNull();
});
test("only deletes the specified vod", async () => {
const [firstVod, secondVod] = await VodFactory.createMany(2, {
submitterUserId: users.id(1),
});
await VodRepository.deleteById(firstVod.id);
const firstResult = await VodRepository.findVodById(firstVod.id);
const secondResult = await VodRepository.findVodById(secondVod.id);
expect(firstResult).toBeNull();
expect(secondResult).not.toBeNull();
});
});