Can't login in a client unit test

Hi everybody,

I have some trouble testing my methods with authenticated user, from the client side.

In my test, I first call Accounts.createUser twice to create two user, using a method so that it runs on the server. First weird thing : the users are created as Meteor.users.find({}).fetch() returns an array with my two users on server, but it does retun an empty array on client.
Then, I try to login one of the user from the client side, using Meteor.loginWithPassword. It throws the following error message : error.accounts.Login forbidden [403] on client.

I think I am missing something, maybe some function is async and need a callback, but I can’t manage to figure this out.

There is a related issue here : http://stackoverflow.com/questions/37230608/cannot-authenticate-user-in-meteor-1-3-with-useraccounts

I also am using Meteor 1.3, with account-base, account-password and useraccounts.

Here is the complete code :

if (Meteor.isClient){
    describe('Events collection', () => {
        before(()=>{
            // reset the database (needs a method as we are on client)
            Meteor.call('testing.resetDatabase');
            // create an account
            // we don't use Account.createUser directly since it auto-login the user if called on client
            Meteor.call('testing.createUser',{
                username:'foobar',
                email:'foo@bar.com',
                password:'password'
            });
            Meteor.call('testing.createUser',{
                username:'johndoe',
                email:'john@doe.com',
                password:'password'
            });
            Meteor.loginWithPassword({email:'foo@bar.com'},'password',
            function(error){
                // FIXME : throw a 403, why ??
                console.log(error);
            });
            // stubbing the database
            StubCollections.stub(Events);
        })
        beforeEach(()=>{
            // reset the database (needs a method as we are on client)
            Meteor.call('testing.resetDatabase');
        });
        describe('Authorizations', () => {
            it('Can not insert an event while unauthenticated', () => {
                Meteor.call('events.insert', "foo", {}, "blah");
                assert.equal(Events.find({name:"foo"}).count(),0);
            });
        });
        describe('Methods', () => {
            before(()=>{
               // is undefined...
                console.log("loggedin ?: " + Meteor.userId() );
            });
            it('Can insert an event', () => {
                Meteor.call('events.insert', "foo", {}, "blah");
                assert.equal(Events.find({name:"foo"}).count(),1);
            });
            xit("Can remove an event", ()=>{
                Meteor.call('events.remove', "foo", {}, "blah");
                assert.equal(Events.find({name:"foo"}).count(),0);
                // todo
            });
            after(()=>{
                // logout if necessary
                if (Meteor.userId()){
                    AccountTemplates.logout();
                }
            });
        });

        after(()=>{
            // Restore the `Events` collection
            StubCollections.restore();
        });
    });
}

Thanks in advance for your help :slight_smile:

What you’re doing is actually an integration test not a unit test since it spans past your unit of code and going to the database. What you may want to do is do a Chimp test that prepares the database for you and then logs in via the client.

1 Like

Hi, thanks for your answer.

Indeed, my testing method may be wrong. I am actually trying to unit test my method, in order to check that it detects if the user is logged in or not and if the event is indeed inserted, not to build an integration test (I usually prefer acceptance test + unit test and only use integration tests in case of bugs).

So maybe the solution for me is simply to stub the User collection and the login process. Actually I only need the Meteor.userId() to be set to something non null in order to test the method, the Events collection is already stubbed.

However, I am not sure how to do so. I think we can set up the method context or something, I’ll post here as soon as I find a solution.

I guess it’s simply because it takes some time to createUser() to create the user. You’re trying to log-in before the user is created. Try to log-in inside a createUser() callback or after a timeout.

Hi @laurentpayot,

I think this is ineed the issue, but when called on server side, Accounts.createUser() have no callback, so I don’t know how to wait for it to end on the client.
When called on the client (where callback is authorized), it throws a 403 Signup forbidden, that’s why I had to wrap it in a method. Anyway on client Account.createUser log in the user afterward, but here I simply need to create two users, not to log anybody in.

I tried to stub Meteor.userId() with sinon but it still does not work, in my insert method the user id is still not defined.

Edit : Actually it does work with sinon, I made a mistake in my code. I think this is the more rationnal for unit testing, so my problem is solved. But still I wonder how to authenticate for real… Web development is a mysterious science. Thanks for your ideas !

1 Like

Hi @laurentpayo,
How did you solve this with sinon? are you able to login before each test case. can you give an example where a method required user need to be login before further processing.

1 Like