Nestjs 中角色保护文件的测试用例

Shr*_*rma 1 javascript unit-testing jestjs typeorm nestjs

我不确定如何编写guardin的单元测试用例文件nestjs。我有以下Role.guard.ts文件。我必须创建Role.guard.spec.ts文件。有人可以帮忙吗?

import { Injectable, CanActivate, ExecutionContext, Logger } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_KEY } from './roles.decorator';
import { Role } from './role.enum';

@Injectable()
export class RolesGuard implements CanActivate {
    constructor(private reflector: Reflector) {}

    canActivate(context: ExecutionContext): boolean {
        const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
            context.getHandler(),
            context.getClass(),
        ]);

        const { user } = context.switchToHttp().getRequest();

        if (!user.role) {
            Logger.error('User does not have a role set');
            return false;
        }

        if (user.role === Role.Admin) {
            return true;
        }

        if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
            // No @Roles() decorator set, deny access as not admin
            return false;
        }

        if (requiredRoles.includes(Role.All)) {
            return true;
        }

        return requiredRoles.includes(user.role);
    }
}
Run Code Online (Sandbox Code Playgroud)

我写了下面的代码,但覆盖率问题即将到来。

import { createMock } from '@golevelup/ts-jest';
import { ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { RolesGuard } from "./roles.guard";

describe('RolesGuard', () => {
  let guard: RolesGuard;
  let reflector: Reflector;

  beforeEach(() => {
    reflector = new Reflector();
    guard = new RolesGuard(reflector);
  });

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

  it('should return false if user does not exist', () => {
    reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
    const context = createMock<ExecutionContext>();
    const canActivate = guard.canActivate(context);
    expect(canActivate).toBe(false); 
  })
})
Run Code Online (Sandbox Code Playgroud)

下面的行没有被覆盖。

if (user.role === Role.Admin) {
        return true;
    }

    if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
        // No @Roles() decorator set, deny access as not admin
        return false;
    }

    if (requiredRoles.includes(Role.All)) {
        return true;
    }

    return requiredRoles.includes(user.role);
Run Code Online (Sandbox Code Playgroud)

编辑1:-

下面的测试用例涵盖了我的部分代码。

     it('should return true if user  exist', () => {
        reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
        const context = createMock<ExecutionContext>({
          switchToHttp: () => ({
            getRequest: () => ({
              user: {
                role:'admin'
              }
            }),
          }),
        });
    
        const canActivate = guard.canActivate(context);
        expect(canActivate).toBe(true); 
      })
    
      it('should return false if user does not exist', () => {
        reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
        const context = createMock<ExecutionContext>({
          switchToHttp: () => ({
            getRequest: () => ({
              user: {
                role:'user'
              }
            }),
          }),
        });
    
        const canActivate = guard.canActivate(context);
        expect(canActivate).toBe(false); 
      })
Run Code Online (Sandbox Code Playgroud)

但下面的代码仍然没有被覆盖。

     if (requiredRoles.includes(Role.All)) {
        return true;
    }

    return requiredRoles.includes(user.role);
}
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我吗?

Jar*_*arr 5

看起来您需要能够适当地制作有效负载,以便您的代码能够被命中。有多种方法可以做到这一点,但是,以“Nest”方式,我们可以尝试像文档告诉我们的那样。请注意,在该链接中提供的测试实用程序使模拟变得更加容易。

import { createMock } from '@golevelup/ts-jest';
import { ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { RolesGuard } from "./roles.guard";

describe('RolesGuard', () => {
  let guard: RolesGuard;
  let reflector: Reflector

  beforeEach(async () => {
    reflector = new Reflector();
    guard = new RolesGuard(reflector);
  });

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

  it('should return false if user does not exist', () => {
    reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
    const context = createMock<ExecutionContext>();
    const canActivate = guard.canActivate(context);
    expect(canActivate).toBe(false); 
  })

  it('should return false if user does exist', () => {
    reflector.getAllAndOverride = jest.fn().mockReturnValue(true);

    // Mock the "class" type of this so we can get what we want.
    // We want to tell it to return an object where role is defined.
    const context = createMock<ExecutionContext>({
      switchToHttp: () => ({
        getRequest: () => ({
          user: { role: { /* enter your data here */ }
        }),
      }),
    });

    const canActivate = guard.canActivate(context);
    expect(canActivate).toBe(false); 
  })
})
Run Code Online (Sandbox Code Playgroud)

从这里开始,您的上下文已成功地与您想要的任何内容结合在一起,第二个测试应该开始显示为覆盖您的其他代码分支。您现在可以编辑该role属性,使其看起来像您想要的那样。另请注意,在上面的beforeEach调用中,您应该能够切换到使用测试模块。但这并不详尽,您可能需要添加额外的测试用例来覆盖其他分支。如果您按照我在这里所做的操作,那么这应该是相对微不足道的。

我在这里所做的有意义吗?通过为对象制作自定义有效负载,该roles属性就存在,允许测试评估其他情况。createMock我直接从golevelup.