Skip to content

Task 3-2: Integration Test - Listing, Cancel, Burn Ticket

Phase: 3 Priority: Medium Module: marketplace Depends on: Không có Reference: docs/bountyhunter-blockchain-p2/details/feature-marketplace/SPEC.md

Background

Các luồng Listing NFT, Cancel Listing, và Burn Ticket chưa có integration test. Mỗi luồng hỗ trợ nhiều chain (EVM, Solana, ImmutableX) với logic phân kỳ. Cần đảm bảo mỗi chain path được route đúng và webhook được gọi với payload chính xác. ImmutableX path sử dụng ImmutableUtil riêng biệt cần được mock độc lập.

Tasks

Note: Mock ImmutableUtil thông qua NestJS dependency injection — override provider trong test module. Dùng jest.spyOn cho Solana Connection methods. Mỗi test case nên verify đúng queue name được dùng (LISTING_NFT, CANCEL_LISTING_NFT, BURN_TICKET). Đảm bảo postWithRetry được mock để không gọi thật lên Backend.

  • [ ] Test case 1 — Listing NFT (EVM):
    it('POST /marketplace/listing-nft (EVM) → LISTING_NFT queue → processor → webhook', async () => {
      const res = await request(app.getHttpServer())
        .post('/marketplace/listing-nft')
        .send({ chainId: EVM_CHAIN_ID, ...listingPayload });
    
      expect(res.status).toBe(201);
      const jobs = await listingNftQueue.getJobs(['waiting']);
      expect(jobs).toHaveLength(1);
    
      await waitForJobCompletion('LISTING_NFT');
      expect(mockWebhook).toHaveBeenCalledWith(
        expect.any(String),
        expect.objectContaining({ status: 'SUCCESS' })
      );
    });
    
  • [ ] Test case 2 — Cancel Listing NFT (EVM):
  • Job vào CANCEL_LISTING_NFT queue
  • On-chain cancellation executed
  • Webhook success called
  • [ ] Test case 3 — Burn Ticket (ERC1155):
    it('POST /marketplace/burn-ticket → ERC1155 burn → webhook', async () => {
      mockErc1155.burn.mockResolvedValue({ hash: '0xburn123' });
      // ...verify flow...
      expect(mockWebhook).toHaveBeenCalledWith(
        expect.any(String),
        expect.objectContaining({ status: 'SUCCESS', txHash: '0xburn123' })
      );
    });
    
  • [ ] Test case 4 — ImmutableX path (mock ImmutableUtil):
    it('Listing NFT on ImmutableX → ImmutableUtil.listNft called', async () => {
      const mockImxListNft = jest.spyOn(immutableUtil, 'listNft').mockResolvedValue({ orderId: '123' });
    
      await request(app.getHttpServer())
        .post('/marketplace/listing-nft')
        .send({ chainId: IMX_CHAIN_ID, ...listingPayload });
    
      await waitForJobCompletion('LISTING_NFT');
      expect(mockImxListNft).toHaveBeenCalled();
      expect(mockWebhook).toHaveBeenCalledWith(
        expect.any(String),
        expect.objectContaining({ status: 'SUCCESS', orderId: '123' })
      );
    });
    
  • [ ] Test case 5 — Cancel path khi ImmutableX cancellation fails → failure webhook

Verification / Acceptance Criteria

  • [ ] Listing NFT: job vào đúng queue LISTING_NFT, webhook success sau processor completion
  • [ ] Cancel Listing: on-chain cancellation được gọi, webhook success với txHash
  • [ ] Burn Ticket: ERC1155 burn() được gọi với đúng tokenId và amount
  • [ ] ImmutableX path: ImmutableUtil.listNft() được gọi thay vì ethers.js
  • [ ] ImmutableX failure → failure webhook với errorCode (liên quan task-2-2)
  • [ ] Test pass khi chạy npm run test

Files to Modify

  • src/marketplace/tests/marketplace-listing.integration.spec.ts (tạo mới)
  • src/marketplace/tests/marketplace-burn.integration.spec.ts (tạo mới)