Skip to main content

End-to-End Testing Strategy

Comprehensive E2E testing strategy for FishingLog platform covering backend API, web application, and React Native mobile app.

Overview

This document outlines the recommended E2E testing approach for the FishingLog platform, including:

  • Backend API E2E testing
  • Web Application E2E testing (React/Next.js)
  • Mobile Application E2E testing (React Native)
  • Cross-platform flow testing (e.g., payment flows)

Testing Pyramid

        /\
/ \ E2E Tests (10%)
/----\ - Critical user journeys
/ \ - Payment flows
/--------\ - Cross-platform flows
/ \
/------------\ Integration Tests (30%)
/ \ - API endpoint testing
/----------------\ - Service integration
\----------------/ Unit Tests (60%)
- Business logic
- Utilities
- Helpers

1. Backend API E2E Testing

Primary Tool: xUnit/NUnit + TestContainers

  • xUnit - Standard .NET testing framework
  • TestContainers - Spin up real PostgreSQL containers for testing
  • WebApplicationFactory - ASP.NET Core integration testing
  • Moq - Mocking external services (Stripe, AWS Cognito, etc.)

Why:

  • Native .NET integration
  • Can test real database interactions
  • Fast execution
  • Easy CI/CD integration

2. Web Application E2E Testing

Primary Tool: Playwright

  • Playwright - Modern browser automation
  • Supports Chromium, Firefox, WebKit
  • Built-in test runner and reporting
  • Can test API endpoints too
  • Excellent debugging tools

Why:

  • Fast and reliable
  • Multi-browser support
  • Great developer experience
  • Can test both UI and API
  • Built-in video/screenshot on failure

Alternative: Cypress (if team prefers)

3. Mobile Application E2E Testing

Primary Tool: Detox

  • Detox - React Native E2E testing framework
  • Runs on real devices/simulators
  • Fast execution
  • Great for React Native apps

Why:

  • Built specifically for React Native
  • Fast and reliable
  • Good CI/CD integration
  • Supports both iOS and Android

Alternative: Maestro (if you prefer a more visual approach)

4. API Contract Testing

Tool: Pact or Postman/Newman

  • Pact - Consumer-driven contract testing
  • Postman/Newman - API collection testing

Why:

  • Ensures API contracts between frontend and backend
  • Catches breaking changes early
  • Can be run in CI/CD

Test Infrastructure Setup

Backend Test Project Structure

FishingLog.API.Tests/
├── Integration/
│ ├── Controllers/
│ │ ├── AuthControllerTests.cs
│ │ ├── FishingLogControllerTests.cs
│ │ ├── TournamentControllerTests.cs
│ │ └── PaymentFlowTests.cs
│ ├── Services/
│ │ ├── StripeServiceTests.cs
│ │ └── ContentModerationServiceTests.cs
│ └── Database/
│ └── DbContextTests.cs
├── E2E/
│ ├── UserJourneyTests.cs
│ ├── PaymentFlowTests.cs
│ └── SocialFlowTests.cs
├── Helpers/
│ ├── TestWebApplicationFactory.cs
│ ├── TestDataBuilder.cs
│ └── AuthHelper.cs
└── FishingLog.API.Tests.csproj

Web App Test Structure

web-app/
├── e2e/
│ ├── tests/
│ │ ├── auth.spec.ts
│ │ ├── fishing-log.spec.ts
│ │ ├── tournament.spec.ts
│ │ ├── payment.spec.ts
│ │ └── social.spec.ts
│ ├── fixtures/
│ │ ├── test-users.ts
│ │ └── test-data.ts
│ ├── helpers/
│ │ ├── auth.ts
│ │ └── api.ts
│ └── playwright.config.ts

Mobile App Test Structure

mobile-app/
├── e2e/
│ ├── tests/
│ │ ├── auth.e2e.ts
│ │ ├── fishing-log.e2e.ts
│ │ ├── tournament.e2e.ts
│ │ └── payment.e2e.ts
│ ├── helpers/
│ │ └── auth.ts
│ └── .detoxrc.js

Critical Test Scenarios

1. Authentication Flows

Backend:

  • ✅ User registration via Cognito
  • ✅ User login
  • ✅ Token refresh
  • ✅ Auto user creation on first login
  • ✅ JWT token validation
  • ✅ Unauthorized access handling

Web App:

  • ✅ Login page → Dashboard
  • ✅ Protected route redirect
  • ✅ Token expiration handling
  • ✅ Logout flow

Mobile App:

  • ✅ Login screen → Home screen
  • ✅ Biometric authentication (if implemented)
  • ✅ Token refresh in background
  • ✅ Offline authentication state

2. Payment Flows (Stripe Integration)

Critical Path:

  1. User selects tournament/charter
  2. User clicks register/book
  3. Payment intent created
  4. Stripe payment sheet shown
  5. User completes payment
  6. Webhook received and processed
  7. Registration/booking confirmed

Test Scenarios:

  • ✅ Successful payment flow
  • ✅ Payment failure handling
  • ✅ Webhook processing
  • ✅ Payment intent creation
  • ✅ Refund flow (admin)
  • ✅ Payment retry logic

Tools Needed:

  • Stripe test mode
  • Stripe webhook testing tool
  • Mock Stripe responses for edge cases

3. Fishing Log Flows

User Journey:

  1. User creates fishing log entry
  2. Adds catch details
  3. Uploads photos
  4. Sets privacy settings
  5. Shares to circles (if applicable)
  6. Entry appears in feed

Test Scenarios:

  • ✅ Create log entry
  • ✅ Add catch with species, length, weight
  • ✅ Photo upload
  • ✅ Privacy settings (Public/Friends/Private/Circle)
  • ✅ Circle auto-sharing
  • ✅ Edit/delete entry
  • ✅ View entries list
  • ✅ Filter by date/species/location

4. Social Features

User Journey:

  1. User creates post
  2. Post appears in feed
  3. Other users like/comment
  4. Notifications sent
  5. Content moderation applied

Test Scenarios:

  • ✅ Create post
  • ✅ Like/unlike post
  • ✅ Comment on post
  • ✅ Share to circles
  • ✅ Content moderation (AI)
  • ✅ Report content
  • ✅ Privacy controls

5. Tournament Flows

User Journey:

  1. Browse tournaments
  2. View tournament details
  3. Register (with payment if required)
  4. Submit catches
  5. View leaderboard
  6. View results

Test Scenarios:

  • ✅ Tournament listing
  • ✅ Tournament registration
  • ✅ Payment for registration
  • ✅ Catch submission
  • ✅ Leaderboard updates
  • ✅ Results display

6. Circle (Community) Flows

User Journey:

  1. Discover/create circle
  2. Join circle (or apply)
  3. Share content to circle
  4. View circle feed
  5. Manage circle (if admin)

Test Scenarios:

  • ✅ Circle discovery
  • ✅ Circle creation
  • ✅ Join/apply to circle
  • ✅ Application approval/rejection
  • ✅ Rule-based auto-sharing
  • ✅ Contributor rankings
  • ✅ Member management

Test Data Management

Test Users

Create dedicated test users in Cognito:

# Admin user
aws cognito-idp admin-create-user \
--user-pool-id us-east-2_TZtGx1T3X \
--username admin-test@fishinglog.test \
--user-attributes Name=email,Value=admin-test@fishinglog.test \
--temporary-password TempPass123! \
--message-action SUPPRESS

# Regular user
aws cognito-idp admin-create-user \
--user-pool-id us-east-2_TZtGx1T3X \
--username user-test@fishinglog.test \
--user-attributes Name=email,Value=user-test@fishinglog.test \
--temporary-password TempPass123! \
--message-action SUPPRESS

Test Database

Use TestContainers to spin up isolated PostgreSQL instances:

public class TestWebApplicationFactory : WebApplicationFactory<Program>
{
private readonly PostgreSQLContainer _postgres = new PostgreSQLBuilder()
.WithImage("postgres:16")
.WithDatabase("fishinglog_test")
.WithUsername("test_user")
.WithPassword("test_password")
.Build();

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Replace database connection
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
if (descriptor != null) services.Remove(descriptor);

services.AddDbContext<AppDbContext>(options =>
{
options.UseNpgsql(_postgres.GetConnectionString());
});
});
}
}

Test Data Builders

Create test data builders for consistent test data:

public class FishingLogEntryBuilder
{
private FishingLogEntry _entry = new();

public FishingLogEntryBuilder WithUser(User user)
{
_entry.UserId = user.Id;
return this;
}

public FishingLogEntryBuilder WithLocation(double lat, double lon)
{
_entry.Latitude = lat;
_entry.Longitude = lon;
return this;
}

public FishingLogEntry Build() => _entry;
}

Authentication in Tests

Backend Tests

Mock JWT tokens or use test authentication:

public class AuthHelper
{
public static string GenerateTestToken(string userId, string email)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("test-secret-key");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("sub", userId),
new Claim("email", email),
new Claim("cognito:username", email)
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}

Frontend Tests

Use test credentials or mock authentication:

// Playwright auth helper
export async function loginAsTestUser(page: Page) {
await page.goto('/login');
await page.fill('[name="username"]', 'test-user@fishinglog.test');
await page.fill('[name="password"]', 'TestPassword123!');
await page.click('button[type="submit"]');
await page.waitForURL('/dashboard');

// Save auth state
await page.context().storageState({ path: 'auth-state.json' });
}

Stripe Testing

Test Mode

Always use Stripe test mode in E2E tests:

// appsettings.Test.json
{
"Stripe": {
"SecretKey": "sk_test_...",
"PublishableKey": "pk_test_...",
"WebhookSecret": "whsec_test_..."
}
}

Test Cards

Use Stripe test cards:

  • Success: 4242 4242 4242 4242
  • Decline: 4000 0000 0000 0002
  • 3D Secure: 4000 0027 6000 3184

Webhook Testing

Use Stripe CLI for local webhook testing:

stripe listen --forward-to http://localhost:5000/api/stripe/webhook

CI/CD Integration

GitHub Actions Example

name: E2E Tests

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

jobs:
backend-e2e:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
POSTGRES_DB: fishinglog_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.0.x'
- run: dotnet test FishingLog.API.Tests/FishingLog.API.Tests.csproj

web-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: |
cd web-app
npm ci
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run E2E tests
run: |
cd web-app
npm run test:e2e
env:
API_URL: http://localhost:5000
COGNITO_USER_POOL_ID: ${{ secrets.COGNITO_USER_POOL_ID }}
COGNITO_CLIENT_ID: ${{ secrets.COGNITO_CLIENT_ID }}

mobile-e2e:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: |
cd mobile-app
npm ci
- name: Build app
run: |
cd mobile-app
npm run build:ios
- name: Run Detox tests
run: |
cd mobile-app
npm run test:e2e:ios

Test Environment Setup

Required Services

  1. PostgreSQL - Test database (via TestContainers or Docker)
  2. AWS Cognito - Test user pool (or mock)
  3. Stripe - Test mode API keys
  4. Test Users - Pre-created in Cognito

Environment Variables

# Backend
ASPNETCORE_ENVIRONMENT=Test
ConnectionStrings__DefaultConnection=Host=localhost;Database=fishinglog_test;...
Stripe__SecretKey=sk_test_...
Stripe__PublishableKey=pk_test_...
AWS__Cognito__UserPoolId=us-east-2_TZtGx1T3X
AWS__Cognito__ClientId=6i1opt39o2n5h5ihq471l1ev07

# Frontend
NEXT_PUBLIC_API_URL=http://localhost:5000
NEXT_PUBLIC_COGNITO_USER_POOL_ID=us-east-2_TZtGx1T3X
NEXT_PUBLIC_COGNITO_CLIENT_ID=6i1opt39o2n5h5ihq471l1ev07
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

Best Practices

1. Test Isolation

  • Each test should be independent
  • Clean up test data after each test
  • Use transactions that rollback
  • Don't rely on test execution order

2. Test Data

  • Use factories/builders for test data
  • Create minimal data needed for test
  • Use realistic but anonymized data
  • Clean up after tests

3. Flakiness Prevention

  • Use explicit waits, not fixed delays
  • Wait for network requests to complete
  • Use stable selectors (data-testid)
  • Retry flaky tests with exponential backoff

4. Performance

  • Run tests in parallel when possible
  • Use test databases, not production
  • Mock external services (Stripe, AWS)
  • Cache authentication tokens

5. Debugging

  • Take screenshots/videos on failure
  • Log test steps
  • Use test data IDs in logs
  • Provide clear error messages

Test Coverage Goals

Critical Paths (100% coverage)

  • ✅ Authentication flows
  • ✅ Payment flows
  • ✅ User registration/login
  • ✅ Core CRUD operations

Important Features (80% coverage)

  • ✅ Social features
  • ✅ Tournament flows
  • ✅ Circle features
  • ✅ Content moderation

Nice to Have (60% coverage)

  • ✅ Advanced filtering
  • ✅ Search functionality
  • ✅ Analytics/reporting

Monitoring & Reporting

Test Results

  • Backend: xUnit test results → Azure DevOps/GitHub Actions
  • Web: Playwright HTML report
  • Mobile: Detox test results

Test Metrics

Track:

  • Test execution time
  • Pass/fail rates
  • Flaky test detection
  • Coverage trends

Alerts

  • Failed E2E tests → Slack/Email
  • Flaky test detection
  • Coverage drops below threshold

Getting Started

Phase 1: Backend E2E (Week 1-2)

  1. Create FishingLog.API.Tests project
  2. Set up TestContainers
  3. Create test infrastructure helpers
  4. Write authentication flow tests
  5. Write payment flow tests

Phase 2: Web App E2E (Week 3-4)

  1. Install Playwright
  2. Set up test configuration
  3. Create auth helpers
  4. Write critical user journey tests
  5. Integrate with CI/CD

Phase 3: Mobile App E2E (Week 5-6)

  1. Install Detox
  2. Configure iOS/Android simulators
  3. Create test helpers
  4. Write critical flow tests
  5. Set up CI/CD for mobile

Phase 4: Cross-Platform Tests (Week 7+)

  1. Test payment flows end-to-end
  2. Test social features across platforms
  3. Test data synchronization
  4. Performance testing

Resources

Next Steps

  1. ✅ Review and approve this strategy
  2. ⬜ Set up backend test project
  3. ⬜ Set up web app E2E tests
  4. ⬜ Set up mobile app E2E tests
  5. ⬜ Create test data management system
  6. ⬜ Integrate with CI/CD
  7. ⬜ Write critical path tests
  8. ⬜ Expand test coverage

Last Updated: December 2025
Status: Strategy Document - Ready for Implementation