346 lines
10 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|