import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication, ValidationPipe } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from '../src/app.module'; import { getRepositoryToken } from '@nestjs/typeorm'; import { User } from '../src/modules/users/entities/user.entity'; import { Store } from '../src/modules/stores/entities/store.entity'; import { StoreUser, StoreUserRole } from '../src/modules/stores/entities/store-user.entity'; import { InventoryItem } from '../src/modules/inventory/entities/inventory-item.entity'; import { Correction } from '../src/modules/feedback/entities/correction.entity'; import { JwtService } from '@nestjs/jwt'; import { Repository } from 'typeorm'; describe('FeedbackController (e2e)', () => { let app: INestApplication; let jwtService: JwtService; let userRepository: Repository; let storeRepository: Repository; let storeUserRepository: Repository; let inventoryRepository: Repository; let correctionRepository: Repository; let testUser: User; let testStore: Store; let testItem: InventoryItem; let authToken: string; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); app.useGlobalPipes(new ValidationPipe({ whitelist: true })); await app.init(); jwtService = moduleFixture.get(JwtService); userRepository = moduleFixture.get(getRepositoryToken(User)); storeRepository = moduleFixture.get(getRepositoryToken(Store)); storeUserRepository = moduleFixture.get(getRepositoryToken(StoreUser)); inventoryRepository = moduleFixture.get(getRepositoryToken(InventoryItem)); correctionRepository = moduleFixture.get(getRepositoryToken(Correction)); // Create test user testUser = await userRepository.save({ phone: '+521234567890', name: 'Test Feedback User', }); // Create test store testStore = await storeRepository.save({ name: 'Test Feedback Store', ownerId: testUser.id, }); // Create store-user relationship await storeUserRepository.save({ storeId: testStore.id, userId: testUser.id, role: StoreUserRole.OWNER, }); // Create test inventory item testItem = await inventoryRepository.save({ storeId: testStore.id, name: 'Test Product', quantity: 10, category: 'Test Category', }); // Generate auth token authToken = jwtService.sign({ sub: testUser.id, phone: testUser.phone }); }); afterAll(async () => { // Cleanup await correctionRepository.delete({ inventoryItemId: testItem.id }); await inventoryRepository.delete({ id: testItem.id }); await storeUserRepository.delete({ storeId: testStore.id }); await storeRepository.delete({ id: testStore.id }); await userRepository.delete({ id: testUser.id }); await app.close(); }); describe('/stores/:storeId/inventory/:itemId/correct-quantity (PATCH)', () => { it('should correct item quantity', async () => { const response = await request(app.getHttpServer()) .patch(`/stores/${testStore.id}/inventory/${testItem.id}/correct-quantity`) .set('Authorization', `Bearer ${authToken}`) .send({ quantity: 15, reason: 'Conteo incorrecto' }) .expect(200); expect(response.body.message).toBe('Cantidad corregida exitosamente'); expect(response.body.correction.type).toBe('QUANTITY'); expect(response.body.correction.previousValue.quantity).toBe(10); expect(response.body.correction.newValue.quantity).toBe(15); expect(response.body.item.quantity).toBe(15); }); it('should reject invalid quantity', async () => { await request(app.getHttpServer()) .patch(`/stores/${testStore.id}/inventory/${testItem.id}/correct-quantity`) .set('Authorization', `Bearer ${authToken}`) .send({ quantity: -5 }) .expect(400); }); it('should reject without auth', async () => { await request(app.getHttpServer()) .patch(`/stores/${testStore.id}/inventory/${testItem.id}/correct-quantity`) .send({ quantity: 20 }) .expect(401); }); }); describe('/stores/:storeId/inventory/:itemId/correct-sku (PATCH)', () => { it('should correct item SKU/name', async () => { const response = await request(app.getHttpServer()) .patch(`/stores/${testStore.id}/inventory/${testItem.id}/correct-sku`) .set('Authorization', `Bearer ${authToken}`) .send({ name: 'Corrected Product Name', category: 'New Category', reason: 'Nombre incorrecto', }) .expect(200); expect(response.body.message).toBe('Nombre/SKU corregido exitosamente'); expect(response.body.correction.type).toBe('SKU'); expect(response.body.item.name).toBe('Corrected Product Name'); }); it('should reject empty name', async () => { await request(app.getHttpServer()) .patch(`/stores/${testStore.id}/inventory/${testItem.id}/correct-sku`) .set('Authorization', `Bearer ${authToken}`) .send({ name: '' }) .expect(400); }); }); describe('/stores/:storeId/inventory/:itemId/confirm (POST)', () => { it('should confirm item as correct', async () => { const response = await request(app.getHttpServer()) .post(`/stores/${testStore.id}/inventory/${testItem.id}/confirm`) .set('Authorization', `Bearer ${authToken}`) .expect(201); expect(response.body.message).toBe('Item confirmado exitosamente'); expect(response.body.correction.type).toBe('CONFIRMATION'); }); }); describe('/stores/:storeId/inventory/:itemId/history (GET)', () => { it('should return correction history', async () => { const response = await request(app.getHttpServer()) .get(`/stores/${testStore.id}/inventory/${testItem.id}/history`) .set('Authorization', `Bearer ${authToken}`) .expect(200); expect(response.body.corrections).toBeDefined(); expect(Array.isArray(response.body.corrections)).toBe(true); expect(response.body.corrections.length).toBeGreaterThan(0); }); it('should return 404 for non-existent item', async () => { await request(app.getHttpServer()) .get(`/stores/${testStore.id}/inventory/00000000-0000-0000-0000-000000000000/history`) .set('Authorization', `Bearer ${authToken}`) .expect(404); }); }); describe('/products/submit (POST)', () => { it('should submit new product', async () => { const response = await request(app.getHttpServer()) .post('/products/submit') .set('Authorization', `Bearer ${authToken}`) .send({ storeId: testStore.id, name: 'New Product Submission', category: 'Beverages', }) .expect(201); expect(response.body.message).toBe('Producto enviado para revision'); expect(response.body.submission.status).toBe('PENDING'); }); }); describe('/products/search (GET)', () => { it('should search products', async () => { const response = await request(app.getHttpServer()) .get('/products/search?q=test') .set('Authorization', `Bearer ${authToken}`) .expect(200); expect(response.body.products).toBeDefined(); expect(Array.isArray(response.body.products)).toBe(true); }); }); });