Skip to content

Commit

Permalink
add a unit test reproduction for #7780
Browse files Browse the repository at this point in the history
  • Loading branch information
brainkim committed Apr 5, 2021
1 parent ae7fb67 commit 22ee1b1
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 1 deletion.
190 changes: 190 additions & 0 deletions src/react/hooks/__tests__/useSubscription.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,194 @@ describe('useSubscription Hook', () => {
expect(context).toEqual('Audi');
});
});

it('should handle multiple subscriptions properly', () => {
const subscription = gql`
subscription {
car {
make
}
}
`;

const results = ['Audi', 'BMW'].map(make => ({
result: { data: { car: { make } } }
}));

const link = new MockSubscriptionLink();
const client = new ApolloClient({
link,
cache: new Cache({ addTypename: false })
});

let renderCount = 0;
const Component = () => {
const { loading: loading1, data: data1, error: error1 } = useSubscription(subscription);
const { loading: loading2, data: data2, error: error2 } = useSubscription(subscription);
switch (renderCount) {
case 0:
expect(loading1).toBe(true);
expect(error1).toBeUndefined();
expect(data1).toBeUndefined();
expect(loading2).toBe(true);
expect(error2).toBeUndefined();
expect(data2).toBeUndefined();
break;
case 1:
expect(loading1).toBe(false);
expect(data1).toEqual(results[0].result.data);
expect(loading2).toBe(true);
expect(data2).toBe(undefined);
break;
case 2:
expect(loading1).toBe(false);
expect(data1).toEqual(results[0].result.data);
expect(loading2).toBe(false);
expect(data2).toEqual(results[0].result.data);
break;
case 3:
expect(loading1).toBe(false);
expect(data1).toEqual(results[1].result.data);
expect(loading2).toBe(false);
expect(data2).toEqual(results[0].result.data);
break;
case 4:
expect(loading1).toBe(false);
expect(data1).toEqual(results[1].result.data);
expect(loading2).toBe(false);
expect(data2).toEqual(results[1].result.data);
break;
default:
}

renderCount += 1;
return null;
};

for (let i = 0; i < results.length; i++) {
setTimeout(() => {
link.simulateResult(results[i]);
});
}

render(
<ApolloProvider client={client}>
<Component />
</ApolloProvider>
);

return wait(() => {
expect(renderCount).toBe(5);
});
});

it('should handle immediate completions gracefully', () => {
const subscription = gql`
subscription {
car {
make
}
}
`;

const result = {
result: { data: null },
}

const link = new MockSubscriptionLink();
const client = new ApolloClient({
link,
cache: new Cache({ addTypename: false })
});

let renderCount = 0;
const Component = () => {
const { loading, data, error } = useSubscription(subscription);
switch (renderCount) {
case 0:
expect(loading).toBe(true);
expect(data).toBeUndefined();
expect(error).toBeUndefined();
break;
case 1:
expect(loading).toBe(false);
expect(data).toEqual(result.result.data);
break;
case 10:
throw new Error("Infinite rendering detected");
default:
console.log(renderCount, {loading, data, error});
}

renderCount += 1;
return null;
};

// Simulating the behavior of HttpLink, which calls next and complete in sequence.
link.simulateResult(result, /* complete */ true);
render(
<ApolloProvider client={client}>
<Component />
</ApolloProvider>
);

return wait(() => {
expect(renderCount).toBe(2);
});
});

it('should handle immediate completions with multiple subscriptions gracefully', () => {
const subscription = gql`
subscription {
car {
make
}
}
`;

const result = {
result: { data: null },
}

const link = new MockSubscriptionLink();
const client = new ApolloClient({
link,
cache: new Cache({ addTypename: false })
});

let renderCount = 0;
const Component = () => {
const { loading: loading1, data: data1, error: error1 } = useSubscription(subscription);
const { loading: loading2, data: data2, error: error2 } = useSubscription(subscription);
switch (renderCount) {
case 0:
expect(loading1).toBe(true);
expect(data1).toBeUndefined();
expect(error1).toBeUndefined();
expect(loading2).toBe(true);
expect(data2).toBeUndefined();
expect(error2).toBeUndefined();
break;
// TODO: fill in the remaining expectations for this test
case 10:
throw new Error("Infinite rendering detected");
default:
}

renderCount += 1;
return null;
};

// Simulating the behavior of HttpLink, which calls next and complete in sequence.
link.simulateResult(result, /* complete */ true);
render(
<ApolloProvider client={client}>
<Component />
</ApolloProvider>
);

return wait(() => {
expect(renderCount).toBe(1);
});
});
});
2 changes: 1 addition & 1 deletion src/utilities/testing/mocking/mockSubscriptionLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export class MockSubscriptionLink extends ApolloLink {
const { observers } = this;
if (!observers.length) throw new Error('subscription torn down');
observers.forEach(observer => {
if (complete && observer.complete) observer.complete();
if (result.result && observer.next) observer.next(result.result);
if (result.error && observer.error) observer.error(result.error);
if (complete && observer.complete) observer.complete();
});
}, result.delay || 0);
}
Expand Down

0 comments on commit 22ee1b1

Please sign in to comment.