I’m kinda stumped – I’ve read through the many postings on here about Axios + MSW [1] [2] [3] and I can’t quite figure out where i’m going wrong.
What I’m doing – I’m trying to use MSW to intercept network requests that are made by Axios to inject responses for testing.
Code:
Test file (this will fail, I’m just trying to get it to work properly)-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { jobsDashboardResponse } from "../../../tests/mocks/msw/handlers"
import { server as mswServer } from "../../../tests/mocks/msw/server"
import { bacalhauAPI } from "../bacalhau"
// Enable request interception.
beforeAll(() => mswServer.listen())
// Reset handlers so that each test could alter them
// without affecting other, unrelated tests.
afterEach(() => mswServer.resetHandlers())
// Don't forget to clean up afterwards.
afterAll(() => mswServer.close())
describe("Basic fetch of mocked API", () => {
it("should GET /orchestrator/jobs", async () => {
const jobsResponse = { a: 2 }
mswServer.use(jobsDashboardResponse)
mswServer.listHandlers()
const jobs = await bacalhauAPI.listJobs()
expect(jobs).toEqual(jobsResponse)
})
})
BacalhauAPI server ts:
import axios, { AxiosInstance } from "axios"
import {
JobListRequest,
} from "../helpers/jobInterfaces"
class BacalhauAPI {
apiClient: AxiosInstance
constructor(baseURL: string) {
this.apiClient = axios.create({
baseURL,
headers: {
"Content-Type": "application/json",
},
})
}
async listJobs(labels?: string[], nextToken?: string): Promise<JobsResponse> {
try {
const params: JobListRequest = {
order_by: "created_at",
reverse: true,
limit: 10,
labels: labels ? `env in (${labels.join(",")})` : undefined,
next_token: nextToken,
}
const response = await this.apiClient.get("/orchestrator/jobs", {
params,
})
return response.data as JobsResponse
} catch (error) {
console.error("An error occurred while listing jobs:", error)
throw error
}
}
}
function getAPIConfig(
property: "host" | "port" | "base",
defaultValue: string
): string {
const declared = document
.querySelector(`link[rel=api-${property}]`)
?.getAttribute("href")
const useDefault =
declared === undefined ||
declared?.match(/{{2}/) ||
declared === "" ||
declared === null
return useDefault ? defaultValue : declared || ""
}
const host = getAPIConfig("host", document.location.hostname)
const port = getAPIConfig("port", "1234")
const base = getAPIConfig("base", "api/v1")
export const bacalhauAPI = new BacalhauAPI(
`${document.location.protocol}//${host}:${port}/${base}`
)
msw handlers:
import { http, HttpResponse, RequestHandler, RequestHandlerOptions } from "msw";
import { TestData } from "../../basic/msw.tests";
export const jobsDashboardResponse = http.get('http://localhost:1234/api/v1/orchestrator/jobs', ({ cookies }) => {
// Placeholders for messing around with cookies
const { v } = cookies
return HttpResponse.json(v === 'a' ? { foo: 'a' } : { bar: 'b' })
})
export const handlers: RequestHandler<any, any, any, RequestHandlerOptions>[] = [jobsDashboardResponse]
msw server:
import { setupServer } from "msw/node"
import { handlers } from "./handlers"
export const server = setupServer(...handlers)
The error:
console.error
An error occurred while listing jobs: AxiosError {
message: 'Network Error',
name: 'AxiosError',
code: 'ERR_NETWORK',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function], Blob: [class Blob] },
validateStatus: [Function: validateStatus],
headers: Object [AxiosHeaders] {
Accept: 'application/json, text/plain, */*',
'Content-Type': null
},
baseURL: 'http://localhost:1234/api/v1',
params: {
order_by: 'created_at',
reverse: true,
limit: 10,
labels: undefined,
next_token: undefined
},
method: 'get',
url: '/orchestrator/jobs',
data: undefined
},
request: XMLHttpRequest {
open: [Function: open],
setRequestHeader: [Function: setRequestHeader],
send: [Function: send],
abort: [Function: abort],
getResponseHeader: [Function: getResponseHeader],
getAllResponseHeaders: [Function: getAllResponseHeaders],
overrideMimeType: [Function: overrideMimeType],
onreadystatechange: [Getter/Setter],
readyState: 4,
timeout: [Getter/Setter],
withCredentials: [Getter/Setter],
upload: [Getter],
responseURL: [Getter],
status: [Getter],
statusText: [Getter],
responseType: [Getter/Setter],
response: [Getter],
responseText: [Getter],
responseXML: [Getter],
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4
}
}
When I console.log or debug, it’s clearly getting grabbed by the MSW handler. So what’s up?
[1] Reactjs: MSW mock handlers failing with Error “Network request failed”
[2] FETCH_ERROR “TypeError [ERR_INVALID_URL]: Invalid URL” for requests made in tests
[3] Jest returns “Network Error” when doing a mock request with axios and msw