1// Copyright (C) 2019 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4import Vuex from 'vuex'; 5 6import { ProjectMembersApiGql } from '@/api/projectMembers'; 7import { ProjectsApiGql } from '@/api/projects'; 8import { makeProjectMembersModule, PROJECT_MEMBER_MUTATIONS } from '@/store/modules/projectMembers'; 9import { makeProjectsModule } from '@/store/modules/projects'; 10import { SortDirection } from '@/types/common'; 11import { ProjectMember, ProjectMemberOrderBy, ProjectMembersPage } from '@/types/projectMembers'; 12import { Project } from '@/types/projects'; 13import { PM_ACTIONS } from '@/utils/constants/actionNames'; 14import { createLocalVue } from '@vue/test-utils'; 15 16const projectsApi = new ProjectsApiGql(); 17const projectsModule = makeProjectsModule(projectsApi); 18const selectedProject = new Project(); 19selectedProject.id = '1'; 20projectsModule.state.selectedProject = selectedProject; 21 22const FIRST_PAGE = 1; 23const TEST_ERROR = 'testError'; 24const UNREACHABLE_ERROR = 'should be unreachable'; 25 26const Vue = createLocalVue(); 27const pmApi = new ProjectMembersApiGql(); 28const projectMembersModule = makeProjectMembersModule(pmApi); 29 30Vue.use(Vuex); 31 32const store = new Vuex.Store<{ 33 projectsModule: typeof projectsModule.state, 34 projectMembersModule: typeof projectMembersModule.state, 35}>({modules: { projectsModule, projectMembersModule }}); 36const state = store.state.projectMembersModule; 37const date = new Date(0); 38const projectMember1 = new ProjectMember('testFullName1', 'testShortName1', 'test1@example.com', date, '1'); 39const projectMember2 = new ProjectMember('testFullName2', 'testShortName2', 'test2@example.com', date, '2'); 40 41describe('mutations', () => { 42 it('fetch project members', function () { 43 const testProjectMembersPage = new ProjectMembersPage(); 44 testProjectMembersPage.projectMembers = [projectMember1]; 45 testProjectMembersPage.totalCount = 1; 46 testProjectMembersPage.pageCount = 1; 47 48 store.commit(PROJECT_MEMBER_MUTATIONS.FETCH, testProjectMembersPage); 49 50 expect(state.page.projectMembers.length).toBe(1); 51 expect(state.page.search).toBe(''); 52 expect(state.page.order).toBe(ProjectMemberOrderBy.NAME); 53 expect(state.page.orderDirection).toBe(SortDirection.ASCENDING); 54 expect(state.page.limit).toBe(6); 55 expect(state.page.pageCount).toBe(1); 56 expect(state.page.currentPage).toBe(1); 57 expect(state.page.totalCount).toBe(1); 58 }); 59 60 it('set project members page', function () { 61 store.commit(PROJECT_MEMBER_MUTATIONS.SET_PAGE, 2); 62 63 expect(state.cursor.page).toBe(2); 64 }); 65 66 it('set search query', function () { 67 store.commit(PROJECT_MEMBER_MUTATIONS.SET_SEARCH_QUERY, 'testSearchQuery'); 68 69 expect(state.cursor.search).toBe('testSearchQuery'); 70 }); 71 72 it('set sort order', function () { 73 store.commit(PROJECT_MEMBER_MUTATIONS.CHANGE_SORT_ORDER, ProjectMemberOrderBy.EMAIL); 74 75 expect(state.cursor.order).toBe(ProjectMemberOrderBy.EMAIL); 76 }); 77 78 it('set sort direction', function () { 79 store.commit(PROJECT_MEMBER_MUTATIONS.CHANGE_SORT_ORDER_DIRECTION, SortDirection.DESCENDING); 80 81 expect(state.cursor.orderDirection).toBe(SortDirection.DESCENDING); 82 }); 83 84 it('toggle selection', function () { 85 const testProjectMembersPage = new ProjectMembersPage(); 86 testProjectMembersPage.projectMembers = [projectMember1]; 87 testProjectMembersPage.totalCount = 1; 88 testProjectMembersPage.pageCount = 1; 89 90 store.commit(PROJECT_MEMBER_MUTATIONS.TOGGLE_SELECTION, projectMember1); 91 92 expect(state.page.projectMembers[0].isSelected).toBe(true); 93 expect(state.selectedProjectMembersEmails.length).toBe(1); 94 95 store.commit(PROJECT_MEMBER_MUTATIONS.FETCH, testProjectMembersPage); 96 97 expect(state.selectedProjectMembersEmails.length).toBe(1); 98 99 store.commit(PROJECT_MEMBER_MUTATIONS.TOGGLE_SELECTION, projectMember1); 100 101 expect(state.page.projectMembers[0].isSelected).toBe(false); 102 expect(state.selectedProjectMembersEmails.length).toBe(0); 103 }); 104 105 it('clear selection', function () { 106 store.commit(PROJECT_MEMBER_MUTATIONS.CLEAR_SELECTION); 107 108 state.page.projectMembers.forEach((pm: ProjectMember) => { 109 expect(pm.isSelected).toBe(false); 110 }); 111 112 expect(state.selectedProjectMembersEmails.length).toBe(0); 113 }); 114 115 it('clear store', function () { 116 store.commit(PROJECT_MEMBER_MUTATIONS.CLEAR); 117 118 expect(state.cursor.page).toBe(1); 119 expect(state.cursor.search).toBe(''); 120 expect(state.cursor.order).toBe(ProjectMemberOrderBy.NAME); 121 expect(state.cursor.orderDirection).toBe(SortDirection.ASCENDING); 122 expect(state.page.projectMembers.length).toBe(0); 123 expect(state.selectedProjectMembersEmails.length).toBe(0); 124 }); 125}); 126 127describe('actions', () => { 128 beforeEach(() => { 129 jest.resetAllMocks(); 130 }); 131 132 it('add project members', async function () { 133 jest.spyOn(pmApi, 'add').mockReturnValue(Promise.resolve()); 134 135 try { 136 await store.dispatch(PM_ACTIONS.ADD, [projectMember1.user.email]); 137 throw new Error(TEST_ERROR); 138 } catch (err) { 139 expect(err.message).toBe(TEST_ERROR); 140 } 141 }); 142 143 it('add project member throws error when api call fails', async function () { 144 jest.spyOn(pmApi, 'add').mockImplementation(() => { 145 throw new Error(TEST_ERROR); 146 }); 147 148 const stateDump = state; 149 150 try { 151 await store.dispatch(PM_ACTIONS.ADD, [projectMember1.user.email]); 152 } catch (err) { 153 expect(err.message).toBe(TEST_ERROR); 154 expect(state).toBe(stateDump); 155 156 return; 157 } 158 159 fail(UNREACHABLE_ERROR); 160 }); 161 162 it('delete project members', async function () { 163 jest.spyOn(pmApi, 'delete').mockReturnValue(Promise.resolve()); 164 165 try { 166 await store.dispatch(PM_ACTIONS.DELETE, [projectMember1.user.email]); 167 throw new Error(TEST_ERROR); 168 } catch (err) { 169 expect(err.message).toBe(TEST_ERROR); 170 } 171 }); 172 173 it('delete project member throws error when api call fails', async function () { 174 jest.spyOn(pmApi, 'delete').mockImplementation(() => { 175 throw new Error(TEST_ERROR); 176 }); 177 178 const stateDump = state; 179 180 try { 181 await store.dispatch(PM_ACTIONS.DELETE, [projectMember1.user.email]); 182 } catch (err) { 183 expect(err.message).toBe(TEST_ERROR); 184 expect(state).toBe(stateDump); 185 186 return; 187 } 188 189 fail(UNREACHABLE_ERROR); 190 }); 191 192 it('fetch project members', async function () { 193 jest.spyOn(pmApi, 'get').mockReturnValue( 194 Promise.resolve(new ProjectMembersPage( 195 [projectMember1], 196 '', 197 ProjectMemberOrderBy.NAME, 198 SortDirection.ASCENDING, 199 6, 200 1, 201 1, 202 1)), 203 ); 204 205 await store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE); 206 207 expect(state.page.projectMembers[0].isSelected).toBe(false); 208 expect(state.page.projectMembers[0].joinedAt).toBe(projectMember1.joinedAt); 209 expect(state.page.projectMembers[0].user.email).toBe(projectMember1.user.email); 210 expect(state.page.projectMembers[0].user.id).toBe(projectMember1.user.id); 211 expect(state.page.projectMembers[0].user.partnerId).toBe(projectMember1.user.partnerId); 212 expect(state.page.projectMembers[0].user.fullName).toBe(projectMember1.user.fullName); 213 expect(state.page.projectMembers[0].user.shortName).toBe(projectMember1.user.shortName); 214 }); 215 216 it('fetch project members throws error when api call fails', async function () { 217 jest.spyOn(pmApi, 'get').mockImplementation(() => { 218 throw new Error(TEST_ERROR); 219 }); 220 221 const stateDump = state; 222 223 try { 224 await store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE); 225 } catch (err) { 226 expect(err.message).toBe(TEST_ERROR); 227 expect(state).toBe(stateDump); 228 229 return; 230 } 231 232 fail(UNREACHABLE_ERROR); 233 }); 234 235 it('set project members search query', function () { 236 store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, 'search'); 237 238 expect(state.cursor.search).toBe('search'); 239 }); 240 241 it('set project members sort by', function () { 242 store.dispatch(PM_ACTIONS.SET_SORT_BY, ProjectMemberOrderBy.CREATED_AT); 243 244 expect(state.cursor.order).toBe(ProjectMemberOrderBy.CREATED_AT); 245 }); 246 247 it('set sort direction', function () { 248 store.dispatch(PM_ACTIONS.SET_SORT_DIRECTION, SortDirection.DESCENDING); 249 250 expect(state.cursor.orderDirection).toBe(SortDirection.DESCENDING); 251 }); 252 253 it('toggle selection', async function () { 254 jest.spyOn(pmApi, 'get').mockReturnValue( 255 Promise.resolve(new ProjectMembersPage( 256 [projectMember1, projectMember2], 257 '', 258 ProjectMemberOrderBy.NAME, 259 SortDirection.ASCENDING, 260 6, 261 1, 262 1, 263 2)), 264 ); 265 266 await store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE); 267 store.dispatch(PM_ACTIONS.TOGGLE_SELECTION, projectMember1); 268 269 expect(state.page.projectMembers[0].isSelected).toBe(true); 270 expect(state.selectedProjectMembersEmails.length).toBe(1); 271 272 store.dispatch(PM_ACTIONS.TOGGLE_SELECTION, projectMember2); 273 274 expect(state.page.projectMembers[1].isSelected).toBe(true); 275 expect(state.selectedProjectMembersEmails.length).toBe(2); 276 277 await store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE); 278 279 expect(state.page.projectMembers[1].isSelected).toBe(true); 280 expect(state.selectedProjectMembersEmails.length).toBe(2); 281 282 store.dispatch(PM_ACTIONS.TOGGLE_SELECTION, projectMember1); 283 284 expect(state.page.projectMembers[0].isSelected).toBe(false); 285 expect(state.selectedProjectMembersEmails.length).toBe(1); 286 }); 287 288 it('clear selection', function () { 289 store.dispatch(PM_ACTIONS.CLEAR_SELECTION); 290 291 state.page.projectMembers.forEach((pm: ProjectMember) => { 292 expect(pm.isSelected).toBe(false); 293 }); 294 }); 295 296 it('clear store', function () { 297 store.commit(PM_ACTIONS.CLEAR); 298 299 expect(state.cursor.page).toBe(1); 300 expect(state.cursor.search).toBe(''); 301 expect(state.cursor.order).toBe(ProjectMemberOrderBy.NAME); 302 expect(state.cursor.orderDirection).toBe(SortDirection.ASCENDING); 303 expect(state.page.projectMembers.length).toBe(0); 304 305 state.page.projectMembers.forEach((pm: ProjectMember) => { 306 expect(pm.isSelected).toBe(false); 307 }); 308 }); 309}); 310 311describe('getters', () => { 312 const selectedProjectMember = new ProjectMember('testFullName2', 'testShortName2', 'test2@example.com', date, '2'); 313 314 it('selected project members', function () { 315 const testProjectMembersPage = new ProjectMembersPage(); 316 testProjectMembersPage.projectMembers = [selectedProjectMember]; 317 testProjectMembersPage.totalCount = 1; 318 testProjectMembersPage.pageCount = 1; 319 320 store.commit(PROJECT_MEMBER_MUTATIONS.FETCH, testProjectMembersPage); 321 store.commit(PROJECT_MEMBER_MUTATIONS.TOGGLE_SELECTION, selectedProjectMember); 322 323 const retrievedProjectMembers = store.getters.selectedProjectMembers; 324 325 expect(retrievedProjectMembers[0].user.id).toBe(selectedProjectMember.user.id); 326 }); 327}); 328