Type-graphql: Jest does not cover decorators with parameters

Created on 2 Jan 2020  路  13Comments  路  Source: MichalLytek/type-graphql

Describe the bug
When using Jest coverage, decorators with additional parameters appear as uncovered :

  • @Field(type => ID)
  • @Field(type => [Team])
  • @Query(returns => User)
  • @Mutation(returns => User)
  • Plain decorators such as @Field() are covered.

To Reproduce
User class

@ObjectType()
export class User {
  @Field(type => ID)
  @IsMongoId()
  _id!: Types.ObjectId;

  @Field()
  @IsEmail()
  email!: string;

  @Field()
  @IsString()
  name!: string;

  @Field(type => [Team])
  @IsArray()
  teams?: Team[];
}

User resolver

@Resolver(of => User)
export class UserResolver {
  constructor(private readonly usersService: UserService) {}

  @Query(returns => User)
  async user(@Args('id') id: string): Promise<User> {
    const user = await this.usersService.findById(id);
    if (!user) {
      throw new NotFoundException(id);
    }
    return user;
  }

  @Query(returns => [User])
  async users(): Promise<User[]> {
    return await this.usersService.findAll();
  }

  @Mutation(returns => User)
  @UsePipes(new ValidationPipe())
  async addUser(
    @Args('addUserInput') addUserInput: AddUserInput
  ): Promise<User> {
    return await this.usersService.add(addUserInput);
  }
}

Jest output

src/user                    |    92.54 |      100 |    72.22 |       91.8 
  user.model.ts             |    89.47 |      100 |        0 |      88.24 
  user.resolver.ts          |    86.36 |      100 |     62.5 |         85 

Expected behavior
Decorators should be covered

Logs
If applicable, add some console logs to help explain your problem.
You can paste the errors with stack trace that were printed when the error occured.

Environment (please complete the following information):

  • OS: Linux Alpine 3.10.3
  • Node v13.3.0
  • Package v0.17.5
  • TypeScript v3.6.3

Additional context

  • Jest v24.9.0
  • Typegoose v6.1.8
  • NestJS 6

Did I miss something ? I read issue #377 but didn't find a solution.
Thank you !

Question Solved

All 13 comments

decorators with additional parameters appear as uncovered

I think that only parameters, not the whole decorator call is uncovered.
If you want to avoid such things, use _type => User or () => User syntax.

It is indeed only with functions as parameters, though @Resolver(of => User) decorator is covered.

I tried both your suggestions, none of them get covered.

@Resolver is always called, the callback of => User only when you use @FieldResolver on some of its methods.

I don't understand how I should unit-test them. I made the following test file for the resolver, so each decorator should get covered, right ?

describe('UserResolver', () => {
  let resolver: UserResolver;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UserResolver, UserService]
    }).compile();

    resolver = module.get<UserResolver>(UserResolver);
  });

  it('should be defined', () => {
    expect(resolver).toBeDefined();
  });

  it('should return all users', async () => {
    expect(await resolver.users()).toStrictEqual(users);
  });

  it('should return a single user', async () => {
    expect(await resolver.user('5dfb9aedd8b56d001b4c1362')).toBe(users[0]);
  });

  it('should throw an exception', async () => {
    try {
      await resolver.user('5dfb9aedd8b56d001b4c1363');
    } catch (error) {
      expect(error).toBeInstanceOf(NotFoundException);
    }
  });

  it('should add a user', async () => {
    expect(await resolver.addUser(addUserInput)).toBe(users[0]);
  });
});

Just use:

@Resolver() // without callback
export class UserResolver {}

when you don't have a field resolver.

And

  @Field(() => ID) // without args
  @IsMongoId()
  _id!: Types.ObjectId;

for other cases

I'm sorry, I don't understand everything. Based on what you wrote and the doc, I should :

  • specify a type for @Field() when it isn't a simple type (e.g. ID or any complex type I defined elsewhere, but in that case it's not covered)
  • specify a type for @Resolver() when resolver has field resolvers
  • specify a return type for @Query and @Mutation

If this is correct, does it mean that field decorators with complex types and query/mutation can't be covered ?

If this is correct,

Yes

field decorators with complex types and query/mutation can't be covered ?

Why do you think so?

It shows you the lines as not covered because you don't use type or returns parameter in the callback body.
What you don't understand?

I went through the documentation again, I don't get how I should use type and returns parameters

They can't be consumed as their type is void. They acts just like a description, a documentation, to make the code easier to read.

So that's what I'm saying, I can't cover them, right ?

Fuck yes! As I said - use @Resolver() without callback and @Field(() => ID) without args.

Nothing more I can do, so closing this issue 馃敀

I already tried your suggestion to omit args with @Field(() => ID) and @Query(() => User), but it still appears as uncovered.
Thank you for your time anyway.

So please post an issue on the Jest repo that it doesn't properly report coverage for decorators.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tongtwist picture tongtwist  路  3Comments

oliversalzburg picture oliversalzburg  路  3Comments

winuxue picture winuxue  路  4Comments

Asim13se picture Asim13se  路  3Comments

itsgracian picture itsgracian  路  3Comments