Skip to content

Commit

Permalink
coverage: provide overall statistics about coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
velias committed Jan 17, 2023
1 parent 7eb5e8d commit c08c811
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 35 deletions.
119 changes: 87 additions & 32 deletions example/coverage.json
Original file line number Diff line number Diff line change
@@ -1,71 +1,126 @@
{
"sources": [
{
"body": "query post {\n post {\n ... on Post {\n id\n title\n }\n createdAtSomePoint\n }\n}\n",
"name": "./documents/post.graphql",
"body": "query depthPost {\n post {\n id\n title @client\n author {\n id\n name\n }\n }\n}",
"name": "/home/velias/Devel/projects/github/graphql-inspector/example/documents/depth-post.graphql",
"locationOffset": {
"line": 1,
"column": 1
}
},
{
"body": "query post {\n post {\n ... on Post {\n id\n title\n }\n createdAtSomePoint\n }\n}",
"name": "/home/velias/Devel/projects/github/graphql-inspector/example/documents/post.graphql",
"locationOffset": {
"line": 1,
"column": 1
}
}
],
"types": {
"Query": {
"hits": 1,
"type": "Query",
"children": {
"post": {
"hits": 1,
"locations": {
"./documents/post.graphql": [
{
"start": 15,
"end": 93
}
]
}
},
"posts": {
"hits": 0,
"locations": {}
}
}
},
"Post": {
"hits": 2,
"hits": 4,
"fieldsCount": 4,
"fieldsCountCovered": 2,
"type": "Post",
"children": {
"id": {
"hits": 1,
"hits": 2,
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {
"./documents/post.graphql": [
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/depth-post.graphql": [
{
"start": 31,
"end": 33
}
],
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/post.graphql": [
{
"start": 46,
"end": 48
}
]
}
},
"children": {}
},
"title": {
"hits": 1,
"hits": 2,
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {
"./documents/post.graphql": [
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/depth-post.graphql": [
{
"start": 38,
"end": 51
}
],
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/post.graphql": [
{
"start": 55,
"end": 60
}
]
}
},
"children": {}
},
"createdAt": {
"hits": 0,
"locations": {}
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {},
"children": {}
},
"modifiedAt": {
"hits": 0,
"locations": {}
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {},
"children": {}
}
}
},
"Query": {
"hits": 2,
"fieldsCount": 2,
"fieldsCountCovered": 1,
"type": "Query",
"children": {
"post": {
"hits": 2,
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/depth-post.graphql": [
{
"start": 20,
"end": 94
}
],
"/home/velias/Devel/projects/github/graphql-inspector/example/documents/post.graphql": [
{
"start": 15,
"end": 93
}
]
},
"children": {}
},
"posts": {
"hits": 0,
"fieldsCount": 0,
"fieldsCountCovered": 0,
"locations": {},
"children": {}
}
}
}
},
"stats": {
"numTypes": 2,
"numTypesCoveredFully": 0,
"numTypesCovered": 2,
"numFields": 6,
"numFiledsCovered": 3
}
}
7 changes: 7 additions & 0 deletions packages/commands/coverage/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ function renderCoverage(coverage: SchemaCoverage) {
Logger.log(chalk.grey('}\n'));
}
}

Logger.log(`Types covered: ${((coverage.stats.numTypesCovered / coverage.stats.numTypes) * 100).toFixed(1)}%`);
Logger.log(
`Types covered fully: ${((coverage.stats.numTypesCoveredFully / coverage.stats.numTypes) * 100).toFixed(1)}%`
);
Logger.log(`Fields covered: ${((coverage.stats.numFiledsCovered / coverage.stats.numFields) * 100).toFixed(1)}%`);
Logger.log(``);
}

function indent(line: string, space: number): string {
Expand Down
10 changes: 9 additions & 1 deletion packages/core/__tests__/coverage/coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('coverage', () => {
type Query {
post: Post
posts: [Post!]
objectById(id: ID!): Identifiable
objectById(id: ID!, unused: String): Identifiable
}
type Mutation {
Expand Down Expand Up @@ -66,6 +66,7 @@ describe('coverage', () => {
expect(results.types.Query.children.post.hits).toEqual(1);
expect(results.types.Query.children.objectById.hits).toEqual(1);
expect(results.types.Query.children.objectById.children.id.hits).toEqual(1);
expect(results.types.Query.children.objectById.children.unused.hits).toEqual(0);
// Post
expect(results.types.Post.hits).toEqual(5);
expect(results.types.Post.children.id.hits).toEqual(2);
Expand All @@ -81,6 +82,13 @@ describe('coverage', () => {
expect(results.types.Mutation.children.submitPost.hits).toEqual(1);
expect(results.types.Mutation.children.submitPost.children.title.hits).toEqual(1);
expect(results.types.Mutation.children.submitPost.children.author.hits).toEqual(1);

// stats
expect(results.stats.numTypes).toEqual(4);
expect(results.stats.numTypesCovered).toEqual(4);
expect(results.stats.numTypesCoveredFully).toEqual(1);
expect(results.stats.numFields).toEqual(14);
expect(results.stats.numFiledsCovered).toEqual(10);
});

test('introspection', () => {
Expand Down
57 changes: 57 additions & 0 deletions packages/core/src/coverage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ export interface Location {

export interface ArgumentCoverage {
hits: number;
fieldsCount: number;
fieldsCountCovered: number;
locations: {
[name: string]: Array<Location>;
};
}

export interface TypeChildCoverage {
hits: number;
fieldsCount: number;
fieldsCountCovered: number;
locations: {
[name: string]: Array<Location>;
};
Expand All @@ -38,6 +42,8 @@ export interface TypeChildCoverage {

export interface TypeCoverage {
hits: number;
fieldsCount: number;
fieldsCountCovered: number;
type: GraphQLNamedType;
children: {
[name: string]: TypeChildCoverage;
Expand All @@ -49,6 +55,13 @@ export interface SchemaCoverage {
types: {
[typename: string]: TypeCoverage;
};
stats: {
numTypes: number;
numTypesCoveredFully: number;
numTypesCovered: number;
numFields: number;
numFiledsCovered: number;
};
}

export interface InvalidDocument {
Expand All @@ -60,6 +73,13 @@ export function coverage(schema: GraphQLSchema, sources: Source[]): SchemaCovera
const coverage: SchemaCoverage = {
sources,
types: {},
stats: {
numTypes: 0,
numTypesCoveredFully: 0,
numTypesCovered: 0,
numFields: 0,
numFiledsCovered: 0,
},
};
const typeMap = schema.getTypeMap();
const typeInfo = new TypeInfo(schema);
Expand Down Expand Up @@ -114,6 +134,8 @@ export function coverage(schema: GraphQLSchema, sources: Source[]): SchemaCovera
if (isObjectType(type) || isInterfaceType(type)) {
const typeCoverage: TypeCoverage = {
hits: 0,
fieldsCount: 0,
fieldsCountCovered: 0,
type,
children: {},
};
Expand All @@ -124,13 +146,17 @@ export function coverage(schema: GraphQLSchema, sources: Source[]): SchemaCovera

typeCoverage.children[field.name] = {
hits: 0,
fieldsCount: 0,
fieldsCountCovered: 0,
locations: {},
children: {},
};

for (const arg of field.args) {
typeCoverage.children[field.name].children[arg.name] = {
hits: 0,
fieldsCount: 0,
fieldsCountCovered: 0,
locations: {},
};
}
Expand All @@ -153,5 +179,36 @@ export function coverage(schema: GraphQLSchema, sources: Source[]): SchemaCovera
});
});

for (const key in coverage.types) {
const me = coverage.types[key];
processStats(me);

coverage.stats.numTypes++;
if (me.fieldsCountCovered > 0) coverage.stats.numTypesCovered++;
if (me.fieldsCount == me.fieldsCountCovered) coverage.stats.numTypesCoveredFully++;
coverage.stats.numFields += me.fieldsCount;
coverage.stats.numFiledsCovered += me.fieldsCountCovered;
}

return coverage;
}

function processStats(me: TypeCoverage | TypeChildCoverage) {
const children = me.children;
if (children) {
for (const k in children) {
const ch = children[k];

if ((ch as TypeChildCoverage).children !== undefined) {
processStats(ch as TypeChildCoverage);
me.fieldsCount += ch.fieldsCount;
me.fieldsCountCovered += ch.fieldsCountCovered;
}

me.fieldsCount++;
if (ch.hits > 0) {
me.fieldsCountCovered++;
}
}
}
}
4 changes: 2 additions & 2 deletions website/src/pages/docs/essentials/coverage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ graphql-inspector coverage DOCUMENTS SCHEMA

### Output

Depending on enabled flags, a printed GraphQL Schema with stats per each field and a JSON file with
data.
Depending on enabled flags, a printed GraphQL Schema with stats per each field and overall stats,
a JSON file with data.

0 comments on commit c08c811

Please sign in to comment.