integration tests
This commit is contained in:
321
tests/integration/harness/integration-test-harness.test.ts
Normal file
321
tests/integration/harness/integration-test-harness.test.ts
Normal file
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user