freshyo/apps/user-ui/tests/mocks/api.ts
2026-09-17 23:13:32 +05:30

90 lines
3.4 KiB
TypeScript

/**
* Network-layer mocks for the user-ui tests.
*
* Everything the home page fetches goes through one of two doors:
* - tRPC -> global.fetch (common.essentialConsts, ...)
* - axios -> the assets CDN (products.json, stores.json, slots.json, availability.json)
*
* Both are stubbed here and both fail loudly on an unmocked URL, so a new
* dependency introduced by app code surfaces as a test failure instead of a
* silent empty render.
*
* The tRPC URL is matched on the procedure path rather than the host, because
* BASE_API_URL (packages/ui/index.ts) is a local address during development.
* `jest.mock('axios')` lives in tests/setup.ts so it is registered before any
* app module imports axios.
*
* Fixtures are imported as JSON rather than read with `fs`: importing a Node
* builtin pulls @types/node into the typecheck program, which flips
* `setTimeout` from `number` to `NodeJS.Timeout` and breaks unrelated app types.
*
* NOTE: mock-slots-response.json is a snapshot of a real day (see the
* deliveryTime values). The home page drops past slots, so those fixtures need
* refreshing once their dates fall behind.
*/
import essentialConsts from '../__fixtures__/essentialConsts.json'
import availability from './mock-availability-response.json'
import products from './mock-products-response.json'
import slots from './mock-slots-response.json'
import stores from './mock-stores-response.json'
export const ESSENTIAL_CONSTS_URL =
'https://worker.freshyo.in/api/trpc/common.essentialConsts?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%7D'
// Derived by useCacheUrl / useAvailabilityCacheUrl / useSlotsCacheUrl from the
// essentialConsts payload above (assetsDomain, apiCacheKey, cacheVersion,
// availabilityVersionNum, slotsVersionNum).
export const PRODUCTS_URL =
'https://assets.freshyo.in/api-cache/v-755/products.json'
export const AVAILABILITY_URL =
'https://assets.freshyo.in/av-72/availability.json'
export const STORES_URL = 'https://assets.freshyo.in/api-cache/v-755/stores.json'
export const SLOTS_URL = 'https://assets.freshyo.in/slots/v-401/slots.json?v=123'
/** Route a CDN file name to its mock response. */
const mockForCacheFile = (url: string): unknown => {
if (url.includes('products.json')) return products
if (url.includes('stores.json')) return stores
if (url.includes('slots.json')) return slots
if (url.includes('availability.json')) return availability
throw new Error(`[tests] unmocked assets request: ${url}`)
}
const jsonResponse = (body: unknown) => ({
ok: true,
status: 200,
statusText: 'OK',
headers: new Map(),
url: '',
json: async () => body,
text: async () => JSON.stringify(body),
})
/**
* Install the fetch + axios stubs and return the handles for assertions.
* Call from beforeEach so each test starts from a clean call history.
*/
export function setupApiMocks() {
const axios = require('axios')
axios.get.mockImplementation(async (url: string) => ({
data: mockForCacheFile(url),
status: 200,
statusText: 'OK',
headers: {},
config: {},
}))
const fetchMock = jest.fn(async (url: string) => {
if (url.includes('common.essentialConsts')) {
return jsonResponse(essentialConsts)
}
throw new Error(`[tests] unmocked fetch: ${url}`)
})
;(global as unknown as { fetch: unknown }).fetch = fetchMock
return { fetchMock, axiosGet: axios.get }
}