diff --git a/__tests__/ReactRelayFragmentContainer-test.tsx b/__tests__/ReactRelayFragmentContainer-test.tsx
index c592e940..41633f0a 100644
--- a/__tests__/ReactRelayFragmentContainer-test.tsx
+++ b/__tests__/ReactRelayFragmentContainer-test.tsx
@@ -14,22 +14,16 @@
import * as React from 'react';
import * as ReactTestRenderer from 'react-test-renderer';
-import {
- useQuery,
- useFragment,
- RelayEnvironmentProvider,
- useRelayEnvironment,
- NETWORK_ONLY,
-} from '../src';
+import { useQuery, useFragment, RelayEnvironmentProvider, useRelayEnvironment, NETWORK_ONLY } from '../src';
function createHooks(component, options?: any) {
- const result = ReactTestRenderer.create(component, options);
+ let result;
ReactTestRenderer.act(() => {
+ result = ReactTestRenderer.create(component, options);
jest.runAllImmediates();
});
return result;
}
-
const ReactRelayFragmentContainer = {
createContainer: (Component, spec) => (props) => {
const { user, ...others } = props;
@@ -127,10 +121,7 @@ describe('ReactRelayFragmentContainer', () => {
`;
UserQueryWithCond = graphql`
- query ReactRelayFragmentContainerTestUserWithCondQuery(
- $id: ID!
- $condGlobal: Boolean!
- ) {
+ query ReactRelayFragmentContainerTestUserWithCondQuery($id: ID!, $condGlobal: Boolean!) {
node(id: $id) {
...ReactRelayFragmentContainerTestUserFragment @arguments(cond: $condGlobal)
}
@@ -138,7 +129,7 @@ describe('ReactRelayFragmentContainer', () => {
`;
UserFragment = graphql`
fragment ReactRelayFragmentContainerTestUserFragment on User
- @argumentDefinitions(cond: { type: "Boolean!", defaultValue: true }) {
+ @argumentDefinitions(cond: { type: "Boolean!", defaultValue: true }) {
id
name @include(if: $cond)
}
@@ -338,12 +329,7 @@ describe('ReactRelayFragmentContainer', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '842472',
- { cond: true },
- ownerUser2.request,
- ),
+ selector: createReaderSelector(UserFragment, '842472', { cond: true }, ownerUser2.request),
});
});
@@ -358,8 +344,7 @@ describe('ReactRelayFragmentContainer', () => {
environment.lookup.mockClear();
environment.subscribe.mockClear();
- userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data
- .node;
+ userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -389,12 +374,7 @@ describe('ReactRelayFragmentContainer', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '4',
- { cond: false },
- ownerUser1WithCondVar.request,
- ),
+ selector: createReaderSelector(UserFragment, '4', { cond: false }, ownerUser1WithCondVar.request),
});
});
diff --git a/__tests__/ReactRelayPaginationContainer-test.tsx b/__tests__/ReactRelayPaginationContainer-test.tsx
index 8bf00c56..5bcdddcc 100644
--- a/__tests__/ReactRelayPaginationContainer-test.tsx
+++ b/__tests__/ReactRelayPaginationContainer-test.tsx
@@ -18,8 +18,9 @@ import { usePagination, RelayEnvironmentProvider, useRelayEnvironment } from '..
import { forceCache } from '../src/Utils';
function createHooks(component, options?: any) {
- const result = ReactTestRenderer.create(component, options);
+ let result;
ReactTestRenderer.act(() => {
+ result = ReactTestRenderer.create(component, options);
jest.runAllImmediates();
});
return result;
@@ -165,18 +166,14 @@ describe('ReactRelayPaginationContainer', () => {
UserFragment = graphql`
fragment ReactRelayPaginationContainerTestUserFragment on User
- @refetchable(queryName: "ReactRelayPaginationContainerUserFragmentRefetchQuery")
- @argumentDefinitions(
- isViewerFriendLocal: { type: "Boolean", defaultValue: false }
- orderby: { type: "[String]" }
- ) {
+ @refetchable(queryName: "ReactRelayPaginationContainerUserFragmentRefetchQuery")
+ @argumentDefinitions(
+ isViewerFriendLocal: { type: "Boolean", defaultValue: false }
+ orderby: { type: "[String]" }
+ ) {
id
- friends(
- after: $after
- first: $count
- orderby: $orderby
- isViewerFriend: $isViewerFriendLocal
- ) @connection(key: "UserFragment_friends") {
+ friends(after: $after, first: $count, orderby: $orderby, isViewerFriend: $isViewerFriendLocal)
+ @connection(key: "UserFragment_friends") {
edges {
node {
id
@@ -533,8 +530,7 @@ describe('ReactRelayPaginationContainer', () => {
environment.lookup.mockClear();
environment.subscribe.mockClear();
- userPointer = environment.lookup(ownerUser1WithOtherVar.fragment, ownerUser1WithOtherVar)
- .data.node;
+ userPointer = environment.lookup(ownerUser1WithOtherVar.fragment, ownerUser1WithOtherVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -637,8 +633,7 @@ describe('ReactRelayPaginationContainer', () => {
environment.subscribe.mockClear();
// Pass an updated user pointer that references different variables
- userPointer = environment.lookup(ownerUser1WithOtherVar.fragment, ownerUser1WithOtherVar)
- .data.node;
+ userPointer = environment.lookup(ownerUser1WithOtherVar.fragment, ownerUser1WithOtherVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -909,11 +904,8 @@ describe('ReactRelayPaginationContainer', () => {
`;
UserFragment = graphql`
fragment ReactRelayPaginationContainerTestNoConnectionOnFragmentUserFragment on User
- @refetchable(
- queryName: "ReactRelayPaginationContainerTestNoConnectionUserFragmentRefetchQuery"
- ) {
- friends(after: $after, first: $count, orderby: $orderby)
- @connection(key: "UserFragment_friends") {
+ @refetchable(queryName: "ReactRelayPaginationContainerTestNoConnectionUserFragmentRefetchQuery") {
+ friends(after: $after, first: $count, orderby: $orderby) @connection(key: "UserFragment_friends") {
edges {
node {
id
@@ -1129,11 +1121,14 @@ describe('ReactRelayPaginationContainer', () => {
it('updates after pagination (if more results)', () => {
const userPointer = environment.lookup(ownerUser1.fragment, ownerUser1).data.node;
- ReactTestRenderer.create(
-
-
- ,
- );
+ ReactTestRenderer.act(() => {
+ ReactTestRenderer.create(
+
+
+ ,
+ );
+ jest.runAllImmediates();
+ });
expect(render.mock.calls.length).toBe(1);
expect(render.mock.calls[0][0].user.friends.edges.length).toBe(1);
@@ -1168,8 +1163,6 @@ describe('ReactRelayPaginationContainer', () => {
expect(render.mock.calls.length).toBe(3);
expect(render.mock.calls[0][0].user.friends.edges.length).toBe(1);
expect(render.mock.calls[0][0].relay.isLoadingNext).toBe(true);
- expect(render.mock.calls[1][0].user.friends.edges.length).toBe(2);
- expect(render.mock.calls[1][0].relay.isLoadingNext).toBe(true);
expect(render.mock.calls[2][0].user.friends.edges.length).toBe(2);
expect(render.mock.calls[2][0].relay.isLoadingNext).toBe(false);
expect(render.mock.calls[2][0].relay.hasMore).toBe(true);
@@ -1177,11 +1170,14 @@ describe('ReactRelayPaginationContainer', () => {
it('updates after pagination (if no more results)', () => {
const userPointer = environment.lookup(ownerUser1.fragment, ownerUser1).data.node;
- ReactTestRenderer.create(
-
-
- ,
- );
+ ReactTestRenderer.act(() => {
+ ReactTestRenderer.create(
+
+
+ ,
+ );
+ jest.runAllImmediates();
+ });
expect(render.mock.calls.length).toBe(1);
expect(render.mock.calls[0][0].user.friends.edges.length).toBe(1);
@@ -1216,8 +1212,6 @@ describe('ReactRelayPaginationContainer', () => {
expect(render.mock.calls.length).toBe(3);
expect(render.mock.calls[0][0].user.friends.edges.length).toBe(1);
expect(render.mock.calls[0][0].relay.isLoadingNext).toBe(true);
- expect(render.mock.calls[1][0].user.friends.edges.length).toBe(2);
- expect(render.mock.calls[1][0].relay.isLoadingNext).toBe(true);
expect(render.mock.calls[2][0].user.friends.edges.length).toBe(2);
expect(render.mock.calls[2][0].relay.isLoadingNext).toBe(false);
expect(render.mock.calls[2][0].relay.hasMore).toBe(false);
@@ -1402,9 +1396,7 @@ describe('ReactRelayPaginationContainer', () => {
isViewerFriendLocal: false,
};
loadMore(1, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache)).toBe(true);
});
it('calls the callback when the fetch succeeds', () => {
@@ -1611,9 +1603,7 @@ describe('ReactRelayPaginationContainer', () => {
isViewerFriendLocal: false,
};
refetchConnection(1, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache)).toBe(true);
});
it('calls the callback when the fetch succeeds', () => {
@@ -1867,9 +1857,9 @@ describe('ReactRelayPaginationContainer', () => {
});
expect(references.length).toBe(1);
expect(references[0].dispose).not.toBeCalled();
- expect(render.mock.calls.length).toBe(4);
- expect(render.mock.calls[3][0].user.friends.edges.length).toBe(1);
- expect(render.mock.calls[3][0]).toEqual({
+ expect(render.mock.calls.length).toBe(3);
+ expect(render.mock.calls[2][0].user.friends.edges.length).toBe(1);
+ expect(render.mock.calls[2][0]).toEqual({
user: {
id: '4',
friends: {
@@ -1937,9 +1927,7 @@ describe('ReactRelayPaginationContainer', () => {
isViewerFriendLocal: true,
id: '4',
};
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, variables, forceCache)).toBe(true);
});
it('should not refetch connection if container is unmounted', () => {
diff --git a/__tests__/ReactRelayQueryRenderer-test.tsx b/__tests__/ReactRelayQueryRenderer-test.tsx
index c62f2767..528bbeb0 100644
--- a/__tests__/ReactRelayQueryRenderer-test.tsx
+++ b/__tests__/ReactRelayQueryRenderer-test.tsx
@@ -23,8 +23,9 @@ import * as ReactTestRenderer from 'react-test-renderer';
//import readContext from "react-relay/lib/readContext";
function createHooks(component, options?: any) {
- const result = ReactTestRenderer.create(component, options);
+ let result;
ReactTestRenderer.act(() => {
+ result = ReactTestRenderer.create(component, options);
jest.runAllImmediates();
});
return result;
@@ -63,7 +64,7 @@ const loadingState = {
isLoading: true,
};
-function expectToBeRendered(render, readyState) {
+function expectToBeRenderedStore(render, readyState) {
const calls = render.mock.calls;
// Ensure useEffect is called before other timers
expect(calls.length).toBe(2);
@@ -72,6 +73,13 @@ function expectToBeRendered(render, readyState) {
return { pass: true };
}
+function expectToBeRendered(render, readyState, isLoading = false) {
+ const calls = render.mock.calls;
+ // Ensure useEffect is called before other timers
+ expect(calls.length).toBe(1);
+ expect(calls[0][0]).toEqual({ ...readyState, isLoading });
+ return { pass: true };
+}
const QueryRendererHook = (props) => {
const {
render,
@@ -83,6 +91,7 @@ const QueryRendererHook = (props) => {
skip,
onComplete,
onResponse,
+ UNSTABLE_renderPolicy,
} = props;
const relays = useQuery(query, variables, {
networkCacheConfig: cacheConfig,
@@ -91,6 +100,7 @@ const QueryRendererHook = (props) => {
skip,
onComplete,
onResponse,
+ UNSTABLE_renderPolicy,
});
return {render(relays)};
@@ -105,6 +115,7 @@ const ReactRelayQueryRenderer = (props) => (
describe('ReactRelayQueryRenderer', () => {
let TestQuery;
let NextQuery;
+ let CompleteTestQuery;
let cacheConfig;
let environment;
let render;
@@ -121,6 +132,17 @@ describe('ReactRelayQueryRenderer', () => {
},
};
+ const responseComplete = {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '4',
+ name: 'Zuck',
+ username: 'Zuck',
+ },
+ },
+ };
+
const responseErrors = {
data: {
node: {
@@ -195,6 +217,17 @@ describe('ReactRelayQueryRenderer', () => {
}
`;
+ CompleteTestQuery = graphql`
+ query ReactRelayQueryRendererTestCompleteQuery($id: ID = "") {
+ node(id: $id) {
+ id
+ username
+ name
+ ...ReactRelayQueryRendererTestFragment
+ }
+ }
+ `;
+
NextQuery = graphql`
query ReactRelayQueryRendererTestNextQuery($id: ID!) {
node(id: $id) {
@@ -220,6 +253,198 @@ describe('ReactRelayQueryRenderer', () => {
});
describe('when initialized', () => {
+ it('check store and network', () => {
+ environment.mockClear();
+ environment.commitUpdate((_store) => {
+ let root = _store.get(ROOT_ID);
+ if (!root) {
+ root = _store.create(ROOT_ID, ROOT_TYPE);
+ }
+ const user = _store.create('4', 'User');
+ user.setValue('4', 'id');
+ user.setValue('Zuck', 'name');
+ user.setValue('Zuck', 'username');
+ root.setLinkedRecord(user, 'node', { id: '4' });
+ });
+ createHooks(
+ ,
+ );
+
+ expect(environment.execute.mock.calls.length).toBe(1);
+ const owner = createOperationDescriptor(CompleteTestQuery, variables);
+ expectToBeRendered(
+ render,
+ {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ name: 'Zuck',
+ username: 'Zuck',
+ __isWithinUnmatchedTypeRefinement: false,
+ __id: '4',
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+ __fragmentOwner: owner.request,
+ },
+ },
+ retry: expect.any(Function),
+ },
+ true,
+ );
+ render.mockClear();
+ environment.mock.resolve(CompleteTestQuery, responseComplete);
+ expectToBeRendered(render, {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ name: 'Zuck',
+ username: 'Zuck',
+ __isWithinUnmatchedTypeRefinement: false,
+ __id: '4',
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+ __fragmentOwner: owner.request,
+ },
+ },
+ retry: expect.any(Function),
+ });
+ });
+
+ it('check store and network partial', () => {
+ environment.mockClear();
+ environment.commitUpdate((_store) => {
+ let root = _store.get(ROOT_ID);
+ if (!root) {
+ root = _store.create(ROOT_ID, ROOT_TYPE);
+ }
+ const user = _store.create('4', 'User');
+ user.setValue('4', 'id');
+ user.setValue('Zuck', 'name');
+ root.setLinkedRecord(user, 'node', { id: '4' });
+ });
+ createHooks(
+ ,
+ );
+
+ expect(environment.execute.mock.calls.length).toBe(1);
+ const owner = createOperationDescriptor(CompleteTestQuery, variables);
+ expectToBeRendered(
+ render,
+ {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ name: 'Zuck',
+ username: undefined,
+ __isWithinUnmatchedTypeRefinement: false,
+ __id: '4',
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+ __fragmentOwner: owner.request,
+ },
+ },
+ retry: expect.any(Function),
+ },
+ true,
+ );
+ render.mockClear();
+ environment.mock.resolve(CompleteTestQuery, responseComplete);
+ expectToBeRenderedStore(render, {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ name: 'Zuck',
+ username: 'Zuck',
+ __isWithinUnmatchedTypeRefinement: false,
+ __id: '4',
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+ __fragmentOwner: owner.request,
+ },
+ },
+ retry: expect.any(Function),
+ });
+ });
+ /*
+ it('observe query polling store and network', () => {
+ const onComplete = jest.fn(() => undefined);
+ const newCacheConfig = {
+ ...cacheConfig,
+ poll: 1,
+ };
+ environment.mockClear();
+ environment.commitUpdate((_store) => {
+ let root = _store.get(ROOT_ID);
+ if (!root) {
+ root = _store.create(ROOT_ID, ROOT_TYPE);
+ }
+ const user = _store.create('4', 'User');
+ user.setValue('4', 'id');
+ user.setValue('Zuck', 'name');
+ root.setLinkedRecord(user, 'node', { id: '4' });
+ });
+ createHooks(
+
+
+ ,
+ );
+
+ expect(environment.execute.mock.calls.length).toBe(1);
+ expect(onComplete).not.toBeCalled();
+ render.mockClear();
+ environment.mock.resolve(TestQuery, response);
+ expect(onComplete).not.toBeCalled();
+ const owner = createOperationDescriptor(TestQuery, variables, newCacheConfig);
+ expectToBeRendered(render, {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ __isWithinUnmatchedTypeRefinement: false,
+
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+
+ __fragmentOwner: owner.request,
+ __id: '4',
+ },
+ },
+ retry: expect.any(Function),
+ });
+ });
+*/
it('skip', () => {
const renderer = createHooks(
@@ -321,6 +546,50 @@ describe('ReactRelayQueryRenderer', () => {
});
});
+ it('observe query polling', () => {
+ const onComplete = jest.fn(() => undefined);
+ const newCacheConfig = {
+ ...cacheConfig,
+ poll: 1,
+ };
+ createHooks(
+
+
+ ,
+ );
+
+ expect(environment.execute.mock.calls.length).toBe(1);
+ expect(onComplete).not.toBeCalled();
+ render.mockClear();
+ environment.mock.resolve(TestQuery, response);
+ expect(onComplete).not.toBeCalled();
+ const owner = createOperationDescriptor(TestQuery, variables, newCacheConfig);
+ expectToBeRendered(render, {
+ error: null,
+ data: {
+ node: {
+ id: '4',
+ __isWithinUnmatchedTypeRefinement: false,
+
+ __fragments: {
+ ReactRelayQueryRendererTestFragment: {},
+ },
+
+ __fragmentOwner: owner.request,
+ __id: '4',
+ },
+ },
+ retry: expect.any(Function),
+ });
+ });
+
describe('when constructor fires multiple times', () => {
describe('when store does not have snapshot and fetch does not return snapshot', () => {
it('fetches the query only once, renders loading state', () => {
@@ -358,11 +627,10 @@ describe('ReactRelayQueryRenderer', () => {
unstable_concurrentUpdatesByDefault: true,
});
});
-
+
// Flush some of the changes, but don't commit
(Scheduler as any).unstable_flushNumberOfYields(2);
-
expect((Scheduler as any).unstable_clearYields()).toEqual(['A', 'B']);
expect(renderer.toJSON()).toEqual(null);
expect().loadingRendered();
@@ -373,7 +641,6 @@ describe('ReactRelayQueryRenderer', () => {
renderer.update();
});
-
expect(environment.execute.mock.calls.length).toBe(1);
expect().loadingRendered();
});
@@ -665,8 +932,8 @@ describe('ReactRelayQueryRenderer', () => {
// request
thirdRequest.resolve(thirdResponse);
secondRequest.resolve(secondResponse);
- expect(render.mock.calls.length).toEqual(4);
- const lastRender = render.mock.calls[3][0];
+ expect(render.mock.calls.length).toEqual(3);
+ const lastRender = render.mock.calls[2][0];
expect(lastRender).toEqual({
error: null,
data: {
@@ -1138,9 +1405,7 @@ describe('ReactRelayQueryRenderer', () => {
render,
variables,
});
- expect(environment.mock.isLoading(TestQuery, expectedVariables, cacheConfig)).toBe(
- true,
- );
+ expect(environment.mock.isLoading(TestQuery, expectedVariables, cacheConfig)).toBe(true);
expect().loadingRendered();
});
@@ -1250,7 +1515,7 @@ describe('ReactRelayQueryRenderer', () => {
});
it('refetch the query if `retry`', () => {
- expect.assertions(7);
+ expect.assertions(6);
render.mockClear();
const error = new Error('network fails');
environment.mock.reject(TestQuery, error);
@@ -1313,7 +1578,7 @@ describe('ReactRelayQueryRenderer', () => {
}
}
const renderer = createHooks();
- expect.assertions(7);
+ expect.assertions(5);
mockA.mockClear();
mockB.mockClear();
environment.mock.resolve(TestQuery, response);
@@ -1384,7 +1649,7 @@ describe('ReactRelayQueryRenderer', () => {
});
it('renders the query results', () => {
- expect.assertions(3);
+ expect.assertions(2);
render.mockClear();
environment.mock.resolve(TestQuery, response);
const owner = createOperationDescriptor(TestQuery, variables);
@@ -1848,7 +2113,7 @@ describe('ReactRelayQueryRenderer', () => {
render.mockClear();
environment.mock.resolve(TestQuery, response);
- expect(render).toBeCalledTimes(2);
+ expect(render).toBeCalledTimes(1);
const readyState = render.mock.calls[0][0];
expect(readyState.retry).not.toBe(null);
environment.mockClear();
@@ -1888,7 +2153,7 @@ describe('ReactRelayQueryRenderer', () => {
render.mockClear();
environment.mock.resolve(TestQuery, response);
- expect(render).toBeCalledTimes(2);
+ expect(render).toBeCalledTimes(1);
const readyState = render.mock.calls[0][0];
expect(readyState.retry).not.toBe(null);
environment.mockClear();
@@ -1916,7 +2181,7 @@ describe('ReactRelayQueryRenderer', () => {
render.mockClear();
environment.mock.resolve(TestQuery, response);
- expect(render).toBeCalledTimes(2);
+ expect(render).toBeCalledTimes(1);
const readyState = render.mock.calls[0][0];
expect(readyState.retry).not.toBe(null);
environment.mockClear();
@@ -1986,8 +2251,8 @@ describe('ReactRelayQueryRenderer', () => {
let response = null;
const onResponse = (res) => {
response = res;
- console.log('onResponse test', res);
};
+
createHooks(
{
onResponse={onResponse}
/>,
);
- expect.assertions(4);
+
+ expect.assertions(3);
+
render.mockClear();
environment.mock.resolve(TestQuery, responseErrors);
const owner = createOperationDescriptor(TestQuery, variables);
diff --git a/__tests__/ReactRelayRefetchContainer-test.tsx b/__tests__/ReactRelayRefetchContainer-test.tsx
index b4e5a6e5..b771796e 100644
--- a/__tests__/ReactRelayRefetchContainer-test.tsx
+++ b/__tests__/ReactRelayRefetchContainer-test.tsx
@@ -12,16 +12,13 @@
/* eslint-disable */
import * as React from 'react';
import * as ReactTestRenderer from 'react-test-renderer';
-import {
- useRefetchable as useRefetch,
- RelayEnvironmentProvider,
- useRelayEnvironment,
-} from '../src';
+import { useRefetchable as useRefetch, RelayEnvironmentProvider, useRelayEnvironment } from '../src';
import { forceCache } from '../src/Utils';
-function createHooks(component) {
- const result = ReactTestRenderer.create(component);
+function createHooks(component, options?: any) {
+ let result;
ReactTestRenderer.act(() => {
+ result = ReactTestRenderer.create(component, options);
jest.runAllImmediates();
});
return result;
@@ -38,14 +35,7 @@ const ReactRelayRefetchContainer = {
fetchPolicy: options?.fetchPolicy,
});
};
- return (
-
- );
+ return ;
},
};
@@ -137,8 +127,8 @@ describe('ReactRelayRefetchContainer', () => {
`;
UserFragment = graphql`
fragment ReactRelayRefetchContainerTestUserFragment on User
- @refetchable(queryName: "ReactRelayRefetchContainerTestUserFragmentRefetchQuery")
- @argumentDefinitions(cond: { type: "Boolean", defaultValue: true }) {
+ @refetchable(queryName: "ReactRelayRefetchContainerTestUserFragmentRefetchQuery")
+ @argumentDefinitions(cond: { type: "Boolean", defaultValue: true }) {
id
name @include(if: $cond)
}
@@ -379,12 +369,7 @@ describe('ReactRelayRefetchContainer', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '842472',
- { cond: true },
- ownerUser2.request,
- ),
+ selector: createReaderSelector(UserFragment, '842472', { cond: true }, ownerUser2.request),
});
});
@@ -399,8 +384,7 @@ describe('ReactRelayRefetchContainer', () => {
environment.lookup.mockClear();
environment.subscribe.mockClear();
- userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data
- .node;
+ userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -432,12 +416,7 @@ describe('ReactRelayRefetchContainer', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '4',
- { cond: false },
- ownerUser1WithCondVar.request,
- ),
+ selector: createReaderSelector(UserFragment, '4', { cond: false }, ownerUser1WithCondVar.request),
});
});
@@ -458,9 +437,7 @@ describe('ReactRelayRefetchContainer', () => {
id: '4',
};
refetch(refetchVariables, null, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(true);
environment.mock.resolve(UserFragmentRefetchQuery, {
data: {
node: {
@@ -473,8 +450,7 @@ describe('ReactRelayRefetchContainer', () => {
environment.subscribe.mockClear();
// Pass an updated user pointer that references different variables
- userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data
- .node;
+ userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -506,12 +482,7 @@ describe('ReactRelayRefetchContainer', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '4',
- { cond: false },
- ownerUser1WithCondVar.request,
- ),
+ selector: createReaderSelector(UserFragment, '4', { cond: false }, ownerUser1WithCondVar.request),
});
});
@@ -683,9 +654,7 @@ describe('ReactRelayRefetchContainer', () => {
id: '4',
};
refetch(refetchVariables, null, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(true);
environment.mock.resolve(UserFragmentRefetchQuery, {
data: {
node: {
@@ -707,9 +676,7 @@ describe('ReactRelayRefetchContainer', () => {
};
refetch(refetchVariables, null, jest.fn(), refetchOptions);
expect(render.mock.calls.length).toBe(2);
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(false);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(false);
expect(environment.execute).toBeCalledTimes(0);
});
@@ -819,13 +786,11 @@ describe('ReactRelayRefetchContainer', () => {
},
});
refetch(refetchVariables, null, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, fetchedVariables, forceCache),
- ).toBe(false);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, fetchedVariables, forceCache)).toBe(false);
});
it('renders with the results of the new variables on success', () => {
- expect.assertions(10);
+ expect.assertions(8);
expect(render.mock.calls.length).toBe(1);
expect(render.mock.calls[0][0].user.name).toBe('Zuck');
variables = {
@@ -845,11 +810,9 @@ describe('ReactRelayRefetchContainer', () => {
},
},
});
- expect(render.mock.calls.length).toBe(4);
- expect(render.mock.calls[2][0].isLoading).toBe(true);
+ expect(render.mock.calls.length).toBe(3);
+ expect(render.mock.calls[2][0].isLoading).toBe(false);
expect(render.mock.calls[2][0].user.name).toBe(undefined);
- expect(render.mock.calls[3][0].isLoading).toBe(false);
- expect(render.mock.calls[3][0].user.name).toBe(undefined);
});
it('does not update variables on failure', () => {
diff --git a/__tests__/RelayHooks-test.tsx b/__tests__/RelayHooks-test.tsx
index a2382623..a283bb84 100644
--- a/__tests__/RelayHooks-test.tsx
+++ b/__tests__/RelayHooks-test.tsx
@@ -4,18 +4,12 @@ import * as ReactTestRenderer from 'react-test-renderer';
import { createOperationDescriptor, graphql } from 'relay-runtime';
import { createMockEnvironment } from 'relay-test-utils-internal';
-import {
- useOssFragment,
- RelayEnvironmentProvider,
- useRelayEnvironment,
- usePagination,
- useRefetchable,
-} from '../src';
+import { useOssFragment, RelayEnvironmentProvider, useRelayEnvironment, usePagination, useRefetchable } from '../src';
function createHooks(component, options?: any) {
- let result;// = ReactTestRenderer.create(component, options);
+ let result;
ReactTestRenderer.act(() => {
- result= ReactTestRenderer.create(component, options);
+ result = ReactTestRenderer.create(component, options);
jest.runAllImmediates();
});
return result;
@@ -84,18 +78,14 @@ describe('useMemo resolver functions', () => {
environment = createMockEnvironment();
UserFragment = graphql`
fragment RelayHooksTestUserFragment on User
- @refetchable(queryName: "RelayHooksTestUserFragmentRefetchQuery")
- @argumentDefinitions(
- isViewerFriendLocal: { type: "Boolean", defaultValue: false }
- orderby: { type: "[String]" }
- ) {
+ @refetchable(queryName: "RelayHooksTestUserFragmentRefetchQuery")
+ @argumentDefinitions(
+ isViewerFriendLocal: { type: "Boolean", defaultValue: false }
+ orderby: { type: "[String]" }
+ ) {
id
- friends(
- after: $after
- first: $count
- orderby: $orderby
- isViewerFriend: $isViewerFriendLocal
- ) @connection(key: "UserFragment_friends") {
+ friends(after: $after, first: $count, orderby: $orderby, isViewerFriend: $isViewerFriendLocal)
+ @connection(key: "UserFragment_friends") {
edges {
node {
id
@@ -115,8 +105,7 @@ describe('useMemo resolver functions', () => {
node(id: $id) {
id
__typename
- ...RelayHooksTestUserFragment
- @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby)
+ ...RelayHooksTestUserFragment @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby)
}
}
`;
@@ -174,20 +163,11 @@ describe('useMemo resolver functions', () => {
};
function useOssFragmentJest(fragmentNode, fragmentRef) {
- const [data, refetchFunction] = useOssFragment(
- fragmentNode,
- fragmentRef,
- false,
- 'useOssFragment',
- );
+ const [data, refetchFunction] = useOssFragment(fragmentNode, fragmentRef, false, 'useOssFragment');
renderSpy(data, refetchFunction);
return [data, refetchFunction];
}
- TestContainer = ReactRelayContainer.createContainer(
- TestComponent,
- UserFragment,
- UserQuery,
- );
+ TestContainer = ReactRelayContainer.createContainer(TestComponent, UserFragment, UserQuery);
});
it('re-renders on subscription callbac', () => {
const userPointer = environment.lookup(ownerUser1.fragment, ownerUser1).data.node;
@@ -281,11 +261,7 @@ describe('useMemo resolver functions', () => {
renderSpy(data, refetch);
return [data, refetch];
}
- TestContainer = ReactRelayContainer.createContainer(
- TestComponent,
- UserFragment,
- UserQuery,
- );
+ TestContainer = ReactRelayContainer.createContainer(TestComponent, UserFragment, UserQuery);
});
it('re-renders on subscription callbac', () => {
const userPointer = environment.lookup(ownerUser1.fragment, ownerUser1).data.node;
@@ -379,11 +355,7 @@ describe('useMemo resolver functions', () => {
renderSpy(data, refetch);
return [data, refetch];
}
- TestContainer = ReactRelayContainer.createContainer(
- TestComponent,
- UserFragment,
- UserQuery,
- );
+ TestContainer = ReactRelayContainer.createContainer(TestComponent, UserFragment, UserQuery);
});
it('re-renders on subscription callbac', () => {
const userPointer = environment.lookup(ownerUser1.fragment, ownerUser1).data.node;
diff --git a/__tests__/usePaginationFragment-test.tsx b/__tests__/usePaginationFragment-test.tsx
index 60a15f7e..d9dd427d 100644
--- a/__tests__/usePaginationFragment-test.tsx
+++ b/__tests__/usePaginationFragment-test.tsx
@@ -65,13 +65,7 @@ import * as React from 'react';
import { useMemo, useState } from 'react';
import * as TestRenderer from 'react-test-renderer';
import { getFragment, getRequest, graphql, OperationDescriptor, Variables } from 'relay-runtime';
-import {
- ConnectionHandler,
- FRAGMENT_OWNER_KEY,
- FRAGMENTS_KEY,
- ID_KEY,
- createOperationDescriptor,
-} from 'relay-runtime';
+import { ConnectionHandler, FRAGMENT_OWNER_KEY, FRAGMENTS_KEY, ID_KEY, createOperationDescriptor } from 'relay-runtime';
import { ReactRelayContext, usePaginationFragment as usePaginationFragmentOriginal } from '../src';
const warning = require('fbjs/lib/warning');
@@ -195,12 +189,12 @@ describe('usePaginationFragment', () => {
`;
gqlFragment = getFragment(graphql`
fragment usePaginationFragmentTestUserFragment on User
- @refetchable(queryName: "usePaginationFragmentTestUserFragmentPaginationQuery")
- @argumentDefinitions(
- isViewerFriendLocal: { type: "Boolean", defaultValue: false }
- orderby: { type: "[String]" }
- scale: { type: "Float" }
- ) {
+ @refetchable(queryName: "usePaginationFragmentTestUserFragmentPaginationQuery")
+ @argumentDefinitions(
+ isViewerFriendLocal: { type: "Boolean", defaultValue: false }
+ orderby: { type: "[String]" }
+ scale: { type: "Float" }
+ ) {
id
name
friends(
@@ -224,14 +218,12 @@ describe('usePaginationFragment', () => {
`);
gqlFragmentWithStreaming = getFragment(graphql`
fragment usePaginationFragmentTestUserFragmentWithStreaming on User
- @refetchable(
- queryName: "usePaginationFragmentTestUserFragmentStreamingPaginationQuery"
- )
- @argumentDefinitions(
- isViewerFriendLocal: { type: "Boolean", defaultValue: false }
- orderby: { type: "[String]" }
- scale: { type: "Float" }
- ) {
+ @refetchable(queryName: "usePaginationFragmentTestUserFragmentStreamingPaginationQuery")
+ @argumentDefinitions(
+ isViewerFriendLocal: { type: "Boolean", defaultValue: false }
+ orderby: { type: "[String]" }
+ scale: { type: "Float" }
+ ) {
id
name
friends(
@@ -318,8 +310,7 @@ describe('usePaginationFragment', () => {
$last: Int
) {
node(id: $id) {
- ...usePaginationFragmentTestUserFragment
- @arguments(isViewerFriendLocal: true, orderby: ["name"])
+ ...usePaginationFragmentTestUserFragment @arguments(isViewerFriendLocal: true, orderby: ["name"])
}
}
`);
@@ -356,30 +347,25 @@ describe('usePaginationFragment', () => {
id: '',
};
// eslint-disable-next-line prettier/prettier
- gqlPaginationQuery = require('./__generated__/usePaginationFragmentTestUserFragmentPaginationQuery.graphql')
- .default;
+ gqlPaginationQuery =
+ require('./__generated__/usePaginationFragmentTestUserFragmentPaginationQuery.graphql').default;
// eslint-disable-next-line prettier/prettier
- gqlPaginationQueryWithStreaming = require('./__generated__/usePaginationFragmentTestUserFragmentStreamingPaginationQuery.graphql')
- .default;
+ gqlPaginationQueryWithStreaming =
+ require('./__generated__/usePaginationFragmentTestUserFragmentStreamingPaginationQuery.graphql').default;
invariant(
areEqual(gqlFragment.metadata?.refetch?.operation.default, gqlPaginationQuery),
'useRefetchableFragment-test: Expected refetchable fragment metadata to contain operation.',
);
invariant(
- areEqual(
- gqlFragmentWithStreaming.metadata?.refetch?.operation.default,
- gqlPaginationQueryWithStreaming,
- ),
+ areEqual(gqlFragmentWithStreaming.metadata?.refetch?.operation.default, gqlPaginationQueryWithStreaming),
'useRefetchableFragment-test: Expected refetchable fragment metadata to contain operation.',
);
query = createOperationDescriptor(gqlQuery, variables, { force: true });
- queryNestedFragment = createOperationDescriptor(
- gqlQueryNestedFragment,
- variablesNestedFragment,
- { force: true },
- );
+ queryNestedFragment = createOperationDescriptor(gqlQueryNestedFragment, variablesNestedFragment, {
+ force: true,
+ });
queryWithoutID = createOperationDescriptor(gqlQueryWithoutID, variablesWithoutID, {
force: true,
});
@@ -481,9 +467,7 @@ describe('usePaginationFragment', () => {
const [owner, _setOwner] = useState(props.owner);
const [_, _setCount] = useState(0);
const fragment = props.fragment ?? gqlFragment;
- const nodeUserRef = useMemo(() => environment.lookup(owner.fragment).data?.node, [
- owner,
- ]);
+ const nodeUserRef = useMemo(() => environment.lookup(owner.fragment).data?.node, [owner]);
const ownerOperationRef = useMemo(
() => ({
[ID_KEY]: owner.request.variables.id ?? owner.request.variables.nodeID,
@@ -494,9 +478,7 @@ describe('usePaginationFragment', () => {
}),
[owner, fragment.name],
);
- const userRef = props.hasOwnProperty('userRef')
- ? props.userRef
- : nodeUserRef ?? ownerOperationRef;
+ const userRef = props.hasOwnProperty('userRef') ? props.userRef : nodeUserRef ?? ownerOperationRef;
setOwner = _setOwner;
@@ -510,26 +492,16 @@ describe('usePaginationFragment', () => {
setEnvironment = _setEnv;
- return (
-
- {children}
-
- );
+ return {children};
};
- renderFragment = (args?: {
- isConcurrent?: boolean;
- owner?: any;
- userRef?: any;
- fragment?: any;
- }): any => {
+ renderFragment = (args?: { isConcurrent?: boolean; owner?: any; userRef?: any; fragment?: any }): any => {
const { isConcurrent = false, ...props } = args ?? {};
let renderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
{
- console.log('error', error);
return `Error: ${error.message}`;
}}
>
@@ -589,9 +561,7 @@ describe('usePaginationFragment', () => {
}
`);
const renderer = renderFragment({ fragment: UserFragment });
- expect(
- renderer.toJSON().includes('Remove `@relay(plural: true)` from fragment'),
- ).toEqual(true);
+ expect(renderer.toJSON().includes('Remove `@relay(plural: true)` from fragment')).toEqual(true);
});
it('should throw error if fragment is missing @refetchable directive', () => {
@@ -615,9 +585,7 @@ describe('usePaginationFragment', () => {
});
const renderer = renderFragment({ fragment: UserFragment, owner });
expect(
- renderer
- .toJSON()
- .includes('Did you forget to add a @refetchable directive to the fragment?'),
+ renderer.toJSON().includes('Did you forget to add a @refetchable directive to the fragment?'),
).toEqual(true);
});
@@ -634,7 +602,7 @@ describe('usePaginationFragment', () => {
const UserFragment = getFragment(graphql`
fragment usePaginationFragmentTest3UserFragment on User
- @refetchable(queryName: "usePaginationFragmentTest3UserFragmentRefetchQuery") {
+ @refetchable(queryName: "usePaginationFragmentTest3UserFragmentRefetchQuery") {
id
}
`);
@@ -643,14 +611,10 @@ describe('usePaginationFragment', () => {
force: true,
});
const renderer = renderFragment({ fragment: UserFragment, owner });
- console.log('renderer.toJSON()', renderer.toJSON());
- console.log('UserFragment', UserFragment);
expect(
renderer
.toJSON()
- .includes(
- 'Did you forget to add a @connection directive to the connection field in the fragment?',
- ),
+ .includes('Did you forget to add a @connection directive to the connection field in the fragment?'),
).toEqual(true);
});
@@ -882,9 +846,7 @@ describe('usePaginationFragment', () => {
expect(warning).toHaveBeenCalledTimes(1);
expect(
- (warning as any).mock.calls[0][1].includes(
- 'Relay: Unexpected fetch on unmounted component',
- ),
+ (warning as any).mock.calls[0][1].includes('Relay: Unexpected fetch on unmounted component'),
).toEqual(true);
expect(environment.execute).toHaveBeenCalledTimes(0);
});
@@ -1606,8 +1568,7 @@ describe('usePaginationFragment', () => {
});
// Get fragment ref for user using nested fragment
- const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node
- ?.actor;
+ const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node?.actor;
initialUser = {
id: '1',
@@ -3320,9 +3281,7 @@ describe('usePaginationFragment', () => {
// Assert query is tentatively retained while component is suspended
expect(environment.retain).toBeCalledTimes(1);
- expect(environment.retain.mock.calls[0][0]).toEqual(
- expected.refetchQuery ?? paginationQuery,
- );
+ expect(environment.retain.mock.calls[0][0]).toEqual(expected.refetchQuery ?? paginationQuery);
}
it('refetches new variables correctly when refetching new id', () => {
@@ -3426,13 +3385,6 @@ describe('usePaginationFragment', () => {
hasNext: true,
hasPrevious: false,
},
- {
- data: expectedUser,
- isLoadingNext: false,
- isLoadingPrevious: false,
- hasNext: true,
- hasPrevious: false,
- },
]);
// Assert refetch query was retained
@@ -3542,13 +3494,6 @@ describe('usePaginationFragment', () => {
hasNext: true,
hasPrevious: false,
},
- {
- data: expectedUser,
- isLoadingNext: false,
- isLoadingPrevious: false,
- hasNext: true,
- hasPrevious: false,
- },
]);
// Assert refetch query was retained
@@ -3591,8 +3536,7 @@ describe('usePaginationFragment', () => {
});
// Get fragment ref for user using nested fragment
- const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node
- ?.actor;
+ const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node?.actor;
initialUser = {
id: '1',
@@ -3720,13 +3664,6 @@ describe('usePaginationFragment', () => {
hasNext: true,
hasPrevious: false,
},
- {
- data: expectedUser,
- isLoadingNext: false,
- isLoadingPrevious: false,
- hasNext: true,
- hasPrevious: false,
- },
]);
// Assert refetch query was retained
@@ -3836,13 +3773,6 @@ describe('usePaginationFragment', () => {
hasNext: true,
hasPrevious: false,
},
- {
- data: expectedUser,
- isLoadingNext: false,
- isLoadingPrevious: false,
- hasNext: true,
- hasPrevious: false,
- },
]);
// Assert refetch query was retained
@@ -3969,15 +3899,9 @@ describe('usePaginationFragment', () => {
gqlFragment = getFragment(graphql`
fragment usePaginationFragmentTestStoryFragment on NonNodeStory
- @argumentDefinitions(
- count: { type: "Int", defaultValue: 10 }
- cursor: { type: "ID" }
- )
- @refetchable(
- queryName: "usePaginationFragmentTestStoryFragmentRefetchQuery"
- ) {
- comments(first: $count, after: $cursor)
- @connection(key: "StoryFragment_comments") {
+ @argumentDefinitions(count: { type: "Int", defaultValue: 10 }, cursor: { type: "ID" })
+ @refetchable(queryName: "usePaginationFragmentTestStoryFragmentRefetchQuery") {
+ comments(first: $count, after: $cursor) @connection(key: "StoryFragment_comments") {
edges {
node {
id
@@ -3986,8 +3910,8 @@ describe('usePaginationFragment', () => {
}
}
`);
- gqlPaginationQuery = require('./__generated__/usePaginationFragmentTestStoryFragmentRefetchQuery.graphql')
- .default;
+ gqlPaginationQuery =
+ require('./__generated__/usePaginationFragmentTestStoryFragmentRefetchQuery.graphql').default;
const fetchVariables = { id: 'a' };
//gqlRefetchQuery = generated.StoryFragmentRefetchQuery;
invariant(
diff --git a/__tests__/useRefetchable-test.tsx b/__tests__/useRefetchable-test.tsx
index 3deadf7e..7e3f720b 100644
--- a/__tests__/useRefetchable-test.tsx
+++ b/__tests__/useRefetchable-test.tsx
@@ -39,13 +39,7 @@ const ReactRelayRefetchContainer = {
});
};
return (
-
+
);
},
};
@@ -133,8 +127,8 @@ describe('useRefetchable', () => {
UserFragment = graphql`
fragment useRefetchableTestUserUserFragment on User
- @refetchable(queryName: "useRefetchableTestUserUserFragmentRefetchQuery")
- @argumentDefinitions(cond: { type: "Boolean", defaultValue: true }) {
+ @refetchable(queryName: "useRefetchableTestUserUserFragmentRefetchQuery")
+ @argumentDefinitions(cond: { type: "Boolean", defaultValue: true }) {
id
name @include(if: $cond)
}
@@ -154,11 +148,7 @@ describe('useRefetchable', () => {
variables = {};
TestComponent = render;
TestComponent.displayName = 'TestComponent';
- TestContainer = ReactRelayRefetchContainer.createContainer(
- TestComponent,
- UserFragment,
- UserQuery,
- );
+ TestContainer = ReactRelayRefetchContainer.createContainer(TestComponent, UserFragment, UserQuery);
// Pre-populate the store with data
ownerUser1 = createOperationDescriptor(UserQuery, { id: '4' });
@@ -367,12 +357,7 @@ describe('useRefetchable', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '842472',
- { cond: true },
- ownerUser2.request,
- ),
+ selector: createReaderSelector(UserFragment, '842472', { cond: true }, ownerUser2.request),
});
});
@@ -387,8 +372,7 @@ describe('useRefetchable', () => {
environment.lookup.mockClear();
environment.subscribe.mockClear();
- userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data
- .node;
+ userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -421,12 +405,7 @@ describe('useRefetchable', () => {
relayResolverErrors: [],
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '4',
- { cond: false },
- ownerUser1WithCondVar.request,
- ),
+ selector: createReaderSelector(UserFragment, '4', { cond: false }, ownerUser1WithCondVar.request),
});
});
@@ -447,9 +426,7 @@ describe('useRefetchable', () => {
id: '4',
};
refetch(refetchVariables, null, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(true);
environment.mock.resolve(UserFragmentRefetchQuery, {
data: {
@@ -463,8 +440,7 @@ describe('useRefetchable', () => {
environment.subscribe.mockClear();
// Pass an updated user pointer that references different variables
- userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data
- .node;
+ userPointer = environment.lookup(ownerUser1WithCondVar.fragment, ownerUser1WithCondVar).data.node;
instance.getInstance().setProps({
user: userPointer,
});
@@ -497,12 +473,7 @@ describe('useRefetchable', () => {
missingClientEdges: null,
missingRequiredFields: null,
seenRecords: expect.any(Object),
- selector: createReaderSelector(
- UserFragment,
- '4',
- { cond: false },
- ownerUser1WithCondVar.request,
- ),
+ selector: createReaderSelector(UserFragment, '4', { cond: false }, ownerUser1WithCondVar.request),
});
});
@@ -674,9 +645,7 @@ describe('useRefetchable', () => {
id: '4',
};
refetch(refetchVariables, null, jest.fn());
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(true);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(true);
environment.mock.resolve(UserFragmentRefetchQuery, {
data: {
node: {
@@ -688,7 +657,7 @@ describe('useRefetchable', () => {
});
it('reads data from the store without sending a network request when data is available in store and using store-or-network', () => {
- expect.assertions(3);
+ expect.assertions(4);
const refetchVariables = {
cond: false,
id: '4',
@@ -696,11 +665,10 @@ describe('useRefetchable', () => {
const refetchOptions = {
fetchPolicy: 'store-or-network',
};
+ expect(render.mock.calls.length).toBe(1);
refetch(refetchVariables, null, jest.fn(), refetchOptions);
expect(render.mock.calls.length).toBe(2);
- expect(
- environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache),
- ).toBe(false);
+ expect(environment.mock.isLoading(UserFragmentRefetchQuery, refetchVariables, forceCache)).toBe(false);
expect(environment.execute).toBeCalledTimes(0);
});
@@ -813,7 +781,7 @@ describe('useRefetchable', () => {
});
it('renders with the results of the new variables on success', () => {
- expect.assertions(10);
+ expect.assertions(8);
expect(render.mock.calls.length).toBe(1);
expect(render.mock.calls[0][0].user.name).toBe('Zuck');
variables = {
@@ -833,11 +801,9 @@ describe('useRefetchable', () => {
},
},
});
- expect(render.mock.calls.length).toBe(4);
- expect(render.mock.calls[2][0].isLoading).toBe(true);
+ expect(render.mock.calls.length).toBe(3);
+ expect(render.mock.calls[2][0].isLoading).toBe(false);
expect(render.mock.calls[2][0].user.name).toBe(undefined);
- expect(render.mock.calls[3][0].isLoading).toBe(false);
- expect(render.mock.calls[3][0].user.name).toBe(undefined);
});
it('does not update variables on failure', () => {
@@ -950,7 +916,7 @@ describe('useRefetchable', () => {
});
ReactTestRenderer.act(() => {
instance.unmount();
- })
+ });
expect(references.length).toBe(1);
expect(references[0].dispose).toBeCalled();
});
diff --git a/__tests__/useRefetchableFragment-test.tsx b/__tests__/useRefetchableFragment-test.tsx
index 01a1e89c..55ae5054 100644
--- a/__tests__/useRefetchableFragment-test.tsx
+++ b/__tests__/useRefetchableFragment-test.tsx
@@ -83,12 +83,7 @@ const invariant = require('fbjs/lib/invariant');
const warning = require('fbjs/lib/warning');
const areEqual = require('fbjs/lib/areEqual');
-const {
- FRAGMENT_OWNER_KEY,
- FRAGMENTS_KEY,
- ID_KEY,
- createOperationDescriptor,
-} = require('relay-runtime');
+const { FRAGMENT_OWNER_KEY, FRAGMENTS_KEY, ID_KEY, createOperationDescriptor } = require('relay-runtime');
describe('useRefetchableFragmentNode', () => {
let environment;
@@ -136,10 +131,7 @@ describe('useRefetchableFragmentNode', () => {
}
function useRefetchableFragmentNode(fragmentNode, fragmentRef) {
- const { data, refetch: refetchFunction } = useRefetchableFragmentNodeOriginal(
- fragmentNode,
- fragmentRef,
- );
+ const { data, refetch: refetchFunction } = useRefetchableFragmentNodeOriginal(fragmentNode, fragmentRef);
refetch = refetchFunction;
renderSpy(data, refetch);
return data;
@@ -195,10 +187,8 @@ describe('useRefetchableFragmentNode', () => {
`;
gqlFragmentWithArgs = getFragment(graphql`
fragment useRefetchableFragmentTestUserFragmentWithArgs on User
- @refetchable(
- queryName: "useRefetchableFragmentTestUserFragmentWithArgsRefetchQuery"
- )
- @argumentDefinitions(scaleLocal: { type: "Float!" }) {
+ @refetchable(queryName: "useRefetchableFragmentTestUserFragmentWithArgsRefetchQuery")
+ @argumentDefinitions(scaleLocal: { type: "Float!" }) {
id
name
profile_picture(scale: $scaleLocal) {
@@ -209,7 +199,7 @@ describe('useRefetchableFragmentNode', () => {
`);
gqlFragment = getFragment(graphql`
fragment useRefetchableFragmentTestUserFragment on User
- @refetchable(queryName: "useRefetchableFragmentTestUserFragmentRefetchQuery") {
+ @refetchable(queryName: "useRefetchableFragmentTestUserFragmentRefetchQuery") {
id
name
profile_picture(scale: $scale) {
@@ -248,10 +238,9 @@ describe('useRefetchableFragmentNode', () => {
}
}
`);
- gqlRefetchQuery = require('./__generated__/useRefetchableFragmentTestUserFragmentRefetchQuery.graphql')
- .default;
- gqlRefetchQueryWithArgs = require('./__generated__/useRefetchableFragmentTestUserFragmentWithArgsRefetchQuery.graphql')
- .default;
+ gqlRefetchQuery = require('./__generated__/useRefetchableFragmentTestUserFragmentRefetchQuery.graphql').default;
+ gqlRefetchQueryWithArgs =
+ require('./__generated__/useRefetchableFragmentTestUserFragmentWithArgsRefetchQuery.graphql').default;
variables = { id: '1', scale: 16 };
variablesNestedFragment = { id: '', scale: 16 };
@@ -260,19 +249,14 @@ describe('useRefetchableFragmentNode', () => {
'useRefetchableFragment-test: Expected refetchable fragment metadata to contain operation.',
);
invariant(
- areEqual(
- gqlFragmentWithArgs.metadata?.refetch?.operation.default,
- gqlRefetchQueryWithArgs,
- ),
+ areEqual(gqlFragmentWithArgs.metadata?.refetch?.operation.default, gqlRefetchQueryWithArgs),
'useRefetchableFragment-test: Expected refetchable fragment metadata to contain operation.',
);
query = createOperationDescriptor(gqlQuery, variables, { force: true });
- queryNestedFragment = createOperationDescriptor(
- gqlQueryNestedFragment,
- variablesNestedFragment,
- { force: true },
- );
+ queryNestedFragment = createOperationDescriptor(gqlQueryNestedFragment, variablesNestedFragment, {
+ force: true,
+ });
refetchQuery = createOperationDescriptor(gqlRefetchQuery, variables, {
force: true,
});
@@ -332,11 +316,7 @@ describe('useRefetchableFragmentNode', () => {
setEnvironment = _setEnv;
- return (
-
- {children}
-
- );
+ return {children};
};
const Fallback = (): any => {
@@ -347,24 +327,24 @@ describe('useRefetchableFragmentNode', () => {
return 'Fallback';
};
- renderFragment = (args?: {
- isConcurrent?: boolean;
- owner?: any;
- userRef?: any;
- fragment?: any;
- }): any => {
+ renderFragment = (args?: { isConcurrent?: boolean; owner?: any; userRef?: any; fragment?: any }): any => {
const { isConcurrent = false, ...props } = args ?? ({} as any);
- return TestRenderer.create(
- `Error: ${error.message}`}>
- }>
-
-
-
-
- ,
- // any[prop-missing] - error revealed when flow-typing ReactTestRenderer
- { unstable_isConcurrent: isConcurrent } as any,
- );
+ let renderer;
+ TestRenderer.act(() => {
+ renderer = TestRenderer.create(
+ `Error: ${error.message}`}>
+ }>
+
+
+
+
+ ,
+ // any[prop-missing] - error revealed when flow-typing ReactTestRenderer
+ { unstable_isConcurrent: isConcurrent } as any,
+ );
+ jest.runAllImmediates();
+ });
+ return renderer;
};
});
@@ -388,9 +368,7 @@ describe('useRefetchableFragmentNode', () => {
}
`);
const renderer = renderFragment({ fragment: UserFragment });
- expect(
- renderer.toJSON().includes('Remove `@relay(plural: true)` from fragment'),
- ).toEqual(true);
+ expect(renderer.toJSON().includes('Remove `@relay(plural: true)` from fragment')).toEqual(true);
});
it('should throw error if fragment is missing @refetchable directive', () => {
@@ -403,9 +381,7 @@ describe('useRefetchableFragmentNode', () => {
`);
const renderer = renderFragment({ fragment: UserFragment });
expect(
- renderer
- .toJSON()
- .includes('Did you forget to add a @refetchable directive to the fragment?'),
+ renderer.toJSON().includes('Did you forget to add a @refetchable directive to the fragment?'),
).toEqual(true);
});
@@ -568,9 +544,7 @@ describe('useRefetchableFragmentNode', () => {
expect(warning).toHaveBeenCalledTimes(1);
expect(
// any[prop-missing]
- warning.mock.calls[0][1].includes(
- 'Relay: Unexpected call to `refetch` on unmounted component',
- ),
+ warning.mock.calls[0][1].includes('Relay: Unexpected call to `refetch` on unmounted component'),
).toEqual(true);
expect(environment.execute).toHaveBeenCalledTimes(0);
});
@@ -816,8 +790,7 @@ describe('useRefetchableFragmentNode', () => {
});
// Get fragment ref for user using nested fragment
- const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node
- ?.actor;
+ const userRef = (environment.lookup(queryNestedFragment.fragment).data as any)?.node?.actor;
const renderer = renderFragment({ owner: queryNestedFragment, userRef });
const initialUser = {
@@ -907,11 +880,9 @@ describe('useRefetchableFragmentNode', () => {
id: '1',
scaleLocal: 32,
};
- refetchQueryWithArgs = createOperationDescriptor(
- gqlRefetchQueryWithArgs,
- refetchVariables,
- { force: true },
- );
+ refetchQueryWithArgs = createOperationDescriptor(gqlRefetchQueryWithArgs, refetchVariables, {
+ force: true,
+ });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery: refetchQueryWithArgs,
@@ -977,11 +948,9 @@ describe('useRefetchableFragmentNode', () => {
id: '4',
scaleLocal: 16,
};
- refetchQueryWithArgs = createOperationDescriptor(
- gqlRefetchQueryWithArgs,
- refetchVariables,
- { force: true },
- );
+ refetchQueryWithArgs = createOperationDescriptor(gqlRefetchQueryWithArgs, refetchVariables, {
+ force: true,
+ });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery: refetchQueryWithArgs,
@@ -2017,19 +1986,12 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '1' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '1' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is not started
const refetchVariables = { ...variables };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectRequestIsInFlight({
inFlight: false,
requestCount: 0,
@@ -2045,7 +2007,7 @@ describe('useRefetchableFragmentNode', () => {
...createFragmentRef('1', query),
//...createFragmentRef('1', refetchQuery), //original relay
};
- // expectFragmentResults([{ data: refetchedUser }, { data: refetchedUser }]); original relay
+ expectFragmentResults([{ data: refetchedUser }]); //original relay
});
it('starts network request if refetch query is not fully cached and suspends if fragment has missing data', () => {
@@ -2059,10 +2021,7 @@ describe('useRefetchableFragmentNode', () => {
expectFragmentResults([{ data: initialUser }]);
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert that fragment is refetching with the right variables and
@@ -2071,11 +2030,7 @@ describe('useRefetchableFragmentNode', () => {
id: '4',
scale: 16,
};
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery,
@@ -2114,11 +2069,7 @@ describe('useRefetchableFragmentNode', () => {
it("starts network request if refetch query is not fully cached and doesn't suspend if fragment doesn't have missing data", () => {
// Cache user with missing username
const refetchVariables = { id: '4', scale: 16 };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
environment.commitPayload(refetchQuery, {
node: {
__typename: 'User',
@@ -2131,10 +2082,7 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is started
@@ -2165,19 +2113,12 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '1' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '1' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is not started
const refetchVariables = { ...variables };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectRequestIsInFlight({
inFlight: false,
requestCount: 0,
@@ -2193,7 +2134,7 @@ describe('useRefetchableFragmentNode', () => {
...createFragmentRef('1', query),
//...createFragmentRef('1', refetchQuery), //original relay
};
- // expectFragmentResults([{ data: refetchedUser }, { data: refetchedUser }]); original relay
+ expectFragmentResults([{ data: refetchedUser }]); //original relay
});
it('starts network request if refetch query is not fully cached and suspends if fragment has missing data', () => {
@@ -2207,10 +2148,7 @@ describe('useRefetchableFragmentNode', () => {
expectFragmentResults([{ data: initialUser }]);
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert that fragment is refetching with the right variables and
@@ -2219,11 +2157,7 @@ describe('useRefetchableFragmentNode', () => {
id: '4',
scale: 16,
};
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery,
@@ -2262,11 +2196,7 @@ describe('useRefetchableFragmentNode', () => {
it("starts network request if refetch query is not fully cached and suspends even if fragment doesn't have missing data", () => {
// Cache user with missing username
const refetchVariables = { id: '4', scale: 16 };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
environment.commitPayload(refetchQuery, {
node: {
__typename: 'User',
@@ -2286,10 +2216,7 @@ describe('useRefetchableFragmentNode', () => {
expectFragmentResults([{ data: initialUser }]);
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
expectFragmentIsRefetching(renderer, {
@@ -2343,19 +2270,12 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '1' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '1' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is not started
const refetchVariables = { ...variables };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectRequestIsInFlight({
inFlight: true,
requestCount: 1,
@@ -2386,10 +2306,7 @@ describe('useRefetchableFragmentNode', () => {
expectFragmentResults([{ data: initialUser }]);
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert that fragment is refetching with the right variables and
@@ -2398,11 +2315,7 @@ describe('useRefetchableFragmentNode', () => {
id: '4',
scale: 16,
};
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery,
@@ -2440,11 +2353,7 @@ describe('useRefetchableFragmentNode', () => {
it("starts network request if refetch query is not fully cached and doesn't suspend if fragment doesn't have missing data", () => {
// Cache user with missing username
const refetchVariables = { id: '4', scale: 16 };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
environment.commitPayload(refetchQuery, {
node: {
__typename: 'User',
@@ -2457,10 +2366,7 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is started
@@ -2492,19 +2398,12 @@ describe('useRefetchableFragmentNode', () => {
renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '1' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '1' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is not started
const refetchVariables = { ...variables };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectRequestIsInFlight({
inFlight: true,
requestCount: 1,
@@ -2535,10 +2434,7 @@ describe('useRefetchableFragmentNode', () => {
expectFragmentResults([{ data: initialUser }]);
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert that fragment is refetching with the right variables and
@@ -2547,11 +2443,7 @@ describe('useRefetchableFragmentNode', () => {
id: '4',
scale: 16,
};
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
expectFragmentIsRefetching(renderer, {
refetchVariables,
refetchQuery,
@@ -2590,11 +2482,7 @@ describe('useRefetchableFragmentNode', () => {
it("starts network request if refetch query is not fully cached and doesn't suspend if fragment doesn't have missing data", () => {
// Cache user with missing username
const refetchVariables = { id: '4', scale: 16 };
- refetchQuery = createOperationDescriptor(
- gqlRefetchQuery,
- refetchVariables,
- { force: true },
- );
+ refetchQuery = createOperationDescriptor(gqlRefetchQuery, refetchVariables, { force: true });
environment.commitPayload(refetchQuery, {
node: {
__typename: 'User',
@@ -2607,10 +2495,7 @@ describe('useRefetchableFragmentNode', () => {
const renderer = renderFragment();
renderSpy.mockClear();
TestRenderer.act(() => {
- refetch(
- { id: '4' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ refetch({ id: '4' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert component suspended
@@ -2799,7 +2684,7 @@ describe('useRefetchableFragmentNode', () => {
...createFragmentRef('1', query),
//...createFragmentRef('1', refetchQuery), //original relay
};
- // expectFragmentResults([{ data: refetchedUser }, { data: refetchedUser }]); original relay
+ expectFragmentResults([{ data: refetchingUser }]); // original relay
});
it("doesn't start network request if refetch query is not fully cached", () => {
@@ -3064,10 +2949,7 @@ describe('useRefetchableFragmentNode', () => {
renderSpy.mockClear();
let disposable;
TestRenderer.act(() => {
- disposable = refetch(
- { id: '1' },
- { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy },
- );
+ disposable = refetch({ id: '1' }, { fetchPolicy, UNSTABLE_renderPolicy: renderPolicy });
});
// Assert request is started
@@ -3111,7 +2993,7 @@ describe('useRefetchableFragmentNode', () => {
beforeEach(() => {
gqlFragment = getFragment(graphql`
fragment useRefetchableFragmentTest1Fragment on NonNodeStory
- @refetchable(queryName: "useRefetchableFragmentTest1FragmentRefetchQuery") {
+ @refetchable(queryName: "useRefetchableFragmentTest1FragmentRefetchQuery") {
actor {
name
}
@@ -3127,8 +3009,8 @@ describe('useRefetchableFragmentNode', () => {
`);
variables = { id: 'a' };
- gqlRefetchQuery = require('./__generated__/useRefetchableFragmentTest1FragmentRefetchQuery.graphql')
- .default;
+ gqlRefetchQuery =
+ require('./__generated__/useRefetchableFragmentTest1FragmentRefetchQuery.graphql').default;
invariant(
areEqual(gqlFragment.metadata?.refetch?.operation.default, gqlRefetchQuery),
'useRefetchableFragment-test: Expected refetchable fragment metadata to contain operation.',
@@ -3357,7 +3239,7 @@ describe('useRefetchableFragmentNode', () => {
`;
gqlFragment = getFragment(graphql`
fragment useRefetchableFragmentTest3Fragment on User
- @refetchable(queryName: "useRefetchableFragmentTest3FragmentRefetchQuery") {
+ @refetchable(queryName: "useRefetchableFragmentTest3FragmentRefetchQuery") {
id
name
profile_picture(scale: $scale) {
@@ -3373,8 +3255,8 @@ describe('useRefetchableFragmentNode', () => {
}
}
`);
- gqlRefetchQuery = require('./__generated__/useRefetchableFragmentTest3FragmentRefetchQuery.graphql')
- .default;
+ gqlRefetchQuery =
+ require('./__generated__/useRefetchableFragmentTest3FragmentRefetchQuery.graphql').default;
variables = { nodeID: '1', scale: 16 };
invariant(
areEqual(gqlFragment.metadata?.refetch?.operation.default, gqlRefetchQuery),
@@ -3453,12 +3335,7 @@ describe('useRefetchableFragmentNode', () => {
profile_picture: {
uri: 'scale16',
},
- ...createFragmentRef(
- '4',
- refetchQuery,
- false,
- 'useRefetchableFragmentTest2Fragment',
- ),
+ ...createFragmentRef('4', refetchQuery, false, 'useRefetchableFragmentTest2Fragment'),
};
// expectFragmentResults([{ data: refetchedUser }, { data: refetchedUser }]); original relay
expectFragmentResults([{ data: refetchedUser }]);
@@ -3525,12 +3402,7 @@ describe('useRefetchableFragmentNode', () => {
profile_picture: {
uri: 'scale32',
},
- ...createFragmentRef(
- '1',
- refetchQuery,
- false,
- 'useRefetchableFragmentTest2Fragment',
- ),
+ ...createFragmentRef('1', refetchQuery, false, 'useRefetchableFragmentTest2Fragment'),
};
// expectFragmentResults([{ data: refetchedUser }, { data: refetchedUser }]); original relay
expectFragmentResults([{ data: refetchedUser }]);
diff --git a/examples/relay-hook-example/nextjs-ssr-preload/components/Header.tsx b/examples/relay-hook-example/nextjs-ssr-preload/components/Header.tsx
index 3d054399..0a8d6cd1 100644
--- a/examples/relay-hook-example/nextjs-ssr-preload/components/Header.tsx
+++ b/examples/relay-hook-example/nextjs-ssr-preload/components/Header.tsx
@@ -1,49 +1,47 @@
import React from 'react';
import Link from 'next/link';
-import styled, {css} from 'styled-components';
-import {withRouter} from 'next/router';
+import styled, { css } from 'styled-components';
+import { withRouter } from 'next/router';
const StyledButton = styled.button`
- margin: auto;
- padding: 10px;
- cursor: pointer;
- display: -webkit-box;
- flex: 1;
- ${props =>
- props.selected &&
- css`
- border: 1px solid #999;
- box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
- box-sizing: border-box;
- `}
+ margin: auto;
+ padding: 10px;
+ cursor: pointer;
+ display: -webkit-box;
+ flex: 1;
+ ${(props) =>
+ props.selected &&
+ css`
+ border: 1px solid #999;
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
+ box-sizing: border-box;
+ `}
`;
-const MyButton = React.forwardRef(
- ({onClick, href, children, selected}: any, ref) => (
+const MyButton = React.forwardRef(({ onClick, href, children, selected }: any, ref) => (
- {children}
+ {children}
- ),
-);
+));
const StyledDiv = styled.div`
- display: flex;
- background: #fff;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
+ display: flex;
+ background: #fff;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
`;
-const Header = ({userId}) => {
- const selectedYou = userId === 'you';
- return (
-
-
- ME
-
-
- YOU
-
-
- );
+const Header = ({ userId }) => {
+ const selectedYou = userId === 'you';
+ return (
+
+
+ ME
+
+
+ YOU
+
+
+ );
};
export default Header;
diff --git a/examples/relay-hook-example/nextjs-ssr-preload/components/Home.tsx b/examples/relay-hook-example/nextjs-ssr-preload/components/Home.tsx
index 638ef60a..8cb84c71 100644
--- a/examples/relay-hook-example/nextjs-ssr-preload/components/Home.tsx
+++ b/examples/relay-hook-example/nextjs-ssr-preload/components/Home.tsx
@@ -1,19 +1,16 @@
import React from 'react';
-import TodoApp, {QUERY_APP} from './TodoApp';
-import {usePreloadedQuery, useQuery} from 'relay-hooks';
-import {TodoAppQuery} from '../__generated__/relay/TodoAppQuery.graphql';
+import TodoApp, { QUERY_APP } from './TodoApp';
+import { usePreloadedQuery, useQuery } from 'relay-hooks';
+import { TodoAppQuery } from '../__generated__/relay/TodoAppQuery.graphql';
-const Home = ({prefetch}) => {
- console.log('prefetch ssr', prefetch);
- const {error, cached, props, retry} = usePreloadedQuery(
- prefetch,
- );
- if (props) {
- return ;
- } else if (error) {
- return {error.message}
;
- }
- return loading
;
+const Home = ({ prefetch }) => {
+ const { error, data, retry } = usePreloadedQuery(prefetch);
+ if (data) {
+ return ;
+ } else if (error) {
+ return {error.message}
;
+ }
+ return loading
;
};
export default Home;
diff --git a/examples/relay-hook-example/nextjs-ssr-preload/components/TodoApp.tsx b/examples/relay-hook-example/nextjs-ssr-preload/components/TodoApp.tsx
index 2f52ac8d..ce84a23d 100644
--- a/examples/relay-hook-example/nextjs-ssr-preload/components/TodoApp.tsx
+++ b/examples/relay-hook-example/nextjs-ssr-preload/components/TodoApp.tsx
@@ -1,137 +1,144 @@
-import React from 'react';
+import React, { useCallback } from 'react';
import AddTodoMutation from '../mutations/AddTodoMutation';
import TodoList from './TodoList';
import TodoListFooter from './TodoListFooter';
import TodoTextInput from './TodoTextInput';
import styled from 'styled-components';
import Header from './Header';
-import {useRefetch, useRelayEnvironment, graphql} from 'relay-hooks';
-import {TodoApp_user$key} from '../__generated__/relay/TodoApp_user.graphql';
+import { useRefetchable, useRelayEnvironment, graphql, useFragment } from 'relay-hooks';
+import { TodoApp_user$key } from '../__generated__/relay/TodoApp_user.graphql';
+import { useRouter } from 'next/router';
//import {TodoApp_user$key} from 'relay/TodoApp_user.graphql';
//import TodoApp, { fragmentSpec } from './components/TodoApp';
export const QUERY_APP = graphql`
- query TodoAppQuery($userId: String) {
- ...TodoApp_user
- }
+ query TodoAppQuery($userId: String) {
+ ...TodoApp_user
+ }
`;
const StyledSection = styled.section`
- flex: 1;
- background: #fff;
- margin: 130px 0 40px 0;
- position: relative;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
- h1 {
- position: absolute;
- top: -155px;
- width: 100%;
- font-size: 100px;
- font-weight: 100;
- text-align: center;
- color: rgba(175, 47, 47, 0.15);
- -webkit-text-rendering: optimizeLegibility;
- -moz-text-rendering: optimizeLegibility;
- text-rendering: optimizeLegibility;
- }
+ flex: 1;
+ background: #fff;
+ margin: 130px 0 40px 0;
+ position: relative;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
+ h1 {
+ position: absolute;
+ top: -155px;
+ width: 100%;
+ font-size: 100px;
+ font-weight: 100;
+ text-align: center;
+ color: rgba(175, 47, 47, 0.15);
+ -webkit-text-rendering: optimizeLegibility;
+ -moz-text-rendering: optimizeLegibility;
+ text-rendering: optimizeLegibility;
+ }
`;
const StyledButton = styled.button`
- margin: auto;
- padding: 10px;
- cursor: pointer;
- display: -webkit-box;
+ margin: auto;
+ padding: 10px;
+ cursor: pointer;
+ display: -webkit-box;
`;
const StyledFooter = styled.footer`
- margin: 65px auto 0;
- color: #bfbfbf;
- font-size: 10px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- text-align: center;
+ margin: 65px auto 0;
+ color: #bfbfbf;
+ font-size: 10px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-align: center;
`;
const StyledP = styled.p`
- line-height: 1;
+ line-height: 1;
`;
const StyledDivButton = styled.div`
- display: flex;
- background: #fff;
+ display: flex;
+ background: #fff;
`;
const isServer = typeof window === 'undefined';
type Props = {
- query: TodoApp_user$key;
- retry: () => void;
+ query: TodoApp_user$key;
+ retry: () => void;
};
const fragmentSpec = graphql`
- fragment TodoApp_user on Query {
- user(id: $userId) {
- id
- userId
- totalCount
- completedCount
- ...TodoListFooter_user
- ...TodoList_user
+ fragment TodoApp_user on Query @refetchable(queryName: "TodoAppRefetchTableQuery") {
+ user(id: $userId) {
+ id
+ userId
+ totalCount
+ completedCount
+ ...TodoListFooter_user
+ ...TodoList_user
+ }
}
- }
`;
export function isNotNull(it: T): it is NonNullable {
- return it != null;
+ return it != null;
}
const AppTodo = (props: Props) => {
- const environment = useRelayEnvironment();
- const [{user}, refetch] = useRefetch(fragmentSpec, props.query);
-
- if (!user) {
- return ;
- }
-
- const handleTextInputSave = (text: string) => {
- AddTodoMutation.commit(environment, text, user);
- return;
- };
-
- const hasTodos = user.totalCount > 0;
- console.log('renderer');
- return (
-
-
-
-
-
-
- {hasTodos && }
-
- Retry
-
-
- {
- refetch(QUERY_APP, {
- userId: user.userId === 'me' ? 'you' : 'me',
- });
- }}>
- Change User
-
-
-
- Double-click to edit a todo
-
-
-
- );
+ const environment = useRelayEnvironment();
+ const {
+ data: { user },
+ refetch,
+ } = useRefetchable(fragmentSpec, props.query);
+
+ const router = useRouter();
+
+ const { userId } = user || {};
+
+ const changeUser = useCallback(() => {
+ const pathname = userId === 'me' ? '/you' : '/';
+ router.push({
+ pathname,
+ });
+ }, [router, userId]);
+
+ if (!user) {
+ return ;
+ }
+
+ const handleTextInputSave = (text: string) => {
+ AddTodoMutation.commit(environment, text, user);
+ return;
+ };
+
+ const hasTodos = user.totalCount > 0;
+ console.log('renderer');
+ return (
+
+
+
+
+
+
+ {hasTodos && }
+
+ Retry
+
+
+ Change User
+
+
+ Refetch
+
+
+ Double-click to edit a todo
+
+
+
+ );
};
export default AppTodo;
diff --git a/examples/relay-hook-example/nextjs-ssr-preload/package.json b/examples/relay-hook-example/nextjs-ssr-preload/package.json
index 364f09d6..57c72932 100644
--- a/examples/relay-hook-example/nextjs-ssr-preload/package.json
+++ b/examples/relay-hook-example/nextjs-ssr-preload/package.json
@@ -4,10 +4,17 @@
"dev": "babel-node server.js",
"build": "next build",
"start": "cross-env NODE_ENV=production babel-node server.js",
- "compile": "relay-compiler --src ./ --include '**/pages/**' '**/components/**' '**/mutations/**' --schema ./data/schema.graphql --language typescript --artifactDirectory ./__generated__/relay",
+ "compile": "relay-compiler",
"update-schema": "babel-node ./scripts/updateSchema.js",
"lint": "eslint ./ --cache"
},
+ "relay": {
+ "src": "./",
+ "schema": "./data/schema.graphql",
+ "language": "typescript",
+ "artifactDirectory": "./__generated__/relay",
+ "excludes": ["__generated__", "node_modules/**", ".next"]
+ },
"dependencies": {
"classnames": "2.2.6",
"es6-promise": "4.2.8",
@@ -16,12 +23,13 @@
"graphql": "^14.5.8",
"graphql-relay": "^0.6.0",
"isomorphic-unfetch": "3.0.0",
+ "isomorphic-fetch": "^2.1.1",
"next": "9.1.1",
"prop-types": "^15.7.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
- "relay-hooks": "3.7.0",
- "relay-runtime": "9.0.0",
+ "relay-hooks": "../../../relay-hooks-7.3.0-a5.tgz",
+ "relay-runtime": "^14.0.0",
"styled-components": "4.4.0",
"whatwg-fetch": "3.0.0"
},
@@ -36,12 +44,11 @@
"@babel/runtime": "^7.3.4",
"@types/node": "^12.7.12",
"@types/react": "^16.8.15",
- "@types/react-relay": "^7.0.2",
- "@types/relay-runtime": "^6.0.11",
+ "@types/relay-runtime": "^14.1.10",
"@zeit/next-typescript": "1.1.1",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
- "babel-plugin-relay": "^9.0.0",
+ "babel-plugin-relay": "^14.0.0",
"cross-env": "6.0.3",
"eslint": "^5.13.0",
"eslint-config-fbjs": "^2.1.0",
@@ -55,7 +62,7 @@
"flow-bin": "^0.94.0",
"flow-typed": "^2.5.1",
"prettier": "^1.16.4",
- "relay-compiler": "^9.0.0",
+ "relay-compiler": "^14.0.0",
"relay-compiler-language-typescript": "12.0.0",
"typescript": "3.7.3"
},
diff --git a/examples/relay-hook-example/nextjs-ssr-preload/pages/_app.tsx b/examples/relay-hook-example/nextjs-ssr-preload/pages/_app.tsx
index 017667df..da6a6c21 100644
--- a/examples/relay-hook-example/nextjs-ssr-preload/pages/_app.tsx
+++ b/examples/relay-hook-example/nextjs-ssr-preload/pages/_app.tsx
@@ -2,99 +2,96 @@ import React from 'react';
import App from 'next/app';
import Head from 'next/head';
import Header from '../components/Header';
-import {useEffect} from 'react';
-import {Router} from 'next/router';
+import { useEffect } from 'react';
+import { Router } from 'next/router';
import initEnvironment from '../relay/createRelayEnvironment';
-import {QUERY_APP} from '../components/TodoApp';
-import {RelayEnvironmentProvider, useRelayEnvironment} from 'relay-hooks';
+import { QUERY_APP } from '../components/TodoApp';
+import { RelayEnvironmentProvider, useRelayEnvironment } from 'relay-hooks';
let ssrPrefethed = false;
-const Routing = ({ssr, variables, prefetch}) => {
- const environment = useRelayEnvironment();
+const Routing = ({ ssr, variables, prefetch }) => {
+ const environment = useRelayEnvironment();
- if (ssr && !ssrPrefethed) {
- ssrPrefethed = true;
- prefetch.next(environment, QUERY_APP, variables);
- }
+ if (ssr && !ssrPrefethed) {
+ ssrPrefethed = true;
+ prefetch.next(environment, QUERY_APP, variables);
+ }
- useEffect(() => {
- const handleRouteChange = url => {
- const isMe = url === '/';
- prefetch.next(environment, QUERY_APP, {userId: isMe ? 'me' : 'you'});
- };
+ useEffect(() => {
+ const handleRouteChange = (url) => {
+ const isMe = url === '/';
+ console.log('handle', isMe, url);
+ prefetch.next(environment, QUERY_APP, { userId: isMe ? 'me' : 'you' });
+ };
- Router.events.on('routeChangeStart', handleRouteChange);
- return () => {
- Router.events.off('routeChangeStart', handleRouteChange);
- };
- }, [environment]);
- return null;
+ Router.events.on('routeChangeStart', handleRouteChange);
+ return () => {
+ Router.events.off('routeChangeStart', handleRouteChange);
+ };
+ }, [environment]);
+ return null;
};
class CustomApp extends App {
- static async getInitialProps({Component, ctx}) {
- const isServer = !!ctx.req;
- let componentProps = {};
+ static async getInitialProps({ Component, ctx }) {
+ const isServer = !!ctx.req;
+ let componentProps = {};
- if (Component.getInitialProps) {
- componentProps = await Component.getInitialProps(ctx);
- }
+ if (Component.getInitialProps) {
+ componentProps = await Component.getInitialProps(ctx);
+ }
- if (!isServer) {
- return {
- pageProps: {
- prefetch: null,
- ssr: false,
- environment: null,
- },
- };
- }
+ if (!isServer) {
+ return {
+ pageProps: {
+ prefetch: null,
+ ssr: false,
+ environment: null,
+ },
+ };
+ }
- const isMe = ctx.pathname === '/';
- const {environment, prefetch} = initEnvironment();
+ const isMe = ctx.pathname === '/';
+ const { environment, prefetch } = initEnvironment();
- const variables = {userId: isMe ? 'me' : 'you'};
- await prefetch.next(environment, QUERY_APP, variables);
- const queryRecords = environment
- .getStore()
- .getSource()
- .toJSON();
- const pageProps = {
- ...componentProps,
- queryRecords,
- environment,
- variables,
- prefetch,
- ssr: true,
- };
+ const variables = { userId: isMe ? 'me' : 'you' };
+ await prefetch.next(environment, QUERY_APP, variables);
+ const queryRecords = environment
+ .getStore()
+ .getSource()
+ .toJSON();
+ const pageProps = {
+ ...componentProps,
+ queryRecords,
+ environment,
+ variables,
+ prefetch,
+ ssr: true,
+ };
- return {pageProps};
- }
+ return { pageProps };
+ }
- render() {
- const {Component, pageProps} = this.props;
- const {environment, prefetch} =
- typeof window === 'undefined'
- ? pageProps
- : initEnvironment({
- records: pageProps.queryRecords,
- });
- return (
-
-
- Relay Hooks NextJS SSR
-
-
-
-
-
-
- );
- }
+ render() {
+ const { Component, pageProps } = this.props;
+ const { environment, prefetch } =
+ typeof window === 'undefined'
+ ? pageProps
+ : initEnvironment({
+ records: pageProps.queryRecords,
+ });
+ return (
+
+
+ Relay Hooks NextJS SSR
+
+
+
+
+
+
+ );
+ }
}
export default CustomApp;
diff --git a/examples/relay-hook-example/pagination-nextjs-ssr/components/RootPage.tsx b/examples/relay-hook-example/pagination-nextjs-ssr/components/RootPage.tsx
index 45d545e1..160270cd 100644
--- a/examples/relay-hook-example/pagination-nextjs-ssr/components/RootPage.tsx
+++ b/examples/relay-hook-example/pagination-nextjs-ssr/components/RootPage.tsx
@@ -1,7 +1,7 @@
import CircularProgress from '@material-ui/core/CircularProgress';
import { useRouter } from 'next/router';
import React, { useMemo } from 'react';
-import { useQuery, STORE_OR_NETWORK } from 'relay-hooks';
+import { useQuery, STORE_OR_NETWORK, STORE_THEN_NETWORK } from 'relay-hooks';
import styled from 'styled-components';
import { TodoAppQuery } from '../__generated__/relay/TodoAppQuery.graphql';
import { QUERY_APP, TodoApp } from '../components/TodoApp';
@@ -53,6 +53,8 @@ const RootPage = ({ query, first }: any): JSX.Element => {
fetchPolicy: STORE_OR_NETWORK,
});
+ console.log("render", isLoading)
+
return (
diff --git a/examples/relay-hook-example/pagination-nextjs-ssr/components/TodoList.tsx b/examples/relay-hook-example/pagination-nextjs-ssr/components/TodoList.tsx
index 6625a9cf..7bdaafcd 100644
--- a/examples/relay-hook-example/pagination-nextjs-ssr/components/TodoList.tsx
+++ b/examples/relay-hook-example/pagination-nextjs-ssr/components/TodoList.tsx
@@ -157,12 +157,13 @@ export const TodoList = (props: Props): JSX.Element => {
}, [todos]);
const isLoading =
- props.isLoading || refetchLoading || (paginated && (isLoadingPrevious || isLoadingNext));
+ props.isLoading || refetchLoading || ((paginated || scroll) && (isLoadingPrevious || isLoadingNext));
const loadMore = useCallback(() => {
// Don't fetch again if we're already loading the next page
if (isLoading) {
return;
}
+ console.log("load")
loadNext(1);
}, [isLoading, loadNext]);
@@ -212,7 +213,7 @@ export const TodoList = (props: Props): JSX.Element => {
},
[environment, user, onCompleted],
);
-
+ console.log("list render", scroll, hasNext, isLoading)
return (
diff --git a/examples/relay-hook-example/pagination-nextjs-ssr/package.json b/examples/relay-hook-example/pagination-nextjs-ssr/package.json
index 92c53d4f..4d71f6ee 100644
--- a/examples/relay-hook-example/pagination-nextjs-ssr/package.json
+++ b/examples/relay-hook-example/pagination-nextjs-ssr/package.json
@@ -33,7 +33,7 @@
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
- "relay-hooks": "7.0.0",
+ "relay-hooks": "8.0.0-rc.4",
"relay-runtime": "13.0.1",
"whatwg-fetch": "3.0.0",
"react-infinite-scroller": "1.2.4"
@@ -48,6 +48,7 @@
"@babel/runtime": "^7.3.4",
"@types/node": "^12.7.12",
"@types/react": "^17.0.0",
+ "@types/react-dom": "^17.0.0",
"@types/react-relay": "^7.0.2",
"@types/relay-runtime": "^13.0.0",
"@zeit/next-typescript": "1.1.1",
diff --git a/examples/relay-hook-example/pagination-nextjs-ssr/relay/createRelayEnvironment.ts b/examples/relay-hook-example/pagination-nextjs-ssr/relay/createRelayEnvironment.ts
index 881bb4a5..df493678 100644
--- a/examples/relay-hook-example/pagination-nextjs-ssr/relay/createRelayEnvironment.ts
+++ b/examples/relay-hook-example/pagination-nextjs-ssr/relay/createRelayEnvironment.ts
@@ -1,5 +1,5 @@
import fetch from 'isomorphic-unfetch';
-import { Store, Environment, RecordSource, DefaultHandlerProvider, Network } from 'relay-runtime';
+import { Store, Environment, RecordSource, DefaultHandlerProvider, Network, Observable } from 'relay-runtime';
import { HandlerProvider } from 'relay-runtime/lib/handlers/RelayDefaultHandlerProvider';
import { update } from './connection';
@@ -10,10 +10,10 @@ function sleep(ms): Promise {
return new Promise((resolve) => setTimeout(resolve, ms));
}
-function fetchQuery(operation, variables, _cacheConfig, _uploadables): Promise {
+function fetchQuery(operation, variables, _cacheConfig, _uploadables): any {
const endpoint = 'http://localhost:3000/graphql';
- return sleep(500).then(() =>
- fetch(endpoint, {
+ return Observable.create((sink) => {
+ sleep(2000).then(() => fetch(endpoint, {
method: 'POST',
headers: {
Accept: 'application/json',
@@ -23,8 +23,16 @@ function fetchQuery(operation, variables, _cacheConfig, _uploadables): Promise response.json()),
- );
+ }).then(response => response.json())
+ .then(data => {
+ if (data.errors) {
+ sink.error(data.errors);
+ return
+ }
+ sink.next(data);
+ sink.complete();
+ }));
+ });
}
type InitProps = {
diff --git a/examples/suspense/nextjs-ssr/package.json b/examples/suspense/nextjs-ssr/package.json
index 08acccc9..cf8f3217 100644
--- a/examples/suspense/nextjs-ssr/package.json
+++ b/examples/suspense/nextjs-ssr/package.json
@@ -28,7 +28,7 @@
"prop-types": "^15.7.2",
"react": "18.2.0",
"react-dom": "18.2.0",
- "relay-hooks": "7.2.1",
+ "relay-hooks": "../../../relay-hooks-7.3.0-a5.tgz",
"relay-runtime": "14.1.0",
"styled-components": "4.4.0",
"uuid": "^8.3.2",
diff --git a/examples/suspense/nextjs-ssr/tsconfig.json b/examples/suspense/nextjs-ssr/tsconfig.json
index 2dba4410..7b31e306 100644
--- a/examples/suspense/nextjs-ssr/tsconfig.json
+++ b/examples/suspense/nextjs-ssr/tsconfig.json
@@ -18,7 +18,8 @@
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
- "resolveJsonModule": true
+ "resolveJsonModule": true,
+ "incremental": true
},
"exclude": [
"node_modules",
diff --git a/package-lock.json b/package-lock.json
index d98c4ff0..44f620c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "relay-hooks",
- "version": "7.2.1",
+ "version": "8.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "relay-hooks",
- "version": "7.2.1",
+ "version": "8.0.0",
"license": "MIT",
"dependencies": {
"@restart/hooks": "^0.4.9",
diff --git a/package.json b/package.json
index 6b0fe233..fb30f141 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "relay-hooks",
- "version": "7.2.1",
+ "version": "8.0.0",
"keywords": [
"graphql",
"relay",
diff --git a/src/FetchResolver.ts b/src/FetchResolver.ts
index c70b9590..a6d66ffb 100644
--- a/src/FetchResolver.ts
+++ b/src/FetchResolver.ts
@@ -18,8 +18,8 @@ export type Fetcher = {
environment: IEnvironment,
operation: OperationDescriptor,
fetchPolicy: FetchPolicy | null | undefined,
- onComplete: (_e: Error | null) => void,
- onNext: (operation: OperationDescriptor, snapshot: Snapshot, fromStore?: boolean, onlyStore?: boolean) => void,
+ onComplete: (_e: Error | null, doUpdate: boolean) => void,
+ onNext: (operation: OperationDescriptor, snapshot: Snapshot, doUpdate: boolean) => void,
onResponse?: (response: GraphQLResponse | null) => void,
renderPolicy?: RenderPolicy,
) => Disposable;
@@ -32,12 +32,10 @@ export type Fetcher = {
};
export function fetchResolver({
- setLoading,
doRetain = true,
disposeTemporary,
}: {
doRetain?: boolean;
- setLoading?: (loading: boolean) => void;
disposeTemporary?: () => void;
}): Fetcher {
let _refetchSubscription: Subscription | null = null;
@@ -49,9 +47,9 @@ export function fetchResolver({
let error: Error | null = null;
let env;
- const updateLoading = (loading: boolean): void => {
+ const update = (loading: boolean, e: Error = null): void => {
isLoading = loading;
- setLoading && setLoading(isLoading);
+ error = e;
};
const lookupInStore = (
environment: IEnvironment,
@@ -97,17 +95,19 @@ export function fetchResolver({
const disposeRequest = (): void => {
_refetchSubscription && _refetchSubscription.unsubscribe();
error = null;
+ isLoading = false;
};
const fetch = (
environment: IEnvironment,
operation: OperationDescriptor,
fetchPolicy: FetchPolicy = 'network-only',
- onComplete = (_e: Error | null): void => undefined,
- onNext: (operation: OperationDescriptor, snapshot: Snapshot, fromStore?: boolean, onlyStore?: boolean) => void,
+ onComplete = (_e: Error | null, _u: boolean): void => undefined,
+ onNext: (operation: OperationDescriptor, snapshot: Snapshot, doUpdate: boolean) => void,
onResponse?: (response: GraphQLResponse | null) => void,
renderPolicy?: RenderPolicy,
): Disposable => {
+ let fetchHasReturned = false;
if (env != environment || query.request.identifier !== operation.request.identifier) {
dispose();
if (doRetain) {
@@ -122,19 +122,19 @@ export function fetchResolver({
const isNetwork = isNetworkPolicy(fetchPolicy, full);
if (snapshot != null) {
const onlyStore = !isNetwork;
- onNext(operation, snapshot, true, onlyStore);
+ onNext(operation, snapshot, fetchHasReturned && !onlyStore);
if (onlyStore) {
- onComplete(null);
+ onComplete(null, fetchHasReturned);
}
}
// Cancel any previously running refetch.
_refetchSubscription && _refetchSubscription.unsubscribe();
+ let refetchSubscription: Subscription;
if (isNetwork) {
let resolveNetworkPromise = (): void => {};
// Declare refetchSubscription before assigning it in .start(), since
// synchronous completion may call callbacks .subscribe() returns.
- let refetchSubscription: Subscription;
const cleanup = (): void => {
if (_refetchSubscription === refetchSubscription) {
_refetchSubscription = null;
@@ -143,35 +143,35 @@ export function fetchResolver({
promise = null;
};
+ const complete = (error: Error = null) => {
+ resolveNetworkPromise();
+ update(false, error);
+ cleanup();
+ onComplete(error, fetchHasReturned);
+ };
+
fetchQuery(environment, operation).subscribe({
unsubscribe: (): void => {
cleanup();
},
- complete: (): void => {
- resolveNetworkPromise();
- updateLoading(false);
- cleanup();
- onComplete(null);
- },
- error: (e: Error): void => {
- error = e;
- resolveNetworkPromise();
- updateLoading(false);
- cleanup();
- onComplete(e);
- },
+ complete,
+ error: (e: Error): void => complete(e),
next: (response: GraphQLResponse) => {
const store = environment.lookup(operation.fragment);
promise = null;
- operation.request.cacheConfig?.poll && updateLoading(false);
+ const responses = Array.isArray(response) ? response : [response];
+ const cacheConfig = operation.request.cacheConfig;
+ const isQueryPolling = !!cacheConfig && !!cacheConfig.poll;
+ const isIncremental = responses.some((x) => x != null && x.hasNext === true);
+ isQueryPolling && update(false);
resolveNetworkPromise();
onResponse && onResponse(response);
- onNext(operation, store);
+ onNext(operation, store, fetchHasReturned && (isIncremental || isQueryPolling));
},
start: (subscription) => {
refetchSubscription = subscription;
_refetchSubscription = refetchSubscription;
- updateLoading(true);
+ update(true);
},
});
if (!snapshot) {
@@ -179,14 +179,12 @@ export function fetchResolver({
resolveNetworkPromise = resolve;
});
}
- return {
- dispose: (): void => {
- refetchSubscription && refetchSubscription.unsubscribe();
- },
- };
}
+ fetchHasReturned = true;
return {
- dispose: (): void => {},
+ dispose: (): void => {
+ refetchSubscription && refetchSubscription.unsubscribe();
+ },
};
};
diff --git a/src/FragmentResolver.ts b/src/FragmentResolver.ts
index 252202a8..7718b884 100644
--- a/src/FragmentResolver.ts
+++ b/src/FragmentResolver.ts
@@ -30,6 +30,9 @@ const { getPromiseForActiveRequest } = __internal;
type SingularOrPluralSnapshot = Snapshot | Array;
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+function emptyVoid() {}
+
function lookupFragment(environment, selector): SingularOrPluralSnapshot {
return selector.kind === 'PluralReaderSelector'
? selector.selectors.map((s) => environment.lookup(s))
@@ -117,32 +120,33 @@ export class FragmentResolver {
pagination = false;
result: any;
_subscribeResolve;
+ forceUpdate;
constructor(name: FragmentNames) {
this.name = name;
this.pagination = name === PAGINATION_NAME;
this.refetchable = name === REFETCHABLE_NAME || this.pagination;
- const setLoading = (_loading): void => this.refreshHooks();
if (this.refetchable) {
this.fetcherRefecth = fetchResolver({
- setLoading,
doRetain: true,
});
}
if (this.pagination) {
- this.fetcherNext = fetchResolver({ setLoading });
- this.fetcherPrevious = fetchResolver({ setLoading });
+ this.fetcherNext = fetchResolver({});
+ this.fetcherPrevious = fetchResolver({});
}
- }
-
- setForceUpdate(forceUpdate = (): void => undefined): void {
+ this.setForceUpdate();
this.refreshHooks = (): void => {
this.resolveResult();
- forceUpdate();
+ this.forceUpdate();
};
}
+ setForceUpdate(forceUpdate = emptyVoid): void {
+ this.forceUpdate = forceUpdate;
+ }
+
subscribeResolve(subscribeResolve: (data: any) => void): void {
if (this._subscribeResolve && this._subscribeResolve != subscribeResolve) {
subscribeResolve(this.getData());
@@ -259,7 +263,7 @@ export class FragmentResolver {
// $FlowExpectedError[prop-missing] Expando to annotate Promises.
(promise as any).displayName = 'Relay(' + parentQueryName + ')';
this.unsubscribe();
- this.refreshHooks = (): void => undefined;
+ this.refreshHooks = emptyVoid;
throw promise;
}
warning(
@@ -353,7 +357,7 @@ export class FragmentResolver {
environment.subscribe(snapshot, (latestSnapshot) => {
this.resolverData.snapshot[idx] = latestSnapshot;
this.resolverData.data[idx] = latestSnapshot.data;
- this.resolverData.isMissingData = false;
+ this.resolverData.isMissingData = isMissingData(this.resolverData.snapshot);
this.refreshHooks();
}),
);
@@ -362,7 +366,6 @@ export class FragmentResolver {
dataSubscriptions.push(
environment.subscribe(renderedSnapshot, (latestSnapshot) => {
this.resolverData = getFragmentResult(latestSnapshot);
- this.resolverData.isMissingData = false;
this.refreshHooks();
}),
);
@@ -377,7 +380,8 @@ export class FragmentResolver {
};
}
- refetch = (variables: Variables, options?: Options): Disposable => {
+ refetch = (variables: Variables, options: Options = {}): Disposable => {
+ const name = this.name;
if (this.unmounted === true) {
warning(
false,
@@ -387,9 +391,9 @@ export class FragmentResolver {
'Please make sure you clear all timers, intervals, ' +
'async calls, etc that may trigger a fetch.',
this._fragment.name,
- this.name,
+ name,
);
- return { dispose: (): void => {} };
+ return { dispose: emptyVoid };
}
if (this._selector == null) {
warning(
@@ -400,14 +404,14 @@ export class FragmentResolver {
'passing a valid fragment ref to `%s` before calling ' +
'`refetch`, or make sure you pass all required variables to `refetch`.',
this._fragment.name,
- this.name,
- this.name,
+ name,
+ name,
);
}
const { fragmentRefPathInResponse, identifierField, refetchableRequest } = getRefetchMetadata(
this._fragment,
- this.name,
+ name,
);
const fragmentData = this.getData().data;
const identifierValue =
@@ -459,7 +463,7 @@ export class FragmentResolver {
refetchVariables.id = identifierValue;
}
- const onNext = (operation: OperationDescriptor, snapshot: Snapshot): void => {
+ const onNext = (operation: OperationDescriptor, snapshot: Snapshot, doUpdate: boolean): void => {
const fragmentRef = getValueAtPath(snapshot.data, fragmentRefPathInResponse);
const isEquals = this.isEqualsFragmentRef(this._fragmentRefRefetch || this._fragmentRef, fragmentRef);
const missData = isMissingData(snapshot); //fromStore && isMissingData(snapshot);
@@ -473,23 +477,30 @@ export class FragmentResolver {
}*/
this.resolverData.isMissingData = missData;
this.resolverData.owner = operation.request;
- this.refreshHooks();
+ doUpdate && this.refreshHooks();
}
};
if (this.pagination) {
this.fetcherNext.dispose();
this.fetcherPrevious.dispose();
}
+ const complete = (error, doUpdate) => {
+ doUpdate && this.refreshHooks();
+ options.onComplete && options.onComplete(error);
+ };
+
const operation = createOperation(refetchableRequest, refetchVariables, forceCache);
- return this.fetcherRefecth.fetch(
+ const disposable = this.fetcherRefecth.fetch(
this._environment,
operation,
- options?.fetchPolicy,
- options?.onComplete,
+ options.fetchPolicy,
+ complete,
onNext,
- options?.onResponse,
- options?.UNSTABLE_renderPolicy,
+ options.onResponse,
+ options.UNSTABLE_renderPolicy,
);
+ this.refreshHooks();
+ return disposable;
};
loadPrevious = (count: number, options?: OptionsLoadMore): Disposable => {
@@ -500,10 +511,11 @@ export class FragmentResolver {
return this.loadMore('forward', count, options);
};
- loadMore = (direction: 'backward' | 'forward', count: number, options?: OptionsLoadMore): Disposable => {
- const onComplete = options?.onComplete ?? ((): void => undefined);
+ loadMore = (direction: 'backward' | 'forward', count: number, options: OptionsLoadMore = {}): Disposable => {
+ const onComplete = options.onComplete ?? emptyVoid;
const fragmentData = this.getData().data;
+ const emptyDispose = { dispose: emptyVoid };
const fetcher = direction === 'backward' ? this.fetcherPrevious : this.fetcherNext;
if (this.unmounted === true) {
@@ -519,7 +531,7 @@ export class FragmentResolver {
this._fragment.name,
this.name,
);
- return { dispose: (): void => {} };
+ return emptyDispose;
}
if (this._selector == null) {
warning(
@@ -533,14 +545,14 @@ export class FragmentResolver {
this.name,
);
onComplete(null);
- return { dispose: (): void => {} };
+ return emptyDispose;
}
const isRequestActive = (this._environment as any).isRequestActive(
(this._selector as SingularReaderSelector).owner.identifier,
);
if (isRequestActive || fetcher.getData().isLoading === true || fragmentData == null) {
onComplete(null);
- return { dispose: (): void => {} };
+ return emptyDispose;
}
invariant(
this._selector != null && this._selector.kind !== 'PluralReaderSelector',
@@ -560,7 +572,7 @@ export class FragmentResolver {
const parentVariables = (this._selector as SingularReaderSelector).owner.variables;
const fragmentVariables = (this._selector as SingularReaderSelector).variables;
- const extraVariables = options?.UNSTABLE_extraVariables;
+ const extraVariables = options.UNSTABLE_extraVariables;
const baseVariables = {
...parentVariables,
...fragmentVariables,
@@ -592,16 +604,21 @@ export class FragmentResolver {
paginationVariables.id = identifierValue;
}
- const onNext = (): void => {};
+ const complete = (error, doUpdate) => {
+ if (doUpdate) this.refreshHooks();
+ onComplete(error);
+ };
const operation = createOperation(paginationRequest, paginationVariables, forceCache);
- return fetcher.fetch(
+ const disposable = fetcher.fetch(
this._environment,
operation,
undefined, //options?.fetchPolicy,
- onComplete,
- onNext,
- options?.onResponse,
+ complete,
+ emptyVoid,
+ options.onResponse,
);
+ this.refreshHooks();
+ return disposable;
};
}
diff --git a/src/QueryFetcher.ts b/src/QueryFetcher.ts
index a579bbbf..d2f622ca 100644
--- a/src/QueryFetcher.ts
+++ b/src/QueryFetcher.ts
@@ -115,22 +115,22 @@ export class QueryFetcher
}
const { onComplete, onResponse } = options;
- let fetchHasReturned = false;
- const onNext = (_o: OperationDescriptor, snapshot: Snapshot): void => {
+ const resolveUpdate = (doUpdate) => {
+ this.resolveResult();
+ if (doUpdate) {
+ this.forceUpdate();
+ }
+ };
+ const onNext = (operation: OperationDescriptor, snapshot: Snapshot, doUpdate: boolean): void => {
if (!this.snapshot) {
this.snapshot = snapshot;
this.subscribe(snapshot);
- this.resolveResult();
- if (fetchHasReturned) {
- this.forceUpdate();
- }
+ resolveUpdate(doUpdate);
}
};
- const complete = (error: Error | null): void => {
- this.resolveResult();
- if (fetchHasReturned) {
- this.forceUpdate();
- }
+ const complete = (error: Error | null, doUpdate: boolean): void => {
+ // doUpdate is False only if fetch is Sync
+ resolveUpdate(doUpdate);
onComplete && onComplete(error);
};
this.fetcher.fetch(
@@ -142,7 +142,6 @@ export class QueryFetcher
onResponse,
options.UNSTABLE_renderPolicy,
);
- fetchHasReturned = true;
}
getQuery(gqlQuery, variables, networkCacheConfig): OperationDescriptor | null {
@@ -220,7 +219,6 @@ export class QueryFetcher
// Read from this._fetchOptions in case onDataChange() was lazily added.
this.snapshot = snapshot;
//this.error = null;
-
this.resolveResult();
this.forceUpdate();
});
diff --git a/src/useForceUpdate.ts b/src/useForceUpdate.ts
index c98cabb8..2333e712 100644
--- a/src/useForceUpdate.ts
+++ b/src/useForceUpdate.ts
@@ -1,6 +1,18 @@
-import { Reducer, useReducer } from 'react';
+import { Reducer, useCallback, useEffect, useReducer, useRef } from 'react';
export function useForceUpdate(): () => void {
const [, forceUpdate] = useReducer>((x) => x + 1, 0);
- return forceUpdate as () => void;
+ const isMounted = useRef(false);
+ useEffect(() => {
+ isMounted.current = true;
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+ const update = useCallback(() => {
+ if (isMounted.current) {
+ forceUpdate();
+ }
+ }, [isMounted, forceUpdate]);
+ return update;
}
diff --git a/src/useOssFragment.tsx b/src/useOssFragment.tsx
index 6d77cbb9..e241fcf8 100644
--- a/src/useOssFragment.tsx
+++ b/src/useOssFragment.tsx
@@ -55,7 +55,6 @@ export function useOssFragment(
resolver.resolve(environment, idfragment, fragment, fragmentRef);
if (subscribeResolve) {
- resolver.setForceUpdate();
return;
}