如何使用practicalmeteor:mocha在Meteor的单元测试中伪造用户?

时间:2018-01-30 15:38:18

标签: javascript unit-testing meteor mocha

我在尝试测试流星中需要连接用户的方法时遇到了困难。基本上我需要测试应用程序的用户是否可以在其购物车中添加文章。这些方法将测试用户是否已连接,并且为了测试将使用Meteor.userId()。这似乎是单元测试中的问题,因为我得到错误:
“Meteor.userId只能在方法调用或发布中调用。”

到目前为止,我尝试做了这篇文章中提出的建议:How to unit test a meteor method with practicalmeteor:mocha但我不明白解决方案在做什么。

这是我的测试方法:

import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { assert } from 'meteor/practicalmeteor:chai';
import { sinon } from 'meteor/practicalmeteor:sinon';

import { Carts } from '/imports/api/carts/carts.js';
import { Articles } from '/imports/api/articles/articles.js';

import '/imports/api/carts/carts.methods.js';

import { SecurityEnsurer } from '/lib/security/security.js';

function randomInt (low, high) {
    return Math.floor(Math.random() * (high - low) + low);
}

if (Meteor.isServer) {
  describe('Carts', () => {
  describe('methods', () => {
    let currentUser;

    beforeEach(() => {
      Factory.define('user', Meteor.users, {
        name: "userTest",
        currentUser: {
          email: 'user@shop.info',
          password: '123456',
        }

      });

      currentUser = Factory.create('user');
      sinon.stub(Meteor, 'user');
      Meteor.user.returns(currentUser);

      Articles.remove({});

      articleId = Articles.insert({
        name : "azerty",
        description : "descTest",
        modelNumber : "wxcvbn",
        categoryName : "CatTest",
        price : 1,
        advisedPrice: 2,
        supplierDiscount : 0,
        brandId : "BrandTest",
        isAvailable: true,
        restockingTime: 42,
        color: "Yellow",
        technicals: [
          {
            name : "GPU",
            value : "Intel"
          },
        ],
      });

      Carts.insert({
        owner: currentUser,
        entries: [],
      });

    });

    afterEach(() => {
      Meteor.user.restore();
      Articles.remove({});
      Carts.remove({});
    });

    it('can add article', () => {
      let quantity = randomInt(1,50);

      const addArticleToCart = Meteor.server.method_handlers['carts.addArticle'];

      const invocation = {};

      addArticleToCart.apply(invocation, [articleId, quantity]);

      assert.equal(Cart.find({owner: currentUser, entries: {$elemMatch: {articleId, quantity}}}).count(), 1);
      });
    });
  }); 
}

如果有人可以帮我找到如何创建我的测试,这对我很有帮助。

2 个答案:

答案 0 :(得分:1)

在调用Meteor方法时伪造用户,我找到的唯一方法是使用mdg:validated-method包,它提供了一个围绕Meteor方法的框架。这个框架现在似乎是标准(参见Meteor guide),但它需要重新编写你的方法和应用内调用。

在使用此框架描述方法之后,您可以在测试时使用userId参数调用它们,使用这种代码(验证我的方法返回403错误):

assert.throws(function () {
    updateData._execute({userId: myExternalUserId}, {
        id: dataId,
        data: {name: "test"}
    });
}, Meteor.Error, /403/);

仅供参考,这是我在进行自动化测试时添加的软件包(使用Meteor 1.6):

meteortesting:mocha
dburles:factory
practicalmeteor:chai
johanbrook:publication-collector

答案 1 :(得分:0)

这是我设置假登录用户以测试发布和方法的方法:

1)创建用户

2)存根,即替换Meteor.user()和Meteor.userId()函数,它们返回方法中当前登录的用户

3)将用户的_id提供给PublicationsCollector,后者会将其发送到您的发布函数中。

这是我的操作方式,希望您可以适应以下情况:

import { Meteor } from 'meteor/meteor';
import { Factory } from 'meteor/dburles:factory';
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { resetDatabase } from 'meteor/xolvio:cleaner';
import faker from 'faker';
import { Random } from 'meteor/random';
import { chai, assert } from 'meteor/practicalmeteor:chai';
import sinon from 'sinon';
// and also import your publish and collection

Factory.define('user', Meteor.users, {
    'name': 'Josephine',
});

if (Meteor.isServer) {
    describe('Menus', () => {
        beforeEach(function () {
            resetDatabase();

            const currentUser = Factory.create('user');
            sinon.stub(Meteor, 'user');
            Meteor.user.returns(currentUser); // now Meteor.user() will return the user we just created

            sinon.stub(Meteor, 'userId');
            Meteor.userId.returns(currentUser._id); // needed in methods

            // and create a Menu object in the Menus collection
        });

        afterEach(() => {
            Meteor.user.restore();
            resetDatabase();
        });

        describe('publish', () => {
            it('can view menus', (done) => {
                const collector = new PublicationCollector({ 'userId': Meteor.user()._id }); // give publish a value for this.userId
                collector.collect(
                    'menus',
                    (collections) => {
                        assert.equal(collections.menus.length, 1);
                        done();
                    },
                );
            });
        });
    });
}

您还可以编写一个测试来调用依赖Meteor.userId()的Meteor方法:

expect(() => { Meteor.call('myMethod'); }).to.not.throw(Meteor.Error);