在使用 Cucumber / Selenium 进行测试时登录时 Meteor 应用程序挂起

Meteor app hangs when logging in when testing with Cucumber / Selenium

我是 Cucumber 和 Velocity 的新手,想测试注册用户的登录流程。当用户登录时,加载微调器就永远挂在那里。 Meteor.loggingIn() returns false。我可以在 meteor-cucumber 集合中看到用户,如果我输入任何虚假的电子邮件和密码,它会立即提醒我登录尝试失败。

这是我的一部分 login-user.feature

Background:
    Given the user database is reset
    And the user is logged out
    And the user is at '/login'

@dev
Scenario: a registered user with a verified email address wants to login
    Given the user is registered and verified
    When the user has entered the required login information
    And the clicks the "Login" button
    Then the user will be viewing the 'story-of-the-day' template

这是我的步骤定义:

this.Given(/^the user database is reset$/, function () {
        server.call('_clearUsers');
    });

this.Given(/^the user is logged out$/, function () {
        server.call('_logout');
    });

this.When(/^the user is at '\/login'$/, function () {
        client.url(path.join(process.env.ROOT_URL, '/login'));
        client.waitForExist('.template-login');
    });

this.Given(/^the user is registered and verified$/, function () {
        userID = server.call('_createUser');
        expect(userID).toBeDefined();

        var result = server.call('_setVerifiedEmail', userID);
        expect(result).toBe(1);
    });

this.When(/^the user has entered the required login information$/, function () {
        client.setValue("#login-email", "xdzcaslm@sharklasers.com");
        client.setValue("#login-password", "Password123");
    });

this.When(/^the clicks the "([^"]*)" button$/, function () {
        client.submitForm("form");
    });

this.Then(/^the user will be viewing the 'story\-of\-the\-day' template$/, function () {
        client.waitForExist('.template-story-of-the-day');
    });

以下是相关的 Meteor 方法:

Meteor.methods({
    _createUser: function() {
        return Accounts.createUser({
            username: "PMoons",
            email: "xdzcaslm@sharklasers.com",
            password: "Password123",
            profile: {
                first_name: "Peter",
                last_name: "Mooney"
            }
        });
    },
    _getUserID: function() {
        return Meteor.users.findOne()._id;
    },
    _sendVerificationEmail: function(userID) {
        Accounts.sendVerificationEmail(userID);
    },
    _getVerificationToken: function(userID) {
        return Meteor.users.findOne(userID).services.email.verificationTokens[0].token;
    },
    _setVerifiedEmail: function(userID) {
        return Meteor.users.update({'_id': userID}, {$set: {'emails.0.verified': true}});
    },
    _logout: function() {
        Meteor.users.update({}, {$set: { "services.resume.loginTokens" : [] }});
    },
    _clearUsers: function() {
        Meteor.users.remove({});
    }
});

这是应用程序中的登录逻辑:

Template.login.events({
    'submit form': function(event, template) {
        event.preventDefault();
        $(event.target).blur();

        var email = template.find('#login-email').value;
        var password = template.find('#login-password').value;

        Meteor.loginWithPassword(email, password, function(error){
            if(error){
                alert('Login attempt failed. Please try again.');
            } else {
                Router.go('/dashboard');
            }
        });
    }
});

如有任何帮助,我们将不胜感激。

不确定这是否对您有帮助,但这是我的一组步骤定义,并且效果很好。不用担心 this.clientclient 之间的区别。最后我检查了一下,我的 xolvio:cucumber 版本坏了,client 停止工作了。我想如果你看看下面的内容并借鉴它,你应该能够让你的测试工作。

编辑:这些可能会得到改进。我没有像我应该的那样等待输入字段出现。

  this.Given(/^I am on the site$/, function () {
    this.client.url(process.env.ROOT_URL);
  });

  this.Given(/^my account exists$/, function () {
    server.call('createTestAccount');
  });

  this.Given(/^I am not currently logged in$/, function () {
    this.client.executeAsync(function (done) {
      Meteor.logout(done);
    });
  });

  this.Given(/^I am on the login page$/, function () {
    this.client.url(process.env.ROOT_URL + 'artist/login');
  });

  this.When(/^I correctly fill out the form and click submit$/, function () {
    this.client.setValue('#email', 'test@user.com');
    this.client.setValue('#password', 'test123');
    this.client.submitForm('#login-form');
  });

  this.Then(/^I am logged in and redirected to the artist dashboard$/, function () {
    var client = this.client;

    client.waitUntil(function () {
      return client.url().value === process.env.ROOT_URL + 'artist/dashboard';
    });
  });

然后是其他一些额外内容:

/tests/cucumber/features/support/hooks.js

module.exports = function () {
  this.Before(function () {
    server.call('reset');
  });
};

/tests/cucumber/fixtures/user-fixtures.js

Meteor.methods({
  'reset': function () {
    Meteor.users.remove({});
  },

  'createTestAccount': function () {
    Accounts.createUser({
      email: 'test@user.com',
      password: 'test123',
      profile: {
        firstName: 'Test',
        lastName: 'User'
      }
    });
  },

  'isLoggedIn': function () {
    return !!Meteor.userId();
  }
});

所以我在查看我的 router.js 文件后发现了问题的解决方案。事实证明,当我在常规应用程序中注册用户时,会在登录时引用的用户对象中设置一个字段,以确定用户应该去哪里。我的 fixture.js _createUser Meteor 方法中未设置此字段。因此,当测试为 运行 并且在没有此特定字段的情况下创建用户时,用户会不断被重定向回 /login

对我来说,这是一个很好的例子,说明为什么测试很重要,因为它让人质疑为什么该字段首先在注册时设置,而不是后来在应用程序中设置。