actions_spec.js 6.48 KB
Newer Older
1 2
import Vue from 'vue';
import _ from 'underscore';
3
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
4
import * as actions from '~/notes/stores/actions';
5
import store from '~/notes/stores';
6
import testAction from '../../helpers/vuex_action_helper';
7
import { resetStore } from '../helpers';
Simon Knox's avatar
Simon Knox committed
8
import { discussionMock, notesDataMock, userDataMock, noteableDataMock, individualNote } from '../mock_data';
9

10
describe('Actions Notes Store', () => {
11 12 13 14
  afterEach(() => {
    resetStore(store);
  });

15
  describe('setNotesData', () => {
16 17 18 19
    it('should set received notes data', (done) => {
      testAction(actions.setNotesData, null, { notesData: {} }, [
        { type: 'SET_NOTES_DATA', payload: notesDataMock },
      ], done);
20 21 22
    });
  });

Simon Knox's avatar
Simon Knox committed
23
  describe('setNoteableData', () => {
24
    it('should set received issue data', (done) => {
Simon Knox's avatar
Simon Knox committed
25 26
      testAction(actions.setNoteableData, null, { noteableData: {} }, [
        { type: 'SET_NOTEABLE_DATA', payload: noteableDataMock },
27 28
      ], done);
    });
29 30 31
  });

  describe('setUserData', () => {
32 33 34 35 36
    it('should set received user data', (done) => {
      testAction(actions.setUserData, null, { userData: {} }, [
        { type: 'SET_USER_DATA', payload: userDataMock },
      ], done);
    });
37 38 39
  });

  describe('setLastFetchedAt', () => {
40 41 42 43 44
    it('should set received timestamp', (done) => {
      testAction(actions.setLastFetchedAt, null, { lastFetchedAt: {} }, [
        { type: 'SET_LAST_FETCHED_AT', payload: 'timestamp' },
      ], done);
    });
45 46 47
  });

  describe('setInitialNotes', () => {
48 49
    it('should set initial notes', (done) => {
      testAction(actions.setInitialNotes, null, { notes: [] }, [
50
        { type: 'SET_INITIAL_NOTES', payload: [individualNote] },
51
      ], done);
52 53 54 55
    });
  });

  describe('setTargetNoteHash', () => {
56 57 58 59 60
    it('should set target note hash', (done) => {
      testAction(actions.setTargetNoteHash, null, { notes: [] }, [
        { type: 'SET_TARGET_NOTE_HASH', payload: 'hash' },
      ], done);
    });
61 62 63
  });

  describe('toggleDiscussion', () => {
64 65 66 67
    it('should toggle discussion', (done) => {
      testAction(actions.toggleDiscussion, null, { notes: [discussionMock] }, [
        { type: 'TOGGLE_DISCUSSION', payload: { discussionId: discussionMock.id } },
      ], done);
68 69
    });
  });
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

  describe('async methods', () => {
    const interceptor = (request, next) => {
      next(request.respondWith(JSON.stringify({}), {
        status: 200,
      }));
    };

    beforeEach(() => {
      Vue.http.interceptors.push(interceptor);
    });

    afterEach(() => {
      Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
    });

    describe('closeIssue', () => {
      it('sets state as closed', (done) => {
        store.dispatch('closeIssue', { notesData: { closeIssuePath: '' } })
          .then(() => {
            expect(store.state.noteableData.state).toEqual('closed');
91
            expect(store.state.isToggleStateButtonLoading).toEqual(false);
92 93 94 95 96 97 98 99 100 101 102
            done();
          })
          .catch(done.fail);
      });
    });

    describe('reopenIssue', () => {
      it('sets state as reopened', (done) => {
        store.dispatch('reopenIssue', { notesData: { reopenIssuePath: '' } })
          .then(() => {
            expect(store.state.noteableData.state).toEqual('reopened');
103
            expect(store.state.isToggleStateButtonLoading).toEqual(false);
104 105 106 107 108 109 110 111 112 113 114
            done();
          })
          .catch(done.fail);
      });
    });
  });

  describe('emitStateChangedEvent', () => {
    it('emits an event on the document', () => {
      document.addEventListener('issuable_vue_app:change', (event) => {
        expect(event.detail.data).toEqual({ id: '1', state: 'closed' });
Filipa Lacerda's avatar
Filipa Lacerda committed
115
        expect(event.detail.isClosed).toEqual(false);
116 117 118 119 120 121
      });

      store.dispatch('emitStateChangedEvent', { id: '1', state: 'closed' });
    });
  });

122 123 124 125 126 127 128 129 130 131 132 133 134 135
  describe('toggleStateButtonLoading', () => {
    it('should set loading as true', (done) => {
      testAction(actions.toggleStateButtonLoading, true, {}, [
        { type: 'TOGGLE_STATE_BUTTON_LOADING', payload: true },
      ], done);
    });

    it('should set loading as false', (done) => {
      testAction(actions.toggleStateButtonLoading, false, {}, [
        { type: 'TOGGLE_STATE_BUTTON_LOADING', payload: false },
      ], done);
    });
  });

136 137 138 139 140 141 142 143 144 145 146 147 148
  describe('toggleIssueLocalState', () => {
    it('sets issue state as closed', (done) => {
      testAction(actions.toggleIssueLocalState, 'closed', {}, [
        { type: 'CLOSE_ISSUE', payload: 'closed' },
      ], done);
    });

    it('sets issue state as reopened', (done) => {
      testAction(actions.toggleIssueLocalState, 'reopened', {}, [
        { type: 'REOPEN_ISSUE', payload: 'reopened' },
      ], done);
    });
  });
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

  describe('poll', () => {
    beforeEach((done) => {
      jasmine.clock().install();

      spyOn(Vue.http, 'get').and.callThrough();

      store.dispatch('setNotesData', notesDataMock)
        .then(done)
        .catch(done.fail);
    });

    afterEach(() => {
      jasmine.clock().uninstall();
    });

    it('calls service with last fetched state', (done) => {
      const interceptor = (request, next) => {
        next(request.respondWith(JSON.stringify({
          notes: [],
          last_fetched_at: '123456',
        }), {
          status: 200,
          headers: {
            'poll-interval': '1000',
          },
        }));
      };

      Vue.http.interceptors.push(interceptor);
      Vue.http.interceptors.push(headersInterceptor);

      store.dispatch('poll')
        .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
        .then(() => {
          expect(Vue.http.get).toHaveBeenCalledWith(jasmine.anything(), {
            url: jasmine.anything(),
            method: 'get',
            headers: {
              'X-Last-Fetched-At': undefined,
            },
          });
          expect(store.state.lastFetchedAt).toBe('123456');

          jasmine.clock().tick(1500);
        })
        .then(() => new Promise((resolve) => {
          requestAnimationFrame(resolve);
        }))
        .then(() => {
          expect(Vue.http.get.calls.count()).toBe(2);
          expect(Vue.http.get.calls.mostRecent().args[1].headers).toEqual({
            'X-Last-Fetched-At': '123456',
          });
        })
        .then(() => store.dispatch('stopPolling'))
        .then(() => {
          Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
          Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
        })
        .then(done)
        .catch(done.fail);
    });
  });
213
});