90 lines
3.4 KiB
TypeScript
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 }
|
|
}
|