Skip to content

Commit

Permalink
Command-level unit tests for codegen (#464)
Browse files Browse the repository at this point in the history
* Command-level unit tests for codegen

* Add unit tests for additional targets

* Reset volume before each unit test

* Add unit tests for JSON target

* Increase Jest timeout

* Add unit test for schema downloading

* Increase Jest timeout for check/publish tests
  • Loading branch information
shadaj committed Jun 30, 2018
1 parent 77fc89e commit 7d99a31
Show file tree
Hide file tree
Showing 18 changed files with 7,599 additions and 891 deletions.
8,031 changes: 7,150 additions & 881 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/apollo-cli/@types/fs-monkey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "fs-monkey";
1 change: 1 addition & 0 deletions packages/apollo-cli/@types/memfs.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "memfs";
6 changes: 4 additions & 2 deletions packages/apollo-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"env-ci": "^2.1.0",
"git-parse": "^1.0.3",
"git-rev-sync": "^1.12.0",
"globby": "^8.0.1",
"glob": "^7.1.2",
"graphql": "^0.13.1",
"graphql-tag": "^2.9.2",
"heroku-cli-util": "^8.0.9",
Expand Down Expand Up @@ -64,7 +64,9 @@
"ts-jest": "^22.4.6",
"ts-node": "^5.0.1",
"tslib": "^1.9.0",
"typescript": "^2.8.3"
"typescript": "^2.8.3",
"memfs": "^2.9.1",
"fs-monkey": "^0.3.3"
},
"precommit": "pretty-quick --staged",
"engines": {
Expand Down
12 changes: 12 additions & 0 deletions packages/apollo-cli/src/__mocks__/localfs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {Volume, createFsFromVolume} from 'memfs';
import {patchFs} from 'fs-monkey';

export const vol = Volume.fromJSON({});
export const fs = createFsFromVolume(vol);

export function withGlobalFS<T>(thunk: () => T): T {
const unpatch = patchFs(vol);
const ret = thunk();
unpatch();
return ret;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`successful codegen infers Flow target and writes types 1`] = `
"
/* @flow */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: SimpleQuery
// ====================================================
export type SimpleQuery = {
hello: string
};
/* @flow */
/* eslint-disable */
// This file was automatically generated and should not be edited.
//==============================================================
// START Enums and Input Objects
//==============================================================
//==============================================================
// END Enums and Input Objects
//=============================================================="
`;

exports[`successful codegen infers JSON target and writes operations 1`] = `
"{
\\"operations\\": [
{
\\"filePath\\": \\"queryOne.graphql\\",
\\"operationName\\": \\"SimpleQuery\\",
\\"operationType\\": \\"query\\",
\\"rootType\\": \\"Query\\",
\\"variables\\": [],
\\"source\\": \\"query SimpleQuery {\\\\n hello\\\\n}\\",
\\"fields\\": [
{
\\"responseName\\": \\"hello\\",
\\"fieldName\\": \\"hello\\",
\\"type\\": \\"String!\\",
\\"isConditional\\": false,
\\"isDeprecated\\": false
}
],
\\"fragmentSpreads\\": [],
\\"inlineFragments\\": [],
\\"fragmentsReferenced\\": [],
\\"sourceWithFragments\\": \\"query SimpleQuery {\\\\n hello\\\\n}\\",
\\"operationId\\": \\"4de1e386589b0853a102a87a3f21ca25266116517e59c1e8be9442e2571f00bc\\"
}
],
\\"fragments\\": [],
\\"typesUsed\\": []
}"
`;

exports[`successful codegen infers Scala target and writes types 1`] = `
"// This file was automatically generated and should not be edited.
object SimpleQueryQuery extends com.apollographql.scalajs.GraphQLQuery {
val operationString =
\\"query SimpleQuery {\\" +
\\" hello\\" +
\\"}\\"
val operation = com.apollographql.scalajs.gql(operationString)
type Variables = Unit
case class Data(hello: String) {
}
object Data {
val possibleTypes = scala.collection.Set(\\"Query\\")
}
}"
`;

exports[`successful codegen infers Swift target and writes types 1`] = `
"// This file was automatically generated and should not be edited.
import Apollo
public final class SimpleQueryQuery: GraphQLQuery {
public let operationDefinition =
\\"query SimpleQuery {\\\\n hello\\\\n}\\"
public init() {
}
public struct Data: GraphQLSelectionSet {
public static let possibleTypes = [\\"Query\\"]
public static let selections: [GraphQLSelection] = [
GraphQLField(\\"hello\\", type: .nonNull(.scalar(String.self))),
]
public private(set) var resultMap: ResultMap
public init(unsafeResultMap: ResultMap) {
self.resultMap = unsafeResultMap
}
public init(hello: String) {
self.init(unsafeResultMap: [\\"__typename\\": \\"Query\\", \\"hello\\": hello])
}
public var hello: String {
get {
return resultMap[\\"hello\\"]! as! String
}
set {
resultMap.updateValue(newValue, forKey: \\"hello\\")
}
}
}
}"
`;

exports[`successful codegen infers TypeScript target and writes types 1`] = `
"
/* tslint:disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: SimpleQuery
// ====================================================
export interface SimpleQuery {
hello: string;
}
/* tslint:disable */
// This file was automatically generated and should not be edited.
//==============================================================
// START Enums and Input Objects
//==============================================================
//==============================================================
// END Enums and Input Objects
//=============================================================="
`;

exports[`successful codegen writes Flow types next to sources when no output is set 1`] = `
"
/* @flow */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: SimpleQuery
// ====================================================
export type SimpleQuery = {
hello: string
};
/* @flow */
/* eslint-disable */
// This file was automatically generated and should not be edited.
//==============================================================
// START Enums and Input Objects
//==============================================================
//==============================================================
// END Enums and Input Objects
//=============================================================="
`;

exports[`successful codegen writes TypeScript types next to sources when no output is set 1`] = `
"
/* tslint:disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: SimpleQuery
// ====================================================
export interface SimpleQuery {
hello: string;
}
/* tslint:disable */
// This file was automatically generated and should not be edited.
//==============================================================
// START Enums and Input Objects
//==============================================================
//==============================================================
// END Enums and Input Objects
//=============================================================="
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
query SimpleQuery {
hello
}
146 changes: 146 additions & 0 deletions packages/apollo-cli/src/commands/codegen/__tests__/generate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
jest.mock(
"apollo-codegen-core/lib/localfs",
() => {
return require("../../../__mocks__/localfs");
}
);

// this is because of herkou-cli-utils hacky mocking system on their console logger
import { stdout, mockConsole } from "heroku-cli-util";
import * as path from "path";
import * as fs from "fs";
import { test as setup } from "apollo-cli-test";
import { introspectionQuery, print, execute, buildSchema } from "graphql";
import gql from "graphql-tag";
import { fs as mockFS, vol } from "apollo-codegen-core/lib/localfs";

const test = setup.do(() => mockConsole());
const fullSchema = execute(
buildSchema(
fs.readFileSync(path.resolve(__dirname, "../../schema/__tests__/fixtures/schema.graphql"), {
encoding: "utf-8",
})
),
gql(introspectionQuery)
).data;

const simpleQuery = fs.readFileSync(path.resolve(__dirname, "./fixtures/simpleQuery.graphql"));

beforeEach(() => {
vol.reset();
vol.fromJSON({
"__blankFileSoDirectoryExists": ""
});
})

jest.setTimeout(15000);

describe("successful codegen", () => {
test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"queryOne.graphql": simpleQuery.toString()
});
})
.command(["codegen:generate", "--schema=schema.json", "API.swift"])
.it("infers Swift target and writes types", () => {
expect(mockFS.readFileSync("API.swift").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"queryOne.graphql": simpleQuery.toString()
});
})
.command(["codegen:generate", "--schema=schema.json", "API.scala"])
.it("infers Scala target and writes types", () => {
expect(mockFS.readFileSync("API.scala").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"queryOne.graphql": simpleQuery.toString()
});
})
.command(["codegen:generate", "--schema=schema.json", "API.ts"])
.it("infers TypeScript target and writes types", () => {
expect(mockFS.readFileSync("API.ts").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"queryOne.graphql": simpleQuery.toString()
});
})
.command(["codegen:generate", "--schema=schema.json", "API.js"])
.it("infers Flow target and writes types", () => {
expect(mockFS.readFileSync("API.js").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"queryOne.graphql": simpleQuery.toString()
});
})
.command(["codegen:generate", "--schema=schema.json", "operations.json"])
.it("infers JSON target and writes operations", () => {
expect(mockFS.readFileSync("operations.json").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"directory/component.tsx": `
gql\`
query SimpleQuery {
hello
}
\`;
`
});
})
.command(["codegen:generate", "--schema=schema.json", "--queries=**/*.tsx", "--target=typescript"])
.it("writes TypeScript types next to sources when no output is set", () => {
expect(mockFS.readFileSync("directory/SimpleQuery.ts").toString()).toMatchSnapshot();
});

test
.do(() => {
vol.fromJSON({
"schema.json": JSON.stringify(fullSchema.__schema),
"directory/component.jsx": `
gql\`
query SimpleQuery {
hello
}
\`;
`
});
})
.command(["codegen:generate", "--schema=schema.json", "--queries=**/*.jsx", "--target=flow"])
.it("writes Flow types next to sources when no output is set", () => {
expect(mockFS.readFileSync("directory/SimpleQuery.js").toString()).toMatchSnapshot();
});
});

describe("error handling", () => {
test
.command(["codegen:generate", "--target=foobar"])
.catch(err => expect(err.message).toMatch(/Unsupported target: foobar/))
.it("errors with an unsupported target");

test
.command(["codegen:generate", "--target=swift"])
.catch(err => expect(err.message).toMatch(/The output path must be specified/))
.it("errors when no output file is provided");
});
Loading

0 comments on commit 7d99a31

Please sign in to comment.