apollo-feature-requests
apollo-feature-requests copied to clipboard
Optional loading state skipping for mocked requests
Motivation
In our project we have setup visual tests of screens that relied on Apollo for fetching information before rendering. These requests were being mocked by setting a MockLink with mocked responses, but we noticed that visual tests were failing because the screen capture was being made in a transitional state between loading and loaded states, which for our use case was undesired.
This solution was inspired by reading about a similar situation in StackOverflow
Proposed solution
We noticed that the issue was inside MockLink's request function, where the actual returning of the mocked responses is wrapped inside a setTimeout function, which forces a loading state even when the mock has explicitly specified a delay of 0. In our project we have copied the MockLink implementation by copying the project and modifying the offending section with the following:
const handleObserver = (
observer: ZenObservable.SubscriptionObserver<
FetchResult<
{
[key: string]: any
},
Record<string, any>,
Record<string, any>
>
>
) => {
if (configError) {
try {
// The onError function can return false to indicate that
// configError need not be passed to observer.error. For
// example, the default implementation of onError calls
// observer.error(configError) and then returns false to
// prevent this extra (harmless) observer.error call.
if (this.onError(configError, observer) !== false) {
throw configError
}
} catch (error) {
observer.error(error)
}
} else if (response) {
if (response.error) {
observer.error(response.error)
} else {
if (response.result) {
observer.next(
typeof response.result === 'function'
? (response.result as ResultFunction<FetchResult>)()
: response.result
)
}
observer.complete()
}
}
}
return new Observable((observer) => {
let timer: ReturnType<typeof setTimeout> | undefined
// we keep the original implementation if delay is explicitly set
if (response?.delay) {
timer = setTimeout(() => {
handleObserver(observer)
}, response.delay)
} else {
// it no delay is set, then we directly return the mocked responses without setTimeout
handleObserver(observer)
}
return () => {
if (timer) clearTimeout(timer)
}
})