Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/egeuysall/ryva-archive/llms.txt

Use this file to discover all available pages before exploring further.

Ryva maintains a comprehensive testing strategy with an 80% coverage requirement enforced in CI/CD.

Testing Stack

Frontend (Web)

  • Vitest - Unit and integration testing
  • React Testing Library - Component testing
  • Playwright - End-to-end testing
  • @vitest/coverage-v8 - Coverage reporting

Backend (API)

  • Go testing - Built-in testing framework
  • testify - Assertion and mocking library
  • httptest - HTTP handler testing
  • Coverage tools - Go coverage reporting

Running Tests

Quick Commands

make test

Frontend Test Commands

1

Navigate to Web Directory

cd apps/web
2

Run Tests

pnpm test

Backend Test Commands

1

Navigate to API Directory

cd apps/api
2

Run Tests

make test

Coverage Requirements

Mandatory Coverage Threshold: 80%All pull requests must maintain at least 80% test coverage. CI/CD will fail if coverage drops below this threshold.

Viewing Coverage Reports

cd apps/web
pnpm test:coverage
# Opens coverage report in browser

Writing Tests

Frontend Testing Guidelines

Component Tests

import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { UserProfile } from './UserProfile';

describe('UserProfile', () => {
  it('renders user information correctly', () => {
    const user = {
      name: 'John Doe',
      email: 'john@example.com',
    };

    render(<UserProfile user={user} />);

    expect(screen.getByText('John Doe')).toBeInTheDocument();
    expect(screen.getByText('john@example.com')).toBeInTheDocument();
  });

  it('handles missing user gracefully', () => {
    render(<UserProfile user={null} />);

    expect(screen.getByText('No user found')).toBeInTheDocument();
  });
});

Hook Tests

import { renderHook, waitFor } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { useUserData } from './useUserData';

describe('useUserData', () => {
  it('fetches user data successfully', async () => {
    const { result } = renderHook(() => useUserData('user-123'));

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false);
    });

    expect(result.current.data).toBeDefined();
    expect(result.current.error).toBeNull();
  });
});

E2E Tests (Playwright)

import { test, expect } from '@playwright/test';

test.describe('Authentication Flow', () => {
  test('user can log in successfully', async ({ page }) => {
    await page.goto('http://localhost:3000/login');

    await page.fill('input[name="email"]', 'test@example.com');
    await page.fill('input[name="password"]', 'password123');
    await page.click('button[type="submit"]');

    await expect(page).toHaveURL('http://localhost:3000/dashboard');
    await expect(page.locator('h1')).toContainText('Dashboard');
  });

  test('shows error for invalid credentials', async ({ page }) => {
    await page.goto('http://localhost:3000/login');

    await page.fill('input[name="email"]', 'wrong@example.com');
    await page.fill('input[name="password"]', 'wrongpassword');
    await page.click('button[type="submit"]');

    await expect(page.locator('.error-message')).toBeVisible();
  });
});

Backend Testing Guidelines

Unit Tests

package service

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestCalculateTotal(t *testing.T) {
	tests := []struct {
		name     string
		items    []Item
		expected float64
	}{
		{
			name:     "empty cart",
			items:    []Item{},
			expected: 0.0,
		},
		{
			name: "single item",
			items: []Item{
				{Price: 10.00, Quantity: 2},
			},
			expected: 20.00,
		},
		{
			name: "multiple items",
			items: []Item{
				{Price: 10.00, Quantity: 2},
				{Price: 5.00, Quantity: 3},
			},
			expected: 35.00,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := CalculateTotal(tt.items)
			assert.Equal(t, tt.expected, result)
		})
	}
}

HTTP Handler Tests

package handler

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestCreateUserHandler(t *testing.T) {
	// Setup
	reqBody := map[string]string{
		"name":  "John Doe",
		"email": "john@example.com",
	}
	body, _ := json.Marshal(reqBody)
	req := httptest.NewRequest(http.MethodPost, "/users", bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()

	// Execute
	handler := NewUserHandler(mockUserService)
	handler.CreateUser(w, req)

	// Assert
	assert.Equal(t, http.StatusCreated, w.Code)

	var response map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &response)
	assert.Equal(t, "John Doe", response["name"])
}

Integration Tests

package integration

import (
	"context"
	"testing"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestUserServiceIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	// Setup test database
	db := setupTestDB(t)
	defer db.Close()

	ctx := context.Background()
	userService := NewUserService(db)

	// Create user
	user, err := userService.CreateUser(ctx, &CreateUserRequest{
		Name:  "Test User",
		Email: "test@example.com",
	})
	require.NoError(t, err)
	assert.NotEmpty(t, user.ID)

	// Fetch user
	fetchedUser, err := userService.GetUser(ctx, user.ID)
	require.NoError(t, err)
	assert.Equal(t, user.Email, fetchedUser.Email)

	// Update user
	err = userService.UpdateUser(ctx, user.ID, &UpdateUserRequest{
		Name: "Updated Name",
	})
	require.NoError(t, err)

	// Verify update
	updatedUser, err := userService.GetUser(ctx, user.ID)
	require.NoError(t, err)
	assert.Equal(t, "Updated Name", updatedUser.Name)
}

Testing Best Practices

General Guidelines

  1. Write tests first - Consider TDD approach
  2. Test behavior, not implementation - Focus on what, not how
  3. Keep tests independent - Each test should run in isolation
  4. Use descriptive names - Test names should explain what they test
  5. Follow AAA pattern - Arrange, Act, Assert
  6. Mock external dependencies - Use mocks for APIs, databases, etc.
  7. Test edge cases - Include boundary conditions and error cases
  8. Maintain tests - Update tests when code changes

Frontend Best Practices

  • Use Testing Library queries - getByRole, getByLabelText, etc.
  • Avoid implementation details - Don’t test CSS classes or component internals
  • Test user interactions - Simulate real user behavior
  • Use accessible queries - Encourages accessible components
  • Wait for async updates - Use waitFor for async operations
  • Clean up after tests - Use cleanup utilities

Backend Best Practices

  • Use table-driven tests - Test multiple scenarios efficiently
  • Always use context.Context - For database operations and cancellation
  • Test error paths - Ensure errors are handled correctly
  • Use testify assertions - More readable than manual checks
  • Mock interfaces, not structs - Keep mocks flexible
  • Test concurrent scenarios - Use goroutines to test race conditions

CI/CD Integration

Automated Testing in CI

All tests run automatically on:
  • Every pull request
  • Every push to develop/master
  • Before deployment

CI Test Workflow

1

Linting

Code style checks run first
2

Unit Tests

Fast unit tests run in parallel
3

Integration Tests

Integration tests verify module interactions
4

E2E Tests

Full application tests run last
5

Coverage Check

Coverage must be ≥80% or CI fails
If any test fails or coverage drops below 80%, the PR cannot be merged.

Troubleshooting

Common Issues

Tests Fail Locally But Pass in CI

  • Ensure .env files are configured correctly
  • Check for system-specific dependencies
  • Verify database state is clean between tests

Flaky Tests

  • Add proper waits for async operations
  • Avoid hardcoded timeouts
  • Ensure tests don’t depend on timing
  • Check for race conditions

Low Coverage

  • Identify untested code with coverage reports
  • Add tests for edge cases
  • Test error handling paths
  • Don’t test external libraries
Run make test-coverage (API) or pnpm test:coverage (Web) to see exactly which lines need test coverage.

Continuous Improvement

  • Review test coverage regularly
  • Refactor tests when code changes
  • Remove obsolete tests
  • Keep test suite fast (under 5 minutes)
  • Document complex test scenarios
  • Share testing knowledge with team