Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
## Upcoming

- `apollo`
- Improve performance of CLI when running projects by delaying or not calling validation [#1559](https://github.com/apollographql/apollo-tooling/pull/1559)
Comment thread
JakeDawkins marked this conversation as resolved.
Outdated
- Use "table" package for tabular output and word wrap support [#1524](https://github.com/apollographql/apollo-tooling/pull/1524)
- Use new single step mutation for checking federated service schemas [#1539](https://github.com/apollographql/apollo-tooling/pull/1539)
- Add support for `localSchemaFile` for federated service commands [#1489](https://github.com/apollographql/apollo-tooling/pull/1489)
- `apollo-codegen-core`
- <First `apollo-codegen-core` related entry goes here>
- Improve performance of validation when client fields are present or not [#1559](https://github.com/apollographql/apollo-tooling/pull/1559)
- `apollo-codegen-flow`
- <First `apollo-codegen-flow` related entry goes here>
- `apollo-codegen-scala`
Expand All @@ -28,7 +29,7 @@
- `apollo-tools`
- <First `apollo-tools` related entry goes here>
- `vscode-apollo`
- <First `vscode-apollo` related entry goes here>
- Improve performance of validation when client fields are present or not [#1559](https://github.com/apollographql/apollo-tooling/pull/1559)

## `apollo@2.18.3`

Expand Down
3 changes: 3 additions & 0 deletions packages/apollo-language-server/__mocks__/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { fs } from "memfs";

module.exports = fs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import { NoMissingClientDirectives } from "../validation";
import { GraphQLClientProject } from "../../project/client";
import { readFileSync } from "fs";
import { basename } from "path";

import { vol } from "memfs";
import { LoadingHandler } from "../../loadingHandler";
import { ApolloConfig, ClientConfig } from "../../config";
import URI from "vscode-uri";

const serviceSchema = /* GraphQL */ `
type Query {
me: User
}

type User {
name: String
friends: [User]
}
`;
const clientSchema = /* GraphQL */ `
extend type Query {
isOnline: Boolean
}
extend type User {
isLiked: Boolean
localUser: User
}
`;
const a = /* GraphQL */ `
query a {
isOnline
me {
name
localUser @client {
friends {
isLiked
}
}
friends {
name
isLiked
}
}
}
`;

const b = /* GraphQL */ `
query b {
me {
... {
isLiked
}
... @client {
localUser {
name
}
}
}
}
`;

const c = /* GraphQL */ `
query c {
me {
...isLiked
}
}
fragment localUser on User @client {
localUser {
name
}
}
fragment isLiked on User {
isLiked
...localUser
}
`;

const d = /* GraphQL */ `
fragment isLiked on User {
isLiked
}
query d {
me {
...isLiked
...locaUser
}
}
fragment localUser on User @client {
localUser {
name
}
}
`;

const e = /* GraphQL */ `
fragment friends on User {
friends {
...isLiked
... on User @client {
localUser {
name
}
}
}
}
query e {
isOnline @client
me {
...friends
}
}
fragment isLiked on User {
isLiked
}
`;

// TODO support inline fragment spreads
const f = /* GraphQL */ `
query f {
me {
...isLiked @client
}
}
fragment isLiked on User {
isLiked
}
`;

const rootURI = URI.file(process.cwd());

const config = new ApolloConfig({
client: {
service: {
name: "server",
localSchemaFile: "./schema.graphql"
},
includes: ["./src/**.graphql"],
excludes: ["./__tests__"],
validationRules: [NoMissingClientDirectives]
},
engine: {}
}) as ClientConfig;

class MockLoadingHandler implements LoadingHandler {
handle<T>(_message: string, value: Promise<T>): Promise<T> {
return value;
}
handleSync<T>(_message: string, value: () => T): T {
return value();
}
showError(_message: string): void {}
}

jest.mock("fs");

describe("client state", () => {
beforeEach(() => {
vol.fromJSON({
"apollo.config.js": `module.exports = {
client: {
service: {
localSchemaFile: './schema.graphql'
}
}
}`,
"schema.graphql": serviceSchema,
"src/client-schema.graphql": clientSchema,
"src/a.graphql": a,
"src/b.graphql": b,
"src/c.graphql": c,
"src/d.graphql": d,
"src/e.graphql": e
// "src/f.graphql": f,
});
});
afterEach(jest.restoreAllMocks);

it("should report validation errors for missing @client directives", async () => {
const project = new GraphQLClientProject({
config,
loadingHandler: new MockLoadingHandler(),
rootURI
});

const errors = Object.create(null);
project.onDiagnostics(({ diagnostics, uri }) => {
const path = basename(URI.parse(uri).path);
diagnostics.forEach(({ error }: any) => {
if (!errors[path]) errors[path] = [];
errors[path].push(error);
});
});

await project.whenReady;
await project.validate();

expect(errors).toMatchInlineSnapshot(`
Object {
"a.graphql": Array [
[GraphQLError: @client directive is missing on local field "isOnline"],
[GraphQLError: @client directive is missing on local field "isLiked"],
],
"b.graphql": Array [
[GraphQLError: @client directive is missing on fragment around local fields "isLiked"],
],
"c.graphql": Array [
[GraphQLError: @client directive is missing on fragment "isLiked" around local fields "isLiked,localUser"],
],
"d.graphql": Array [
[GraphQLError: @client directive is missing on fragment "isLiked" around local fields "isLiked"],
],
"e.graphql": Array [
[GraphQLError: @client directive is missing on fragment "isLiked" around local fields "isLiked"],
],
}
`);
});
});
Loading