GraphQL mocking utilities for NestJS with decorator-based mock data generation
npm install @duestel/graphql-mockDecorator-based GraphQL mocking for NestJS. Generate realistic mock data for your resolvers.
``bash`
npm install @duestel/graphql-mock
1. Import the module
`typescript
import { GqlMockModule } from "@duestel/graphql-mock";
@Module({
imports: [GraphQLModule.forRoot({ ... }), GqlMockModule],
})
export class AppModule {}
`
2. Define models with @Mock
`typescript
import { Mock, MockHelpers } from "@duestel/graphql-mock";
import { randPhrase, randParagraph } from "@ngneat/falso";
// Base post
@ObjectType()
export class Post {
@Mock(() => randPhrase())
@Field()
title: string;
@Mock(() => randParagraph())
@Field()
content: string;
@Mock(MockHelpers.enum(PostType))
@Field(() => PostType)
type: PostType;
}
// Post subtypes for unions
@ObjectType()
export class MediaPost extends Post {
@Mock(() => PostType.MEDIA)
declare type: PostType.MEDIA;
@Mock(MockHelpers.relationMany(() => Media, { count: 3 }))
@Field(() => [Media])
media: Media[];
}
@ObjectType()
export class TextPost extends Post {
@Mock(() => PostType.TEXT)
declare type: PostType.TEXT;
}
`
3. Add @MockQuery to resolvers
`typescript
@Resolver(() => Post)
export class PostResolver {
// Simple list
@MockQuery(() => Post, { count: 10 })
@Query(() => [Post])
posts() { ... }
// Union types - randomly picks MediaPost or TextPost
@MockQuery(MockQueryHelpers.union(MediaPost, TextPost), { count: 10 })
@Query(() => [PostUnion])
feed() { ... }
// By ID with consistent ID matching
@MockQueryWithStore((store, { id }) => store.get("Post", id))
@Query(() => Post)
post(@Args("id") id: string) { ... }
}
`
4. Pagination
`typescript
// === Offset-based pagination ===
@ObjectType()
export class PaginatedPosts extends createPaginatedType(Post) {}
// Returns: { docs, totalDocs, limit, page, totalPages, prevPage, nextPage, hasPrevPage, hasNextPage }
// For unions
@ObjectType()
export class PaginatedFeed extends createUnionPaginatedType(PostUnion, [MediaPost, TextPost]) {}
// Resolver
@MockQuery(MockQueryHelpers.paginated(PaginatedPosts, { totalDocs: 100 }))
@Query(() => PaginatedPosts)
posts(@Args("pagination") pagination: PaginatedInput) { ... }
// === Cursor-based pagination ===
@ObjectType()
export class CursorPaginatedPosts extends createCursorPaginatedType(Post) {}
// Returns: { docs: Post[], nextCursor: string | null }
// For unions
@ObjectType()
export class CursorPaginatedFeed extends createUnionCursorPaginatedType(PostUnion, [MediaPost, TextPost]) {}
// Resolver
@MockQuery(MockQueryHelpers.cursorPaginated(CursorPaginatedPosts, { maxCursorIterations: 10 }))
@Query(() => CursorPaginatedPosts)
feed(@Args("pagination") pagination: CursorPaginatedInput) { ... }
`
5. Run with mock environment
`bash`
NODE_ENV=mock npm run start
| Decorator | Purpose |
| ----------------------------------- | ---------------------------------- |
| @Mock(generator, opts?) | Define mock generator for a field |@MockQuery(type, opts?)
| | Mock a Query resolver |@MockMutation(type, opts?)
| | Mock a Mutation resolver |@MockResolveField(type, opts?)
| | Mock a field resolver |@MockQueryWithStore(fn, opts?)
| | Query with persistent MockStore |@MockMutationWithStore(fn, opts?)
| | Mutation with persistent MockStore |
`typescript`
{ count?: number, environments?: string[], debug?: boolean }
Default environments: ['mock', 'staging', 'test']
`typescript`
MockHelpers.enum(EnumType); // Random enum value
MockHelpers.relation(() => Type); // Nested object
MockHelpers.relationMany(() => Type, { count }); // Nested array
MockHelpers.union(
() => TypeA,
() => TypeB
); // Random union type
`typescript
// Union types - randomly picks one type per item
MockQueryHelpers.union(MediaPost, TextPost);
// Offset-based pagination
MockQueryHelpers.paginated(PaginatedPosts, { totalDocs: 100 });
// Cursor-based pagination
MockQueryHelpers.cursorPaginated(CursorPaginatedPosts, {
maxCursorIterations: 10,
});
`
For stateful mocking where mutations persist data:
`typescript``
@MockMutationWithStore((store, { input }) => {
store.set("Post", input.id, { title: input.title });
return store.get("Post", input.id);
})
@Mutation(() => Post)
createPost(@Args("input") input: CreatePostInput) { ... }
MIT — Built by Duestel