import { Test, TestingModule } from '@nestjs/testing'; import { ConfigModule } from '@nestjs/config'; import { PrismaService } from '../../../src/infrastructure/persistence/prisma/prisma.service'; import { AppVersionRepositoryImpl } from '../../../src/infrastructure/persistence/repositories/app-version.repository.impl'; import { AppVersionMapper } from '../../../src/infrastructure/persistence/mappers/app-version.mapper'; import { AppVersion } from '../../../src/domain/entities/app-version.entity'; import { Platform } from '../../../src/domain/enums/platform.enum'; import { VersionCode } from '../../../src/domain/value-objects/version-code.vo'; import { VersionName } from '../../../src/domain/value-objects/version-name.vo'; import { BuildNumber } from '../../../src/domain/value-objects/build-number.vo'; import { DownloadUrl } from '../../../src/domain/value-objects/download-url.vo'; import { FileSize } from '../../../src/domain/value-objects/file-size.vo'; import { FileSha256 } from '../../../src/domain/value-objects/file-sha256.vo'; import { Changelog } from '../../../src/domain/value-objects/changelog.vo'; describe('AppVersionRepository Integration Tests', () => { let repository: AppVersionRepositoryImpl; let prisma: PrismaService; beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env.test', }), ], providers: [ PrismaService, AppVersionMapper, AppVersionRepositoryImpl, ], }).compile(); repository = module.get(AppVersionRepositoryImpl); prisma = module.get(PrismaService); // Connect to test database await prisma.$connect(); }); afterAll(async () => { await prisma.$disconnect(); }); beforeEach(async () => { // Clean up test data await prisma.appVersion.deleteMany({}); }); const createTestVersion = () => { return AppVersion.create({ platform: Platform.ANDROID, versionCode: VersionCode.create(100), versionName: VersionName.create('1.0.0'), buildNumber: BuildNumber.create('100'), downloadUrl: DownloadUrl.create('https://example.com/app.apk'), fileSize: FileSize.create(10485760n), fileSha256: FileSha256.create('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'), changelog: Changelog.create('Test version for integration testing'), isForceUpdate: false, createdBy: 'test-user', }); }; describe('save', () => { it('should save new app version', async () => { const version = createTestVersion(); const saved = await repository.save(version); expect(saved.id).toBe(version.id); expect(saved.versionCode.value).toBe(100); expect(saved.versionName.value).toBe('1.0.0'); }); it('should save version and retrieve it from database', async () => { const version = createTestVersion(); await repository.save(version); const found = await repository.findById(version.id); expect(found).not.toBeNull(); expect(found!.id).toBe(version.id); expect(found!.versionCode.value).toBe(version.versionCode.value); }); }); describe('findById', () => { it('should find version by id', async () => { const version = createTestVersion(); await repository.save(version); const found = await repository.findById(version.id); expect(found).not.toBeNull(); expect(found!.id).toBe(version.id); }); it('should return null for non-existent id', async () => { const found = await repository.findById('non-existent-id'); expect(found).toBeNull(); }); }); describe('findLatestByPlatform', () => { it('should find latest enabled version by platform', async () => { const v1 = createTestVersion(); const v2 = AppVersion.create({ platform: Platform.ANDROID, versionCode: VersionCode.create(200), versionName: VersionName.create('2.0.0'), buildNumber: BuildNumber.create('200'), downloadUrl: DownloadUrl.create('https://example.com/app-v2.apk'), fileSize: FileSize.create(20971520n), fileSha256: FileSha256.create('0000000000000000000000000000000000000000000000000000000000000000'), changelog: Changelog.create('Version 2.0.0 with new features'), isForceUpdate: false, createdBy: 'test-user', }); await repository.save(v1); await repository.save(v2); const latest = await repository.findLatestByPlatform(Platform.ANDROID); expect(latest).not.toBeNull(); expect(latest!.versionCode.value).toBe(200); }); it('should return null if no enabled versions exist', async () => { const latest = await repository.findLatestByPlatform(Platform.ANDROID); expect(latest).toBeNull(); }); it('should not return disabled versions', async () => { const version = createTestVersion(); version.disable('test-user'); await repository.save(version); const latest = await repository.findLatestByPlatform(Platform.ANDROID); expect(latest).toBeNull(); }); }); describe('findByPlatformAndVersionCode', () => { it('should find version by platform and version code', async () => { const version = createTestVersion(); await repository.save(version); const found = await repository.findByPlatformAndVersionCode( Platform.ANDROID, VersionCode.create(100), ); expect(found).not.toBeNull(); expect(found!.versionCode.value).toBe(100); }); it('should return null if version not found', async () => { const found = await repository.findByPlatformAndVersionCode( Platform.ANDROID, VersionCode.create(999), ); expect(found).toBeNull(); }); }); describe('findAllByPlatform', () => { it('should find all enabled versions by default', async () => { const v1 = createTestVersion(); const v2 = AppVersion.create({ platform: Platform.ANDROID, versionCode: VersionCode.create(200), versionName: VersionName.create('2.0.0'), buildNumber: BuildNumber.create('200'), downloadUrl: DownloadUrl.create('https://example.com/app-v2.apk'), fileSize: FileSize.create(20971520n), fileSha256: FileSha256.create('0000000000000000000000000000000000000000000000000000000000000000'), changelog: Changelog.create('Version 2.0.0'), isForceUpdate: false, createdBy: 'test-user', }); v2.disable('test-user'); await repository.save(v1); await repository.save(v2); const versions = await repository.findAllByPlatform(Platform.ANDROID); expect(versions).toHaveLength(1); expect(versions[0].versionCode.value).toBe(100); }); it('should find all versions including disabled when requested', async () => { const v1 = createTestVersion(); const v2 = AppVersion.create({ platform: Platform.ANDROID, versionCode: VersionCode.create(200), versionName: VersionName.create('2.0.0'), buildNumber: BuildNumber.create('200'), downloadUrl: DownloadUrl.create('https://example.com/app-v2.apk'), fileSize: FileSize.create(20971520n), fileSha256: FileSha256.create('0000000000000000000000000000000000000000000000000000000000000000'), changelog: Changelog.create('Version 2.0.0'), isForceUpdate: false, createdBy: 'test-user', }); v2.disable('test-user'); await repository.save(v1); await repository.save(v2); const versions = await repository.findAllByPlatform(Platform.ANDROID, true); expect(versions).toHaveLength(2); }); }); describe('update', () => { it('should update existing version', async () => { const version = createTestVersion(); await repository.save(version); version.setForceUpdate(true, 'test-user'); await repository.update(version.id, version); const updated = await repository.findById(version.id); expect(updated).not.toBeNull(); expect(updated!.isForceUpdate).toBe(true); }); }); describe('toggleEnabled', () => { it('should toggle enabled status', async () => { const version = createTestVersion(); await repository.save(version); await repository.toggleEnabled(version.id, false); const disabled = await repository.findById(version.id); expect(disabled!.isEnabled).toBe(false); await repository.toggleEnabled(version.id, true); const enabled = await repository.findById(version.id); expect(enabled!.isEnabled).toBe(true); }); }); describe('delete', () => { it('should delete version', async () => { const version = createTestVersion(); await repository.save(version); await repository.delete(version.id); const found = await repository.findById(version.id); expect(found).toBeNull(); }); it('should not throw when deleting non-existent version', async () => { await expect(repository.delete('non-existent-id')).resolves.not.toThrow(); }); }); });