meteor/meteor

View on GitHub
packages/accounts-base/accounts_reconnect_tests.js

Summary

Maintainability
A
0 mins
Test Coverage
if (Meteor.isServer) {
  Meteor.methods({
    getConnectionUserId: function() {
      return this.userId;
    }
  });
}

if (Meteor.isClient) {
  const loginAsUser1 = (onUser1LoggedIn) => {
    Accounts.createUser({
      username: `testuser1-${Random.id()}`,
      password: `password1-${Random.id()}`
    }, onUser1LoggedIn);
  };

  Tinytest.addAsync('accounts - reconnect auto-login', (test, done) => {
    function disconnectAndReconnect(callback) {
      test.equal(Meteor.status().status, "connected");

      function pollUntilDisconnected() {
        if (Meteor.status().status === "offline") {
          Meteor.reconnect();
          pollUntilReconnected();
        } else {
          Meteor.setTimeout(pollUntilDisconnected, 10);
        }
      }

      function pollUntilReconnected() {
        if (Meteor.status().status === "connected") {
          if (typeof callback === "function") {
            callback();
          }
        } else {
          Meteor.setTimeout(pollUntilReconnected, 10);
        }
      }

      Meteor.disconnect();
      pollUntilDisconnected();
    }

    let onReconnectCalls = 0;
    const reconnectHandler = () => onReconnectCalls++;
    Meteor.connection.onReconnect = reconnectHandler;

    const username2 = `testuser2-${Random.id()}`;
    const password2 = `password2-${Random.id()}`;
    let timeoutHandle;
    let onLoginStopper;

    loginAsUser1((err) => {
      test.isUndefined(err, 'Unexpected error logging in as user1');
      Accounts.createUser({
        username: username2,
        password: password2
      }, onUser2LoggedIn);
    });

    const onUser2LoggedIn = err => {
      test.isUndefined(err, 'Unexpected error logging in as user2');
      onLoginStopper = Accounts.onLogin(onUser2LoggedInAfterReconnect);
      disconnectAndReconnect();
    }

    const onUser2LoggedInAfterReconnect = () => {
      onLoginStopper.stop();
      Meteor.loginWithPassword('non-existent-user', 'or-wrong-password',
        onFailedLogin);
    }

    const onFailedLogin = err => {
      test.instanceOf(err, Meteor.Error, 'No Meteor.Error on login failure');
      onLoginStopper = Accounts.onLogin(onUser2LoggedInAfterReconnectAfterFailedLogin);
      disconnectAndReconnect();
      timeoutHandle = Meteor.setTimeout(failTest, 5000);
    }

    const failTest = () => {
      onLoginStopper.stop();
      test.fail('Issue #4970 has occured.');
      Meteor.call('getConnectionUserId', checkFinalState);
    }

    const onUser2LoggedInAfterReconnectAfterFailedLogin = () => {
      onLoginStopper.stop();
      Meteor.clearTimeout(timeoutHandle);
      Meteor.call('getConnectionUserId', checkFinalState);
    }

    const checkFinalState = (err, connectionUserId) => {
      test.isUndefined(err, 'Unexpected error calling getConnectionUserId');
      test.equal(connectionUserId, Meteor.userId(),
        'userId is different on client and server');
      test.equal(Meteor.connection.onReconnect, reconnectHandler,
        'Meteor.connection.onReconnect changed');
      test.equal(onReconnectCalls, 2, 'wrong # of reconnect handler calls');
      done();
    }
  });

  // Make sure that when a logged in user is disconnected then reconnected,
  // they still only have one Accounts login onReconnect callback set.
  // Addresses: https://github.com/meteor/meteor/issues/9140
  Tinytest.addAsync(
    'accounts - verify single onReconnect callback',
    (test, done) => {
      loginAsUser1((err) => {
        test.isUndefined(err, 'Unexpected error logging in as user1');
        test.equal(
          Object.keys(DDP._reconnectHook.callbacks).length,
          1,
          'Only one onReconnect callback should be registered'
        );
        Meteor.disconnect();
        test.isFalse(Meteor.status().connected);
        Meteor.reconnect();
        setTimeout(() => {
          test.isTrue(Meteor.status().connected);
          test.equal(
            Object.keys(DDP._reconnectHook.callbacks).length,
            1,
            'Only one onReconnect callback should be registered'
          );
          done();
        }, 1000);
      });
    }
  );
}