【问题标题】:Testing firebase functions in vuejs在 vuejs 中测试 firebase 函数
【发布时间】:2020-06-10 14:53:38
【问题描述】:

我想对我的 vue 组件进行单元测试。由于我正在使用firebase,这有点困难。

首先,我创建了一个__mocks__ 文件夹来包含我所有的模拟函数。在那个文件夹中,我创建了firebase.js:

import * as firebase from 'firebase';

const onAuthStateChanged = jest.fn();

const getRedirectResult = jest.fn(() => Promise.resolve({
  user: {
    displayName: 'redirectResultTestDisplayName',
    email: 'redirectTest@test.com',
    emailVerified: true,
  },
}));

const sendEmailVerification = jest.fn(() => Promise.resolve('result of sendEmailVerification'));

const sendPasswordResetEmail = jest.fn(() => Promise.resolve());

const createUserWithEmailAndPassword = jest.fn(() => {
  console.log('heeeeelllo');
  Promise.resolve({
    user: {
      displayName: 'redirectResultTestDisplayName',
      email: 'redirectTest@test.com',
      emailVerified: true,
    },
  });
});

const signInWithEmailAndPassword = jest.fn(() => Promise.resolve('result of signInWithEmailAndPassword'));

const signInWithRedirect = jest.fn(() => Promise.resolve('result of signInWithRedirect'));

const initializeApp = jest // eslint-disable-line no-unused-vars
  .spyOn(firebase, 'initializeApp')
  .mockImplementation(() => ({
    auth: () => ({
      createUserWithEmailAndPassword,
      signInWithEmailAndPassword,
      currentUser: {
        sendEmailVerification,
      },
      signInWithRedirect,
    }),
  }));

jest.spyOn(firebase, 'auth').mockImplementation(() => ({
  onAuthStateChanged,
  currentUser: {
    displayName: 'testDisplayName',
    email: 'test@test.com',
    emailVerified: true,
  },
  getRedirectResult,
  sendPasswordResetEmail,
}));

firebase.auth.FacebookAuthProvider = jest.fn(() => {});
firebase.auth.GoogleAuthProvider = jest.fn(() => {});

这个文件,我取自:https://github.com/mrbenhowl/mocking-firebase-initializeApp-and-firebase-auth-using-jest

我要测试的组件名为EmailSignupLogin。在这种特殊情况下,我想测试registerViaEmail-方法:

methods: {
    registerViaEmail() {
      if (this.password.length > 0 && this.password === this.passwordReenter) {
        firebase.auth().createUserWithEmailAndPassword(this.emailAdress, this.password).then((result) => {
          const { user } = result;
          console.log(result);
          this.setUser(user);
          this.$router.push('/stocks');
        }).catch((error) => {
          const errorCode = error.code;
          const errorMessage = error.message;
          this.error = errorMessage;
          console.error(errorCode, errorMessage);
        });
      } else {
        this.error = 'passwords not matching';
      }
    },
  },

现在到我的测试文件(email-signup-login.spec.js):

import { mount } from '@vue/test-utils';
import Vue from 'vue';
import EmailSignupLogin from '@/components/email-signup-login';

jest.mock('../../__mocks__/firebase');

describe('EmailSignupLogin', () => {
  let wrapper;
  const mockFunction = jest.fn();

  beforeEach(() => {
    wrapper = mount(EmailSignupLogin, {
      data() {
        return {
          password: '123456',
          passwordReenter: '123456',
          emailAdress: 'test@test.com',
        };
      },
      store: {
        actions: {
          setUser: mockFunction,
        },
      },
    });
  });

  describe('methods', () => {
    describe('#registerViaEmail', () => {
      it('calls mockFunction', async () => {
        await wrapper.vm.registerViaEmail();

        expect(mockFunction).toHaveBeenCalled();
      });
    });
  });
});

registerViaEmail-方法中,我调用setUser-action,这是一个vuex-action。

问题是它似乎没有从__mocks__/firebase.js 调用我的模拟函数。谁能告诉我为什么?

【问题讨论】:

  • 您遇到了什么错误?如果没有,您可以尝试将所需的功能添加到测试文件一次并检查是否可以正常工作?

标签: javascript firebase unit-testing vue.js jestjs


【解决方案1】:

您的代码中出现了几个问题:

  1. registerViaEmail() 不是 async(不返回 Promise),所以 await 调用过早返回,此时您的测试会尝试断言尚未发生的事情。要解决此问题,只需使用 Promise 包装函数体即可:
registerViaEmail() {
  return new Promise((resolve, reject) => {
    if (this.password.length > 0 && this.password === this.passwordReenter) {
      firebase.auth().createUserWithEmailAndPassword(this.emailAdress, this.password).then((result) => {
        //...
        resolve()
      }).catch((error) => {
        //...
        reject()
      });
    } else {
      //...
      reject()
    }
  })
},
  1. 您提到的script 不适用于Jest __mocks__。脚本本身直接修改firebase 对象,将其方法/属性替换为模拟。要使用该脚本,只需要在导入使用firebase的测试模块之前导入即可:
import './firebase-mock' // <-- order important
import EmailSignupLogin from '@/components/EmailSignupLogin'
  1. createUserWithEmailAndPassword 不返回任何内容。它看起来像 originally returned the Promise,但是您使用 console.log 对其进行了修改,并忘记继续返回 Promise,这导致此方法无法被 awaited(与 #1 相同的问题)。解决方案是返回Promise:
const createUserWithEmailAndPassword = jest.fn(() => {
  console.log('heeeeelllo')
  return /*?*/ Promise.resolve(/*...*/)
})
  1. createUserWithEmailAndPassword 是要在 EmailSignupLogin 中测试的方法,但它目前没有在您的 auth 模拟对象中模拟。它只是在initializeApp.auth 的返回中被嘲笑,但这不是它在EmailSignupLogin 中使用的内容。要解决此问题,请将 createUserWithEmailAndPassword 复制到您的 auth 模拟对象:
jest.spyOn(firebase, 'auth').mockImplementation(() => ({
  onAuthStateChanged,
  currentUser: {
    displayName: 'testDisplayName',
    email: 'test@test.com',
    emailVerified: true,
  },
  getRedirectResult,
  sendPasswordResetEmail,
  createUserWithEmailAndPassword, //?
}));
  1. 在您的测试设置中,您使用普通对象模拟了商店,但它实际上需要是 Vuex.Store 的实例:
mount({
  //store: { /*...*/ },              //❌DON'T DO THIS
  store: new Vuex.Store({ /*...*/ }) //✅
})

Github demo

【讨论】:

    猜你喜欢
    • 2020-10-24
    • 2019-12-25
    • 2018-11-13
    • 2019-04-13
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 2021-02-03
    相关资源
    最近更新 更多