← back to Wine Finder Next

__tests__/integration/api-marketplace.test.ts

247 lines

// Integration Tests for Marketplace API
import { NextRequest } from 'next/server';
import { GET, POST } from '@/app/api/membership/marketplace/route';

jest.mock('@/lib/membershipDatabase');
jest.mock('@/lib/rateLimit');
jest.mock('@/lib/auth');
jest.mock('@/lib/securityMonitoring');

import { marketplaceDb } from '@/lib/membershipDatabase';
import { checkRateLimit, getClientIdentifier } from '@/lib/rateLimit';
import { logAudit } from '@/lib/auth';
import { analyzeRequest } from '@/lib/securityMonitoring';

describe('Marketplace API Integration Tests', () => {
  beforeEach(() => {
    jest.clearAllMocks();

    (checkRateLimit as jest.Mock).mockReturnValue({
      success: true,
      limit: 100,
      remaining: 99,
      reset: Date.now() + 60000,
    });

    (getClientIdentifier as jest.Mock).mockReturnValue('127.0.0.1');
    (logAudit as jest.Mock).mockReturnValue(undefined);
    (analyzeRequest as jest.Mock).mockReturnValue({ safe: true, threats: [] });
  });

  describe('GET /api/membership/marketplace', () => {
    it('should return all listings', async () => {
      const mockListings = [
        {
          id: 'listing_1',
          listingType: 'membership',
          itemId: 'unit_1',
          bottleId: 'bottle_1',
          sellerId: 'user_1',
          sellerName: 'Test Seller',
          price: 15.50,
          currency: 'USD',
          status: 'active',
          listedAt: new Date(),
        },
      ];

      (marketplaceDb.getAll as jest.Mock).mockReturnValue(mockListings);

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace');
      const response = await GET(request);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.success).toBe(true);
      expect(data.data).toHaveLength(1);
      expect(data.data[0].price).toBe(15.50);
    });

    it('should filter by active listings', async () => {
      const mockActiveListings = [
        {
          id: 'listing_active',
          listingType: 'membership',
          itemId: 'unit_1',
          bottleId: 'bottle_1',
          sellerId: 'user_1',
          sellerName: 'Seller',
          price: 10,
          currency: 'USD',
          status: 'active',
          listedAt: new Date(),
        },
      ];

      (marketplaceDb.getActive as jest.Mock).mockReturnValue(mockActiveListings);

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace?active=true');
      const response = await GET(request);
      const data = await response.json();

      expect(marketplaceDb.getActive).toHaveBeenCalled();
      expect(data.data.every((l: any) => l.status === 'active')).toBe(true);
    });

    it('should filter by seller ID', async () => {
      const sellerId = 'user_123';
      const mockSellerListings = [
        {
          id: 'listing_seller',
          listingType: 'membership',
          itemId: 'unit_1',
          bottleId: 'bottle_1',
          sellerId,
          sellerName: 'Seller',
          price: 10,
          currency: 'USD',
          status: 'active',
          listedAt: new Date(),
        },
      ];

      (marketplaceDb.getBySellerId as jest.Mock).mockReturnValue(mockSellerListings);

      const request = new NextRequest(`http://localhost:3000/api/membership/marketplace?sellerId=${sellerId}`);
      const response = await GET(request);
      const data = await response.json();

      expect(marketplaceDb.getBySellerId).toHaveBeenCalledWith(sellerId);
      expect(data.success).toBe(true);
    });

    it('should validate seller ID format', async () => {
      const invalidSellerId = '<script>alert(1)</script>';

      const request = new NextRequest(`http://localhost:3000/api/membership/marketplace?sellerId=${invalidSellerId}`);
      const response = await GET(request);
      const data = await response.json();

      expect(response.status).toBe(400);
      expect(data.success).toBe(false);
      expect(data.error).toContain('Invalid seller ID format');
    });
  });

  describe('POST /api/membership/marketplace', () => {
    it('should create a new listing', async () => {
      const newListing = {
        id: 'listing_new',
        listingType: 'membership',
        itemId: 'unit_123',
        bottleId: 'bottle_456',
        sellerId: 'user_1',
        sellerName: 'Test Seller',
        price: 20.00,
        currency: 'USD',
        status: 'active',
        listedAt: new Date(),
      };

      (marketplaceDb.create as jest.Mock).mockReturnValue(newListing);

      const requestBody = {
        listingType: 'membership',
        itemId: 'unit_123',
        bottleId: 'bottle_456',
        sellerId: 'user_1',
        sellerName: 'Test Seller',
        price: 20.00,
        currency: 'USD',
        status: 'active',
      };

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace', {
        method: 'POST',
        body: JSON.stringify(requestBody),
      });

      const response = await POST(request);
      const data = await response.json();

      expect(response.status).toBe(200);
      expect(data.success).toBe(true);
      expect(data.data.price).toBe(20.00);
      expect(data.message).toBe('Listing created successfully');
    });

    it('should validate seller ID on POST', async () => {
      const requestBody = {
        sellerId: 'invalid_id',
        price: 10,
      };

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace', {
        method: 'POST',
        body: JSON.stringify(requestBody),
      });

      const response = await POST(request);
      const data = await response.json();

      expect(response.status).toBe(400);
      expect(data.success).toBe(false);
      expect(data.error).toContain('Invalid seller ID format');
    });

    it('should validate price format', async () => {
      const requestBody = {
        sellerId: 'user_1',
        price: -10,
      };

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace', {
        method: 'POST',
        body: JSON.stringify(requestBody),
      });

      const response = await POST(request);
      const data = await response.json();

      expect(response.status).toBe(400);
      expect(data.success).toBe(false);
      expect(data.error).toContain('Invalid price format');
    });

    it('should log marketplace creation audit', async () => {
      const newListing = {
        id: 'listing_audit',
        listingType: 'membership',
        itemId: 'unit_1',
        bottleId: 'bottle_1',
        sellerId: 'user_1',
        sellerName: 'Seller',
        price: 15,
        currency: 'USD',
        status: 'active',
        listedAt: new Date(),
      };

      (marketplaceDb.create as jest.Mock).mockReturnValue(newListing);

      const request = new NextRequest('http://localhost:3000/api/membership/marketplace', {
        method: 'POST',
        body: JSON.stringify({
          sellerId: 'user_1',
          price: 15,
        }),
      });

      await POST(request);

      expect(logAudit).toHaveBeenCalledWith({
        action: 'MARKETPLACE_CREATE',
        resource: `marketplace/${newListing.id}`,
        ipAddress: '127.0.0.1',
        userAgent: expect.any(String),
        success: true,
        metadata: {
          listingId: newListing.id,
          sellerId: newListing.sellerId,
          price: newListing.price,
        },
      });
    });
  });
});