diff --git a/packages/accounts-base/accounts_client.js b/packages/accounts-base/accounts_client.js index 9cada0c20b..0a50eba3d8 100644 --- a/packages/accounts-base/accounts_client.js +++ b/packages/accounts-base/accounts_client.js @@ -12,11 +12,12 @@ return currentUserSubscriptionData && currentUserSubscriptionData.loaded; }; + // This calls userId and userLoaded, both of which are reactive. Meteor.user = function () { var userId = Meteor.userId(); if (!userId) return null; - if (currentUserSubscriptionData && currentUserSubscriptionData.loaded) + if (Meteor.userLoaded()) return Meteor.users.findOne(userId); // Not yet loaded: return a minimal object. return {_id: userId}; diff --git a/packages/accounts-password/package.js b/packages/accounts-password/package.js index 4d00cc27f1..9eb408ad43 100644 --- a/packages/accounts-password/package.js +++ b/packages/accounts-password/package.js @@ -14,7 +14,7 @@ Package.on_use(function(api) { }); Package.on_test(function(api) { - api.use(['accounts-password', 'tinytest', 'test-helpers']); + api.use(['accounts-password', 'tinytest', 'test-helpers', 'deps']); api.add_files('passwords_tests_setup.js', 'server'); api.add_files('passwords_tests.js', ['client', 'server']); api.add_files('email_tests_setup.js', 'server'); diff --git a/packages/accounts-password/passwords_tests.js b/packages/accounts-password/passwords_tests.js index 33c5182b1b..d647c7f269 100644 --- a/packages/accounts-password/passwords_tests.js +++ b/packages/accounts-password/passwords_tests.js @@ -63,6 +63,54 @@ if (Meteor.isClient) (function () { loggedInAs(username, test, expect)); }, logoutStep, + // This next step tests reactive contexts which are reactive on + // Meteor.user() without explicitly calling Meteor.userLoaded() --- we want + // to make sure that user loading finishing invalidates them too. + function (test, expect) { + // Set up a reactive context that only refreshes when Meteor.user() is + // invalidated. + var user; + var handle1 = Meteor._autorun(function () { + user = Meteor.user(); + }); + // At the beginning, we're not logged in. + test.equal(user, null); + + // This will get called once a second context (which does explicitly call + // Meteor.userLoaded()) tells us we are ready. + var callWhenLoaded = expect(function () { + Meteor.flush(); + // ... and this means that the first context did refresh and give us + // data. + test.isTrue(user.emails); + handle1.stop(); + }); + var waitForLoaded = expect(function () { + Meteor._autorun(function(handle2) { + if (!Meteor.userLoaded()) return; + handle2.stop(); + callWhenLoaded(); + }); + }); + Meteor.loginWithPassword(username, password, expect(function (error) { + test.equal(error, undefined); + test.notEqual(Meteor.userId(), null); + // Since userId has changed, the first autorun has been invalidated, so + // flush will re-run it and user will become not null. In the *CURRENT + // IMPLEMENTATION*, we will have just called _makeClientLoggedIn which + // just started a new meteor.currentUser subscription. There is no way + // that it is complete yet because we haven't gotten back to the event + // loop to actually get the data, so user.emails hasn't been populated + // yet. (That said, if we redo how userLoaded is implemented to not + // involve unsub/sub, it's possible that this test may become flaky by + // the test.isFalse failing.) + Meteor.flush(); + test.notEqual(user, null); + test.isFalse(user.emails); + waitForLoaded(); + })); + }, + logoutStep, function (test, expect) { Meteor.loginWithPassword({username: username}, password, loggedInAs(username, test, expect));