From 2a4e9781f1b0eb087f541c3d81d58f29c013bb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Fournier?= Date: Wed, 24 Sep 2025 16:50:15 +0200 Subject: [PATCH] Move user tests and add new read model test --- src/lib/features/users/user-store.ts | 2 +- .../features/users/user-updates-read-model.ts | 34 +++++++++++++++--- .../{stores => users}/user-store.e2e.test.ts | 0 .../users/user-updates-read-model.e2e.test.ts | 35 +++++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) rename src/test/e2e/{stores => users}/user-store.e2e.test.ts (100%) create mode 100644 src/test/e2e/users/user-updates-read-model.e2e.test.ts diff --git a/src/lib/features/users/user-store.ts b/src/lib/features/users/user-store.ts index 4f29fed104..ce9d061615 100644 --- a/src/lib/features/users/user-store.ts +++ b/src/lib/features/users/user-store.ts @@ -44,7 +44,7 @@ const mapUserToColumns = (user: ICreateUser) => ({ image_url: user.imageUrl, }); -export const rowToUser = (row) => { +const rowToUser = (row) => { if (!row) { throw new NotFoundError('No user found'); } diff --git a/src/lib/features/users/user-updates-read-model.ts b/src/lib/features/users/user-updates-read-model.ts index c8533a1a9a..8a94384b39 100644 --- a/src/lib/features/users/user-updates-read-model.ts +++ b/src/lib/features/users/user-updates-read-model.ts @@ -1,9 +1,33 @@ import type { Logger, LogProvider } from '../../logger.js'; import type { Db } from '../../db/db.js'; -import { rowToUser, USER_COLUMNS_PUBLIC, USERS_TABLE } from './user-store.js'; -import type { User } from '../../internals.js'; +import { USER_COLUMNS_PUBLIC, USERS_TABLE } from './user-store.js'; +import type { Row } from '../../db/crud/row-type.js'; +type Response = { + id: number; + name?: string; + username?: string; + email?: string; + imageUrl?: string; + seenAt?: Date; + createdAt?: Date; + updatedAt?: Date | null; + deletedAt?: Date | null; +}; +const toResponse = (row: Row): Response => { + return { + id: row.id, + name: row.name, + username: row.username, + email: row.email, + imageUrl: row.image_url, + seenAt: row.seen_at, + createdAt: row.created_at, + updatedAt: row.updated_at, + deletedAt: row.deleted_at, + }; +}; export class UserUpdatesReadModel { private db: Db; @@ -29,7 +53,7 @@ export class UserUpdatesReadModel { async getUsersUpdatedAfter( date: Date, limit: number = 100, - ): Promise { + ): Promise { const result = await this.db(USERS_TABLE) .where({ // also consider deleted users (different than activeUsers query) @@ -38,8 +62,8 @@ export class UserUpdatesReadModel { updated_at: { $gt: date }, }) .orderBy('updated_at', 'asc') - .select(USER_COLUMNS_PUBLIC) + .select([...USER_COLUMNS_PUBLIC, 'updated_at', 'deleted_at']) .limit(limit); - return result.map(rowToUser); + return result.map(toResponse); } } diff --git a/src/test/e2e/stores/user-store.e2e.test.ts b/src/test/e2e/users/user-store.e2e.test.ts similarity index 100% rename from src/test/e2e/stores/user-store.e2e.test.ts rename to src/test/e2e/users/user-store.e2e.test.ts diff --git a/src/test/e2e/users/user-updates-read-model.e2e.test.ts b/src/test/e2e/users/user-updates-read-model.e2e.test.ts new file mode 100644 index 0000000000..baed11def4 --- /dev/null +++ b/src/test/e2e/users/user-updates-read-model.e2e.test.ts @@ -0,0 +1,35 @@ +import dbInit, { type ITestDb } from '../helpers/database-init.js'; +import getLogger from '../../fixtures/no-logger.js'; +import type { IUnleashStores } from '../../../lib/types/index.js'; +import { beforeAll, afterAll, test, expect } from 'vitest'; +let stores: IUnleashStores; +let db: ITestDb; + +beforeAll(async () => { + db = await dbInit('user_store_serial', getLogger, { + experimental: { flags: {} }, + }); + stores = db.stores; +}); + +afterAll(async () => { + await db.destroy(); +}); + +test('should have no users', async () => { + const readModel = stores.userUpdatesReadModel; + const lastUpdatedAt = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt).toBeNull(); + + const users = await readModel.getUsersUpdatedAfter(new Date(0)); + expect(users).toEqual([]); +}); + +test('should have no users', async () => { + const readModel = stores.userUpdatesReadModel; + const lastUpdatedAt = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt).toBeNull(); + + const users = await readModel.getUsersUpdatedAfter(new Date(0)); + expect(users).toEqual([]); +});