diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-11-23 15:04:03 +0300 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2017-11-23 15:04:03 +0300 |
commit | 45631562565760add7a7c52a6137e891f3a0c8f4 (patch) | |
tree | 44915f7c46d05fb8c6197662a3341ea8fb610f06 /spec/javascripts/environments/environments_app_spec.js | |
parent | 1d8ab59ebfa0d57e4015665c470c8339cd258a2c (diff) |
Improve environments performance
Diffstat (limited to 'spec/javascripts/environments/environments_app_spec.js')
-rw-r--r-- | spec/javascripts/environments/environments_app_spec.js | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js new file mode 100644 index 00000000000..d02adb25b4e --- /dev/null +++ b/spec/javascripts/environments/environments_app_spec.js @@ -0,0 +1,318 @@ +import Vue from 'vue'; +import environmentsComponent from '~/environments/components/environments_app.vue'; +import { environment, folder } from './mock_data'; +import { headersInterceptor } from '../helpers/vue_resource_helper'; +import mountComponent from '../helpers/vue_mount_component_helper'; + +describe('Environment', () => { + const mockData = { + endpoint: 'environments.json', + canCreateEnvironment: true, + canCreateDeployment: true, + canReadEnvironment: true, + cssContainerClass: 'container', + newEnvironmentPath: 'environments/new', + helpPagePath: 'help', + }; + + let EnvironmentsComponent; + let component; + + beforeEach(() => { + EnvironmentsComponent = Vue.extend(environmentsComponent); + }); + + describe('successfull request', () => { + describe('without environments', () => { + const environmentsEmptyResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify([]), { + status: 200, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsEmptyResponseInterceptor); + Vue.http.interceptors.push(headersInterceptor); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsEmptyResponseInterceptor, + ); + Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor); + }); + + it('should render the empty state', (done) => { + component = mountComponent(EnvironmentsComponent, mockData); + + setTimeout(() => { + expect( + component.$el.querySelector('.js-new-environment-button').textContent, + ).toContain('New environment'); + + expect( + component.$el.querySelector('.js-blank-state-title').textContent, + ).toContain('You don\'t have any environments right now.'); + + done(); + }, 0); + }); + }); + + describe('with paginated environments', () => { + const environmentsResponseInterceptor = (request, next) => { + next((response) => { + response.headers.set('X-nExt-pAge', '2'); + }); + + next(request.respondWith(JSON.stringify({ + environments: [environment], + stopped_count: 1, + available_count: 0, + }), { + status: 200, + headers: { + 'X-nExt-pAge': '2', + 'x-page': '1', + 'X-Per-Page': '1', + 'X-Prev-Page': '', + 'X-TOTAL': '37', + 'X-Total-Pages': '2', + }, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsResponseInterceptor); + Vue.http.interceptors.push(headersInterceptor); + component = mountComponent(EnvironmentsComponent, mockData); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsResponseInterceptor, + ); + Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor); + }); + + it('should render a table with environments', (done) => { + setTimeout(() => { + expect(component.$el.querySelectorAll('table')).not.toBeNull(); + expect( + component.$el.querySelector('.environment-name').textContent.trim(), + ).toEqual(environment.name); + done(); + }, 0); + }); + + describe('pagination', () => { + it('should render pagination', (done) => { + setTimeout(() => { + expect( + component.$el.querySelectorAll('.gl-pagination li').length, + ).toEqual(5); + done(); + }, 0); + }); + + it('should make an API request when page is clicked', (done) => { + spyOn(component, 'updateContent'); + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(component.updateContent).toHaveBeenCalledWith({ scope: 'available', page: '2' }); + done(); + }, 0); + }); + + it('should make an API request when using tabs', (done) => { + setTimeout(() => { + spyOn(component, 'updateContent'); + component.$el.querySelector('.js-environments-tab-stopped').click(); + + expect(component.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); + done(); + }); + }); + }); + }); + }); + + describe('unsuccessfull request', () => { + const environmentsErrorResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify([]), { + status: 500, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsErrorResponseInterceptor); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsErrorResponseInterceptor, + ); + }); + + it('should render empty state', (done) => { + component = mountComponent(EnvironmentsComponent, mockData); + + setTimeout(() => { + expect( + component.$el.querySelector('.js-blank-state-title').textContent, + ).toContain('You don\'t have any environments right now.'); + done(); + }, 0); + }); + }); + + describe('expandable folders', () => { + const environmentsResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify({ + environments: [folder], + stopped_count: 0, + available_count: 1, + }), { + status: 200, + headers: { + 'X-nExt-pAge': '2', + 'x-page': '1', + 'X-Per-Page': '1', + 'X-Prev-Page': '', + 'X-TOTAL': '37', + 'X-Total-Pages': '2', + }, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsResponseInterceptor); + component = mountComponent(EnvironmentsComponent, mockData); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsResponseInterceptor, + ); + }); + + it('should open a closed folder', (done) => { + setTimeout(() => { + component.$el.querySelector('.folder-name').click(); + + Vue.nextTick(() => { + expect( + component.$el.querySelector('.folder-icon i.fa-caret-right').getAttribute('style'), + ).toContain('display: none'); + expect( + component.$el.querySelector('.folder-icon i.fa-caret-down').getAttribute('style'), + ).not.toContain('display: none'); + done(); + }); + }); + }); + + it('should close an opened folder', (done) => { + setTimeout(() => { + // open folder + component.$el.querySelector('.folder-name').click(); + + Vue.nextTick(() => { + // close folder + component.$el.querySelector('.folder-name').click(); + + Vue.nextTick(() => { + expect( + component.$el.querySelector('.folder-icon i.fa-caret-down').getAttribute('style'), + ).toContain('display: none'); + expect( + component.$el.querySelector('.folder-icon i.fa-caret-right').getAttribute('style'), + ).not.toContain('display: none'); + done(); + }); + }); + }); + }); + + it('should show children environments and a button to show all environments', (done) => { + setTimeout(() => { + // open folder + component.$el.querySelector('.folder-name').click(); + + Vue.nextTick(() => { + const folderInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify({ + environments: [environment], + }), { status: 200 })); + }; + + Vue.http.interceptors.push(folderInterceptor); + + // wait for next async request + setTimeout(() => { + expect(component.$el.querySelectorAll('.js-child-row').length).toEqual(1); + expect(component.$el.querySelector('.text-center > a.btn').textContent).toContain('Show all'); + + Vue.http.interceptors = _.without(Vue.http.interceptors, folderInterceptor); + done(); + }); + }); + }); + }); + }); + + describe('methods', () => { + const environmentsEmptyResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify([]), { + status: 200, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsEmptyResponseInterceptor); + Vue.http.interceptors.push(headersInterceptor); + + component = mountComponent(EnvironmentsComponent, mockData); + spyOn(history, 'pushState').and.stub(); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsEmptyResponseInterceptor, + ); + Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor); + }); + + describe('updateContent', () => { + it('should set given parameters', (done) => { + component.updateContent({ scope: 'stopped', page: '3' }) + .then(() => { + expect(component.page).toEqual('3'); + expect(component.scope).toEqual('stopped'); + expect(component.requestData.scope).toEqual('stopped'); + expect(component.requestData.page).toEqual('3'); + done(); + }) + .catch(done.fail); + }); + }); + + describe('onChangeTab', () => { + it('should set page to 1', () => { + spyOn(component, 'updateContent'); + component.onChangeTab('stopped'); + + expect(component.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); + }); + }); + + describe('onChangePage', () => { + it('should update page and keep scope', () => { + spyOn(component, 'updateContent'); + component.onChangePage(4); + + expect(component.updateContent).toHaveBeenCalledWith({ scope: component.scope, page: '4' }); + }); + }); + }); +}); |