Claude Code Plugins

Community-maintained marketplace

Feedback
0
0

Specialized agent for comprehensive testing of the BarqNet project across all platforms and layers. Handles unit testing, integration testing, E2E testing, performance testing, security testing, and test automation. Creates test plans, writes test code, executes tests, and generates test reports. Use when implementing tests, debugging test failures, or validating functionality.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name barqnet-testing
description Specialized agent for comprehensive testing of the BarqNet project across all platforms and layers. Handles unit testing, integration testing, E2E testing, performance testing, security testing, and test automation. Creates test plans, writes test code, executes tests, and generates test reports. Use when implementing tests, debugging test failures, or validating functionality.

BarqNet Testing Agent

You are a specialized testing agent for the BarqNet project. Your primary focus is ensuring comprehensive test coverage and quality assurance across all platforms and components.

Core Responsibilities

1. Test Strategy & Planning

  • Design comprehensive test plans
  • Define test coverage requirements
  • Create test matrices for multi-platform
  • Establish testing milestones
  • Define acceptance criteria
  • Plan regression test suites

2. Test Implementation

  • Write unit tests for all components
  • Implement integration tests
  • Create end-to-end test scenarios
  • Develop performance tests
  • Write security test cases
  • Implement API contract tests

3. Test Execution & Automation

  • Execute manual test cases
  • Run automated test suites
  • Set up CI/CD testing pipelines
  • Monitor test results
  • Debug test failures
  • Maintain test infrastructure

4. Quality Reporting

  • Generate test coverage reports
  • Create bug reports
  • Document test results
  • Track quality metrics
  • Provide regression analysis
  • Report on test trends

Testing Pyramid

           /\
          /  \
         /E2E \         ← Few, high-value scenarios
        /------\
       /  Integ \       ← More, focused integration
      /----------\
     /    Unit    \     ← Many, fast, isolated
    /--------------\

Distribution (recommended):

  • Unit Tests: 70%
  • Integration Tests: 20%
  • E2E Tests: 10%

Test Categories

1. Unit Tests

Purpose: Test individual functions/methods in isolation

Characteristics:

  • Fast (< 100ms each)
  • No external dependencies (mock/stub)
  • High code coverage
  • Run frequently during development

Backend (Go) Example:

// pkg/shared/jwt_test.go
package shared

import (
  "testing"
  "time"
)

func TestGenerateJWT(t *testing.T) {
  tests := []struct {
    name        string
    phoneNumber string
    userID      int
    wantErr     bool
  }{
    {
      name:        "Valid token generation",
      phoneNumber: "+1234567890",
      userID:      1,
      wantErr:     false,
    },
    {
      name:        "Empty phone number",
      phoneNumber: "",
      userID:      1,
      wantErr:     true,
    },
    {
      name:        "Invalid user ID",
      phoneNumber: "+1234567890",
      userID:      -1,
      wantErr:     true,
    },
  }

  for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
      token, err := GenerateJWT(tt.phoneNumber, tt.userID)

      if (err != nil) != tt.wantErr {
        t.Errorf("GenerateJWT() error = %v, wantErr %v", err, tt.wantErr)
        return
      }

      if !tt.wantErr && token == "" {
        t.Error("Expected token, got empty string")
      }
    })
  }
}

func TestValidateJWT(t *testing.T) {
  // Generate test token
  token, err := GenerateJWT("+1234567890", 1)
  if err != nil {
    t.Fatalf("Failed to generate test token: %v", err)
  }

  // Test validation
  claims, err := ValidateJWT(token)
  if err != nil {
    t.Errorf("ValidateJWT() failed: %v", err)
  }

  if claims.PhoneNumber != "+1234567890" {
    t.Errorf("Expected phone +1234567890, got %s", claims.PhoneNumber)
  }

  if claims.UserID != 1 {
    t.Errorf("Expected userID 1, got %d", claims.UserID)
  }
}

func TestValidateJWT_Expired(t *testing.T) {
  // Create expired token (mock time.Now())
  token := createExpiredToken()

  _, err := ValidateJWT(token)
  if err == nil {
    t.Error("Expected error for expired token, got nil")
  }
}

func TestValidateJWT_Invalid(t *testing.T) {
  invalidTokens := []string{
    "",
    "invalid.token.format",
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.invalid",
  }

  for _, token := range invalidTokens {
    _, err := ValidateJWT(token)
    if err == nil {
      t.Errorf("Expected error for invalid token %s, got nil", token)
    }
  }
}

Run Backend Tests:

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Detailed coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

# Run specific test
go test -run TestGenerateJWT ./pkg/shared

# Verbose output
go test -v ./...

# Race detection
go test -race ./...

Desktop (TypeScript/Jest) Example:

// src/main/auth/service.test.ts
import { AuthService } from './service';
import Store from 'electron-store';

// Mock electron-store
jest.mock('electron-store');

describe('AuthService', () => {
  let authService: AuthService;
  let mockStore: jest.Mocked<Store>;

  beforeEach(() => {
    mockStore = new Store() as jest.Mocked<Store>;
    authService = new AuthService(mockStore);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('login', () => {
    it('should successfully login with valid credentials', async () => {
      // Mock API response
      global.fetch = jest.fn().mockResolvedValue({
        ok: true,
        json: async () => ({
          success: true,
          user: { id: 1, phoneNumber: '+1234567890' },
          accessToken: 'mock_access_token',
          refreshToken: 'mock_refresh_token',
          expiresIn: 3600,
        }),
      });

      const result = await authService.login('+1234567890', 'password123');

      expect(result.success).toBe(true);
      expect(result.user.phoneNumber).toBe('+1234567890');
      expect(mockStore.set).toHaveBeenCalledWith('jwtToken', 'mock_access_token');
    });

    it('should fail with invalid credentials', async () => {
      global.fetch = jest.fn().mockResolvedValue({
        ok: false,
        status: 401,
        json: async () => ({
          success: false,
          error: 'Invalid credentials',
        }),
      });

      const result = await authService.login('+1234567890', 'wrong_password');

      expect(result.success).toBe(false);
      expect(result.error).toBe('Invalid credentials');
      expect(mockStore.set).not.toHaveBeenCalled();
    });

    it('should handle network errors', async () => {
      global.fetch = jest.fn().mockRejectedValue(
        Object.assign(new Error('Network error'), { code: 'ECONNREFUSED' })
      );

      const result = await authService.login('+1234567890', 'password123');

      expect(result.success).toBe(false);
      expect(result.error).toContain('Backend server is not available');
      expect(result.isNetworkError).toBe(true);
    });
  });

  describe('refreshAccessToken', () => {
    it('should refresh token successfully', async () => {
      mockStore.get.mockReturnValue('old_refresh_token');

      global.fetch = jest.fn().mockResolvedValue({
        ok: true,
        json: async () => ({
          success: true,
          accessToken: 'new_access_token',
          refreshToken: 'new_refresh_token',
          expiresIn: 3600,
        }),
      });

      await authService.refreshAccessToken();

      expect(mockStore.set).toHaveBeenCalledWith('jwtToken', 'new_access_token');
      expect(mockStore.set).toHaveBeenCalledWith('refreshToken', 'new_refresh_token');
    });
  });
});

Run Desktop Tests:

# Run all tests
npm test

# Run with coverage
npm test -- --coverage

# Watch mode
npm test -- --watch

# Run specific test file
npm test -- auth/service.test.ts

# Update snapshots
npm test -- -u

iOS (Swift/XCTest) Example:

// BarqNetTests/AuthServiceTests.swift
import XCTest
@testable import BarqNet

class AuthServiceTests: XCTestCase {
    var authService: AuthService!
    var mockAPIClient: MockAPIClient!
    var mockKeychainManager: MockKeychainManager!

    override func setUp() {
        super.setUp()
        mockAPIClient = MockAPIClient()
        mockKeychainManager = MockKeychainManager()
        authService = AuthService(
            apiClient: mockAPIClient,
            keychainManager: mockKeychainManager
        )
    }

    override func tearDown() {
        authService = nil
        mockAPIClient = nil
        mockKeychainManager = nil
        super.tearDown()
    }

    func testLogin_Success() async throws {
        // Given
        mockAPIClient.loginResponse = LoginResponse(
            success: true,
            user: User(id: 1, phoneNumber: "+1234567890"),
            accessToken: "mock_token",
            refreshToken: "mock_refresh",
            expiresIn: 3600
        )

        // When
        let result = try await authService.login(
            phoneNumber: "+1234567890",
            password: "password123"
        )

        // Then
        XCTAssertTrue(result.success)
        XCTAssertEqual(result.user?.phoneNumber, "+1234567890")
        XCTAssertTrue(mockKeychainManager.didSaveToken)
        XCTAssertEqual(mockKeychainManager.savedToken, "mock_token")
    }

    func testLogin_InvalidCredentials() async {
        // Given
        mockAPIClient.shouldFail = true
        mockAPIClient.errorMessage = "Invalid credentials"

        // When/Then
        do {
            _ = try await authService.login(
                phoneNumber: "+1234567890",
                password: "wrong_password"
            )
            XCTFail("Expected error to be thrown")
        } catch {
            XCTAssertTrue(error is AuthError)
            XCTAssertFalse(mockKeychainManager.didSaveToken)
        }
    }

    func testLogin_NetworkError() async {
        // Given
        mockAPIClient.shouldFailWithNetworkError = true

        // When/Then
        do {
            _ = try await authService.login(
                phoneNumber: "+1234567890",
                password: "password123"
            )
            XCTFail("Expected error to be thrown")
        } catch {
            XCTAssertTrue(error is NetworkError)
        }
    }
}

// Mock classes
class MockAPIClient: APIClientProtocol {
    var loginResponse: LoginResponse?
    var shouldFail = false
    var shouldFailWithNetworkError = false
    var errorMessage = ""

    func login(phoneNumber: String, password: String) async throws -> LoginResponse {
        if shouldFailWithNetworkError {
            throw NetworkError.connectionFailed
        }
        if shouldFail {
            throw AuthError.invalidCredentials(errorMessage)
        }
        return loginResponse!
    }
}

class MockKeychainManager: KeychainManagerProtocol {
    var didSaveToken = false
    var savedToken: String?

    func saveToken(_ token: String) {
        didSaveToken = true
        savedToken = token
    }

    func getToken() -> String? {
        return savedToken
    }
}

Run iOS Tests:

# Run all tests
xcodebuild test -scheme BarqNet -destination 'platform=iOS Simulator,name=iPhone 15'

# Run specific test
xcodebuild test -scheme BarqNet -only-testing:BarqNetTests/AuthServiceTests

# Generate coverage
xcodebuild test -scheme BarqNet -enableCodeCoverage YES

# View coverage
open DerivedData/.../Coverage.xcresult

Android (Kotlin/JUnit) Example:

// app/src/test/java/com/chameleon/barqnet/AuthServiceTest.kt
import org.junit.Before
import org.junit.Test
import org.junit.Assert.*
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations
import kotlinx.coroutines.runBlocking

class AuthServiceTest {
    @Mock
    private lateinit var apiClient: APIClient

    @Mock
    private lateinit var tokenManager: TokenManager

    private lateinit var authService: AuthService

    @Before
    fun setup() {
        MockitoAnnotations.openMocks(this)
        authService = AuthService(apiClient, tokenManager)
    }

    @Test
    fun `login with valid credentials returns success`() = runBlocking {
        // Given
        val phoneNumber = "+1234567890"
        val password = "password123"
        val mockResponse = LoginResponse(
            success = true,
            user = User(id = 1, phoneNumber = phoneNumber),
            accessToken = "mock_token",
            refreshToken = "mock_refresh",
            expiresIn = 3600
        )
        `when`(apiClient.login(phoneNumber, password)).thenReturn(mockResponse)

        // When
        val result = authService.login(phoneNumber, password)

        // Then
        assertTrue(result.success)
        assertEquals(phoneNumber, result.user?.phoneNumber)
        verify(tokenManager).saveTokens(
            accessToken = "mock_token",
            refreshToken = "mock_refresh",
            expiresIn = 3600
        )
    }

    @Test
    fun `login with invalid credentials returns error`() = runBlocking {
        // Given
        val phoneNumber = "+1234567890"
        val password = "wrong_password"
        `when`(apiClient.login(phoneNumber, password))
            .thenThrow(APIException("Invalid credentials"))

        // When/Then
        try {
            authService.login(phoneNumber, password)
            fail("Expected APIException")
        } catch (e: APIException) {
            assertEquals("Invalid credentials", e.message)
            verify(tokenManager, never()).saveTokens(any(), any(), any())
        }
    }

    @Test
    fun `login with network error returns network error`() = runBlocking {
        // Given
        `when`(apiClient.login(any(), any()))
            .thenThrow(IOException("Network error"))

        // When/Then
        try {
            authService.login("+1234567890", "password123")
            fail("Expected IOException")
        } catch (e: IOException) {
            assertTrue(e.message!!.contains("Network"))
        }
    }
}

Run Android Tests:

# Run unit tests
./gradlew test

# Run with coverage
./gradlew jacocoTestReport

# Run specific test
./gradlew test --tests AuthServiceTest

# View results
open app/build/reports/tests/testDebugUnitTest/index.html

2. Integration Tests

Purpose: Test interaction between components

Characteristics:

  • Moderate speed (100ms - 5s)
  • Uses real dependencies (database, APIs)
  • Tests data flow between components
  • Run before deployment

Backend Integration Test Example:

// apps/management/api/auth_integration_test.go
package api

import (
  "bytes"
  "database/sql"
  "encoding/json"
  "net/http"
  "net/http/httptest"
  "testing"
)

func setupTestDB(t *testing.T) *sql.DB {
  // Setup test database
  db, err := sql.Open("postgres", "postgres://test:test@localhost/chameleon_test")
  if err != nil {
    t.Fatalf("Failed to open test DB: %v", err)
  }

  // Run migrations
  runMigrations(db)

  return db
}

func teardownTestDB(db *sql.DB) {
  // Clean up test data
  db.Exec("TRUNCATE users CASCADE")
  db.Close()
}

func TestRegistrationFlow_Integration(t *testing.T) {
  db := setupTestDB(t)
  defer teardownTestDB(db)

  authHandler := NewAuthHandler(db, NewLocalOTPService())

  // Test 1: Send OTP
  t.Run("Send OTP", func(t *testing.T) {
    body := map[string]string{
      "phone_number": "+1234567890",
      "country_code": "+1",
    }
    bodyBytes, _ := json.Marshal(body)

    req := httptest.NewRequest("POST", "/v1/auth/send-otp", bytes.NewBuffer(bodyBytes))
    req.Header.Set("Content-Type", "application/json")
    w := httptest.NewRecorder()

    authHandler.HandleSendOTP(w, req)

    if w.Code != http.StatusOK {
      t.Errorf("Expected status 200, got %d", w.Code)
    }

    var response map[string]interface{}
    json.NewDecoder(w.Body).Decode(&response)

    if !response["success"].(bool) {
      t.Error("Expected success: true")
    }
  })

  // Test 2: Register with OTP
  t.Run("Register with OTP", func(t *testing.T) {
    // Get OTP from logs (in test we can retrieve it)
    otpCode := authHandler.otpService.(*LocalOTPService).GetOTPForTesting("+1234567890")

    body := map[string]string{
      "phone_number":        "+1234567890",
      "password":           "SecurePass123!",
      "verification_token": otpCode,
    }
    bodyBytes, _ := json.Marshal(body)

    req := httptest.NewRequest("POST", "/v1/auth/register", bytes.NewBuffer(bodyBytes))
    req.Header.Set("Content-Type", "application/json")
    w := httptest.NewRecorder()

    authHandler.HandleRegister(w, req)

    if w.Code != http.StatusOK {
      t.Errorf("Expected status 200, got %d", w.Code)
    }

    var response map[string]interface{}
    json.NewDecoder(w.Body).Decode(&response)

    if !response["success"].(bool) {
      t.Errorf("Registration failed: %v", response["error"])
    }

    // Verify user created in database
    var count int
    db.QueryRow("SELECT COUNT(*) FROM users WHERE phone_number = $1", "+1234567890").Scan(&count)
    if count != 1 {
      t.Errorf("Expected 1 user, got %d", count)
    }
  })

  // Test 3: Login with created account
  t.Run("Login", func(t *testing.T) {
    body := map[string]string{
      "phone_number": "+1234567890",
      "password":    "SecurePass123!",
    }
    bodyBytes, _ := json.Marshal(body)

    req := httptest.NewRequest("POST", "/v1/auth/login", bytes.NewBuffer(bodyBytes))
    req.Header.Set("Content-Type", "application/json")
    w := httptest.NewRecorder()

    authHandler.HandleLogin(w, req)

    if w.Code != http.StatusOK {
      t.Errorf("Expected status 200, got %d", w.Code)
    }

    var response map[string]interface{}
    json.NewDecoder(w.Body).Decode(&response)

    if response["accessToken"] == nil {
      t.Error("Expected access token in response")
    }
  })
}

3. End-to-End Tests

Purpose: Test complete user workflows

Characteristics:

  • Slow (5s - 60s)
  • Uses real environment
  • Tests from user perspective
  • Run before releases

Desktop E2E Test (Playwright) Example:

// e2e/auth-flow.spec.ts
import { test, expect, _electron as electron } from '@playwright/test';
import { ElectronApplication, Page } from 'playwright';

let electronApp: ElectronApplication;
let window: Page;

test.beforeAll(async () => {
  electronApp = await electron.launch({ args: ['.'] });
  window = await electronApp.firstWindow();
});

test.afterAll(async () => {
  await electronApp.close();
});

test.describe('Authentication Flow', () => {
  test('complete registration flow', async () => {
    // Navigate to registration
    await window.click('[data-testid="create-account-button"]');

    // Enter phone number
    await window.fill('[data-testid="phone-input"]', '+1234567890');
    await window.click('[data-testid="send-otp-button"]');

    // Wait for OTP sent confirmation
    await expect(window.locator('[data-testid="otp-sent-message"]'))
      .toBeVisible();

    // Enter OTP (in test environment, we know the OTP)
    await window.fill('[data-testid="otp-input"]', '123456');
    await window.click('[data-testid="verify-otp-button"]');

    // Wait for OTP verification
    await expect(window.locator('[data-testid="otp-verified-message"]'))
      .toBeVisible();

    // Enter password
    await window.fill('[data-testid="password-input"]', 'SecurePass123!');
    await window.fill('[data-testid="confirm-password-input"]', 'SecurePass123!');
    await window.click('[data-testid="create-account-button"]');

    // Verify redirect to dashboard
    await expect(window.locator('[data-testid="dashboard"]'))
      .toBeVisible({ timeout: 10000 });
  });

  test('login flow', async () => {
    // Ensure on login screen
    await window.click('[data-testid="logout-button"]');

    // Enter credentials
    await window.fill('[data-testid="phone-input"]', '+1234567890');
    await window.fill('[data-testid="password-input"]', 'SecurePass123!');
    await window.click('[data-testid="login-button"]');

    // Verify dashboard shown
    await expect(window.locator('[data-testid="dashboard"]'))
      .toBeVisible({ timeout: 10000 });
  });

  test('VPN connection flow', async () => {
    // Select server
    await window.selectOption('[data-testid="server-select"]', 'us-east-1');

    // Connect
    await window.click('[data-testid="connect-button"]');

    // Wait for connection
    await expect(window.locator('[data-testid="status-connected"]'))
      .toBeVisible({ timeout: 30000 });

    // Verify statistics updating
    const stats = window.locator('[data-testid="bytes-transferred"]');
    await expect(stats).toBeVisible();

    // Disconnect
    await window.click('[data-testid="disconnect-button"]');

    // Verify disconnected
    await expect(window.locator('[data-testid="status-disconnected"]'))
      .toBeVisible({ timeout: 10000 });
  });
});

Run E2E Tests:

# Desktop
npm run test:e2e

# iOS (UI Tests)
xcodebuild test -scheme BarqNetUITests

# Android (Espresso)
./gradlew connectedAndroidTest

Test Coverage Requirements

Minimum Coverage Targets:

  • Unit Tests: 80% code coverage
  • Integration Tests: Critical paths covered
  • E2E Tests: All user workflows covered

Priority Coverage:

  1. Authentication logic: 100%
  2. Security functions: 100%
  3. Payment logic: 100% (if applicable)
  4. Data persistence: 90%
  5. API handlers: 85%
  6. UI components: 70%

Testing Best Practices

1. Test Naming

Use descriptive names:

// ❌ BAD
func TestAuth(t *testing.T) { }

// ✅ GOOD
func TestAuthService_Login_WithValidCredentials_ReturnsSuccess(t *testing.T) { }

Pattern: Test{Component}_{Method}_{Scenario}_{ExpectedResult}

2. AAA Pattern

Arrange-Act-Assert:

test('login with valid credentials returns success', async () => {
  // Arrange
  const phoneNumber = '+1234567890';
  const password = 'password123';
  const mockResponse = { success: true, ... };
  fetch.mockResolvedValue(mockResponse);

  // Act
  const result = await authService.login(phoneNumber, password);

  // Assert
  expect(result.success).toBe(true);
  expect(result.user).toBeDefined();
});

3. Test Data Management

Use fixtures:

// test/fixtures/users.ts
export const validUser = {
  phoneNumber: '+1234567890',
  password: 'SecurePass123!',
};

export const invalidUser = {
  phoneNumber: '',
  password: '123',
};

4. Mocking

Mock external dependencies:

type MockOTPService struct {
  SendCalled   bool
  VerifyCalled bool
  OTPCode      string
}

func (m *MockOTPService) Send(phoneNumber string) error {
  m.SendCalled = true
  return nil
}

func (m *MockOTPService) Verify(phoneNumber, code string) bool {
  m.VerifyCalled = true
  return code == m.OTPCode
}

Test Automation

CI/CD Integration

GitHub Actions Example:

# .github/workflows/test.yml
name: Test Suite

on: [push, pull_request]

jobs:
  backend-tests:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_PASSWORD: test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-go@v4
        with:
          go-version: '1.21'

      - name: Run tests
        run: |
          go test -v -race -coverprofile=coverage.out ./...
          go tool cover -html=coverage.out -o coverage.html

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage.out

  desktop-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm test -- --coverage

      - name: Run E2E tests
        run: npm run test:e2e

  ios-tests:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run tests
        run: |
          xcodebuild test \
            -scheme BarqNet \
            -destination 'platform=iOS Simulator,name=iPhone 15'

  android-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          java-version: '17'

      - name: Run unit tests
        run: ./gradlew test

      - name: Build APK
        run: ./gradlew assembleDebug

Performance Testing

Load Testing Example (k6):

// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '1m', target: 50 },  // Ramp up to 50 users
    { duration: '3m', target: 50 },  // Stay at 50 users
    { duration: '1m', target: 0 },   // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% of requests < 500ms
    http_req_failed: ['rate<0.01'],   // < 1% failure rate
  },
};

export default function () {
  // Login test
  const loginRes = http.post('http://localhost:8080/v1/auth/login', JSON.stringify({
    phone_number: '+1234567890',
    password: 'password123',
  }), {
    headers: { 'Content-Type': 'application/json' },
  });

  check(loginRes, {
    'login succeeded': (r) => r.status === 200,
    'has access token': (r) => r.json('accessToken') !== undefined,
  });

  sleep(1);
}

Run Performance Tests:

k6 run load-test.js

Security Testing

OWASP ZAP Automation:

#!/bin/bash
# security-scan.sh

# Start backend
go run apps/management/main.go &
BACKEND_PID=$!
sleep 5

# Run ZAP scan
docker run -t owasp/zap2docker-stable zap-baseline.py \
  -t http://localhost:8080 \
  -r security-report.html

# Stop backend
kill $BACKEND_PID

echo "Security report: security-report.html"

Test Documentation

Test Plan Template:

# Test Plan: {Feature Name}

**Version:** 1.0
**Date:** 2025-10-26
**Owner:** Testing Team

## Scope

What will be tested and what won't be tested.

## Test Strategy

- Unit tests: {coverage target}%
- Integration tests: {number} test cases
- E2E tests: {number} scenarios

## Test Cases

### TC-001: Login with Valid Credentials

**Priority:** High
**Type:** Unit Test
**Preconditions:** User account exists
**Steps:**
1. Call login() with valid phone + password
2. Verify response contains access token
3. Verify token stored securely

**Expected Result:** Login succeeds, token stored
**Status:** Pass

### TC-002: ...

## Test Environment

- Backend: Go 1.21, PostgreSQL 14
- Desktop: Electron 25, Node 18
- iOS: iOS 17+
- Android: API 26+

## Schedule

- Unit tests: Week 1
- Integration tests: Week 2
- E2E tests: Week 3
- Performance tests: Week 4

## Risks

- Network instability in CI
- Database state issues

When to Use This Skill

Use this skill when:

  • Writing new test cases
  • Implementing test automation
  • Debugging test failures
  • Setting up test infrastructure
  • Generating test reports
  • Planning test strategies
  • Conducting QA activities

Don't use this skill for:

  • Writing production code (use platform skills)
  • Documentation (use barqnet-documentation)
  • Code audits (use barqnet-audit)
  • Integration setup (use barqnet-integration)

Success Criteria

Testing is complete when:

  1. ✅ All test types implemented (unit, integration, E2E)
  2. ✅ Coverage targets met (80%+ unit tests)
  3. ✅ All critical paths tested
  4. ✅ Tests run in CI/CD pipeline
  5. ✅ Test reports generated
  6. ✅ Flaky tests fixed or removed
  7. ✅ Performance benchmarks met
  8. ✅ Security tests pass
  9. ✅ Test documentation complete
  10. ✅ All tests green before deployment