Files
gridpilot.gg/tests/integration/harness/integration-test-harness.test.ts
Marc Mintel 597bb48248
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 4m51s
Contract Testing / contract-snapshot (pull_request) Has been skipped
integration tests
2026-01-22 17:29:06 +01:00

322 lines
11 KiB
TypeScript

/**
* Integration Test: IntegrationTestHarness
*
* Tests the IntegrationTestHarness infrastructure for orchestrating integration tests
* - Validates setup and teardown hooks
* - Tests database transaction management
* - Verifies constraint violation detection
*
* Focus: Infrastructure testing, NOT business logic
*/
import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, vi } from 'vitest';
import { IntegrationTestHarness, createTestHarness, DEFAULT_TEST_CONFIG } from './index';
import { DatabaseManager } from './database-manager';
import { ApiClient } from './api-client';
describe('IntegrationTestHarness - Infrastructure Tests', () => {
let harness: IntegrationTestHarness;
beforeAll(() => {
// Create a test harness with default configuration
harness = createTestHarness();
});
describe('Construction', () => {
it('should be constructed with configuration', () => {
// Given: Configuration
// When: Creating an IntegrationTestHarness instance
const testHarness = new IntegrationTestHarness(DEFAULT_TEST_CONFIG);
// Then: The instance should be created successfully
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
it('should accept partial configuration', () => {
// Given: Partial configuration
const partialConfig = {
api: {
baseUrl: 'http://localhost:3000',
},
};
// When: Creating an IntegrationTestHarness with partial config
const testHarness = createTestHarness(partialConfig);
// Then: The instance should be created successfully
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
it('should merge default configuration with custom configuration', () => {
// Given: Custom configuration
const customConfig = {
api: {
baseUrl: 'http://localhost:8080',
port: 8080,
},
timeouts: {
setup: 60000,
},
};
// When: Creating an IntegrationTestHarness with custom config
const testHarness = createTestHarness(customConfig);
// Then: The configuration should be merged correctly
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
});
describe('Accessors', () => {
it('should provide access to database manager', () => {
// Given: An IntegrationTestHarness instance
// When: Getting the database manager
const database = harness.getDatabase();
// Then: The database manager should be returned
expect(database).toBeInstanceOf(DatabaseManager);
});
it('should provide access to API client', () => {
// Given: An IntegrationTestHarness instance
// When: Getting the API client
const api = harness.getApi();
// Then: The API client should be returned
expect(api).toBeInstanceOf(ApiClient);
});
it('should provide access to Docker manager', () => {
// Given: An IntegrationTestHarness instance
// When: Getting the Docker manager
const docker = harness.getDocker();
// Then: The Docker manager should be returned
expect(docker).toBeDefined();
expect(docker).toHaveProperty('start');
expect(docker).toHaveProperty('stop');
});
it('should provide access to data factory', () => {
// Given: An IntegrationTestHarness instance
// When: Getting the data factory
const factory = harness.getFactory();
// Then: The data factory should be returned
expect(factory).toBeDefined();
expect(factory).toHaveProperty('createLeague');
expect(factory).toHaveProperty('createSeason');
expect(factory).toHaveProperty('createDriver');
});
});
describe('Setup Hooks', () => {
it('should have beforeAll hook', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for beforeAll hook
// Then: The hook should exist
expect(harness.beforeAll).toBeDefined();
expect(typeof harness.beforeAll).toBe('function');
});
it('should have beforeEach hook', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for beforeEach hook
// Then: The hook should exist
expect(harness.beforeEach).toBeDefined();
expect(typeof harness.beforeEach).toBe('function');
});
});
describe('Teardown Hooks', () => {
it('should have afterAll hook', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for afterAll hook
// Then: The hook should exist
expect(harness.afterAll).toBeDefined();
expect(typeof harness.afterAll).toBe('function');
});
it('should have afterEach hook', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for afterEach hook
// Then: The hook should exist
expect(harness.afterEach).toBeDefined();
expect(typeof harness.afterEach).toBe('function');
});
});
describe('Transaction Management', () => {
it('should have withTransaction method', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for withTransaction method
// Then: The method should exist
expect(harness.withTransaction).toBeDefined();
expect(typeof harness.withTransaction).toBe('function');
});
it('should execute callback within transaction', async () => {
// Given: An IntegrationTestHarness instance
// When: Executing withTransaction
const result = await harness.withTransaction(async (db) => {
// Execute a simple query
const queryResult = await db.query('SELECT 1 as test_value');
return queryResult.rows[0].test_value;
});
// Then: The callback should execute and return the result
expect(result).toBe(1);
});
it('should rollback transaction after callback', async () => {
// Given: An IntegrationTestHarness instance
// When: Executing withTransaction
await harness.withTransaction(async (db) => {
// Execute a query
await db.query('SELECT 1 as test_value');
// The transaction should be rolled back after this
});
// Then: The transaction should be rolled back
// (This is verified by the fact that no error is thrown)
expect(true).toBe(true);
});
});
describe('Constraint Violation Detection', () => {
it('should have expectConstraintViolation method', () => {
// Given: An IntegrationTestHarness instance
// When: Checking for expectConstraintViolation method
// Then: The method should exist
expect(harness.expectConstraintViolation).toBeDefined();
expect(typeof harness.expectConstraintViolation).toBe('function');
});
it('should detect constraint violations', async () => {
// Given: An IntegrationTestHarness instance
// When: Executing an operation that violates a constraint
// Then: Should throw an error
await expect(
harness.expectConstraintViolation(async () => {
// This operation should violate a constraint
throw new Error('constraint violation: duplicate key');
})
).rejects.toThrow('Expected constraint violation but operation succeeded');
});
it('should detect specific constraint violations', async () => {
// Given: An IntegrationTestHarness instance
// When: Executing an operation that violates a specific constraint
// Then: Should throw an error with the expected constraint
await expect(
harness.expectConstraintViolation(
async () => {
// This operation should violate a specific constraint
throw new Error('constraint violation: unique_violation');
},
'unique_violation'
)
).rejects.toThrow('Expected constraint violation but operation succeeded');
});
it('should detect non-constraint errors', async () => {
// Given: An IntegrationTestHarness instance
// When: Executing an operation that throws a non-constraint error
// Then: Should throw an error
await expect(
harness.expectConstraintViolation(async () => {
// This operation should throw a non-constraint error
throw new Error('Some other error');
})
).rejects.toThrow('Expected constraint violation but got: Some other error');
});
});
describe('Configuration', () => {
it('should use default configuration', () => {
// Given: Default configuration
// When: Creating a harness with default config
const testHarness = createTestHarness();
// Then: The configuration should match defaults
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
it('should accept custom configuration', () => {
// Given: Custom configuration
const customConfig = {
api: {
baseUrl: 'http://localhost:9000',
port: 9000,
},
database: {
host: 'custom-host',
port: 5434,
database: 'custom_db',
user: 'custom_user',
password: 'custom_pass',
},
timeouts: {
setup: 30000,
teardown: 15000,
test: 30000,
},
};
// When: Creating a harness with custom config
const testHarness = createTestHarness(customConfig);
// Then: The configuration should be applied
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
it('should merge configuration correctly', () => {
// Given: Partial configuration
const partialConfig = {
api: {
baseUrl: 'http://localhost:8080',
},
timeouts: {
setup: 60000,
},
};
// When: Creating a harness with partial config
const testHarness = createTestHarness(partialConfig);
// Then: The configuration should be merged with defaults
expect(testHarness).toBeInstanceOf(IntegrationTestHarness);
});
});
describe('Default Configuration', () => {
it('should have correct default API configuration', () => {
// Given: Default configuration
// When: Checking default API configuration
// Then: Should match expected defaults
expect(DEFAULT_TEST_CONFIG.api.baseUrl).toBe('http://localhost:3101');
expect(DEFAULT_TEST_CONFIG.api.port).toBe(3101);
});
it('should have correct default database configuration', () => {
// Given: Default configuration
// When: Checking default database configuration
// Then: Should match expected defaults
expect(DEFAULT_TEST_CONFIG.database.host).toBe('localhost');
expect(DEFAULT_TEST_CONFIG.database.port).toBe(5433);
expect(DEFAULT_TEST_CONFIG.database.database).toBe('gridpilot_test');
expect(DEFAULT_TEST_CONFIG.database.user).toBe('gridpilot_test_user');
expect(DEFAULT_TEST_CONFIG.database.password).toBe('gridpilot_test_pass');
});
it('should have correct default timeouts', () => {
// Given: Default configuration
// When: Checking default timeouts
// Then: Should match expected defaults
expect(DEFAULT_TEST_CONFIG.timeouts.setup).toBe(120000);
expect(DEFAULT_TEST_CONFIG.timeouts.teardown).toBe(30000);
expect(DEFAULT_TEST_CONFIG.timeouts.test).toBe(60000);
});
});
});