Skip to content

Commit

Permalink
feat: introduce schema proxy, copy graphql-tools/utils fns and licens…
Browse files Browse the repository at this point in the history
…e into separate folder
  • Loading branch information
alessbell committed Mar 20, 2024
1 parent b9b4263 commit d3d0ed9
Show file tree
Hide file tree
Showing 7 changed files with 599 additions and 3 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"@changesets/changelog-github": "0.5.0",
"@changesets/cli": "2.27.1",
"@graphql-tools/schema": "10.0.3",
"@graphql-tools/utils": "10.0.13",
"@microsoft/api-extractor": "7.42.3",
"@rollup/plugin-node-resolve": "11.2.1",
"@size-limit/esbuild-why": "11.1.1",
Expand Down
Empty file.
36 changes: 36 additions & 0 deletions src/testing/core/schemaProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { addResolversToSchema } from "@graphql-tools/schema";
import type { GraphQLSchema } from "graphql";
import type { Resolvers } from "../../core/types.js";

const proxiedSchema = (
schemaWithMocks: GraphQLSchema,
resolvers: Resolvers
) => {
let targetSchema = addResolversToSchema({
schema: schemaWithMocks,
resolvers,
});

const schema = new Proxy(targetSchema, {
get(target, p) {
if (p === "use") {
return (newResolvers: typeof resolvers) =>
(targetSchema = addResolversToSchema({
schema: schemaWithMocks,
resolvers: {
...resolvers,
...newResolvers,
},
}));
}
if (typeof targetSchema[p] === "function") {
return targetSchema[p].bind(targetSchema);
}
return Reflect.get(target, p);
},
});

return schema;
};

export { proxiedSchema };
21 changes: 21 additions & 0 deletions src/testing/graphql-tools/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 The Guild, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
307 changes: 307 additions & 0 deletions src/testing/graphql-tools/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
// Originally from @graphql-tools/mock
// https://github.com/ardatan/graphql-tools/blob/4b56b04d69b02919f6c5fa4f97d33da63f36e8c8/packages/mock/tests/addMocksToSchema.spec.ts

import { buildSchema, graphql } from "graphql";
import { createMockSchema } from "./utils.js";

const mockDate = new Date().toJSON().split("T")[0];

const mocks = {
Int: () => 6,
Float: () => 22.1,
String: () => "string",
ID: () => "id",
Date: () => mockDate,
};

const typeDefs = /* GraphQL */ `
type User {
id: ID!
age: Int!
name: String!
image: UserImage!
book: Book!
}
type Author {
_id: ID!
name: String!
book: Book!
}
union UserImage = UserImageSolidColor | UserImageURL
type UserImageSolidColor {
color: String!
}
type UserImageURL {
url: String!
}
scalar Date
interface Book {
id: ID!
title: String
publishedAt: Date
}
type TextBook implements Book {
id: ID!
title: String
publishedAt: Date
text: String
}
type ColoringBook implements Book {
id: ID!
title: String
publishedAt: Date
colors: [String]
}
type Query {
viewer: User!
userById(id: ID!): User!
author: Author!
}
type Mutation {
changeViewerName(newName: String!): User!
}
`;

const schema = buildSchema(typeDefs);

describe("addMocksToSchema", () => {
it("basic", async () => {
const query = /* GraphQL */ `
query {
viewer {
id
name
age
}
}
`;

const mockedSchema = createMockSchema(schema, mocks);

const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).not.toBeDefined();
expect(data).toBeDefined();

const viewerData = data?.["viewer"] as any;
expect(typeof viewerData["id"]).toBe("string");
expect(typeof viewerData["name"]).toBe("string");
expect(typeof viewerData["age"]).toBe("number");

const { data: data2 } = await graphql({
schema: mockedSchema,
source: query,
});

const viewerData2 = data2?.["viewer"] as any;

expect(viewerData2["id"]).toEqual(viewerData["id"]);
});

it("handle _id key field", async () => {
const query = /* GraphQL */ `
query {
author {
_id
name
}
}
`;
const mockedSchema = createMockSchema(schema, mocks);
const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).not.toBeDefined();
expect(data).toBeDefined();
const viewerData = data?.["author"] as any;
expect(typeof viewerData["_id"]).toBe("string");
expect(typeof viewerData["name"]).toBe("string");

const { data: data2 } = await graphql({
schema: mockedSchema,
source: query,
});

const viewerData2 = data2?.["author"] as any;

expect(viewerData2["_id"]).toEqual(viewerData["_id"]);
});

it("should handle union type", async () => {
const query = /* GraphQL */ `
query {
viewer {
image {
__typename
... on UserImageURL {
url
}
... on UserImageSolidColor {
color
}
}
}
}
`;

const mockedSchema = createMockSchema(schema, mocks);

const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).not.toBeDefined();
expect(data).toBeDefined();
expect((data!["viewer"] as any)["image"]["__typename"]).toBeDefined();
});

it("should handle interface type", async () => {
const query = /* GraphQL */ `
query {
viewer {
book {
title
__typename
... on TextBook {
text
}
... on ColoringBook {
colors
}
}
}
}
`;

const mockedSchema = createMockSchema(schema, mocks);

const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).not.toBeDefined();
expect(data).toBeDefined();
expect((data!["viewer"] as any)["book"]["__typename"]).toBeDefined();
});

it("should handle custom scalars", async () => {
const query = /* GraphQL */ `
query {
viewer {
book {
title
publishedAt
}
}
}
`;

const mockedSchema = createMockSchema(schema, mocks);

const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).not.toBeDefined();
expect(data).toBeDefined();
expect((data!["viewer"] as any)["book"]["publishedAt"]).toBe(mockDate);
});

it.skip("should handle null fields correctly", async () => {
const schema = buildSchema(/* GraphQL */ `
type Query {
foo: Foo
}
type Foo {
field1: String
field2: Int
}
`);

const mockedSchema = createMockSchema(schema, {
Foo: () => ({
field1: "text",
field2: null,
}),
});

const query = /* GraphQL */ `
{
foo {
field1
field2
}
}
`;
const { data } = await graphql({
schema: mockedSchema,
source: query,
});

const fooData = data?.["foo"] as any;
expect(fooData.field1).toBe("text");
expect(fooData.field2).toBe(null);
});

it.skip("should handle null fields correctly in nested fields", async () => {
const schema = buildSchema(/* GraphQL */ `
type Query {
foo: Foo
}
type Foo {
foo_field: String
boo: Boo
}
type Boo {
boo_field: String
}
`);

const mockedSchema = createMockSchema(schema, {
// TODO: should we allow mocking of concrete types?
Foo: () => ({
foo_field: "text",
boo: null,
}),
});

const query = /* GraphQL */ `
{
foo {
foo_field
boo {
boo_field
}
}
}
`;
const { data, errors } = await graphql({
schema: mockedSchema,
source: query,
});

expect(errors).toBeFalsy();

const fooData = data?.["foo"] as any;
expect(fooData.foo_field).toBe("text");
expect(fooData.boo).toBe(null);
});
});
Loading

0 comments on commit d3d0ed9

Please sign in to comment.