import dedent from 'dedent-js';

import UserStore from '../../lib/models/user-store';
import NO_REPLY_GITHUB_EMAIL from '../../lib/models/user-store';

import {cloneRepository, buildRepository, FAKE_USER} from '../helpers';

describe('UserStore', function() {
  it('loads store with users and committer in repo upon construction', async function() {
    const workdirPath = await cloneRepository('multiple-commits');
    const repository = await buildRepository(workdirPath);
    const store = new UserStore({repository});

    assert.deepEqual(store.getUsers(), []);
    assert.deepEqual(store.committer, {});

    // Store is populated asynchronously
    await assert.async.deepEqual(store.getUsers(), [
      {
        email: 'kuychaco@github.com',
        name: 'Katrina Uychaco',
      },
    ]);
    await assert.async.deepEqual(store.committer, FAKE_USER);
  });

  it('excludes committer and no reply user from `getUsers`', async function() {
    const workdirPath = await cloneRepository('multiple-commits');
    const repository = await buildRepository(workdirPath);
    const store = new UserStore({repository});
    sinon.spy(store, 'addUsers');

    store.addUsers.reset();
    await repository.commit('made a new commit', {allowEmpty: true});

    // todo: this assertion is not consistently passing :-( fix it.
    // await assert.async.equal(store.addUsers.callCount, 1);

    const lastCommit = await repository.getLastCommit();
    assert.strictEqual(lastCommit.getAuthorEmail(), FAKE_USER.email);

    const users = store.getUsers();
    const committerFromStore = users.find(user => user.email === FAKE_USER.email);
    assert.isUndefined(committerFromStore);

    const noReplyUser = users.find(user => user.email === NO_REPLY_GITHUB_EMAIL);
    assert.isUndefined(noReplyUser);
  });

  describe('addUsers', function() {
    it('adds specified users and does not overwrite existing users', async function() {
      const workdirPath = await cloneRepository('multiple-commits');
      const repository = await buildRepository(workdirPath);
      const store = new UserStore({repository});

      await assert.async.lengthOf(store.getUsers(), 1);

      store.addUsers({
        'mona@lisa.com': 'Mona Lisa',
        'hubot@github.com': 'Hubot Robot',
      });

      await assert.async.deepEqual(store.getUsers(), [
        {
          name: 'Hubot Robot',
          email: 'hubot@github.com',
        },
        {
          name: 'Katrina Uychaco',
          email: 'kuychaco@github.com',
        },
        {
          name: 'Mona Lisa',
          email: 'mona@lisa.com',
        },
      ]);
    });
  });

  it('refetches committer when config changes', async function() {
    const workdirPath = await cloneRepository('multiple-commits');
    const repository = await buildRepository(workdirPath);

    const store = new UserStore({repository});
    await assert.async.deepEqual(store.committer, FAKE_USER);

    const newEmail = 'foo@bar.com';
    await repository.setConfig('user.email', newEmail);

    repository.refresh();
    await assert.async.deepEqual(store.committer, {name: FAKE_USER.name, email: newEmail});

    const newName = 'Foo Bar';
    await repository.setConfig('user.name', newName);
    repository.refresh();
    await assert.async.deepEqual(store.committer, {name: newName, email: newEmail});
  });

  it('refetches users when HEAD changes', async function() {
    const workdirPath = await cloneRepository('multiple-commits');
    const repository = await buildRepository(workdirPath);
    await repository.checkout('new-branch', {createNew: true});
    await repository.commit('commit 1', {allowEmpty: true});
    await repository.commit('commit 2', {allowEmpty: true});
    await repository.checkout('master');

    const store = new UserStore({repository});
    await assert.async.deepEqual(store.getUsers(), [
      {
        email: 'kuychaco@github.com',
        name: 'Katrina Uychaco',
      },
    ]);

    sinon.spy(store, 'addUsers');

    // Head changes due to new commit
    await repository.commit(dedent`
      New commit

      Co-authored-by: New Author <new-author@email.com>
    `, {allowEmpty: true});

    await assert.async.equal(store.addUsers.callCount, 1);
    assert.isOk(store.getUsers().find(user => {
      return user.name === 'New Author' && user.email === 'new-author@email.com';
    }));

    // Change head due to branch checkout
    await repository.checkout('new-branch');
    await assert.async.equal(store.addUsers.callCount, 2);
  });
});

@@ -1113,24 +1113,67 @@
 pository%7D);%0A
+    await store.loadUsersFromLocalRepo();%0A%0A
     sinon.sp
@@ -1198,36 +1198,56 @@
 ');%0A
-%0A    store.addUsers.reset();
+    // make a commit with FAKE_USER as committer
 %0A   
@@ -1317,83 +1317,11 @@
 %7D);%0A
-%0A
    
- // todo: this assertion is not consistently passing :-( fix it.%0A    //
  awa
@@ -1369,24 +1369,74 @@
 Count, 1);%0A%0A
+    // verify that FAKE_USER is in commit history%0A
     const la
@@ -1547,24 +1547,94 @@
 ER.email);%0A%0A
+    // verify that FAKE_USER is not in users returned from %60getUsers%60%0A
     const us
@@ -1781,24 +1781,88 @@
 romStore);%0A%0A
+    // verify that no-reply email address is not in users array%0A
     const no

Fix flakey UserStore test