Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify schema in defer tests #3881

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 92 additions & 68 deletions src/execution/__tests__/defer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ const friendType = new GraphQLObjectType({
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString },
promiseNonNullErrorField: {
type: new GraphQLNonNull(GraphQLString),
resolve: () => Promise.resolve(null),
},
nonNullName: { type: new GraphQLNonNull(GraphQLString) },
},
name: 'Friend',
});
Expand All @@ -40,64 +37,36 @@ const friends = [
{ name: 'C-3PO', id: 4 },
];

const hero = { name: 'Luke', id: 1, friends };

const heroType = new GraphQLObjectType({
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString },
slowField: {
type: GraphQLString,
resolve: async () => {
await resolveOnNextTick();
return 'slow';
},
},
errorField: {
type: GraphQLString,
resolve: () => {
throw new Error('bad');
},
},
nonNullErrorField: {
type: new GraphQLNonNull(GraphQLString),
resolve: () => null,
},
promiseNonNullErrorField: {
type: new GraphQLNonNull(GraphQLString),
resolve: () => Promise.resolve(null),
},
nonNullName: { type: new GraphQLNonNull(GraphQLString) },
friends: {
type: new GraphQLList(friendType),
resolve: () => friends,
},
asyncFriends: {
type: new GraphQLList(friendType),
async *resolve() {
yield await Promise.resolve(friends[0]);
},
},
},
name: 'Hero',
});

const hero = { name: 'Luke', id: 1 };

const query = new GraphQLObjectType({
fields: {
hero: {
type: heroType,
resolve: () => hero,
},
},
name: 'Query',
});

const schema = new GraphQLSchema({ query });

async function complete(document: DocumentNode) {
async function complete(document: DocumentNode, rootValue: unknown = { hero }) {
const result = await experimentalExecuteIncrementally({
schema,
document,
rootValue: {},
rootValue,
});

if ('initialResult' in result) {
Expand Down Expand Up @@ -244,11 +213,18 @@ describe('Execute: defer directive', () => {
}
fragment QueryFragment on Query {
hero {
errorField
name
}
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
name: () => {
throw new Error('bad');
},
},
});

expectJSON(result).toDeepEqual([
{
Expand All @@ -260,14 +236,14 @@ describe('Execute: defer directive', () => {
{
data: {
hero: {
errorField: null,
name: null,
},
},
errors: [
{
message: 'bad',
locations: [{ line: 7, column: 11 }],
path: ['hero', 'errorField'],
path: ['hero', 'name'],
},
],
path: [],
Expand Down Expand Up @@ -440,10 +416,17 @@ describe('Execute: defer directive', () => {
}
}
fragment NameFragment on Hero {
errorField
name
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
name: () => {
throw new Error('bad');
},
},
});
expectJSON(result).toDeepEqual([
{
data: { hero: { id: '1' } },
Expand All @@ -452,13 +435,13 @@ describe('Execute: defer directive', () => {
{
incremental: [
{
data: { errorField: null },
data: { name: null },
path: ['hero'],
errors: [
{
message: 'bad',
locations: [{ line: 9, column: 9 }],
path: ['hero', 'errorField'],
path: ['hero', 'name'],
},
],
},
Expand All @@ -476,10 +459,15 @@ describe('Execute: defer directive', () => {
}
}
fragment NameFragment on Hero {
nonNullErrorField
nonNullName
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
nonNullName: () => null,
},
});
expectJSON(result).toDeepEqual([
{
data: { hero: { id: '1' } },
Expand All @@ -493,9 +481,9 @@ describe('Execute: defer directive', () => {
errors: [
{
message:
'Cannot return null for non-nullable field Hero.nonNullErrorField.',
'Cannot return null for non-nullable field Hero.nonNullName.',
locations: [{ line: 9, column: 9 }],
path: ['hero', 'nonNullErrorField'],
path: ['hero', 'nonNullName'],
},
],
},
Expand All @@ -508,27 +496,32 @@ describe('Execute: defer directive', () => {
const document = parse(`
query HeroNameQuery {
hero {
nonNullErrorField
nonNullName
...NameFragment @defer
}
}
fragment NameFragment on Hero {
id
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
nonNullName: () => null,
},
});
expectJSON(result).toDeepEqual({
errors: [
{
message:
'Cannot return null for non-nullable field Hero.nonNullErrorField.',
'Cannot return null for non-nullable field Hero.nonNullName.',
locations: [
{
line: 4,
column: 11,
},
],
path: ['hero', 'nonNullErrorField'],
path: ['hero', 'nonNullName'],
},
],
data: {
Expand All @@ -545,10 +538,15 @@ describe('Execute: defer directive', () => {
}
}
fragment NameFragment on Hero {
promiseNonNullErrorField
nonNullName
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
nonNullName: () => Promise.resolve(null),
},
});
expectJSON(result).toDeepEqual([
{
data: { hero: { id: '1' } },
Expand All @@ -562,9 +560,9 @@ describe('Execute: defer directive', () => {
errors: [
{
message:
'Cannot return null for non-nullable field Hero.promiseNonNullErrorField.',
'Cannot return null for non-nullable field Hero.nonNullName.',
locations: [{ line: 9, column: 9 }],
path: ['hero', 'promiseNonNullErrorField'],
path: ['hero', 'nonNullName'],
},
],
},
Expand All @@ -582,7 +580,7 @@ describe('Execute: defer directive', () => {
}
}
fragment NameFragment on Hero {
slowField
name
friends {
...NestedFragment @defer
}
Expand All @@ -591,7 +589,15 @@ describe('Execute: defer directive', () => {
name
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
name: async () => {
await resolveOnNextTick();
return 'slow';
},
},
});
expectJSON(result).toDeepEqual([
{
data: {
Expand All @@ -602,7 +608,7 @@ describe('Execute: defer directive', () => {
{
incremental: [
{
data: { slowField: 'slow', friends: [{}, {}, {}] },
data: { name: 'slow', friends: [{}, {}, {}] },
path: ['hero'],
},
],
Expand Down Expand Up @@ -671,8 +677,8 @@ describe('Execute: defer directive', () => {
const document = parse(`
query {
hero {
asyncFriends {
promiseNonNullErrorField
friends {
nonNullName
...NameFragment @defer
}
}
Expand All @@ -681,19 +687,29 @@ describe('Execute: defer directive', () => {
name
}
`);
const result = await complete(document);
const result = await complete(document, {
hero: {
...hero,
async *friends() {
yield await Promise.resolve({
...friends[0],
nonNullName: () => Promise.resolve(null),
});
},
},
});
expectJSON(result).toDeepEqual({
data: {
hero: {
asyncFriends: [null],
friends: [null],
},
},
errors: [
{
message:
'Cannot return null for non-nullable field Friend.promiseNonNullErrorField.',
'Cannot return null for non-nullable field Friend.nonNullName.',
locations: [{ line: 5, column: 11 }],
path: ['hero', 'asyncFriends', 0, 'promiseNonNullErrorField'],
path: ['hero', 'friends', 0, 'nonNullName'],
},
],
});
Expand All @@ -719,15 +735,23 @@ describe('Execute: defer directive', () => {
it('original execute function resolves to error if anything is deferred and something else is async', async () => {
const doc = `
query Deferred {
hero { slowField }
hero { name }
... @defer { hero { id } }
}
`;
await expectPromise(
execute({
schema,
document: parse(doc),
rootValue: {},
rootValue: {
hero: {
...hero,
name: async () => {
await resolveOnNextTick();
return 'slow';
},
},
},
}),
).toRejectWith(
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)',
Expand Down