diff --git a/src/compose-generator.test.ts b/src/compose-generator.test.ts index c239e54ea..297642994 100644 --- a/src/compose-generator.test.ts +++ b/src/compose-generator.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose, ACT_PRESET_BASE_IMAGE } from './docker-manager'; import { WrapperConfig } from './types'; +import { baseConfig, mockNetworkConfig } from './test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('generateDockerCompose', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/services/agent-service.test.ts b/src/services/agent-service.test.ts index 17496d4c0..1c8c8cc14 100644 --- a/src/services/agent-service.test.ts +++ b/src/services/agent-service.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose, AGENT_CONTAINER_NAME } from '../docker-manager'; import { WrapperConfig } from '../types'; +import { baseConfig, mockNetworkConfig } from '../test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('agent service', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/services/api-proxy-service.test.ts b/src/services/api-proxy-service.test.ts index ea00b1b11..d6ae987a6 100644 --- a/src/services/api-proxy-service.test.ts +++ b/src/services/api-proxy-service.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose } from '../docker-manager'; import { WrapperConfig } from '../types'; +import { baseConfig, mockNetworkConfig } from '../test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('API proxy sidecar', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/services/cli-proxy-service.test.ts b/src/services/cli-proxy-service.test.ts index 29d9ab649..2f6c95193 100644 --- a/src/services/cli-proxy-service.test.ts +++ b/src/services/cli-proxy-service.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose } from '../docker-manager'; import { WrapperConfig } from '../types'; +import { baseConfig, mockNetworkConfig } from '../test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('CLI proxy sidecar (external DIFC proxy)', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/services/doh-proxy-service.test.ts b/src/services/doh-proxy-service.test.ts index 6e854e611..dbc5b6338 100644 --- a/src/services/doh-proxy-service.test.ts +++ b/src/services/doh-proxy-service.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose } from '../docker-manager'; import { WrapperConfig } from '../types'; +import { baseConfig, mockNetworkConfig } from '../test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('DNS-over-HTTPS proxy sidecar', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/services/squid-service.test.ts b/src/services/squid-service.test.ts index 3f5e86dd7..ddcf9e662 100644 --- a/src/services/squid-service.test.ts +++ b/src/services/squid-service.test.ts @@ -1,10 +1,11 @@ import { generateDockerCompose } from '../docker-manager'; import { WrapperConfig } from '../types'; +import { baseConfig, mockNetworkConfig } from '../test-helpers/docker-test-fixtures.test-utils'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -// Create mock functions +// Create mock functions (must remain per-file — jest.mock() is hoisted before imports) const mockExecaFn = jest.fn(); const mockExecaSync = jest.fn(); @@ -15,24 +16,8 @@ jest.mock('execa', () => { return fn; }); -const baseConfig: Omit = { - allowedDomains: ['github.com', 'npmjs.org'], - agentCommand: 'echo "test"', - logLevel: 'info', - keepContainers: false, - buildLocal: false, - imageRegistry: 'ghcr.io/github/gh-aw-firewall', - imageTag: 'latest', -}; - let mockConfig: WrapperConfig; -const mockNetworkConfig = { - subnet: '172.30.0.0/24', - squidIp: '172.30.0.10', - agentIp: '172.30.0.20', -}; - describe('squid service', () => { beforeEach(() => { mockConfig = { ...baseConfig, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'awf-test-')) }; diff --git a/src/test-helpers/docker-test-fixtures.test-utils.ts b/src/test-helpers/docker-test-fixtures.test-utils.ts new file mode 100644 index 000000000..0e0295f27 --- /dev/null +++ b/src/test-helpers/docker-test-fixtures.test-utils.ts @@ -0,0 +1,33 @@ +/** + * Shared Docker test fixtures used across compose-generator and service unit tests. + * + * Note: `jest.mock('execa', ...)` along with the `mockExecaFn`/`mockExecaSync` + * declarations must remain in each individual test file. Jest hoists jest.mock() + * calls to the top of each file before imports are resolved, so the factory + * closure cannot reference variables from an imported module. + */ + +import { WrapperConfig } from '../types'; + +/** + * Baseline WrapperConfig used in unit tests. Omits `workDir` so each test can + * supply its own temporary directory. + */ +export const baseConfig: Omit = { + allowedDomains: ['github.com', 'npmjs.org'], + agentCommand: 'echo "test"', + logLevel: 'info', + keepContainers: false, + buildLocal: false, + imageRegistry: 'ghcr.io/github/gh-aw-firewall', + imageTag: 'latest', +}; + +/** + * Standard network configuration for the AWF Docker network used in unit tests. + */ +export const mockNetworkConfig = { + subnet: '172.30.0.0/24', + squidIp: '172.30.0.10', + agentIp: '172.30.0.20', +};