Skip to content
97 changes: 97 additions & 0 deletions test/analysis/buildTypeWeights.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,103 @@ describe('Test buildTypeWeightsFromSchema function', () => {
});
});

xdescribe('Not null operator (!) is used', () => {
test('on a scalar, enum or object type', () => {
schema = buildSchema(`
type Human{
homePlanet: String!
age: Int!
isHero: Boolean!
droids: Droid!
episode: Episode!
}
type Droid {
primaryFunction: String
}
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
`);

expect(buildTypeWeightsFromSchema(schema)).toEqual({
human: {
weight: 1,
fields: {
homePlanet: {
weight: 0,
},
age: {
weight: 0,
},
isHero: {
weight: 0,
},
droids: {
resolveTo: 'droid',
},
episode: {
resolveTo: 'episode',
},
},
},
droid: {
weight: 1,
fields: {
primaryFunction: {
weight: 0,
},
},
},
episode: {
weight: 0,
fields: {},
},
});
});

test('on list types', () => {
schema = buildSchema(`
type Planet{
droids(first: Int!): [Droid]!
heroDroids(first: Int!): [Droid!]
villainDroids(first: Int!):[Droid!]!
}
type Droid {
primaryFunction: String
}`);

expect(buildTypeWeightsFromSchema(schema)).toEqual({
planet: {
weight: 1,
fields: {
droids: {
resolveTo: 'droid',
weight: expect.any(Function),
},
heroDroids: {
resolveTo: 'droid',
weight: expect.any(Function),
},
villainDroids: {
resolveTo: 'droid',
weight: expect.any(Function),
},
},
},
droid: {
weight: 1,
fields: {
primaryFunction: {
weight: 0,
},
},
},
});
});
});

// TODO: Tests should be written to account for the additional scenarios possible in a schema
// Mutation type
// Input types (a part of mutations?)
Expand Down
14 changes: 14 additions & 0 deletions test/analysis/typeComplexityAnalysis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TypeWeightObject, Variables } from '../../src/@types/buildTypeWeights';
droid(id: ID!): Droid
human(id: ID!): Human
scalars: Scalars
nonNull: [Droid!]!
}

enum Episode {
Expand Down Expand Up @@ -100,6 +101,7 @@ import { TypeWeightObject, Variables } from '../../src/@types/buildTypeWeights';
const mockWeightFunction = jest.fn();
const mockHumanFriendsFunction = jest.fn();
const mockDroidFriendsFunction = jest.fn();
const nonNullMockWeightFunction = jest.fn();

// this object is created by the schema above for use in all the tests below
const typeWeights: TypeWeightObject = {
Expand Down Expand Up @@ -130,6 +132,10 @@ const typeWeights: TypeWeightObject = {
scalars: {
resolveTo: 'scalars',
},
nonNull: {
resolveTo: 'droid',
weight: nonNullMockWeightFunction,
},
},
},
episode: {
Expand Down Expand Up @@ -333,6 +339,14 @@ describe('Test getQueryTypeComplexity function', () => {
expect(mockWeightFunction.mock.calls[1].length).toBe(3); // calling with arguments and variables
});

test('with bounded lists including non-null operators', () => {
query = `query {nonNull(episode: EMPIRE, first: 3) { name, id } }`;
nonNullMockWeightFunction.mockReturnValueOnce(3);
expect(getQueryTypeComplexity(parse(query), {}, typeWeights)).toBe(4); // 1 Query + 3 reviews
expect(nonNullMockWeightFunction.mock.calls.length).toBe(1);
expect(nonNullMockWeightFunction.mock.calls[0].length).toBe(3);
});

describe('with nested lists', () => {
test('and simple nesting', () => {
query = `query { human(id: 1) { name, friends(first: 5) { name, friends(first: 3){ name }}}} `;
Expand Down
20 changes: 18 additions & 2 deletions test/analysis/weightFunction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ describe('Weight Function correctly parses Argument Nodes if', () => {
type Query {
reviews(episode: Episode!, first: Int = 5): [Review]
heroes(episode: Episode!, first: Int): [Review]
villains(episode: Episode!, limit: Int! = 3): [Review]
characters(episode: Episode!, limit: Int!): [Review]
villains(episode: Episode!, limit: Int! = 3): [Review]!
characters(episode: Episode!, limit: Int!): [Review!]
droids(episode: Episode!, limit: Int!): [Review!]!

}
type Review {
episode: Episode
Expand Down Expand Up @@ -82,6 +84,20 @@ describe('Weight Function correctly parses Argument Nodes if', () => {
});
});

xtest('the list is defined with non-null operators (!)', () => {
const villainsQuery = `query { villains(episode: NEWHOPE, limit: 3) { stars, episode } }`;
const willainsQueryAST: DocumentNode = parse(villainsQuery);
expect(getQueryTypeComplexity(willainsQueryAST, {}, typeWeights)).toBe(4);

const charQuery = `query { characters(episode: NEWHOPE, limit: 3) { stars, episode } }`;
const charQueryAST: DocumentNode = parse(charQuery);
expect(getQueryTypeComplexity(charQueryAST, {}, typeWeights)).toBe(4);

const droidsQuery = `droidsQuery { droids(episode: NEWHOPE, limit: 3) { stars, episode } }`;
const droidsQueryAST: DocumentNode = parse(droidsQuery);
expect(getQueryTypeComplexity(droidsQueryAST, {}, typeWeights)).toBe(4);
});

test('a custom object weight was configured', () => {
const customTypeWeights: TypeWeightObject = buildTypeWeightsFromSchema(schema, {
object: 3,
Expand Down