简体   繁体   English

测试Meteor服务器方法与经过身份验证的用户一起调用客户端代码

[英]Test Meteor server method calling in client code with authenticated users

In a Meteor app, I need to test some client code that has statements such as 在Meteor应用程序中,我需要测试一些包含如下语句的客户端代码:

Meteor.call('foo', param1, param2, (error, result) => { .... });

And, in these methods, I have security checks to make sure that the method can only be called by authenticated users. 并且,在这些方法中,我进行了安全检查,以确保该方法只能由经过身份验证的用户调用。 However, all these tests fail during tests because no user is authenticated. 但是,所有这些测试在测试期间都会失败,因为没有用户通过身份验证。

In each server methods, I check users like this 在每种服务器方法中,我都会像这样检查用户

if (!Roles.userIsInRole(this.userId, [ ...roles ], group)) {
  throw new Meteor.Error('restricted', 'Access denied');
}

I have read that we should directly export the server methods and test them directly, and I actually do this for server methods testing, but it is not possible, here, since I need to test client code that depend on Meteor.call . 我已经读到我们应该直接导出服务器方法并直接对其进行测试,而我实际上是在对服务器方法进行测试,但是在这里是不可能的,因为我需要测试依赖于Meteor.call客户端代码。

I also would certainly not want to have if (Meteor.isTest || Meteor.isAppTest) { ... } all over the place.... 我当然也不想在整个地方都拥有if (Meteor.isTest || Meteor.isAppTest) { ... }

I thought perhaps wrapping my exported methods like this : 我想也许包装我的导出方法是这样的:

export default function methodsWrapper(methods) {

  Object.keys(methods).forEach(method => {
    const fn = methods[method];

    methods[method] = (...args) => {
      const user = Factory.create('user', { roles: { 'default': [ 'admin' ] } });

      return fn.call({ userId: user._id }, ...args);
    };

  });

};

But it only works when calling the methods directly. 但是它仅在直接调用方法时有效。

I'm not sure how I can test my client code with correct security validations. 我不确定如何使用正确的安全验证来测试客户端代码。 How can I test my client code with authenticated users? 如何与经过身份验证的用户一起测试我的客户端代码?

Part I: Making the function an exported function 第一部分:使函数成为导出函数

You just need to add the exported method also to meteor methods. 您只需要将导出的方法也添加到流星方法。

imports/api/foo.js 进口/ api / foo.js

export const foo = function(param1, param2){
    if (!Roles.userIsInRole(this.userId, [ ...roles ], group)) {
        throw new Meteor.Error('restricted', 'Access denied');
    }
    //....and other code
};

This method can then be imported in your server script: 然后可以将该方法导入服务器脚本中:

imports/startup/methods.js 导入/启动/methods.js

import {foo} from '../api/foo.js'

Meteor.methods({
    'foo' : foo
});

So it is available to be called via Mateor.call('foo'...). 因此可以通过Mateor.call('foo'...)进行调用。 Note that the callback has not to be defined in foo's function header, since it is wrapped automatically by meteor. 注意,回调不必在foo的函数头中定义,因为它是由流星自动包装的。

imports/api/foo.tests.js 进口/ api / foo.tests.js

import {foo} from './foo.js'
if (Meteor.isServer) {
    // ... your test setup    
    const result = foo(...) // call foo directly in your test.
}

This is only on the server, now here is the thing for testing on the client: you will not come around calling it via Meteor.call and test the callback result. 这仅在服务器上,现在这里是要在客户端上进行测试的东西:您将不会通过Meteor.call调用它并测试回调结果。 So on your client you still would test like: 因此,在您的客户上,您仍然会进行以下测试:

imports/api/foo.tests.js 进口/ api / foo.tests.js

if (Meteor.isClient) {
    // ... your test setup    
    Meteor.call('foo', ..., function(err, res) {
        // assert no err and res...
    });
}

Additional info: 附加信息:

I would advice you to use mdg:validated-method which allows the same functionality above PLUS gives you more sophisticated control over method execution, document schema validation and flexibility. 我建议您使用mdg:validated-method,它允许使用与PLUS相同的功能,从而使您可以更复杂地控制方法执行,文档架构验证和灵活性。 It is also documented well enough to allow you to implement your above described requirement. 它的文档记录也足够好,可以使您实现上述要求。

See: https://github.com/meteor/validated-method 参见: https : //github.com/meteor/validated-method

Part II: Running you integration test with user auth 第二部分:使用用户身份验证运行集成测试

You have two options here to test your user authentication. 您可以在此处选择两个选项来测试用户身份验证。 They have both advantages and disadvantages and there debates about what is the better approach. 它们既有优点也有缺点,关于什么是更好的方法存在争议。 No mater which one of both you will test, you need to write a server method, that adds an existing user to given set of roles. 不管您要测试的是哪一种,您都需要编写一个服务器方法,该方法将现有用户添加到给定的角色集中。

Approach 1 - Mocking Meteor.user() and Meter.userid() 方法1-模拟Meteor.user()和Meter.userid()

This is basically described/discussed in the following resources: 基本上在以下资源中对此进行了描述/讨论:

A complete gist example 一个完整的要点示例

An example of using either mdg:validated-method or plain methods 使用mdg:validated-method或Plain方法的示例

Using sinon spy and below also an answer from myself by mocking it manually but this may not apply for your case because it is client-only. 在下面使用sinon spy以及下面的方法也可以通过手动模拟来解决我自己的问题,但这可能不适用于您的情况,因为它仅适用于客户端。 Using sinon requires the following package: https://github.com/practicalmeteor/meteor-sinon 使用sinon需要以下程序包: https : //github.com/practicalmeteor/meteor-sinon

Approach 2 - Copying the "real" application behavior 方法2-复制“实际”应用程序行为

In this case you completely test without mocking anything. 在这种情况下,您无需假装即可完全测试。 You create real users and use their data in other tests as well. 您可以创建真实用户,并在其他测试中使用他们的数据。

In any case you need a server method, that creates a new user by given name and roles. 无论如何,您都需要一个服务器方法,该方法通过给定的名称和角色创建一个新用户。 Note that it should only be in a file with .test.js as name. 请注意,它只能位于以.test.js为名称的文件中。 Otherwise it can be considered a risk for security. 否则,可以认为存在安全风险。

/imports/api/accounts/accounts.tests.js /imports/api/accounts/accounts.tests.js

Meteor.methods({
    createtestUser(name,password, roles, group);
    const userId = Accounts.createUser({username:name, password:password});
    Roles.addUserToRoles(userId, roles, group);
    return userId;
});

Note: I often heard that this is bad testing, which I disagree. 注意:我经常听到这是不好的测试,我不同意。 Especially integration testing should mime the real behavior as good as possible und should use less mocking/spying as unit tests do. 尤其是集成测试应该尽可能地模仿真实行为,并且应该像单元测试那样使用更少的模拟/监视。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM