import Vue from 'vue'; import bp from '~/breakpoints'; import appComponent from '~/projects_dropdown/components/app.vue'; import eventHub from '~/projects_dropdown/event_hub'; import ProjectsStore from '~/projects_dropdown/store/projects_store'; import ProjectsService from '~/projects_dropdown/service/projects_service'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; import { currentSession, mockProject, mockRawProject } from '../mock_data'; const createComponent = () => { gon.api_version = currentSession.apiVersion; const Component = Vue.extend(appComponent); const store = new ProjectsStore(); const service = new ProjectsService(currentSession.username); return mountComponent(Component, { store, service, currentUserName: currentSession.username, currentProject: currentSession.project, }); }; const returnServicePromise = (data, failed) => new Promise((resolve, reject) => { if (failed) { reject(data); } else { resolve({ json() { return data; }, }); } }); describe('AppComponent', () => { describe('computed', () => { let vm; beforeEach(() => { vm = createComponent(); }); afterEach(() => { vm.$destroy(); }); describe('frequentProjects', () => { it('should return list of frequently accessed projects from store', () => { expect(vm.frequentProjects).toBeDefined(); expect(vm.frequentProjects.length).toBe(0); vm.store.setFrequentProjects([mockProject]); expect(vm.frequentProjects).toBeDefined(); expect(vm.frequentProjects.length).toBe(1); }); }); describe('searchProjects', () => { it('should return list of frequently accessed projects from store', () => { expect(vm.searchProjects).toBeDefined(); expect(vm.searchProjects.length).toBe(0); vm.store.setSearchedProjects([mockRawProject]); expect(vm.searchProjects).toBeDefined(); expect(vm.searchProjects.length).toBe(1); }); }); }); describe('methods', () => { let vm; beforeEach(() => { vm = createComponent(); }); afterEach(() => { vm.$destroy(); }); describe('toggleFrequentProjectsList', () => { it('should toggle props which control visibility of Frequent Projects list from state passed', () => { vm.toggleFrequentProjectsList(true); expect(vm.isLoadingProjects).toBeFalsy(); expect(vm.isSearchListVisible).toBeFalsy(); expect(vm.isFrequentsListVisible).toBeTruthy(); vm.toggleFrequentProjectsList(false); expect(vm.isLoadingProjects).toBeTruthy(); expect(vm.isSearchListVisible).toBeTruthy(); expect(vm.isFrequentsListVisible).toBeFalsy(); }); }); describe('toggleSearchProjectsList', () => { it('should toggle props which control visibility of Searched Projects list from state passed', () => { vm.toggleSearchProjectsList(true); expect(vm.isLoadingProjects).toBeFalsy(); expect(vm.isFrequentsListVisible).toBeFalsy(); expect(vm.isSearchListVisible).toBeTruthy(); vm.toggleSearchProjectsList(false); expect(vm.isLoadingProjects).toBeTruthy(); expect(vm.isFrequentsListVisible).toBeTruthy(); expect(vm.isSearchListVisible).toBeFalsy(); }); }); describe('toggleLoader', () => { it('should toggle props which control visibility of list loading animation from state passed', () => { vm.toggleLoader(true); expect(vm.isFrequentsListVisible).toBeFalsy(); expect(vm.isSearchListVisible).toBeFalsy(); expect(vm.isLoadingProjects).toBeTruthy(); vm.toggleLoader(false); expect(vm.isFrequentsListVisible).toBeTruthy(); expect(vm.isSearchListVisible).toBeTruthy(); expect(vm.isLoadingProjects).toBeFalsy(); }); }); describe('fetchFrequentProjects', () => { it('should set props for loading animation to `true` while frequent projects list is being loaded', () => { spyOn(vm, 'toggleLoader'); vm.fetchFrequentProjects(); expect(vm.isLocalStorageFailed).toBeFalsy(); expect(vm.toggleLoader).toHaveBeenCalledWith(true); }); it('should set props for loading animation to `false` and props for frequent projects list to `true` once data is loaded', () => { const mockData = [mockProject]; spyOn(vm.service, 'getFrequentProjects').and.returnValue(mockData); spyOn(vm.store, 'setFrequentProjects'); spyOn(vm, 'toggleFrequentProjectsList'); vm.fetchFrequentProjects(); expect(vm.service.getFrequentProjects).toHaveBeenCalled(); expect(vm.store.setFrequentProjects).toHaveBeenCalledWith(mockData); expect(vm.toggleFrequentProjectsList).toHaveBeenCalledWith(true); }); it('should set props for failure message to `true` when method fails to fetch frequent projects list', () => { spyOn(vm.service, 'getFrequentProjects').and.returnValue(null); spyOn(vm.store, 'setFrequentProjects'); spyOn(vm, 'toggleFrequentProjectsList'); expect(vm.isLocalStorageFailed).toBeFalsy(); vm.fetchFrequentProjects(); expect(vm.service.getFrequentProjects).toHaveBeenCalled(); expect(vm.store.setFrequentProjects).toHaveBeenCalledWith([]); expect(vm.toggleFrequentProjectsList).toHaveBeenCalledWith(true); expect(vm.isLocalStorageFailed).toBeTruthy(); }); it('should set props for search results list to `true` if search query was already made previously', () => { spyOn(bp, 'getBreakpointSize').and.returnValue('md'); spyOn(vm.service, 'getFrequentProjects'); spyOn(vm, 'toggleSearchProjectsList'); vm.searchQuery = 'test'; vm.fetchFrequentProjects(); expect(vm.service.getFrequentProjects).not.toHaveBeenCalled(); expect(vm.toggleSearchProjectsList).toHaveBeenCalledWith(true); }); it('should set props for frequent projects list to `true` if search query was already made but screen size is less than 768px', () => { spyOn(bp, 'getBreakpointSize').and.returnValue('sm'); spyOn(vm, 'toggleSearchProjectsList'); spyOn(vm.service, 'getFrequentProjects'); vm.searchQuery = 'test'; vm.fetchFrequentProjects(); expect(vm.service.getFrequentProjects).toHaveBeenCalled(); expect(vm.toggleSearchProjectsList).not.toHaveBeenCalled(); }); }); describe('fetchSearchedProjects', () => { const searchQuery = 'test'; it('should perform search with provided search query', (done) => { const mockData = [mockRawProject]; spyOn(vm, 'toggleLoader'); spyOn(vm, 'toggleSearchProjectsList'); spyOn(vm.service, 'getSearchedProjects').and.returnValue(returnServicePromise(mockData)); spyOn(vm.store, 'setSearchedProjects'); vm.fetchSearchedProjects(searchQuery); setTimeout(() => { expect(vm.searchQuery).toBe(searchQuery); expect(vm.toggleLoader).toHaveBeenCalledWith(true); expect(vm.service.getSearchedProjects).toHaveBeenCalledWith(searchQuery); expect(vm.toggleSearchProjectsList).toHaveBeenCalledWith(true); expect(vm.store.setSearchedProjects).toHaveBeenCalledWith(mockData); done(); }, 0); }); it('should update props for showing search failure', (done) => { spyOn(vm, 'toggleSearchProjectsList'); spyOn(vm.service, 'getSearchedProjects').and.returnValue(returnServicePromise({}, true)); vm.fetchSearchedProjects(searchQuery); setTimeout(() => { expect(vm.searchQuery).toBe(searchQuery); expect(vm.service.getSearchedProjects).toHaveBeenCalledWith(searchQuery); expect(vm.isSearchFailed).toBeTruthy(); expect(vm.toggleSearchProjectsList).toHaveBeenCalledWith(true); done(); }, 0); }); }); describe('logCurrentProjectAccess', () => { it('should log current project access via service', (done) => { spyOn(vm.service, 'logProjectAccess'); vm.currentProject = mockProject; vm.logCurrentProjectAccess(); setTimeout(() => { expect(vm.service.logProjectAccess).toHaveBeenCalledWith(mockProject); done(); }, 1); }); }); describe('handleSearchClear', () => { it('should show frequent projects list when search input is cleared', () => { spyOn(vm.store, 'clearSearchedProjects'); spyOn(vm, 'toggleFrequentProjectsList'); vm.handleSearchClear(); expect(vm.toggleFrequentProjectsList).toHaveBeenCalledWith(true); expect(vm.store.clearSearchedProjects).toHaveBeenCalled(); expect(vm.searchQuery).toBe(''); }); }); describe('handleSearchFailure', () => { it('should show failure message within dropdown', () => { spyOn(vm, 'toggleSearchProjectsList'); vm.handleSearchFailure(); expect(vm.toggleSearchProjectsList).toHaveBeenCalledWith(true); expect(vm.isSearchFailed).toBeTruthy(); }); }); }); describe('created', () => { it('should bind event listeners on eventHub', (done) => { spyOn(eventHub, '$on'); createComponent().$mount(); Vue.nextTick(() => { expect(eventHub.$on).toHaveBeenCalledWith('dropdownOpen', jasmine.any(Function)); expect(eventHub.$on).toHaveBeenCalledWith('searchProjects', jasmine.any(Function)); expect(eventHub.$on).toHaveBeenCalledWith('searchCleared', jasmine.any(Function)); expect(eventHub.$on).toHaveBeenCalledWith('searchFailed', jasmine.any(Function)); done(); }); }); }); describe('beforeDestroy', () => { it('should unbind event listeners on eventHub', (done) => { const vm = createComponent(); spyOn(eventHub, '$off'); vm.$mount(); vm.$destroy(); Vue.nextTick(() => { expect(eventHub.$off).toHaveBeenCalledWith('dropdownOpen', jasmine.any(Function)); expect(eventHub.$off).toHaveBeenCalledWith('searchProjects', jasmine.any(Function)); expect(eventHub.$off).toHaveBeenCalledWith('searchCleared', jasmine.any(Function)); expect(eventHub.$off).toHaveBeenCalledWith('searchFailed', jasmine.any(Function)); done(); }); }); }); describe('template', () => { let vm; beforeEach(() => { vm = createComponent(); }); afterEach(() => { vm.$destroy(); }); it('should render search input', () => { expect(vm.$el.querySelector('.search-input-container')).toBeDefined(); }); it('should render loading animation', (done) => { vm.toggleLoader(true); Vue.nextTick(() => { const loadingEl = vm.$el.querySelector('.loading-animation'); expect(loadingEl).toBeDefined(); expect(loadingEl.classList.contains('prepend-top-20')).toBeTruthy(); expect(loadingEl.querySelector('i').getAttribute('aria-label')).toBe('Loading projects'); done(); }); }); it('should render frequent projects list header', (done) => { vm.toggleFrequentProjectsList(true); Vue.nextTick(() => { const sectionHeaderEl = vm.$el.querySelector('.section-header'); expect(sectionHeaderEl).toBeDefined(); expect(sectionHeaderEl.innerText.trim()).toBe('Frequently visited'); done(); }); }); it('should render frequent projects list', (done) => { vm.toggleFrequentProjectsList(true); Vue.nextTick(() => { expect(vm.$el.querySelector('.projects-list-frequent-container')).toBeDefined(); done(); }); }); it('should render searched projects list', (done) => { vm.toggleSearchProjectsList(true); Vue.nextTick(() => { expect(vm.$el.querySelector('.section-header')).toBe(null); expect(vm.$el.querySelector('.projects-list-search-container')).toBeDefined(); done(); }); }); }); });