DEV Community

Daniel Ioni
Daniel Ioni

Posted on

✅ MyZubster End-to-End Testing Guide

✅ MyZubster End-to-End Testing Guide

Complete testing strategy – from unit tests to full E2E with Monero simulation
📌 What is This Guide?

This guide covers everything you need to know about testing MyZubster:

✅ Unit Testing – Test individual components

✅ Integration Testing – Test API and database interactions

✅ E2E Testing – Test complete user flows

✅ Mocking – Simulate Monero and external services

✅ CI/CD Pipeline – Automated testing in GitHub Actions

✅ Best Practices – Writing maintainable tests
Enter fullscreen mode Exit fullscreen mode

🧩 Testing Architecture Overview
text

┌─────────────────────────────────────────────────────────────────────────────┐
│ Testing Pyramid │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ End-to-End Tests │ │
│ │ (Cypress / Playwright) │ │
│ │ ──────────────────── │ │
│ │ Few, but critical flows │ │
│ │ ~10% of tests │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Integration Tests │ │
│ │ (Jest + Supertest) │ │
│ │ ──────────────────── │ │
│ │ API + Database interactions │ │
│ │ ~30% of tests │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Unit Tests │ │
│ │ (Jest) │ │
│ │ ───────── │ │
│ │ Individual functions and modules │ │
│ │ ~60% of tests │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

📂 Test File Structure
text

myzubster/
├── gateway/
│ ├── tests/
│ │ ├── unit/
│ │ │ ├── monero.test.js
│ │ │ ├── payment.test.js
│ │ │ └── webhook.test.js
│ │ ├── integration/
│ │ │ ├── api.test.js
│ │ │ └── database.test.js
│ │ └── e2e/
│ │ └── payment-flow.test.js
│ └── jest.config.js
├── marketplace/
│ ├── tests/
│ │ ├── unit/
│ │ │ ├── auth.test.js
│ │ │ ├── skills.test.js
│ │ │ ├── orders.test.js
│ │ │ └── escrow.test.js
│ │ ├── integration/
│ │ │ ├── api.test.js
│ │ │ └── database.test.js
│ │ └── e2e/
│ │ ├── order-flow.test.js
│ │ └── dispute-flow.test.js
│ └── jest.config.js
└── tests/
├── e2e/
│ ├── full-flow.test.js
│ └── payment-flow.test.js
└── playwright.config.js

🔧 Step 1: Jest Configuration
1.1 Jest Config for Marketplace

File: marketplace/jest.config.js
javascript

module.exports = {
testEnvironment: 'node',
testMatch: ['/tests//.test.js'],
collectCoverageFrom: [
'routes/
/.js',
'services//*.js',
'models/
/.js',
'middleware/
/.js',
'!/node_modules/',
'!/tests/',
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
setupFilesAfterEnv: ['./tests/setup.js'],
testTimeout: 30000,
verbose: true,
testEnvironmentOptions: {
NODE_ENV: 'test',
},
};

1.2 Jest Config for Gateway

File: gateway/jest.config.js
javascript

module.exports = {
testEnvironment: 'node',
testMatch: ['/tests//.test.js'],
collectCoverageFrom: [
'services/
/.js',
'models//*.js',
'routes/
/.js',
'!
/node_modules/',
'!
/tests/*',
],
coverageThreshold: {
global: {
branches: 75,
functions: 75,
lines: 75,
statements: 75,
},
},
setupFilesAfterEnv: ['./tests/setup.js'],
testTimeout: 30000,
verbose: true,
};

1.3 Test Setup

File: marketplace/tests/setup.js
javascript

const { sequelize } = require('../models');

// Global test setup
beforeAll(async () => {
// Sync database in test mode
await sequelize.sync({ force: true });
});

afterAll(async () => {
// Cleanup
await sequelize.close();
});

// Mock external services
jest.mock('axios');

// Global test utilities
global.createTestUser = async (email = 'test@test.com') => {
// Helper to create test user
};

global.generateTestToken = (user) => {
// Helper to generate JWT for tests
};

🧪 Step 2: Unit Tests
2.1 Auth Unit Tests

File: marketplace/tests/unit/auth.test.js
javascript

const { User } = require('../../models');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

describe('Auth Unit Tests', () => {
describe('Password Hashing', () => {
test('should hash password correctly', async () => {
const password = 'test123';
const hashedPassword = await bcrypt.hash(password, 10);

  expect(hashedPassword).not.toBe(password);
  expect(await bcrypt.compare(password, hashedPassword)).toBe(true);
});

test('should not match wrong password', async () => {
  const password = 'test123';
  const wrongPassword = 'wrong456';
  const hashedPassword = await bcrypt.hash(password, 10);

  expect(await bcrypt.compare(wrongPassword, hashedPassword)).toBe(false);
});
Enter fullscreen mode Exit fullscreen mode

});

describe('JWT Token', () => {
test('should generate valid JWT token', () => {
const user = { id: 1, email: 'test@test.com', role: 'user' };
const token = jwt.sign(user, 'test_secret', { expiresIn: '7d' });
const decoded = jwt.verify(token, 'test_secret');

  expect(decoded.id).toBe(1);
  expect(decoded.email).toBe('test@test.com');
  expect(decoded.role).toBe('user');
});

test('should reject expired token', () => {
  const user = { id: 1, email: 'test@test.com', role: 'user' };
  const token = jwt.sign(user, 'test_secret', { expiresIn: '1ms' });

  // Wait for expiry
  setTimeout(() => {
    expect(() => jwt.verify(token, 'test_secret')).toThrow();
  }, 10);
});
Enter fullscreen mode Exit fullscreen mode

});
});

2.2 Skills Unit Tests

File: marketplace/tests/unit/skills.test.js
javascript

const { Skill } = require('../../models');

describe('Skills Unit Tests', () => {
const validSkillData = {
name: 'Test Skill',
description: 'Test Description',
price: 100,
category: 'development',
sellerId: 1,
};

test('should validate skill data', async () => {
const skill = Skill.build(validSkillData);
const validation = await skill.validate();
expect(validation).toBeUndefined();
});

test('should reject invalid price', async () => {
const invalidData = { ...validSkillData, price: -10 };
const skill = Skill.build(invalidData);
await expect(skill.validate()).rejects.toThrow();
});

test('should reject missing name', async () => {
const invalidData = { ...validSkillData, name: null };
const skill = Skill.build(invalidData);
await expect(skill.validate()).rejects.toThrow();
});

test('should reject missing description', async () => {
const invalidData = { ...validSkillData, description: null };
const skill = Skill.build(invalidData);
await expect(skill.validate()).rejects.toThrow();
});
});

2.3 Escrow Unit Tests

File: marketplace/tests/unit/escrow.test.js
javascript

const { Escrow } = require('../../models');

describe('Escrow Unit Tests', () => {
const validEscrowData = {
orderId: 1,
amount: 150,
currency: 'USD',
moneroAmount: 0.0125,
moneroAddress: '8A1B2C3D4E5F6G7H8I9J0K',
status: 'pending',
};

test('should create escrow with pending status', async () => {
const escrow = Escrow.build(validEscrowData);
expect(escrow.status).toBe('pending');
});

test('should validate amount is positive', async () => {
const invalidData = { ...validEscrowData, amount: -50 };
const escrow = Escrow.build(invalidData);
await expect(escrow.validate()).rejects.toThrow();
});

test('should validate status enum', async () => {
const invalidData = { ...validEscrowData, status: 'invalid_status' };
const escrow = Escrow.build(invalidData);
await expect(escrow.validate()).rejects.toThrow();
});
});

🔗 Step 3: Integration Tests
3.1 Auth Integration Tests

File: marketplace/tests/integration/auth.test.js
javascript

const request = require('supertest');
const app = require('../../server');
const { User } = require('../../models');

describe('Auth Integration Tests', () => {
const testUser = {
email: 'test@test.com',
password: 'test123',
username: 'testuser',
name: 'Test User',
};

describe('Registration', () => {
test('should register a new user', async () => {
const response = await request(app)
.post('/api/auth/register')
.send(testUser)
.expect(201);

  expect(response.body).toHaveProperty('token');
  expect(response.body.user).toHaveProperty('id');
  expect(response.body.user.email).toBe(testUser.email);

  // Verify user in database
  const user = await User.findOne({ where: { email: testUser.email } });
  expect(user).not.toBeNull();
});

test('should reject duplicate email', async () => {
  await request(app)
    .post('/api/auth/register')
    .send(testUser)
    .expect(400);
});

test('should reject missing fields', async () => {
  const invalidData = { email: 'test@test.com' };
  await request(app)
    .post('/api/auth/register')
    .send(invalidData)
    .expect(400);
});
Enter fullscreen mode Exit fullscreen mode

});

describe('Login', () => {
test('should login successfully', async () => {
const response = await request(app)
.post('/api/auth/login')
.send({
email: testUser.email,
password: testUser.password,
})
.expect(200);

  expect(response.body).toHaveProperty('token');
  expect(response.body.user).toHaveProperty('id');
});

test('should reject wrong password', async () => {
  await request(app)
    .post('/api/auth/login')
    .send({
      email: testUser.email,
      password: 'wrong',
    })
    .expect(401);
});

test('should reject non-existent email', async () => {
  await request(app)
    .post('/api/auth/login')
    .send({
      email: 'nonexistent@test.com',
      password: 'test123',
    })
    .expect(401);
});
Enter fullscreen mode Exit fullscreen mode

});
});

3.2 Skills Integration Tests

File: marketplace/tests/integration/skills.test.js
javascript

const request = require('supertest');
const app = require('../../server');
const { User, Skill } = require('../../models');

describe('Skills Integration Tests', () => {
let authToken;
let sellerToken;
let testSkillId;

beforeAll(async () => {
// Create test users
const buyer = await User.create({
email: 'buyer@test.com',
password: 'hashed',
username: 'buyer',
name: 'Buyer Test',
});

const seller = await User.create({
  email: 'seller@test.com',
  password: 'hashed',
  username: 'seller',
  name: 'Seller Test',
  role: 'seller',
});

// Get tokens
// In real tests, login to get tokens
authToken = 'mock_token';
sellerToken = 'mock_seller_token';
Enter fullscreen mode Exit fullscreen mode

});

describe('POST /api/skills', () => {
test('should create a skill as seller', async () => {
const response = await request(app)
.post('/api/skills')
.set('Authorization', Bearer ${sellerToken})
.send({
name: 'Test Skill',
description: 'Test Description',
price: 100,
category: 'development',
})
.expect(201);

  testSkillId = response.body.id;
  expect(response.body.name).toBe('Test Skill');
  expect(response.body.price).toBe(100);
});

test('should reject creation without auth', async () => {
  await request(app)
    .post('/api/skills')
    .send({
      name: 'Test Skill',
      description: 'Test Description',
      price: 100,
      category: 'development',
    })
    .expect(401);
});

test('should reject missing fields', async () => {
  await request(app)
    .post('/api/skills')
    .set('Authorization', `Bearer ${sellerToken}`)
    .send({
      name: 'Test Skill',
      price: 100,
    })
    .expect(400);
});
Enter fullscreen mode Exit fullscreen mode

});

describe('GET /api/skills', () => {
test('should list all skills', async () => {
const response = await request(app)
.get('/api/skills')
.expect(200);

  expect(Array.isArray(response.body.skills)).toBe(true);
  expect(response.body.skills.length).toBeGreaterThan(0);
});

test('should filter by category', async () => {
  const response = await request(app)
    .get('/api/skills?category=development')
    .expect(200);

  expect(response.body.skills[0].category).toBe('development');
});
Enter fullscreen mode Exit fullscreen mode

});

describe('GET /api/skills/:id', () => {
test('should get skill by id', async () => {
const response = await request(app)
.get(/api/skills/${testSkillId})
.expect(200);

  expect(response.body.id).toBe(testSkillId);
});

test('should return 404 for non-existent skill', async () => {
  await request(app)
    .get('/api/skills/99999')
    .expect(404);
});
Enter fullscreen mode Exit fullscreen mode

});
});

3.3 Orders Integration Tests

File: marketplace/tests/integration/orders.test.js
javascript

const request = require('supertest');
const app = require('../../server');
const { Order, User, Skill } = require('../../models');

describe('Orders Integration Tests', () => {
let buyerToken;
let sellerToken;
let testSkillId;

beforeAll(async () => {
// Create test data
const buyer = await User.create({
email: 'buyer@test.com',
password: 'hashed',
username: 'buyer',
name: 'Buyer Test',
});

const seller = await User.create({
  email: 'seller@test.com',
  password: 'hashed',
  username: 'seller',
  name: 'Seller Test',
  role: 'seller',
});

const skill = await Skill.create({
  name: 'Test Skill',
  description: 'Test Description',
  price: 100,
  category: 'development',
  sellerId: seller.id,
});

testSkillId = skill.id;
// Tokens would be obtained via login in real tests
buyerToken = 'mock_buyer_token';
sellerToken = 'mock_seller_token';
Enter fullscreen mode Exit fullscreen mode

});

describe('POST /api/orders', () => {
test('should create order as buyer', async () => {
const response = await request(app)
.post('/api/orders')
.set('Authorization', Bearer ${buyerToken})
.send({ skillId: testSkillId })
.expect(201);

  expect(response.body).toHaveProperty('id');
  expect(response.body.status).toBe('pending');
  expect(response.body.amount).toBe(100);
});

test('should reject self-order', async () => {
  const response = await request(app)
    .post('/api/orders')
    .set('Authorization', `Bearer ${sellerToken}`)
    .send({ skillId: testSkillId })
    .expect(400);

  expect(response.body.error).toBe('Non puoi acquistare la tua stessa competenza');
});

test('should reject non-existent skill', async () => {
  await request(app)
    .post('/api/orders')
    .set('Authorization', `Bearer ${buyerToken}`)
    .send({ skillId: 99999 })
    .expect(404);
});
Enter fullscreen mode Exit fullscreen mode

});

describe('GET /api/orders/my', () => {
test('should get user orders', async () => {
const response = await request(app)
.get('/api/orders/my')
.set('Authorization', Bearer ${buyerToken})
.expect(200);

  expect(Array.isArray(response.body.orders)).toBe(true);
});
Enter fullscreen mode Exit fullscreen mode

});
});

🎭 Step 4: Mocking External Services
4.1 Monero Mock

File: gateway/tests/mocks/monero.mock.js
javascript

// Mock Monero client
const mockMoneroClient = {
getWallet: jest.fn().mockResolvedValue({
getBalance: jest.fn().mockResolvedValue({ getBalance: () => 100000 }),
createSubaddress: jest.fn().mockResolvedValue({
getAddress: () => '8A1B2C3D4E5F6G7H8I9J0K',
getIndex: () => 1,
}),
getTransfers: jest.fn().mockResolvedValue([
{
getTxHash: () => 'tx_123456',
getAmount: () => 0.0125,
getNumConfirmations: () => 10,
isConfirmed: () => true,
getTimestamp: () => Date.now(),
},
]),
send: jest.fn().mockResolvedValue({
getTxHash: () => 'tx_789012',
getAmount: () => 0.0125,
getFee: () => 0.0001,
}),
}),
};

jest.mock('monero-javascript', () => ({
createWalletRpc: jest.fn().mockResolvedValue(mockMoneroClient),
}));

module.exports = mockMoneroClient;

4.2 Webhook Mock

File: marketplace/tests/mocks/webhook.mock.js
javascript

// Mock webhook sender
const mockWebhook = {
sendWebhook: jest.fn().mockResolvedValue({
success: true,
order: { id: 1, status: 'paid' },
}),
};

jest.mock('../../services/webhookSender', () => mockWebhook);

module.exports = mockWebhook;

🎬 Step 5: End-to-End Tests
5.1 Full Flow E2E Test

File: marketplace/tests/e2e/full-flow.test.js
javascript

const request = require('supertest');
const app = require('../../server');
const { sequelize } = require('../../models');

describe('End-to-End Flow Tests', () => {
let buyerToken;
let sellerToken;
let skillId;
let orderId;

// Reset database before each test
beforeEach(async () => {
await sequelize.sync({ force: true });
});

test('Complete flow: Register → Login → Create Skill → Place Order → Pay → Complete', async () => {
// 1. Register buyer
const buyerReg = await request(app)
.post('/api/auth/register')
.send({
email: 'buyer@test.com',
password: 'test123',
username: 'buyer',
name: 'Buyer Test',
})
.expect(201);

// 2. Register seller
const sellerReg = await request(app)
  .post('/api/auth/register')
  .send({
    email: 'seller@test.com',
    password: 'test123',
    username: 'seller',
    name: 'Seller Test',
  })
  .expect(201);

// 3. Login buyer
const buyerLogin = await request(app)
  .post('/api/auth/login')
  .send({
    email: 'buyer@test.com',
    password: 'test123',
  })
  .expect(200);

buyerToken = buyerLogin.body.token;

// 4. Login seller
const sellerLogin = await request(app)
  .post('/api/auth/login')
  .send({
    email: 'seller@test.com',
    password: 'test123',
  })
  .expect(200);

sellerToken = sellerLogin.body.token;

// 5. Promote seller to seller role (in test, skip this step or use admin)
// In real test, we'd update the role in database

// 6. Create skill
const skillRes = await request(app)
  .post('/api/skills')
  .set('Authorization', `Bearer ${sellerToken}`)
  .send({
    name: 'E2E Test Skill',
    description: 'E2E Test Description',
    price: 150,
    category: 'development',
  })
  .expect(201);

skillId = skillRes.body.id;

// 7. Place order
const orderRes = await request(app)
  .post('/api/orders')
  .set('Authorization', `Bearer ${buyerToken}`)
  .send({ skillId })
  .expect(201);

orderId = orderRes.body.id;
expect(orderRes.body.status).toBe('pending');

// 8. Simulate payment (mock Monero)
// In real test, we would trigger the webhook
const webhookRes = await request(app)
  .post('/webhook/order-update')
  .send({
    orderId,
    status: 'confirmed',
    txHash: 'mock_tx_hash',
    amount: 150,
  })
  .expect(200);

// 9. Check order status updated to paid
const orderCheck = await request(app)
  .get(`/api/orders/${orderId}`)
  .set('Authorization', `Bearer ${buyerToken}`)
  .expect(200);

expect(orderCheck.body.status).toBe('paid');

// 10. Update order to in_progress
await request(app)
  .patch(`/api/orders/${orderId}/status`)
  .set('Authorization', `Bearer ${sellerToken}`)
  .send({ status: 'in_progress' })
  .expect(200);

// 11. Complete order
await request(app)
  .patch(`/api/orders/${orderId}/status`)
  .set('Authorization', `Bearer ${sellerToken}`)
  .send({ status: 'completed' })
  .expect(200);

// 12. Verify order completed
const finalOrder = await request(app)
  .get(`/api/orders/${orderId}`)
  .set('Authorization', `Bearer ${buyerToken}`)
  .expect(200);

expect(finalOrder.body.status).toBe('completed');
Enter fullscreen mode Exit fullscreen mode

}, 60000);

test('Dispute flow: Order → Dispute → Resolve', async () => {
// Similar flow for dispute testing
// ... setup code ...

// 1. Create order (using helpers from previous test)
// 2. Open dispute
// 3. Resolve dispute
// 4. Verify resolution
Enter fullscreen mode Exit fullscreen mode

});
});

5.2 Playwright E2E Tests (Frontend)

File: tests/e2e/playwright.config.js
javascript

const { defineConfig } = require('@playwright/test');

module.exports = defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:4000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { browserName: 'chromium' },
},
{
name: 'firefox',
use: { browserName: 'firefox' },
},
{
name: 'webkit',
use: { browserName: 'webkit' },
},
],
});

File: tests/e2e/auth-flow.spec.js
javascript

const { test, expect } = require('@playwright/test');

test.describe('Authentication Flow', () => {
test('should register and login', async ({ page }) => {
await page.goto('/login');

// Go to registration page
await page.click('text=Sign Up');
await expect(page).toHaveURL('/register');

// Fill registration form
await page.fill('input[name="email"]', 'playwright@test.com');
await page.fill('input[name="password"]', 'test123');
await page.fill('input[name="username"]', 'playwright');
await page.fill('input[name="name"]', 'Playwright Test');

// Submit
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');

// Verify user is logged in
await expect(page.locator('text=Playwright Test')).toBeVisible();
Enter fullscreen mode Exit fullscreen mode

});
});

🔄 Step 6: CI/CD Pipeline
6.1 GitHub Actions Workflow

File: .github/workflows/test.yml
yaml

name: Test Suite

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

env:
NODE_VERSION: 18

jobs:
test-marketplace:
name: Test Marketplace
runs-on: ubuntu-latest

services:
  postgres:
    image: postgres:15
    env:
      POSTGRES_PASSWORD: test
      POSTGRES_DB: test
    ports:
      - 5432:5432
    options: >-
      --health-cmd pg_isready
      --health-interval 10s
      --health-timeout 5s
      --health-retries 5

steps:
  - uses: actions/checkout@v3

  - name: Setup Node.js
    uses: actions/setup-node@v3
    with:
      node-version: ${{ env.NODE_VERSION }}
      cache: 'npm'
      cache-dependency-path: marketplace/package-lock.json

  - name: Install dependencies
    working-directory: ./marketplace
    run: npm ci

  - name: Run linter
    working-directory: ./marketplace
    run: npm run lint

  - name: Run unit tests
    working-directory: ./marketplace
    run: npm test -- --testPathPattern=unit

  - name: Run integration tests
    working-directory: ./marketplace
    run: npm test -- --testPathPattern=integration
    env:
      DATABASE_URL: postgresql://postgres:test@localhost:5432/test
      JWT_SECRET: test_secret
      NODE_ENV: test

  - name: Upload coverage report
    uses: codecov/codecov-action@v3
    with:
      directory: ./marketplace/coverage
      flags: marketplace
      name: marketplace
Enter fullscreen mode Exit fullscreen mode

test-gateway:
name: Test Gateway
runs-on: ubuntu-latest

services:
  mongodb:
    image: mongo:6
    ports:
      - 27017:27017

steps:
  - uses: actions/checkout@v3

  - name: Setup Node.js
    uses: actions/setup-node@v3
    with:
      node-version: ${{ env.NODE_VERSION }}
      cache: 'npm'
      cache-dependency-path: gateway/package-lock.json

  - name: Install dependencies
    working-directory: ./gateway
    run: npm ci

  - name: Run tests
    working-directory: ./gateway
    run: npm test
    env:
      MONGODB_URI: mongodb://localhost:27017/test
      JWT_SECRET: test_secret
      NODE_ENV: test

  - name: Upload coverage report
    uses: codecov/codecov-action@v3
    with:
      directory: ./gateway/coverage
      flags: gateway
      name: gateway
Enter fullscreen mode Exit fullscreen mode

test-e2e:
name: End-to-End Tests
runs-on: ubuntu-latest
needs: [test-marketplace, test-gateway]

steps:
  - uses: actions/checkout@v3

  - name: Setup Node.js
    uses: actions/setup-node@v3
    with:
      node-version: ${{ env.NODE_VERSION }}

  - name: Install dependencies
    working-directory: ./marketplace
    run: npm ci

  - name: Start services
    run: |
      docker-compose -f docker-compose.test.yml up -d

  - name: Wait for services
    run: |
      sleep 10
      curl -f http://localhost:4000/health

  - name: Run E2E tests
    working-directory: ./marketplace
    run: npm test -- --testPathPattern=e2e
    env:
      DATABASE_URL: postgresql://postgres:test@localhost:5432/test
      JWT_SECRET: test_secret
      NODE_ENV: test

  - name: Shutdown services
    if: always()
    run: docker-compose -f docker-compose.test.yml down
Enter fullscreen mode Exit fullscreen mode

📊 Step 7: Test Coverage
7.1 Coverage Report
bash

Generate coverage report

npm test -- --coverage

View coverage report

open coverage/lcov-report/index.html

7.2 Coverage Thresholds
Metric Gateway Marketplace
Statements 75% 80%
Branches 70% 75%
Functions 75% 80%
Lines 75% 80%
📝 Step 8: Test Scripts

File: package.json (Add to scripts)
json

{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:ci": "jest --coverage --ci",
"test:unit": "jest --testPathPattern=unit",
"test:integration": "jest --testPathPattern=integration",
"test:e2e": "jest --testPathPattern=e2e --runInBand",
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand"
}
}

🐛 Troubleshooting
"Tests failing in CI"
bash

Run tests in CI environment

NODE_ENV=ci npm test

Debug with verbose output

npm test -- --verbose

Run specific failing test

npm test -- --testNamePattern="test name"

"Database connection timeout"
bash

Increase timeout in jest config

testTimeout: 60000

Check database is running

docker ps | grep postgres

"Mock not working"
bash

Clear Jest cache

jest --clearCache

Run tests with no cache

npm test -- --no-cache

📚 Resources

Jest Documentation: jestjs.io

Supertest: npmjs.com/package/supertest

Playwright: playwright.dev

GitHub Actions: docs.github.com/actions
Enter fullscreen mode Exit fullscreen mode

🌐 Connect with Me

📖 Blog & Articles: DEV.to - Daniel Ioni
🐦 X (Twitter): @myzubster
💼 LinkedIn: Daniel Ioni
🐙 GitHub: DanielIoni-creator
🎵 TikTok: @h4x0r_23

⭐ Star the project on GitHub – it helps a lot!

Built with ❤️ for privacy, freedom, and decentralization.

Happy testing! 🚀
✅ Instructions for Publishing

Copy all the content above

Go to dev.to/new
Enter fullscreen mode Exit fullscreen mode

Top comments (0)