Skip to content

Commit

Permalink
Fix Jest snapshot indentation for graphql-js AST
Browse files Browse the repository at this point in the history
We need to re-indent the lines printed from `graphql-js` in `astSerializer`, because Jest has started to ignore indentation when diffing snapshots, and it does this by invoking snapshot serializers with these values set to 0.

Without re-indenting, every line printed from `graphql-js` would be shown as changed. See jestjs/jest#9203.
  • Loading branch information
martijnwalraven committed Feb 4, 2021
1 parent 68ef9d6 commit 2cb7276
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,57 @@
import { ASTNode, print, Kind, visit } from 'graphql';
import { Plugin, Config, Refs } from 'pretty-format';
import { QueryPlanSelectionNode, QueryPlanInlineFragmentNode } from '@apollo/gateway';
import { SelectionNode as GraphQLJSSelectionNode } from 'graphql';
import { QueryPlanInlineFragmentNode, QueryPlanSelectionNode } from '@apollo/gateway';
import { ASTNode, Kind, print, SelectionNode as GraphQLJSSelectionNode, visit } from 'graphql';
import { Config, NewPlugin, Refs } from 'pretty-format';

export default {
test(value: any) {
// Note that this isn't a reliable test because other objects may also have a `kind` property
// (like query plans!).
// `graphql-js` does have an unexported `isNode` function, but that currently performs the same check
// and doesn't check whether `kind` represents a valid AST node either:
// https://github.com/graphql/graphql-js/blob/998bea680d6e11e1c055a400a887a9539de08f75/src/language/ast.js#L135-L137
// Perhaps we should attempt to contribute an improved `isNode` function.
return value && typeof value.kind === 'string';
},

serialize(
value: ASTNode,
_config: Config,
config: Config,
indentation: string,
_depth: number,
_refs: Refs,
_printer: any,
): string {
return print(remapInlineFragmentNodes(value))
.trim()
.replace(/\n/g, '\n' + indentation);
const lines = print(remapInlineFragmentNodes(value)).trim().split('\n');

// Avoid adding newlines for single line results.
if (lines.length === 0) {
return '';
} else if (lines.length === 1) {
return lines[0];
}

return lines.map(line => {
// We re-indent the lines printed from `graphql-js` to respect the passed in `indentation`
// and`config.indent` values.
// This is important because Jest has started to ignore indentation when diffing snapshots,
// and it does this by invoking snapshot serializers with these values set to 0.
// Without re-indenting, every line printed from `graphql-js` would be shown as changed.
// See https://github.com/facebook/jest/pull/9203
const indentationLength = getIndentationLength(line);
const dedentedLine = line.slice(indentationLength);
// `graphql-js` always indents with 2 spaces
const indentationDepth = indentationLength / 2;

return indentation + config.indent.repeat(indentationDepth) + dedentedLine;
}).join(config.spacingOuter);
},
} as Plugin;
} as NewPlugin;

// From https://github.com/facebook/jest/blob/32aaff83f02c347ccd591727544002490fb4ee9a/packages/jest-snapshot/src/dedentLines.ts#L8
function getIndentationLength(line: string): number {
const result = /^( {2})+/.exec(line);
return result === null ? 0 : result[0].length;
};

/**
* This function converts potential InlineFragmentNodes that WE created
Expand Down Expand Up @@ -78,7 +109,7 @@ export function remapInlineFragmentNodes(node: ASTNode): ASTNode {

function remapSelections(
selections: QueryPlanSelectionNode[],
): ReadonlyArray<GraphQLJSSelectionNode> {
): readonly GraphQLJSSelectionNode[] {
return selections.map((selection) => {
switch (selection.kind) {
case Kind.FIELD:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ function printNode(
`Fetch(service: "${node.serviceName}")` +
' {' +
config.spacingOuter +
indentationNext +
(node.requires
? printer(
// this is an array of selections, so we need to make it a proper
Expand All @@ -61,8 +60,7 @@ function printNode(
printer,
) +
' =>' +
config.spacingOuter +
indentationNext
config.spacingOuter
: '') +
printer(
flattenEntitiesField(parse(node.operation)),
Expand Down

0 comments on commit 2cb7276

Please sign in to comment.