rwadurian/backend/services/admin-service/test/e2e/version.controller.spec.ts

346 lines
10 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as request from 'supertest';
import { PrismaService } from '../../src/infrastructure/persistence/prisma/prisma.service';
import { AppModule } from '../../src/app.module';
import { Platform } from '../../src/domain/enums/platform.enum';
import { Platform as PrismaPlatform } from '@prisma/client';
describe('VersionController (e2e)', () => {
let app: INestApplication;
let prisma: PrismaService;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env.test',
}),
AppModule,
],
}).compile();
app = moduleFixture.createNestApplication();
// Apply same middleware as main.ts
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
}),
);
const apiPrefix = process.env.API_PREFIX || 'api/v1';
app.setGlobalPrefix(apiPrefix);
await app.init();
prisma = moduleFixture.get<PrismaService>(PrismaService);
await prisma.$connect();
});
afterAll(async () => {
await prisma.$disconnect();
await app.close();
});
beforeEach(async () => {
await prisma.appVersion.deleteMany({});
});
const apiPrefix = process.env.API_PREFIX || 'api/v1';
describe('/version (POST)', () => {
it('should create new Android version', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'android',
versionCode: 100,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app.apk',
fileSize: '10485760',
fileSha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
changelog: 'Initial release with basic features',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(201)
.expect((res) => {
expect(res.body.platform).toBe('android');
expect(res.body.versionCode).toBe(100);
expect(res.body.versionName).toBe('1.0.0');
});
});
it('should create new iOS version', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'ios',
versionCode: 100,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app.ipa',
fileSize: '15728640',
fileSha256: '0000000000000000000000000000000000000000000000000000000000000000',
changelog: 'iOS initial release',
minOsVersion: '14.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(201)
.expect((res) => {
expect(res.body.platform).toBe('ios');
expect(res.body.versionCode).toBe(100);
});
});
it('should reject invalid version code', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'android',
versionCode: -1,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app.apk',
fileSize: '10485760',
fileSha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
changelog: 'Invalid version',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(400);
});
it('should reject invalid version name format', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'android',
versionCode: 100,
versionName: '1.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app.apk',
fileSize: '10485760',
fileSha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
changelog: 'Invalid version name',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(400);
});
it('should reject invalid download URL', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'android',
versionCode: 100,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'not-a-url',
fileSize: '10485760',
fileSha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
changelog: 'Invalid URL',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(400);
});
it('should reject invalid SHA256', () => {
return request(app.getHttpServer())
.post(`/${apiPrefix}/version`)
.send({
platform: 'android',
versionCode: 100,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app.apk',
fileSize: '10485760',
fileSha256: 'invalid-sha256',
changelog: 'Invalid SHA256',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
createdBy: 'admin',
})
.expect(400);
});
});
describe('/version/check-update (GET)', () => {
beforeEach(async () => {
// Create test versions
await prisma.appVersion.create({
data: {
id: 'test-v1',
platform: PrismaPlatform.ANDROID,
versionCode: 100,
versionName: '1.0.0',
buildNumber: '100',
downloadUrl: 'https://example.com/app-v1.apk',
fileSize: 10485760n,
fileSha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
changelog: 'Version 1.0.0',
minOsVersion: '5.0',
isEnabled: true,
isForceUpdate: false,
releaseDate: null,
createdBy: 'admin',
createdAt: new Date(),
updatedAt: new Date(),
},
});
await prisma.appVersion.create({
data: {
id: 'test-v2',
platform: PrismaPlatform.ANDROID,
versionCode: 200,
versionName: '2.0.0',
buildNumber: '200',
downloadUrl: 'https://example.com/app-v2.apk',
fileSize: 20971520n,
fileSha256: '0000000000000000000000000000000000000000000000000000000000000000',
changelog: 'Version 2.0.0',
minOsVersion: '6.0',
isEnabled: true,
isForceUpdate: false,
releaseDate: null,
createdBy: 'admin',
createdAt: new Date(),
updatedAt: new Date(),
},
});
});
it('should return update available for older version', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/check-update`)
.query({
platform: 'android',
currentVersionCode: 100,
})
.expect(200)
.expect((res) => {
expect(res.body.hasUpdate).toBe(true);
expect(res.body.latestVersion).toBeDefined();
expect(res.body.latestVersion.versionCode).toBe(200);
expect(res.body.isForceUpdate).toBe(false);
});
});
it('should return no update for latest version', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/check-update`)
.query({
platform: 'android',
currentVersionCode: 200,
})
.expect(200)
.expect((res) => {
expect(res.body.hasUpdate).toBe(false);
expect(res.body.latestVersion).toBeNull();
});
});
it('should return force update flag when enabled', async () => {
// Update version to force update
await prisma.appVersion.update({
where: { id: 'test-v2' },
data: { isForceUpdate: true },
});
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/check-update`)
.query({
platform: 'android',
currentVersionCode: 100,
})
.expect(200)
.expect((res) => {
expect(res.body.hasUpdate).toBe(true);
expect(res.body.isForceUpdate).toBe(true);
});
});
it('should reject invalid platform', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/check-update`)
.query({
platform: 'invalid',
currentVersionCode: 100,
})
.expect(400);
});
it('should reject invalid version code', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/check-update`)
.query({
platform: 'android',
currentVersionCode: -1,
})
.expect(400);
});
});
describe('/version/:platform/latest (GET)', () => {
beforeEach(async () => {
await prisma.appVersion.create({
data: {
id: 'test-latest',
platform: PrismaPlatform.ANDROID,
versionCode: 300,
versionName: '3.0.0',
buildNumber: '300',
downloadUrl: 'https://example.com/app-v3.apk',
fileSize: 31457280n,
fileSha256: '1111111111111111111111111111111111111111111111111111111111111111',
changelog: 'Latest version',
minOsVersion: '7.0',
isEnabled: true,
isForceUpdate: false,
releaseDate: null,
createdBy: 'admin',
createdAt: new Date(),
updatedAt: new Date(),
},
});
});
it('should get latest version for platform', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/android/latest`)
.expect(200)
.expect((res) => {
expect(res.body.platform).toBe('android');
expect(res.body.versionCode).toBe(300);
expect(res.body.versionName).toBe('3.0.0');
});
});
it('should return 404 for platform with no versions', () => {
return request(app.getHttpServer())
.get(`/${apiPrefix}/version/ios/latest`)
.expect(404);
});
});
});