UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

165 lines (136 loc) 5.53 kB
import { Alepha } from "alepha"; import { AlephaApiJobs } from "alepha/api/jobs"; import { $repository } from "alepha/orm"; import { AlephaOrmPostgres } from "alepha/orm/postgres"; import { describe, test } from "vitest"; import { sessions } from "../entities/sessions.ts"; import { users } from "../entities/users.ts"; import { AlephaApiUsers } from "../index.ts"; import { UserJobs } from "../jobs/UserJobs.ts"; import { RealmProvider } from "../providers/RealmProvider.ts"; describe("UserJobs", () => { describe("purgeExpiredSessions", () => { test("deletes expired sessions", async ({ expect }) => { const alepha = Alepha.create() .with(AlephaOrmPostgres) .with(AlephaApiJobs); class TestRepositories { userRepository = $repository(users); sessionRepository = $repository(sessions); } const userJobs = alepha.inject(UserJobs); const repos = alepha.inject(TestRepositories); await alepha.start(); const user = await repos.userRepository.create({ email: "test@example.com", }); const pastDate = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: pastDate, }); await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: pastDate, }); const futureDate = new Date( Date.now() + 24 * 60 * 60 * 1000, ).toISOString(); await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: futureDate, }); expect(await repos.sessionRepository.findMany()).toHaveLength(3); // Cron jobs run inline — trigger awaits the handler synchronously. await userJobs.purgeExpiredSessions.trigger(); const sessionsAfter = await repos.sessionRepository.findMany(); expect(sessionsAfter).toHaveLength(1); expect(new Date(sessionsAfter[0].expiresAt).getTime()).toBeGreaterThan( Date.now(), ); }); test("no-op when no expired sessions exist", async ({ expect }) => { const alepha = Alepha.create() .with(AlephaOrmPostgres) .with(AlephaApiJobs); class TestRepositories { userRepository = $repository(users); sessionRepository = $repository(sessions); } const userJobs = alepha.inject(UserJobs); const repos = alepha.inject(TestRepositories); await alepha.start(); const user = await repos.userRepository.create({ email: "test2@example.com", }); const futureDate = new Date( Date.now() + 24 * 60 * 60 * 1000, ).toISOString(); await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: futureDate, }); expect(await repos.sessionRepository.findMany()).toHaveLength(1); await userJobs.purgeExpiredSessions.trigger(); expect(await repos.sessionRepository.findMany()).toHaveLength(1); }); test("purges idle sessions when expirationIdle is configured", async ({ expect, }) => { const alepha = Alepha.create() .with(AlephaOrmPostgres) .with(AlephaApiJobs) .with(AlephaApiUsers); class TestRepositories { userRepository = $repository(users); sessionRepository = $repository(sessions); } const userJobs = alepha.inject(UserJobs); const repos = alepha.inject(TestRepositories); const realmProvider = alepha.inject(RealmProvider); realmProvider.register("default", { settings: { refreshToken: { expirationIdle: 5 * 60 * 1000 }, // 5 minutes } as never, }); await alepha.start(); const user = await repos.userRepository.create({ email: "idle-sweep@example.com", }); const farFuture = new Date( Date.now() + 30 * 24 * 60 * 60 * 1000, ).toISOString(); const oldUsed = new Date(Date.now() - 30 * 60 * 1000).toISOString(); // 30 min ago const recentUsed = new Date(Date.now() - 60 * 1000).toISOString(); // 1 min ago // Idle by lastUsedAt — should be purged (lastUsedAt > 5 min ago). await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: farFuture, lastUsedAt: oldUsed, }); // Recently used — within idle window, should remain. await repos.sessionRepository.create({ userId: user.id, refreshToken: crypto.randomUUID(), expiresAt: farFuture, lastUsedAt: recentUsed, }); // Pre-migration row (lastUsedAt null) with old createdAt — should be // purged via createdAt fallback. We can't directly set createdAt via // create() (auto-managed), so simulate by creating a row and then // updating lastUsedAt to null while the row is fresh — the createdAt // fallback will not trip yet (createdAt is now). Skip this case in this // test; covered logically by the deleteMany filter shape. expect(await repos.sessionRepository.findMany()).toHaveLength(2); await userJobs.purgeExpiredSessions.trigger(); const remaining = await repos.sessionRepository.findMany(); expect(remaining).toHaveLength(1); expect(remaining[0].lastUsedAt).toBe(recentUsed); }); }); });