diff --git a/src/lib/features/users/user-updates-read-model.ts b/src/lib/features/users/user-updates-read-model.ts index 90112778c9..3595b9c262 100644 --- a/src/lib/features/users/user-updates-read-model.ts +++ b/src/lib/features/users/user-updates-read-model.ts @@ -62,7 +62,12 @@ export class UserUpdatesReadModel { }) .where('updated_at', '>', date) .orderBy('updated_at', 'asc') - .select([...USER_COLUMNS_PUBLIC, 'updated_at', 'deleted_at']) + .select([ + ...USER_COLUMNS_PUBLIC, + 'created_at', + 'updated_at', + 'deleted_at', + ]) .limit(limit); return result.map(toResponse); } 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 index baed11def4..a9bf7ac385 100644 --- a/src/test/e2e/users/user-updates-read-model.e2e.test.ts +++ b/src/test/e2e/users/user-updates-read-model.e2e.test.ts @@ -1,7 +1,7 @@ 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'; +import { beforeAll, test, expect } from 'vitest'; let stores: IUnleashStores; let db: ITestDb; @@ -12,8 +12,8 @@ beforeAll(async () => { stores = db.stores; }); -afterAll(async () => { - await db.destroy(); +beforeEach(async () => { + await stores.userStore.deleteAll(); }); test('should have no users', async () => { @@ -25,11 +25,89 @@ test('should have no users', async () => { expect(users).toEqual([]); }); -test('should have no users', async () => { +test('Adding a user should return that user', async () => { const readModel = stores.userUpdatesReadModel; - const lastUpdatedAt = await readModel.getLastUpdatedAt(); - expect(lastUpdatedAt).toBeNull(); + const userStore = stores.userStore; + const beforeInsert = new Date(Date.now() - 1000); + await userStore.upsert({ email: 'test@example.com' }); - const users = await readModel.getUsersUpdatedAfter(new Date(0)); - expect(users).toEqual([]); + const lastUpdatedAt = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt).toBeDefined(); + expect(lastUpdatedAt).toBeInstanceOf(Date); + // check that it's recent + expect(lastUpdatedAt!.getTime()).toBeGreaterThanOrEqual( + beforeInsert.getTime(), + ); + + const users = await readModel.getUsersUpdatedAfter(beforeInsert); + expect(users).toHaveLength(1); + expect(users[0].email).toBe('test@example.com'); + expect(users[0].createdAt).toBeInstanceOf(Date); + expect(users[0].updatedAt).toBeInstanceOf(Date); + expect(users[0].deletedAt).toBeNull(); +}); + +test('Modifying a user should return that user', async () => { + const readModel = stores.userUpdatesReadModel; + const userStore = stores.userStore; + const inserted = await userStore.upsert({ + email: 'test@example.com', + }); + + const afterInsert = new Date(); + const lastUpdatedAt = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt).toBeDefined(); + expect(lastUpdatedAt).toBeInstanceOf(Date); + + const users = await readModel.getUsersUpdatedAfter(afterInsert); + expect(users).toHaveLength(0); + + await userStore.update(inserted.id, { name: 'New Name' }); + + const lastUpdatedAt2 = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt2).toBeDefined(); + expect(lastUpdatedAt2).toBeInstanceOf(Date); + expect(lastUpdatedAt2!.getTime()).toBeGreaterThanOrEqual( + lastUpdatedAt!.getTime(), + ); + + const users2 = await readModel.getUsersUpdatedAfter(afterInsert); + expect(users2).toHaveLength(1); + expect(users2[0].email).toBe('test@example.com'); + expect(users2[0].name).toBe('New Name'); + expect(users2[0].createdAt).toBeInstanceOf(Date); + expect(users2[0].updatedAt).toBeInstanceOf(Date); + expect(users2[0].deletedAt).toBeNull(); +}); + +test('Deleting a user should return that user', async () => { + const readModel = stores.userUpdatesReadModel; + const userStore = stores.userStore; + const inserted = await userStore.upsert({ + email: 'test@example.com', + }); + + const afterInsert = new Date(); + const lastUpdatedAt = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt).toBeDefined(); + expect(lastUpdatedAt).toBeInstanceOf(Date); + + const users = await readModel.getUsersUpdatedAfter(afterInsert); + expect(users).toHaveLength(0); + + await userStore.delete(inserted.id); + + const lastUpdatedAt2 = await readModel.getLastUpdatedAt(); + expect(lastUpdatedAt2).toBeDefined(); + expect(lastUpdatedAt2).toBeInstanceOf(Date); + expect(lastUpdatedAt2!.getTime()).toBeGreaterThanOrEqual( + lastUpdatedAt!.getTime(), + ); + + const users2 = await readModel.getUsersUpdatedAfter(afterInsert); + expect(users2).toHaveLength(1); + expect(users2[0].email).toBeNull(); // currently we nullify the email but this might change in the future + expect(users2[0].createdAt).toBeInstanceOf(Date); + expect(users2[0].updatedAt).toBeInstanceOf(Date); + expect(users2[0].deletedAt).toBeInstanceOf(Date); });