【问题标题】:NestJS e2e test mock Session decoratorNestJS e2e 测试模拟会话装饰器
【发布时间】:2021-06-04 07:27:27
【问题描述】:

我正在尝试使用 supertest 编写一个 e2e 测试,其中我的控制器实际上使用了 @Session() 装饰器。但是,我不想承担使用 db 连接等启动会话的全部负担,因此我在测试中的应用实际上并没有初始化会话。

我想首先模拟掉装饰器提供的数据并将其替换为静态数据。但是,我真的找不到如何实现这一点的解决方案。

来自控制器的样本:

@Get('/user/me')
public async getMe(@Session() session: Record<string, unknown>) {
  if (!session?.user) {
    throw new InternalServerErrorException();
  }
  return session.user;
}

我最希望模拟的样子:

jest.mock(Session, jest.fn().mockImplementation(() => {
  return { user: { name: "test user" } };
})

但是这行不通。

根据 TypeScript 官方文档,参数装饰器只能用于观察已在特定方法上设置了参数。由于这实际上并不是使用 @Session() 装饰器时发生的事情,因此我尝试查看 Nestjs 如何实际实现这些装饰器的源代码,但我在正确理解它时遇到了一些麻烦。

如果我没记错的话,装饰器似乎写入了一些元数据,另一个装饰器(在这种情况下可能是 @Get()?)可以利用并基于此提取必要的数据。

我对如何正确测试它有点困惑,所以我非常感谢你的一些建议:)

================================================ ==============================

更新:我现在将继续,而不是模拟 Session 装饰器本身模拟 req.session,同时在 beforeAll() 挂钩中设置我的 app。因此我选择了以下解决方案:

app.use((req, res, next) => {
    req.session = {
      user: {
        firstName: 'Max',
        lastName: 'Mustermann',
      },
    };
    next();
});

如果有人知道更好的解决方案,我仍然会很高兴。

【问题讨论】:

    标签: node.js typescript session nestjs


    【解决方案1】:

    为了解决这个问题,创建一个通用函数,为 e2e 创建嵌套应用程序,并提供 hooks 配置,可以覆盖测试模块和应用程序中间件注入 express

    通用设置函数

    
    /**
     * Hook for overriding the testing module
     */
    export type TestingModuleCreatePreHook = (
      moduleBuilder: TestingModuleBuilder,
    ) => TestingModuleBuilder;
    
    
    /**
     * Hook for adding items to nest application
     */
    export type TestingAppCreatePreHook = (
      app: NestExpressApplication,
    ) => Promise<void>;
    
    /**
     * Sets basic e2e testing module of app
     */
    export async function basicE2eSetup(
      config: {
        moduleBuilderHook?: TestingModuleCreatePreHook;
        appInitHook?: TestingAppCreatePreHook;
      } = {},
    ): Promise<[NestExpressApplication, TestingModule]> {
      let moduleBuilder: TestingModuleBuilder = Test.createTestingModule({
        imports: [AppModule],
      });
    
      if (!!config.moduleBuilderHook) {
        moduleBuilder = config.moduleBuilderHook(moduleBuilder);
      }
    
      const moduleFixture: TestingModule = await moduleBuilder.compile();
      const app = moduleFixture.createNestApplication<NestExpressApplication>();  
    
      if (config.appInitHook) {
        await config.appInitHook(app);
      }
    
      return [await app.init(), moduleFixture];
    }
    

    用法

    
    describe('AppController (e2e)', () => {
      let app: INestApplication;
    
      beforeEach(async () => {
        [app] = await basicE2eSetup({
          moduleBuilderHook: (moduleBuilder) => {
            // your overrides go here
            // Refer: https://docs.nestjs.com/fundamentals/testing#end-to-end-testing
            // eg: moduleBuilder.overrideProvider(ProviderName).useValue(value)
            return moduleBuilder;
          },
          appInitHook: async (app) => {
            const result = await someAction();
            // or get some service from app 
            // eg: const service = app.get<YourService>(YourService)
            app.use((req, res, next) => {
              // do something with request of response object
              next();
            })
          } 
        });
      });
    
      it('/ (GET)', () => {
        return request(app.getHttpServer())
          .get('/')
          .expect((res) => {
            expect(res.text).toContain('Hi There');
          });
      });
    });
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-01
      • 2019-12-28
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 2021-02-24
      • 2022-10-06
      • 2016-08-20
      相关资源
      最近更新 更多