facebook / facebook/relay

mockClear does not reset the environment properly

Open
#3,690 3 comments 1 reaction 0 assignees View on GitHub
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

`createMockEnvironment` returns an instance of `environment` with `mockClear`, but this method does not fully clean the internals.
For example, we would like to create only 1 environment and use `mockClear` between tests to reset the internals in place of running `createMockEnvironment` in each of them, in this way we could move the test setup to `jest.env.js` loaded on `setupFilesAfterEnv`, in some way similar to this example:

```javascript
const environment = createMockEnvironment();

const Provider: React.FC = ({children}) => (


{children}


);

const Dummy: React.VFC<{fetchKey?: string | number}> = ({fetchKey}) => {
const data = useLazyLoadQuery(
graphql`
query dummyQuery {
foo
}
`,
{},
{fetchKey},
);

return (


);
};

describe(() => {
afterEach(() => {
environment.mockClear();
});

it('loading', () => {
render();
// none resolve / reject
expect(...);
});

it('error', () => {
render();
environment.mock.rejectMostRecentOperation(new Error('oops'));
expect(...);
});

it('data', () => {
render();
environment.mock.resolveMostRecentOperation({foo: 123})
expect(...);
});
});
```
At present if we run each of the tests above individually, they work, but if we try them altogether, then they fail. For example with:

```text
Invariant Violation: RelayModernMockEnvironment: There are no pending operations in the list
```

The former error is because the `environment` holds some module state for [`requestCachesByEnvironment`](https://github.com/facebook/relay/blob/30995390857adca421a89f0a58b098bf5ef1c839/packages/relay-runtime/query/fetchQueryInternal.js#L310).

And for more complex scenarios where multiple tests are fired in a row, we can hit 2 other caches that are not cleared in `mockClear`. Also we must clear the store between tests as already [reported and PR](https://github.com/facebook/relay/issues/3686).

To sum up, just adding a few lines in the `mockClear` we could use the same instance all the time.
Here a snippet with some methods that "properly" exposed in the API will make it work:

https://github.com/facebook/relay/blob/741741acc84cc03a3c7cba3014b5c5bf210f78d9/packages/relay-test-utils/RelayModernMockEnvironment.js#L534

```javascript
import {getFragmentResourceForEnvironment} from 'react-relay/lib/relay-hooks/FragmentResource'; // <== not exposed in barrel file
import {getQueryResourceForEnvironment} from 'react-relay/lib/relay-hooks/QueryResource'; // <== not exposed in barrel file
import {getRequestCache} from 'relay-runtime/lib/query/fetchqueryInternal'; // <== not exported by the module

...
function createMockEnvironment(
...
const qr = getQueryResourceForEnvironment(environment);
const fr = getFragmentResourceForEnvironment(environment);
const rc = getRequestCache(environment);

qr._cache.clear();
fr._cache.clear();
rc.clear();

// @see https://github.com/facebook/relay/pull/3687
environment.getStore().getSource().clear();
```

@kassens @alunyov @sibelius Do you foresee something against it? Please advise.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.