diff --git a/packages/relay-experimental/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js b/packages/relay-experimental/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js
index b1ad39ba26e54..81bdcfb199d10 100644
--- a/packages/relay-experimental/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js
+++ b/packages/relay-experimental/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js
@@ -51,7 +51,6 @@ describe('useBlockingPaginationFragment with useTransition', () => {
let paginationQuery;
let variables;
let variablesWithoutID;
- let setEnvironment;
let setOwner;
let renderFragment;
let createMockEnvironment;
@@ -84,9 +83,7 @@ describe('useBlockingPaginationFragment with useTransition', () => {
const [startTransition, isPendingNext] = useTransition(
PAGINATION_SUSPENSE_CONFIG,
);
- /* $FlowFixMe(>=0.108.0 site=www,mobile,react_native_fb,oss) This comment suppresses an error found
- * when Flow v0.108.0 was deployed. To see the error delete this comment
- * and run Flow. */
+ // $FlowFixMe
const {data, ...result} = useBlockingPaginationFragmentOriginal(
fragmentNode,
// $FlowFixMe
@@ -110,6 +107,16 @@ describe('useBlockingPaginationFragment with useTransition', () => {
return {data, ...result};
}
+ function assertYieldsWereCleared() {
+ const actualYields = Scheduler.unstable_clearYields();
+ if (actualYields.length !== 0) {
+ throw new Error(
+ 'Log of yielded values is not empty. ' +
+ 'Call expect(Scheduler).toHaveYielded(...) first.',
+ );
+ }
+ }
+
function assertYield(expected, actual) {
expect(actual.data).toEqual(expected.data);
expect(actual.isPendingNext).toEqual(expected.isPendingNext);
@@ -134,14 +141,39 @@ describe('useBlockingPaginationFragment with useTransition', () => {
);
}
- function assertYieldsWereCleared() {
- const actualYields = Scheduler.unstable_clearYields();
- if (actualYields.length !== 0) {
- throw new Error(
- 'Log of yielded values is not empty. ' +
- 'Call expect(Scheduler).toHaveYielded(...) first.',
- );
- }
+ function expectRequestIsInFlight(expected) {
+ expect(environment.execute).toBeCalledTimes(expected.requestCount);
+ expect(
+ environment.mock.isLoading(
+ gqlPaginationQuery,
+ expected.paginationVariables,
+ {force: true},
+ ),
+ ).toEqual(expected.inFlight);
+ }
+
+ function expectFragmentIsPendingOnPagination(
+ renderer,
+ direction: Direction,
+ expected: {|
+ data: mixed,
+ hasNext: boolean,
+ hasPrevious: boolean,
+ paginationVariables: Variables,
+ |},
+ ) {
+ // Assert fragment sets isPending to true
+ expectFragmentResults([
+ {
+ data: expected.data,
+ isPendingNext: direction === 'forward',
+ hasNext: expected.hasNext,
+ hasPrevious: expected.hasPrevious,
+ },
+ ]);
+
+ // Assert refetch query was fetched
+ expectRequestIsInFlight({...expected, inFlight: true, requestCount: 1});
}
function createFragmentRef(id, owner) {
@@ -376,22 +408,17 @@ describe('useBlockingPaginationFragment with useTransition', () => {
data: userData,
} = useBlockingPaginationFragmentWithSuspenseTransition(
fragment,
- /* $FlowFixMe(>=0.108.0 site=www,mobile,react_native_fb,oss) This comment suppresses an error found
- * when Flow v0.108.0 was deployed. To see the error delete this comment
- * and run Flow. */
+ // $FlowFixMe
userRef,
);
return ;
};
const ContextProvider = ({children}) => {
- const [env, _setEnv] = useState(environment);
// TODO(T39494051) - We set empty variables in relay context to make
// Flow happy, but useBlockingPaginationFragment does not use them, instead it uses
// the variables from the fragment owner.
- const relayContext = useMemo(() => ({environment: env}), [env]);
-
- setEnvironment = _setEnv;
+ const relayContext = useMemo(() => ({environment}), []);
return (
@@ -461,829 +488,784 @@ describe('useBlockingPaginationFragment with useTransition', () => {
jest.dontMock('scheduler');
});
- describe('pagination', () => {
- function expectRequestIsInFlight(expected) {
- expect(environment.execute).toBeCalledTimes(expected.requestCount);
- expect(
- environment.mock.isLoading(
- expected.gqlPaginationQuery ?? gqlPaginationQuery,
- expected.paginationVariables,
- {force: true},
- ),
- ).toEqual(expected.inFlight);
- }
+ describe('loadNext', () => {
+ const direction = 'forward';
- function expectFragmentIsPendingOnPagination(
- renderer,
- direction: Direction,
- expected: {|
- data: mixed,
- hasNext: boolean,
- hasPrevious: boolean,
- paginationVariables: Variables,
- gqlPaginationQuery?: $FlowFixMe,
- |},
- ) {
- // Assert fragment sets isPending to true
+ // Sanity check test, should already be tested in useBlockingPagination test
+ it('loads and renders next items in connection', () => {
+ const callback = jest.fn();
+ const renderer = renderFragment();
expectFragmentResults([
{
- data: expected.data,
- isPendingNext: direction === 'forward',
- hasNext: expected.hasNext,
- hasPrevious: expected.hasPrevious,
+ data: initialUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
},
]);
- // Assert refetch query was fetched
- expectRequestIsInFlight({...expected, inFlight: true, requestCount: 1});
- }
-
- describe('loadNext', () => {
- const direction = 'forward';
-
- // Sanity check test, should already be tested in useBlockingPagination test
- it('loads and renders next items in connection', () => {
- const callback = jest.fn();
- const renderer = renderFragment();
- expectFragmentResults([
- {
- data: initialUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
-
- loadNext(1, {onComplete: callback});
+ loadNext(1, {onComplete: callback});
- const paginationVariables = {
- id: '1',
- after: 'cursor:1',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: false,
- orderby: ['name'],
- };
- expectFragmentIsPendingOnPagination(renderer, direction, {
- data: initialUser,
- hasNext: true,
- hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
- expect(callback).toBeCalledTimes(0);
- expect(renderer.toJSON()).toEqual(null);
-
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- username: 'username:node:2',
- },
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:1',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: false,
+ orderby: ['name'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, direction, {
+ data: initialUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
+ });
+ expect(callback).toBeCalledTimes(0);
+ expect(renderer.toJSON()).toEqual(null);
+
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ username: 'username:node:2',
},
- ],
- pageInfo: {
- startCursor: 'cursor:2',
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: true,
},
+ ],
+ pageInfo: {
+ startCursor: 'cursor:2',
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: true,
},
},
},
- });
+ },
+ });
- const expectedUser = {
- ...initialUser,
- friends: {
- ...initialUser.friends,
- edges: [
- {
- cursor: 'cursor:1',
- node: {
- __typename: 'User',
- id: 'node:1',
- name: 'name:node:1',
- ...createFragmentRef('node:1', query),
- },
+ const expectedUser = {
+ ...initialUser,
+ friends: {
+ ...initialUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:1',
+ node: {
+ __typename: 'User',
+ id: 'node:1',
+ name: 'name:node:1',
+ ...createFragmentRef('node:1', query),
},
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- ...createFragmentRef('node:2', query),
- },
+ },
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ ...createFragmentRef('node:2', query),
},
- ],
- pageInfo: {
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:1',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:1',
},
- };
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
- expect(callback).toBeCalledTimes(1);
- });
+ },
+ };
+ expectFragmentResults([
+ {
+ data: expectedUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
+ expect(callback).toBeCalledTimes(1);
+ });
- it('renders pending flag correctly if pagination update is interrupted before it commits (unsuspends)', () => {
- const callback = jest.fn();
- const renderer = renderFragment();
- expectFragmentResults([
- {
- data: initialUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
+ it('renders pending flag correctly if pagination update is interrupted before it commits (unsuspends)', () => {
+ const callback = jest.fn();
+ const renderer = renderFragment();
+ expectFragmentResults([
+ {
+ data: initialUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
- loadNext(1, {onComplete: callback});
+ loadNext(1, {onComplete: callback});
- const paginationVariables = {
- id: '1',
- after: 'cursor:1',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: false,
- orderby: ['name'],
- };
- expectFragmentIsPendingOnPagination(renderer, direction, {
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:1',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: false,
+ orderby: ['name'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, direction, {
+ data: initialUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
+ });
+ expect(callback).toBeCalledTimes(0);
+ expect(renderer.toJSON()).toEqual(null);
+
+ // Schedule a high-pri update while the component is
+ // suspended on pagination
+ Scheduler.unstable_runWithPriority(
+ Scheduler.unstable_UserBlockingPriority,
+ () => {
+ forceUpdate(prev => prev + 1);
+ },
+ );
+
+ // Assert high-pri update is rendered when initial update
+ // that suspended hasn't committed
+ // Assert that the avoided Suspense fallback isn't rendered
+ expect(renderer.toJSON()).toEqual(null);
+ expectFragmentResults([
+ {
data: initialUser,
+ // Assert that isPending flag is still true
+ isPendingNext: true,
hasNext: true,
hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
- expect(callback).toBeCalledTimes(0);
- expect(renderer.toJSON()).toEqual(null);
-
- // Schedule a high-pri update while the component is
- // suspended on pagination
- Scheduler.unstable_runWithPriority(
- Scheduler.unstable_UserBlockingPriority,
- () => {
- forceUpdate(prev => prev + 1);
- },
- );
-
- // Assert high-pri update is rendered when initial update
- // that suspended hasn't committed
- // Assert that the avoided Suspense fallback isn't rendered
- expect(renderer.toJSON()).toEqual(null);
- expectFragmentResults([
- {
- data: initialUser,
- // Assert that isPending flag is still true
- isPendingNext: true,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
+ },
+ ]);
- // Assert list is updated after pagination request completes
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- username: 'username:node:2',
- },
+ // Assert list is updated after pagination request completes
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ username: 'username:node:2',
},
- ],
- pageInfo: {
- startCursor: 'cursor:2',
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: true,
},
+ ],
+ pageInfo: {
+ startCursor: 'cursor:2',
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: true,
},
},
},
- });
+ },
+ });
- const expectedUser = {
- ...initialUser,
- friends: {
- ...initialUser.friends,
- edges: [
- {
- cursor: 'cursor:1',
- node: {
- __typename: 'User',
- id: 'node:1',
- name: 'name:node:1',
- ...createFragmentRef('node:1', query),
- },
+ const expectedUser = {
+ ...initialUser,
+ friends: {
+ ...initialUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:1',
+ node: {
+ __typename: 'User',
+ id: 'node:1',
+ name: 'name:node:1',
+ ...createFragmentRef('node:1', query),
},
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- ...createFragmentRef('node:2', query),
- },
+ },
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ ...createFragmentRef('node:2', query),
},
- ],
- pageInfo: {
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:1',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:1',
},
- };
-
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
- expect(callback).toBeCalledTimes(1);
- });
+ },
+ };
- it('loads more correctly when original variables do not include an id', () => {
- const callback = jest.fn();
- const viewer = environment.lookup(queryWithoutID.fragment).data
- ?.viewer;
- const userRef =
- typeof viewer === 'object' && viewer != null ? viewer?.actor : null;
- invariant(userRef != null, 'Expected to have cached test data');
+ expectFragmentResults([
+ {
+ data: expectedUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
+ expect(callback).toBeCalledTimes(1);
+ });
- let expectedUser = {
- ...initialUser,
- friends: {
- ...initialUser.friends,
- edges: [
- {
- cursor: 'cursor:1',
- node: {
- __typename: 'User',
- id: 'node:1',
- name: 'name:node:1',
- ...createFragmentRef('node:1', queryWithoutID),
- },
+ it('loads more correctly when original variables do not include an id', () => {
+ const callback = jest.fn();
+ const viewer = environment.lookup(queryWithoutID.fragment).data?.viewer;
+ const userRef =
+ typeof viewer === 'object' && viewer != null ? viewer?.actor : null;
+ invariant(userRef != null, 'Expected to have cached test data');
+
+ let expectedUser = {
+ ...initialUser,
+ friends: {
+ ...initialUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:1',
+ node: {
+ __typename: 'User',
+ id: 'node:1',
+ name: 'name:node:1',
+ ...createFragmentRef('node:1', queryWithoutID),
},
- ],
- },
- };
-
- const renderer = renderFragment({owner: queryWithoutID, userRef});
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
-
- loadNext(1, {onComplete: callback});
+ },
+ ],
+ },
+ };
- const paginationVariables = {
- id: '1',
- after: 'cursor:1',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: false,
- orderby: ['name'],
- };
- expectFragmentIsPendingOnPagination(renderer, direction, {
+ const renderer = renderFragment({owner: queryWithoutID, userRef});
+ expectFragmentResults([
+ {
data: expectedUser,
+ isPendingNext: false,
hasNext: true,
hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
- expect(callback).toBeCalledTimes(0);
- expect(renderer.toJSON()).toEqual(null);
-
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- username: 'username:node:2',
- },
+ },
+ ]);
+
+ loadNext(1, {onComplete: callback});
+
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:1',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: false,
+ orderby: ['name'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, direction, {
+ data: expectedUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
+ });
+ expect(callback).toBeCalledTimes(0);
+ expect(renderer.toJSON()).toEqual(null);
+
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ username: 'username:node:2',
},
- ],
- pageInfo: {
- startCursor: 'cursor:2',
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: true,
},
+ ],
+ pageInfo: {
+ startCursor: 'cursor:2',
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: true,
},
},
},
- });
+ },
+ });
- expectedUser = {
- ...initialUser,
- friends: {
- ...initialUser.friends,
- edges: [
- {
- cursor: 'cursor:1',
- node: {
- __typename: 'User',
- id: 'node:1',
- name: 'name:node:1',
- ...createFragmentRef('node:1', queryWithoutID),
- },
+ expectedUser = {
+ ...initialUser,
+ friends: {
+ ...initialUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:1',
+ node: {
+ __typename: 'User',
+ id: 'node:1',
+ name: 'name:node:1',
+ ...createFragmentRef('node:1', queryWithoutID),
},
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- ...createFragmentRef('node:2', queryWithoutID),
- },
+ },
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ ...createFragmentRef('node:2', queryWithoutID),
},
- ],
- pageInfo: {
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:1',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:1',
},
- };
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
- expect(callback).toBeCalledTimes(1);
- });
-
- it('calls callback with error when error occurs during fetch', () => {
- const callback = jest.fn();
- const renderer = renderFragment();
- expectFragmentResults([
- {
- data: initialUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
-
- loadNext(1, {onComplete: callback});
+ },
+ };
+ expectFragmentResults([
+ {
+ data: expectedUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
+ expect(callback).toBeCalledTimes(1);
+ });
- const paginationVariables = {
- id: '1',
- after: 'cursor:1',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: false,
- orderby: ['name'],
- };
- expectFragmentIsPendingOnPagination(renderer, direction, {
+ it('calls callback with error when error occurs during fetch', () => {
+ const callback = jest.fn();
+ const renderer = renderFragment();
+ expectFragmentResults([
+ {
data: initialUser,
+ isPendingNext: false,
hasNext: true,
hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
- expect(callback).toBeCalledTimes(0);
- expect(renderer.toJSON()).toEqual(null);
-
- const error = new Error('Oops');
- environment.mock.reject(gqlPaginationQuery, error);
-
- // We pass the error in the callback, but do not throw during render
- // since we want to continue rendering the existing items in the
- // connection
- expect(callback).toBeCalledTimes(1);
- expect(callback).toBeCalledWith(error);
+ },
+ ]);
+
+ loadNext(1, {onComplete: callback});
+
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:1',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: false,
+ orderby: ['name'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, direction, {
+ data: initialUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
});
+ expect(callback).toBeCalledTimes(0);
+ expect(renderer.toJSON()).toEqual(null);
- it('preserves pagination request if re-rendered with same fragment ref', () => {
- const callback = jest.fn();
- const renderer = renderFragment();
- expectFragmentResults([
- {
- data: initialUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
+ const error = new Error('Oops');
+ environment.mock.reject(gqlPaginationQuery, error);
- loadNext(1, {onComplete: callback});
+ // We pass the error in the callback, but do not throw during render
+ // since we want to continue rendering the existing items in the
+ // connection
+ expect(callback).toBeCalledTimes(1);
+ expect(callback).toBeCalledWith(error);
+ });
- const paginationVariables = {
- id: '1',
- after: 'cursor:1',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: false,
- orderby: ['name'],
- };
- expectFragmentIsPendingOnPagination(renderer, direction, {
+ it('preserves pagination request if re-rendered with same fragment ref', () => {
+ const callback = jest.fn();
+ const renderer = renderFragment();
+ expectFragmentResults([
+ {
data: initialUser,
+ isPendingNext: false,
hasNext: true,
hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
- expect(callback).toBeCalledTimes(0);
- expect(renderer.toJSON()).toEqual(null);
-
- setOwner({...query});
-
- // Assert that request is still in flight after re-rendering
- // with new fragment ref that points to the same data.
- expectRequestIsInFlight({
- inFlight: true,
- requestCount: 1,
- gqlPaginationQuery,
- paginationVariables,
- });
- expect(callback).toBeCalledTimes(0);
-
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- username: 'username:node:2',
- },
+ },
+ ]);
+
+ loadNext(1, {onComplete: callback});
+
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:1',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: false,
+ orderby: ['name'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, direction, {
+ data: initialUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
+ });
+ expect(callback).toBeCalledTimes(0);
+ expect(renderer.toJSON()).toEqual(null);
+
+ setOwner({...query});
+
+ // Assert that request is still in flight after re-rendering
+ // with new fragment ref that points to the same data.
+ expectRequestIsInFlight({
+ inFlight: true,
+ requestCount: 1,
+ gqlPaginationQuery,
+ paginationVariables,
+ });
+ expect(callback).toBeCalledTimes(0);
+
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ username: 'username:node:2',
},
- ],
- pageInfo: {
- startCursor: 'cursor:2',
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: true,
},
+ ],
+ pageInfo: {
+ startCursor: 'cursor:2',
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: true,
},
},
},
- });
+ },
+ });
- const expectedUser = {
- ...initialUser,
- friends: {
- ...initialUser.friends,
- edges: [
- {
- cursor: 'cursor:1',
- node: {
- __typename: 'User',
- id: 'node:1',
- name: 'name:node:1',
- ...createFragmentRef('node:1', query),
- },
+ const expectedUser = {
+ ...initialUser,
+ friends: {
+ ...initialUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:1',
+ node: {
+ __typename: 'User',
+ id: 'node:1',
+ name: 'name:node:1',
+ ...createFragmentRef('node:1', query),
},
- {
- cursor: 'cursor:2',
- node: {
- __typename: 'User',
- id: 'node:2',
- name: 'name:node:2',
- ...createFragmentRef('node:2', query),
- },
+ },
+ {
+ cursor: 'cursor:2',
+ node: {
+ __typename: 'User',
+ id: 'node:2',
+ name: 'name:node:2',
+ ...createFragmentRef('node:2', query),
},
- ],
- pageInfo: {
- endCursor: 'cursor:2',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:1',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:2',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:1',
},
- };
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: true,
- hasNext: true,
- hasPrevious: false,
- },
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
- expect(callback).toBeCalledTimes(1);
- });
+ },
+ };
+ expectFragmentResults([
+ {
+ data: expectedUser,
+ isPendingNext: true,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ {
+ data: expectedUser,
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
+ expect(callback).toBeCalledTimes(1);
});
+ });
- describe('refetch', () => {
- // The bulk of refetch behavior is covered in useRefetchableFragmentNode-test,
- // so this suite covers the pagination-related test cases.
- function expectRefetchRequestIsInFlight(expected) {
- expect(environment.execute).toBeCalledTimes(expected.requestCount);
- expect(
- environment.mock.isLoading(
- expected.gqlRefetchQuery ?? gqlPaginationQuery,
- expected.refetchVariables,
- {force: true},
- ),
- ).toEqual(expected.inFlight);
- }
+ describe('refetch', () => {
+ // The bulk of refetch behavior is covered in useRefetchableFragmentNode-test,
+ // so this suite covers the pagination-related test cases.
+ function expectRefetchRequestIsInFlight(expected) {
+ expect(environment.execute).toBeCalledTimes(expected.requestCount);
+ expect(
+ environment.mock.isLoading(
+ expected.gqlRefetchQuery ?? gqlPaginationQuery,
+ expected.refetchVariables,
+ {force: true},
+ ),
+ ).toEqual(expected.inFlight);
+ }
- function expectFragmentSuspendedOnRefetch(
- renderer,
- expected: {|
- data: mixed,
- hasNext: boolean,
- hasPrevious: boolean,
- refetchVariables: Variables,
- refetchQuery?: OperationDescriptor,
- gqlRefetchQuery?: $FlowFixMe,
- |},
- ) {
- assertYieldsWereCleared();
-
- TestRenderer.act(() => {
- // Wrap in act to ensure passive effects are run
- jest.runAllImmediates();
- });
-
- // Assert component suspended
- Scheduler.unstable_flushNumberOfYields(1);
- const actualYields = Scheduler.unstable_clearYields();
- expect(actualYields.length).toEqual(1);
- expect(actualYields[0]).toEqual('Fallback');
- expect(renderer.toJSON()).toEqual('Fallback');
-
- // Assert refetch query was fetched
- expectRefetchRequestIsInFlight({
- ...expected,
- inFlight: true,
- requestCount: 1,
- });
-
- // 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,
- );
- }
+ function expectFragmentSuspendedOnRefetch(
+ renderer,
+ expected: {|
+ data: mixed,
+ hasNext: boolean,
+ hasPrevious: boolean,
+ refetchVariables: Variables,
+ refetchQuery?: OperationDescriptor,
+ gqlRefetchQuery?: $FlowFixMe,
+ |},
+ ) {
+ assertYieldsWereCleared();
- it('loads more items correctly after refetching', () => {
- const renderer = renderFragment();
- expectFragmentResults([
- {
- data: initialUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
+ TestRenderer.act(() => {
+ // Wrap in act to ensure passive effects are run
+ jest.runAllImmediates();
+ });
- refetch({isViewerFriendLocal: true, orderby: ['lastname']});
+ // Assert component suspended
+ Scheduler.unstable_flushNumberOfYields(1);
+ const actualYields = Scheduler.unstable_clearYields();
+ expect(actualYields.length).toEqual(1);
+ expect(actualYields[0]).toEqual('Fallback');
+ expect(renderer.toJSON()).toEqual('Fallback');
- // Assert that fragment is refetching with the right variables and
- // suspends upon refetch
- const refetchVariables = {
- after: null,
- first: 1,
- before: null,
- last: null,
- id: '1',
- isViewerFriendLocal: true,
- orderby: ['lastname'],
- };
- paginationQuery = createOperationDescriptor(
- gqlPaginationQuery,
- refetchVariables,
- );
- expectFragmentSuspendedOnRefetch(renderer, {
+ // Assert refetch query was fetched
+ expectRefetchRequestIsInFlight({
+ ...expected,
+ inFlight: true,
+ requestCount: 1,
+ });
+
+ // Assert query is tentatively retained while component is suspended
+ expect(environment.retain).toBeCalledTimes(1);
+ expect(environment.retain.mock.calls[0][0]).toEqual(
+ expected.refetchQuery,
+ );
+ }
+
+ it('loads more items correctly after refetching', () => {
+ const renderer = renderFragment();
+ expectFragmentResults([
+ {
data: initialUser,
+ isPendingNext: false,
hasNext: true,
hasPrevious: false,
- refetchVariables,
- refetchQuery: paginationQuery,
- });
+ },
+ ]);
- // Mock network response
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:100',
- node: {
- __typename: 'User',
- id: 'node:100',
- name: 'name:node:100',
- username: 'username:node:100',
- },
+ refetch({isViewerFriendLocal: true, orderby: ['lastname']});
+
+ // Assert that fragment is refetching with the right variables and
+ // suspends upon refetch
+ const refetchVariables = {
+ after: null,
+ first: 1,
+ before: null,
+ last: null,
+ id: '1',
+ isViewerFriendLocal: true,
+ orderby: ['lastname'],
+ };
+ paginationQuery = createOperationDescriptor(
+ gqlPaginationQuery,
+ refetchVariables,
+ );
+ expectFragmentSuspendedOnRefetch(renderer, {
+ data: initialUser,
+ hasNext: true,
+ hasPrevious: false,
+ refetchVariables,
+ refetchQuery: paginationQuery,
+ });
+
+ // Mock network response
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:100',
+ node: {
+ __typename: 'User',
+ id: 'node:100',
+ name: 'name:node:100',
+ username: 'username:node:100',
},
- ],
- pageInfo: {
- endCursor: 'cursor:100',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:100',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:100',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:100',
},
},
},
- });
+ },
+ });
- // Assert fragment is rendered with new data
- const expectedUser = {
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:100',
- node: {
- __typename: 'User',
- id: 'node:100',
- name: 'name:node:100',
- ...createFragmentRef('node:100', paginationQuery),
- },
+ // Assert fragment is rendered with new data
+ const expectedUser = {
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:100',
+ node: {
+ __typename: 'User',
+ id: 'node:100',
+ name: 'name:node:100',
+ ...createFragmentRef('node:100', paginationQuery),
},
- ],
- pageInfo: {
- endCursor: 'cursor:100',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:100',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:100',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:100',
},
- };
-
- jest.runAllImmediates();
- expectFragmentResults([
- {
- data: expectedUser,
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
-
- // Assert refetch query was retained
- expect(release).not.toBeCalled();
- expect(environment.retain).toBeCalledTimes(1);
- expect(environment.retain.mock.calls[0][0]).toEqual(paginationQuery);
-
- // Paginate after refetching
- environment.execute.mockClear();
- loadNext(1);
+ },
+ };
- const paginationVariables = {
- id: '1',
- after: 'cursor:100',
- first: 1,
- before: null,
- last: null,
- isViewerFriendLocal: true,
- orderby: ['lastname'],
- };
- expectFragmentIsPendingOnPagination(renderer, 'forward', {
+ jest.runAllImmediates();
+ expectFragmentResults([
+ {
data: expectedUser,
+ isPendingNext: false,
hasNext: true,
hasPrevious: false,
- paginationVariables,
- gqlPaginationQuery,
- });
+ },
+ ]);
- environment.mock.resolve(gqlPaginationQuery, {
- data: {
- node: {
- __typename: 'User',
- id: '1',
- name: 'Alice',
- friends: {
- edges: [
- {
- cursor: 'cursor:200',
- node: {
- __typename: 'User',
- id: 'node:200',
- name: 'name:node:200',
- username: 'username:node:200',
- },
+ // Assert refetch query was retained
+ expect(release).not.toBeCalled();
+ expect(environment.retain).toBeCalledTimes(1);
+ expect(environment.retain.mock.calls[0][0]).toEqual(paginationQuery);
+
+ // Paginate after refetching
+ environment.execute.mockClear();
+ loadNext(1);
+
+ const paginationVariables = {
+ id: '1',
+ after: 'cursor:100',
+ first: 1,
+ before: null,
+ last: null,
+ isViewerFriendLocal: true,
+ orderby: ['lastname'],
+ };
+ expectFragmentIsPendingOnPagination(renderer, 'forward', {
+ data: expectedUser,
+ hasNext: true,
+ hasPrevious: false,
+ paginationVariables,
+ });
+
+ environment.mock.resolve(gqlPaginationQuery, {
+ data: {
+ node: {
+ __typename: 'User',
+ id: '1',
+ name: 'Alice',
+ friends: {
+ edges: [
+ {
+ cursor: 'cursor:200',
+ node: {
+ __typename: 'User',
+ id: 'node:200',
+ name: 'name:node:200',
+ username: 'username:node:200',
},
- ],
- pageInfo: {
- startCursor: 'cursor:200',
- endCursor: 'cursor:200',
- hasNextPage: true,
- hasPreviousPage: true,
},
+ ],
+ pageInfo: {
+ startCursor: 'cursor:200',
+ endCursor: 'cursor:200',
+ hasNextPage: true,
+ hasPreviousPage: true,
},
},
},
- });
+ },
+ });
- const paginatedUser = {
- ...expectedUser,
- friends: {
- ...expectedUser.friends,
- edges: [
- {
- cursor: 'cursor:100',
- node: {
- __typename: 'User',
- id: 'node:100',
- name: 'name:node:100',
- ...createFragmentRef('node:100', paginationQuery),
- },
+ const paginatedUser = {
+ ...expectedUser,
+ friends: {
+ ...expectedUser.friends,
+ edges: [
+ {
+ cursor: 'cursor:100',
+ node: {
+ __typename: 'User',
+ id: 'node:100',
+ name: 'name:node:100',
+ ...createFragmentRef('node:100', paginationQuery),
},
- {
- cursor: 'cursor:200',
- node: {
- __typename: 'User',
- id: 'node:200',
- name: 'name:node:200',
- ...createFragmentRef('node:200', paginationQuery),
- },
+ },
+ {
+ cursor: 'cursor:200',
+ node: {
+ __typename: 'User',
+ id: 'node:200',
+ name: 'name:node:200',
+ ...createFragmentRef('node:200', paginationQuery),
},
- ],
- pageInfo: {
- endCursor: 'cursor:200',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'cursor:100',
},
+ ],
+ pageInfo: {
+ endCursor: 'cursor:200',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'cursor:100',
},
- };
- expectFragmentResults([
- {
- data: paginatedUser,
- // Assert pending flag is set back to false
- isPendingNext: false,
- hasNext: true,
- hasPrevious: false,
- },
- ]);
- });
+ },
+ };
+ expectFragmentResults([
+ {
+ data: paginatedUser,
+ // Assert pending flag is set back to false
+ isPendingNext: false,
+ hasNext: true,
+ hasPrevious: false,
+ },
+ ]);
});
});
}