【发布时间】:2021-06-29 20:45:18
【问题描述】:
我正在使用新的 Relay Hooks 并发现很难通过测试。我遇到了他们docs 中提到的问题。
如果在usePreloadedQuery之前和之后添加console.log,只会命中“before”调用
//sample test
jest.useFakeTimers()
test("a list of entries is displayed when the component mounts", async () => {
const environment = createMockEnvironment()
environment.mock.queueOperationResolver(operation => {
return MockPayloadGenerator.generate(operation, {
Entry() {
return {
id: "123",
title: "hello",
urlKey: "abc"
}
}
})
})
relay.mock.queuePendingOperation(EntryListQuery, {})
render(<RelayEnvironmentProvider environment={environment}>
<Entries />
</RelayEnvironmentProvider>
)
jest.runAllImmediates()
expect(await screen.getByText(/hello/i)).toBeInTheDocument()
})
//core component I am wanting to test
import { Suspense, useEffect } from "react"
import { useQueryLoader } from "react-relay/hooks"
import { Loading } from "./Loading"
import { EntryList, EntryListQuery } from "./EntryList"
const Entries = () => {
const [queryReference, loadQuery, disposeQuery] = useQueryLoader(EntryListQuery)
useEffect(() => {
if (!queryReference) loadQuery()
}, [disposeQuery, loadQuery, queryReference])
if (!queryReference) return <Loading />
return (
<Suspense fallback={<Loading />}>
<EntryList queryReference={queryReference} />
</Suspense>
)
}
export { Entries }
//the core component's child component
import { usePreloadedQuery } from "react-relay/hooks"
import graphql from "babel-plugin-relay/macro"
import { Link } from "react-router-dom"
import { Entry } from "./Entry"
const EntryListQuery = graphql`
query EntryListQuery {
queryEntry {
id
title
urlKey
}
}
`
const EntryList = ({ queryReference }) => {
const { queryEntry } = usePreloadedQuery(EntryListQuery, queryReference)
return (
<section>
<div className="flex justify-between items-center">
<p>search</p>
<Link to="?action=new">New Entry</Link>
</div>
<ul>
{queryEntry.map(entry => {
if (entry) return <Entry key={entry.id} entry={entry} />
return null
})}
</ul>
</section>
)
}
export { EntryList, EntryListQuery }
我发现loadQuery 正在被调用,但是我在queueOperationResolver 中的console.log 的任何内容都没有出现。如果我在usePreloadedQuery 之前添加一个console.log,它会输出,但之后不会。因此,EntryList 似乎被挂起,查询永远无法解决。
我发现如果我将测试更改为以下也不会触发任何错误,看起来queueOperationResolver 永远不会被调用。
environment.mock.queueOperationResolver(() => new Error("Uh-oh"))
当我在 EntryList 之前的 usePreloadedQuery 代码之前 console.log queryReference 时,它会输出如下所示的对象。所以我知道查询被正确传递了。
{
kind: 'PreloadedQuery',
environment: RelayModernEnvironment {
configName: 'RelayModernMockEnvironment',
_treatMissingFieldsAsNull: false,
__log: [Function: emptyFunction],
requiredFieldLogger: [Function: defaultRequiredFieldLogger],
_defaultRenderPolicy: 'partial',
_operationLoader: undefined,
_operationExecutions: Map(1) { '643ead0ae575426fdd62800c27d6fef3{}' => 'active' },
_network: { execute: [Function: execute] },
_getDataID: [Function: defaultGetDataID],
_publishQueue: RelayPublishQueue {
_hasStoreSnapshot: false,
_handlerProvider: [Function: RelayDefaultHandlerProvider],
_pendingBackupRebase: false,
_pendingData: Set(0) {},
_pendingOptimisticUpdates: Set(0) {},
_store: [RelayModernStore],
_appliedOptimisticUpdates: Set(0) {},
_gcHold: null,
_getDataID: [Function: defaultGetDataID]
},
_scheduler: null,
_store: RelayModernStore {
_gcStep: [Function (anonymous)],
_currentWriteEpoch: 0,
_gcHoldCounter: 0,
_gcReleaseBufferSize: 10,
_gcRun: null,
_gcScheduler: [Function: resolveImmediate],
_getDataID: [Function: defaultGetDataID],
_globalInvalidationEpoch: null,
_invalidationSubscriptions: Set(0) {},
_invalidatedRecordIDs: Set(0) {},
__log: null,
_queryCacheExpirationTime: undefined,
_operationLoader: null,
_optimisticSource: null,
_recordSource: [RelayMapRecordSourceMapImpl],
_releaseBuffer: [],
_roots: [Map],
_shouldScheduleGC: false,
_storeSubscriptions: [RelayStoreSubscriptions],
_updatedRecordIDs: Set(0) {},
_shouldProcessClientComponents: undefined,
getSource: [Function],
lookup: [Function],
notify: [Function],
publish: [Function],
retain: [Function],
subscribe: [Function]
},
options: undefined,
_isServer: false,
__setNet: [Function (anonymous)],
DEBUG_inspect: [Function (anonymous)],
_missingFieldHandlers: undefined,
_operationTracker: RelayOperationTracker {
_ownersToPendingOperationsIdentifier: Map(0) {},
_pendingOperationsToOwnersIdentifier: Map(0) {},
_ownersIdentifierToPromise: Map(0) {}
},
_reactFlightPayloadDeserializer: undefined,
_reactFlightServerErrorHandler: undefined,
_shouldProcessClientComponents: undefined,
execute: [Function: mockConstructor] {
_isMockFunction: true,
getMockImplementation: [Function (anonymous)],
mock: [Getter/Setter],
mockClear: [Function (anonymous)],
mockReset: [Function (anonymous)],
mockRestore: [Function (anonymous)],
mockReturnValueOnce: [Function (anonymous)],
mockResolvedValueOnce: [Function (anonymous)],
mockRejectedValueOnce: [Function (anonymous)],
mockReturnValue: [Function (anonymous)],
mockResolvedValue: [Function (anonymous)],
mockRejectedValue: [Function (anonymous)],
mockImplementationOnce: [Function (anonymous)],
mockImplementation: [Function (anonymous)],
mockReturnThis: [Function (anonymous)],
mockName: [Function (anonymous)],
getMockName: [Function (anonymous)]
},
executeWithSource: [Function: mockConstructor] {
_isMockFunction: true,
getMockImplementation: [Function (anonymous)],
mock: [Getter/Setter],
mockClear: [Function (anonymous)],
mockReset: [Function (anonymous)],
mockRestore: [Function (anonymous)],
mockReturnValueOnce: [Function (anonymous)],
mockResolvedValueOnce: [Function (anonymous)],
mockRejectedValueOnce: [Function (anonymous)],
mockReturnValue: [Function (anonymous)],
mockResolvedValue: [Function (anonymous)],
mockRejectedValue: [Function (anonymous)],
mockImplementationOnce: [Function (anonymous)],
mockImplementation: [Function (anonymous)],
mockReturnThis: [Function (anonymous)],
mockName: [Function (anonymous)],
getMockName: [Function (anonymous)]
},
...
更新
我发现以下测试有效,因此这意味着在尝试模拟使用 useQueryLoader 的组件中的查询时我做错了。
//sample test
test("a list of entries is displayed when the component mounts", async () => {
const environment = createMockEnvironment()
environment.mock.queueOperationResolver(operation => {
return MockPayloadGenerator.generate(operation, {
Entry() {
return {
id: "123",
title: "hello",
urlKey: "abc"
}
}
})
})
relay.mock.queuePendingOperation(EntryListQuery, {})
const queryReference = loadQuery(environment, EntryListQuery, {}, {})
render(<RelayEnvironmentProvider environment={environment}>
<EntryList queryReference={queryReference=} />
</RelayEnvironmentProvider>
)
expect(await screen.getByText(/hello/i)).toBeInTheDocument()
})
【问题讨论】:
标签: javascript reactjs react-testing-library relayjs relay