Skip to content

Commit

Permalink
poc object type mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Jomik committed Feb 12, 2022
1 parent e547f6d commit 04e70a3
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 16 deletions.
8 changes: 6 additions & 2 deletions packages/deno/packages/plugin-mocks/global-types.ts

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

5 changes: 4 additions & 1 deletion packages/deno/packages/plugin-mocks/types.ts

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

17 changes: 15 additions & 2 deletions packages/plugin-mocks/src/global-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SchemaTypes } from '@pothos/core';
import { ResolverMap } from './types';
import { ObjectParam, Resolver, SchemaTypes, ShapeFromTypeParam } from '@pothos/core';
import { Mock, ResolverMap } from './types';
import { MocksPlugin } from '.';

declare global {
Expand All @@ -10,6 +10,19 @@ declare global {

export interface BuildSchemaOptions<Types extends SchemaTypes> {
mocks?: ResolverMap<Types>;
typeMocks?: Mock<Types>[];
}

export interface SchemaBuilder<Types extends SchemaTypes> {
createObjectMock: <
Shape extends NameOrRef extends ObjectParam<Types>
? ShapeFromTypeParam<Types, NameOrRef, false>
: object,
NameOrRef extends ObjectParam<Types> | string,
>(
nameOrRef: NameOrRef,
resolver: Resolver<unknown, unknown, Types['Context'], Partial<Shape>>,
) => Mock<Types>;
}
}
}
60 changes: 49 additions & 11 deletions packages/plugin-mocks/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import './global-types';
import './schema-builder';
import { GraphQLFieldResolver } from 'graphql';
import SchemaBuilder, { BasePlugin, PothosOutputFieldConfig, SchemaTypes } from '@pothos/core';
import { ResolverMap } from './types';
import SchemaBuilder, {
BasePlugin,
PothosOutputFieldConfig,
PothosOutputFieldType,
Resolver,
SchemaTypes,
} from '@pothos/core';
import { Mock, ResolverMap } from './types';

const pluginName = 'mocks' as const;

Expand All @@ -11,13 +18,14 @@ export class MocksPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
resolver: GraphQLFieldResolver<unknown, Types['Context'], object>,
fieldConfig: PothosOutputFieldConfig<Types>,
): GraphQLFieldResolver<unknown, Types['Context'], object> {
const { mocks } = this.options;
const { mocks, typeMocks = [] } = this.options;
const { parentType: typeName, name: fieldName, type: outputType } = fieldConfig;

if (!mocks) {
return resolver;
}

const resolveMock = this.resolveMock(fieldConfig.parentType, fieldConfig.name, mocks);
const resolveMock = this.resolveMock(typeName, fieldName, outputType, mocks, typeMocks);

return resolveMock ?? resolver;
}
Expand All @@ -37,18 +45,48 @@ export class MocksPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
return subscribeMock ?? subscribe;
}

resolveMock(typename: string, fieldName: string, mocks: ResolverMap<Types>) {
const fieldMock = mocks[typename]?.[fieldName] || null;
resolveMock(
typeName: string,
fieldName: string,
outputType: PothosOutputFieldType<Types>,
mocks: ResolverMap<Types>,
typeMocks: Mock<Types>[],
): Resolver<unknown, {}, Types['Context'], unknown> | null {
const fieldMock = mocks[typeName]?.[fieldName] || null;

if (fieldMock) {
if (typeof fieldMock === 'function') {
return fieldMock;
}

return fieldMock.resolve ?? null;
}

if (!fieldMock) {
return null;
if (outputType.kind === 'Object') {
const outputName = (outputType.ref as { name: string }).name;
const mock = typeMocks.find((v) => v.name === outputName);

return mock?.resolver ?? null;
}

if (typeof fieldMock === 'function') {
return fieldMock;
if (outputType.kind === 'Interface') {
const outputName = (outputType.ref as { name: string }).name;
const implementers = this.builder.configStore
.getImplementers(outputName)
.map((implementer) => implementer.name);
const mock = typeMocks.find((v) => implementers.includes(v.name));

return mock?.resolver ?? null;
}

if (outputType.kind === 'List') {
const result = this.resolveMock(typeName, fieldName, outputType.type, mocks, typeMocks);
if (result) {
return (...args) => [result(...args)];
}
}

return fieldMock.resolve || null;
return null;
}

subscribeMock(typename: string, fieldName: string, mocks: ResolverMap<Types>) {
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-mocks/src/schema-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import SchemaBuilder, { SchemaTypes } from '@pothos/core';

const schemaBuilderProto = SchemaBuilder.prototype as PothosSchemaTypes.SchemaBuilder<SchemaTypes>;

schemaBuilderProto.createObjectMock = function createMock(nameOrRef, resolver) {
const name = typeof nameOrRef === 'string' ? nameOrRef : (nameOrRef as { name: string }).name;

return {
name,
resolver: resolver as never,
};
};
5 changes: 5 additions & 0 deletions packages/plugin-mocks/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ export type Resolvers<Types extends SchemaTypes, Parent> = Record<
>;

export type ResolverMap<Types extends SchemaTypes> = Record<string, Resolvers<Types, unknown>>;

export interface Mock<Types extends SchemaTypes> {
name: string;
resolver: Resolver<unknown, unknown, Types['Context'], unknown>;
}
25 changes: 25 additions & 0 deletions packages/plugin-mocks/tests/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,28 @@ Object {
},
}
`;

exports[`mocked type mocks queries lists 1`] = `
Object {
"data": Object {
"r2d2": Object {
"friends": Array [
Object {
"name": "C-3PO",
},
],
"name": "C-3PO",
},
},
}
`;

exports[`mocked type mocks queries stuff 1`] = `
Object {
"data": Object {
"r2d2": Object {
"name": "C-3PO",
},
},
}
`;
59 changes: 59 additions & 0 deletions packages/plugin-mocks/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,63 @@ describe('mocked', () => {

expect(result).toMatchSnapshot();
});

describe('type mocks', () => {
it('queries stuff', async () => {
const DroidMock = builder.createObjectMock('Droid', () => ({
name: 'C-3PO',
}));
const mockedSchema = builder.toSchema({
mocks: {},
typeMocks: [DroidMock],
});

const query = gql`
query {
r2d2 {
name
}
}
`;

const result = await execute({
schema: mockedSchema,
document: query,
contextValue: {},
});

expect(result).toMatchSnapshot();
});

it('queries lists', async () => {
const DroidMock = builder.createObjectMock('Droid', () => ({
type: 'Droid' as const,
name: 'C-3PO',
friends: ['1002', '1003'],
}));
const mockedSchema = builder.toSchema({
mocks: {},
typeMocks: [DroidMock],
});

const query = gql`
query {
r2d2 {
name
friends {
name
}
}
}
`;

const result = await execute({
schema: mockedSchema,
document: query,
contextValue: {},
});

expect(result).toMatchSnapshot();
});
});
});

0 comments on commit 04e70a3

Please sign in to comment.