mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
test: add spread+flag axios mock helper to stop CI mock pollution
Bare `mock.module('axios', () => ({ default: { stubs } }))` is
process-global last-write-wins and drops `axios.create`, `request`,
`isAxiosError`, etc. that real consumers need. In CI's alphabetical
file order, that produces dozens of polluted failures (AgentsPlatformView,
schedule API, memory-stores API, etc.) that don't reproduce on WSL2.
Introduce `tests/mocks/axios.ts` with `setupAxiosMock()` — `require('axios')`
inside the factory, spread real shape, route each verb through a per-suite
`useStubs` flag. beforeAll flips on, afterAll flips off; the spread
fall-through eliminates cross-file leakage.
Refactored 12 axios mockers in tests/, plus the bare `@anthropic/ink` mocks
in ultrareviewCommand and onboarding suites (same pollution pattern broke
AgentsPlatformView's Box/Text rendering).
Verified: 5339/5345 tests pass locally; remaining 6 failures are
pre-existing isolation issues unrelated to this change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,31 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
|
||||
import {
|
||||
afterAll,
|
||||
afterEach,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
mock,
|
||||
test,
|
||||
} from 'bun:test'
|
||||
import { authMock } from '../../../../../../tests/mocks/auth'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
let requestStatus = 200
|
||||
const auditRecords: Record<string, unknown>[] = []
|
||||
|
||||
mock.module('axios', () => ({
|
||||
default: {
|
||||
request: async () => ({
|
||||
status: requestStatus,
|
||||
data: { ok: requestStatus >= 200 && requestStatus < 300 },
|
||||
}),
|
||||
},
|
||||
}))
|
||||
const axiosHandle = setupAxiosMock()
|
||||
axiosHandle.stubs.request = async () => ({
|
||||
status: requestStatus,
|
||||
data: { ok: requestStatus >= 200 && requestStatus < 300 },
|
||||
})
|
||||
|
||||
beforeAll(() => {
|
||||
axiosHandle.useStubs = true
|
||||
})
|
||||
afterAll(() => {
|
||||
axiosHandle.useStubs = false
|
||||
})
|
||||
|
||||
mock.module('src/utils/auth.js', authMock)
|
||||
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
import {
|
||||
afterAll,
|
||||
afterEach,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
mock,
|
||||
test,
|
||||
} from 'bun:test'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
// After this suite finishes, switch our getSecret override off so localVault's
|
||||
// own store.test.ts (running in the same process) sees the real impl.
|
||||
// own store.test.ts (running in the same process) sees the real impl. Also
|
||||
// flip the axios stub flag off so the spread mock falls through to real axios
|
||||
// for any test file that runs after this one.
|
||||
afterAll(() => {
|
||||
useMockForGetSecret = false
|
||||
getSecretShouldThrow = false
|
||||
axiosHandle.useStubs = false
|
||||
})
|
||||
|
||||
beforeAll(() => {
|
||||
axiosHandle.useStubs = true
|
||||
})
|
||||
|
||||
// We mock the LOWER layers (axios + localVault store + http util) rather
|
||||
@@ -34,9 +43,8 @@ const mockAxiosRequest = mock(
|
||||
}),
|
||||
)
|
||||
|
||||
mock.module('axios', () => ({
|
||||
default: { request: mockAxiosRequest },
|
||||
}))
|
||||
const axiosHandle = setupAxiosMock()
|
||||
axiosHandle.stubs.request = mockAxiosRequest
|
||||
|
||||
let mockedSecret: string | null = 'XSECRETXX'
|
||||
let getSecretShouldThrow = false
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { beforeEach, describe, expect, mock, test } from 'bun:test'
|
||||
import {
|
||||
afterAll,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
mock,
|
||||
test,
|
||||
} from 'bun:test'
|
||||
import { logMock } from '../../../../../../tests/mocks/log'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
type MockAxiosResponse = {
|
||||
data: ArrayBuffer
|
||||
@@ -18,17 +27,12 @@ type MockAxiosError = Error & {
|
||||
|
||||
let getMock: (url: string) => Promise<MockAxiosResponse>
|
||||
|
||||
mock.module('axios', () => {
|
||||
const axiosMock = {
|
||||
get: (url: string) => getMock(url),
|
||||
isAxiosError: (error: unknown): error is MockAxiosError =>
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
(error as { isAxiosError?: unknown }).isAxiosError === true,
|
||||
}
|
||||
|
||||
return { default: axiosMock }
|
||||
})
|
||||
const axiosHandle = setupAxiosMock()
|
||||
axiosHandle.stubs.get = (url: string) => getMock(url)
|
||||
axiosHandle.stubs.isAxiosError = (error: unknown): boolean =>
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
(error as { isAxiosError?: unknown }).isAxiosError === true
|
||||
|
||||
mock.module('src/services/analytics/index.js', () => ({
|
||||
logEvent: () => {},
|
||||
@@ -67,6 +71,14 @@ beforeEach(() => {
|
||||
})
|
||||
})
|
||||
|
||||
beforeAll(() => {
|
||||
axiosHandle.useStubs = true
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
axiosHandle.useStubs = false
|
||||
})
|
||||
|
||||
describe('WebFetch response headers', () => {
|
||||
test('reads redirect Location from AxiosHeaders-style get()', async () => {
|
||||
getMock = async () => {
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { describe, expect, mock, test } from 'bun:test'
|
||||
import { afterAll, describe, expect, mock, test } from 'bun:test'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
// Each test below calls `mock.module('axios', ...)` per-test. Re-register a
|
||||
// spread-real axios mock at end-of-file so the per-test stubs do not leak
|
||||
// into subsequent test files (mock.module is process-global, last-write-wins).
|
||||
afterAll(() => {
|
||||
setupAxiosMock()
|
||||
})
|
||||
|
||||
const _abortMock = () => ({
|
||||
AbortError: class AbortError extends Error {
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
|
||||
import {
|
||||
afterAll,
|
||||
afterEach,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
mock,
|
||||
test,
|
||||
} from 'bun:test'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
// Each test below calls `mock.module('axios', ...)` per-test. Without an
|
||||
// afterAll cleanup, the LAST per-test stub leaks into every test file that
|
||||
// runs after this one (mock.module is process-global, last-write-wins). The
|
||||
// spread-real mock registered here at the end re-routes axios to the real
|
||||
// module, undoing the stub leakage so later suites see real axios.
|
||||
afterAll(() => {
|
||||
setupAxiosMock()
|
||||
})
|
||||
|
||||
// Defensive mock: agent.test.ts mocks config.js which can corrupt Bun's
|
||||
// src/* path alias resolution. Provide AbortError directly so the dynamic
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { afterEach, describe, expect, mock, test } from 'bun:test'
|
||||
import { afterAll, afterEach, describe, expect, mock, test } from 'bun:test'
|
||||
import { setupAxiosMock } from '../../../../../../tests/mocks/axios'
|
||||
|
||||
// Each test below calls `mock.module('axios', ...)` per-test. Re-register a
|
||||
// spread-real axios mock at end-of-file so the per-test stubs do not leak
|
||||
// into subsequent test files (mock.module is process-global, last-write-wins).
|
||||
afterAll(() => {
|
||||
setupAxiosMock()
|
||||
})
|
||||
|
||||
const _abortMock = () => ({
|
||||
AbortError: class AbortError extends Error {
|
||||
|
||||
Reference in New Issue
Block a user