1

我遇到了一个让我头疼的问题。我正在使用 passportJSpassport-facebook-token以及passport-google-oauth20在我的 node-express API 中使用 Facebook 和 Google 实现社交登录。

问题出现在单元测试中;我没有找到如何进行集成。

这是我尝试过的:

路线

router.post(
  '/facebook',
  passport.authenticate('facebook-token', { session: false }),
  authCtrl.socialLogin,
);
router.post('/google', passport.authenticate('google', { session: false }), authCtrl.socialLogin);

该路线使用我配置如下的 passportJS 中间件:

passport.use(
  'facebook-token',
  new FacebookTokenStrategy(
    {
      clientID: FACEBOOK_APP_ID,
      clientSecret: FACEBOOK_APP_SECRET,
    },
    async (_accessToken: string, _refreshToken: string, profile, done) => {
      done(null, profile);
    },
  ),
);

passport.use(
  'google',
  new GoogleStrategy(
    {
      clientID: GOOGLE_APP_ID,
      clientSecret: GOOGLE_APP_SECRET,
    },
    async (_accessToken: string, _refreshToken: string, profile, done) => {
      done(undefined, profile);
    },
  ),
);

控制器

这是我的控制器的样子

public async socialLogin(req: Request, res: Response): Promise<any> {
    try {
      const { provider, displayName, emails, photos }: any = req.user;
      const profile = {
        username: displayName.replace(' ', '_').toLowerCase(),
        email: emails ? emails[0].value : null,
        image: photos[0].value,
      };

      console.log(req.user);

      User.findOneAndUpdate(
        { 'profile.username': profile.username, 'profile.email': profile.email },
        { provider, profile, isLoggedIn: true, isAdmin: false },
        { new: true, upsert: true },
        (err, data: any) => {
          if (err) return helper.getServerError(res, err.message);
          const { _id, profile, isAdmin } = data;
          const { email } = profile;
          const token = helper.generateToken({ _id, email, isAdmin });
          return helper.getResponse(res, httpStatus.CREATED, { token, data });
        },
      );
      return helper.getResponse(res, httpStatus.CREATED, { data: profile });
    } catch (error) {
      return helper.getServerError(res, error.message);
    }
  }

const { provider, displayName, emails, photos }: any = req.user;

简而言之,我必须从护照中间件方法user自然返回的对象中接收提供者、显示名称、电子邮件和照片。authenticate()你可以回顾一下路由定义来理解。

单元测试

当我使用 jest 对控制器进行单元测试时,我采用了模拟响应和请求的方法,以便可以将user对象传递给请求。我尝试使用 jest 中的模拟实用程序,但无法正确模拟 express 请求和响应,因此尝试使用不同的第三方库,例如我觉得很有趣的 jest-express

这是我的测试的样子:

describe(Auth.prototype.socialLogin, () => {
    let response: any;
    let request: any;

    beforeEach(() => {
      response = new Response();
    });

    afterAll(() => {
      response.resetMocked();
      request.resetMocked();
    });

    it('should create a new user', async () => {
      const requestMock: any = {
        user: {
          provider: 'facebook-token',
          displayName: 'user name',
          emails: [{ value: 'username@mail.com' }],
          photos: [{ value: 'image.jpg' }],
        },
      };

      request = new Request(requestMock);
      await authCtrl.socialLogin(request, response);
      expect(response.status).toHaveBeenCalledWith(201);
    });
  });

问题

当我运行测试时,我得到了这个响应。

在此处输入图像描述

它清楚地表明控制器正在运行,但它落在了假设以 500 状态响应表示错误请求的 catch 块上。

所以我真的需要帮助,如果有地方我做错了,或者有任何文档可以帮助我有效地模拟快速响应和请求。

4

0 回答 0