diff options
Diffstat (limited to 'spec/javascripts')
141 files changed, 12208 insertions, 9718 deletions
diff --git a/spec/javascripts/.eslintrc b/spec/javascripts/.eslintrc index 3d922021978..9eb0e732572 100644 --- a/spec/javascripts/.eslintrc +++ b/spec/javascripts/.eslintrc @@ -18,6 +18,7 @@ "sandbox": false, "setFixtures": false, "setStyleFixtures": false, + "spyOnDependency": false, "spyOnEvent": false, "ClassSpecHelper": false }, diff --git a/spec/javascripts/activities_spec.js b/spec/javascripts/activities_spec.js index 909a1bf76bc..5dbdcd24296 100644 --- a/spec/javascripts/activities_spec.js +++ b/spec/javascripts/activities_spec.js @@ -3,24 +3,30 @@ import $ from 'jquery'; import 'vendor/jquery.endless-scroll'; import Activities from '~/activities'; +import Pager from '~/pager'; -(() => { +describe('Activities', () => { window.gon || (window.gon = {}); const fixtureTemplate = 'static/event_filter.html.raw'; const filters = [ { id: 'all', - }, { + }, + { id: 'push', name: 'push events', - }, { + }, + { id: 'merged', name: 'merge events', - }, { + }, + { id: 'comments', - }, { + }, + { id: 'team', - }]; + }, + ]; function getEventName(index) { const filter = filters[index]; @@ -32,31 +38,34 @@ import Activities from '~/activities'; return `#${filter.id}_event_filter`; } - describe('Activities', () => { - beforeEach(() => { - loadFixtures(fixtureTemplate); - new Activities(); - }); - - for (let i = 0; i < filters.length; i += 1) { - ((i) => { - describe(`when selecting ${getEventName(i)}`, () => { - beforeEach(() => { - $(getSelector(i)).click(); - }); - - for (let x = 0; x < filters.length; x += 1) { - ((x) => { - const shouldHighlight = i === x; - const testName = shouldHighlight ? 'should highlight' : 'should not highlight'; - - it(`${testName} ${getEventName(x)}`, () => { - expect($(getSelector(x)).parent().hasClass('active')).toEqual(shouldHighlight); - }); - })(x); - } - }); - })(i); - } + beforeEach(() => { + loadFixtures(fixtureTemplate); + spyOn(Pager, 'init').and.stub(); + new Activities(); }); -})(); + + for (let i = 0; i < filters.length; i += 1) { + (i => { + describe(`when selecting ${getEventName(i)}`, () => { + beforeEach(() => { + $(getSelector(i)).click(); + }); + + for (let x = 0; x < filters.length; x += 1) { + (x => { + const shouldHighlight = i === x; + const testName = shouldHighlight ? 'should highlight' : 'should not highlight'; + + it(`${testName} ${getEventName(x)}`, () => { + expect( + $(getSelector(x)) + .parent() + .hasClass('active'), + ).toEqual(shouldHighlight); + }); + })(x); + } + }); + })(i); + } +}); diff --git a/spec/javascripts/badges/components/badge_form_spec.js b/spec/javascripts/badges/components/badge_form_spec.js new file mode 100644 index 00000000000..dd21ec279cb --- /dev/null +++ b/spec/javascripts/badges/components/badge_form_spec.js @@ -0,0 +1,171 @@ +import Vue from 'vue'; +import store from '~/badges/store'; +import BadgeForm from '~/badges/components/badge_form.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { createDummyBadge } from '../dummy_badge'; + +describe('BadgeForm component', () => { + const Component = Vue.extend(BadgeForm); + let vm; + + beforeEach(() => { + setFixtures(` + <div id="dummy-element"></div> + `); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('methods', () => { + beforeEach(() => { + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + props: { + isEditing: false, + }, + }); + }); + + describe('onCancel', () => { + it('calls stopEditing', () => { + spyOn(vm, 'stopEditing'); + + vm.onCancel(); + + expect(vm.stopEditing).toHaveBeenCalled(); + }); + }); + + describe('onSubmit', () => { + describe('if isEditing is true', () => { + beforeEach(() => { + spyOn(vm, 'saveBadge').and.returnValue(Promise.resolve()); + store.replaceState({ + ...store.state, + isSaving: false, + badgeInEditForm: createDummyBadge(), + }); + vm.isEditing = true; + }); + + it('returns immediately if imageUrl is empty', () => { + store.state.badgeInEditForm.imageUrl = ''; + + vm.onSubmit(); + + expect(vm.saveBadge).not.toHaveBeenCalled(); + }); + + it('returns immediately if linkUrl is empty', () => { + store.state.badgeInEditForm.linkUrl = ''; + + vm.onSubmit(); + + expect(vm.saveBadge).not.toHaveBeenCalled(); + }); + + it('returns immediately if isSaving is true', () => { + store.state.isSaving = true; + + vm.onSubmit(); + + expect(vm.saveBadge).not.toHaveBeenCalled(); + }); + + it('calls saveBadge', () => { + vm.onSubmit(); + + expect(vm.saveBadge).toHaveBeenCalled(); + }); + }); + + describe('if isEditing is false', () => { + beforeEach(() => { + spyOn(vm, 'addBadge').and.returnValue(Promise.resolve()); + store.replaceState({ + ...store.state, + isSaving: false, + badgeInAddForm: createDummyBadge(), + }); + vm.isEditing = false; + }); + + it('returns immediately if imageUrl is empty', () => { + store.state.badgeInAddForm.imageUrl = ''; + + vm.onSubmit(); + + expect(vm.addBadge).not.toHaveBeenCalled(); + }); + + it('returns immediately if linkUrl is empty', () => { + store.state.badgeInAddForm.linkUrl = ''; + + vm.onSubmit(); + + expect(vm.addBadge).not.toHaveBeenCalled(); + }); + + it('returns immediately if isSaving is true', () => { + store.state.isSaving = true; + + vm.onSubmit(); + + expect(vm.addBadge).not.toHaveBeenCalled(); + }); + + it('calls addBadge', () => { + vm.onSubmit(); + + expect(vm.addBadge).toHaveBeenCalled(); + }); + }); + }); + }); + + describe('if isEditing is false', () => { + beforeEach(() => { + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + props: { + isEditing: false, + }, + }); + }); + + it('renders one button', () => { + const buttons = vm.$el.querySelectorAll('.row-content-block button'); + expect(buttons.length).toBe(1); + const buttonAddElement = buttons[0]; + expect(buttonAddElement).toBeVisible(); + expect(buttonAddElement).toHaveText('Add badge'); + }); + }); + + describe('if isEditing is true', () => { + beforeEach(() => { + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + props: { + isEditing: true, + }, + }); + }); + + it('renders two buttons', () => { + const buttons = vm.$el.querySelectorAll('.row-content-block button'); + expect(buttons.length).toBe(2); + const buttonSaveElement = buttons[0]; + expect(buttonSaveElement).toBeVisible(); + expect(buttonSaveElement).toHaveText('Save changes'); + const buttonCancelElement = buttons[1]; + expect(buttonCancelElement).toBeVisible(); + expect(buttonCancelElement).toHaveText('Cancel'); + }); + }); +}); diff --git a/spec/javascripts/badges/components/badge_list_row_spec.js b/spec/javascripts/badges/components/badge_list_row_spec.js new file mode 100644 index 00000000000..21bd00d82f0 --- /dev/null +++ b/spec/javascripts/badges/components/badge_list_row_spec.js @@ -0,0 +1,97 @@ +import $ from 'jquery'; +import Vue from 'vue'; +import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants'; +import store from '~/badges/store'; +import BadgeListRow from '~/badges/components/badge_list_row.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { createDummyBadge } from '../dummy_badge'; + +describe('BadgeListRow component', () => { + const Component = Vue.extend(BadgeListRow); + let badge; + let vm; + + beforeEach(() => { + setFixtures(` + <div id="delete-badge-modal" class="modal"></div> + <div id="dummy-element"></div> + `); + store.replaceState({ + ...store.state, + kind: PROJECT_BADGE, + }); + badge = createDummyBadge(); + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + props: { badge }, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders the badge', () => { + const badgeElement = vm.$el.querySelector('.project-badge'); + expect(badgeElement).not.toBeNull(); + expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl); + }); + + it('renders the badge link', () => { + expect(vm.$el).toContainText(badge.linkUrl); + }); + + it('renders the badge kind', () => { + expect(vm.$el).toContainText('Project Badge'); + }); + + it('shows edit and delete buttons', () => { + const buttons = vm.$el.querySelectorAll('.table-button-footer button'); + expect(buttons).toHaveLength(2); + const buttonEditElement = buttons[0]; + expect(buttonEditElement).toBeVisible(); + expect(buttonEditElement).toHaveSpriteIcon('pencil'); + const buttonDeleteElement = buttons[1]; + expect(buttonDeleteElement).toBeVisible(); + expect(buttonDeleteElement).toHaveSpriteIcon('remove'); + }); + + it('calls editBadge when clicking then edit button', () => { + spyOn(vm, 'editBadge'); + + const editButton = vm.$el.querySelector('.table-button-footer button:first-of-type'); + editButton.click(); + + expect(vm.editBadge).toHaveBeenCalled(); + }); + + it('calls updateBadgeInModal and shows modal when clicking then delete button', done => { + spyOn(vm, 'updateBadgeInModal'); + $('#delete-badge-modal').on('shown.bs.modal', () => done()); + + const deleteButton = vm.$el.querySelector('.table-button-footer button:last-of-type'); + deleteButton.click(); + + expect(vm.updateBadgeInModal).toHaveBeenCalled(); + }); + + describe('for a group badge', () => { + beforeEach(done => { + badge.kind = GROUP_BADGE; + + Vue.nextTick() + .then(done) + .catch(done.fail); + }); + + it('renders the badge kind', () => { + expect(vm.$el).toContainText('Group Badge'); + }); + + it('hides edit and delete buttons', () => { + const buttons = vm.$el.querySelectorAll('.table-button-footer button'); + expect(buttons).toHaveLength(0); + }); + }); +}); diff --git a/spec/javascripts/badges/components/badge_list_spec.js b/spec/javascripts/badges/components/badge_list_spec.js new file mode 100644 index 00000000000..9439c578973 --- /dev/null +++ b/spec/javascripts/badges/components/badge_list_spec.js @@ -0,0 +1,88 @@ +import Vue from 'vue'; +import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants'; +import store from '~/badges/store'; +import BadgeList from '~/badges/components/badge_list.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { createDummyBadge } from '../dummy_badge'; + +describe('BadgeList component', () => { + const Component = Vue.extend(BadgeList); + const numberOfDummyBadges = 3; + let vm; + + beforeEach(() => { + setFixtures('<div id="dummy-element"></div>'); + const badges = []; + for (let id = 0; id < numberOfDummyBadges; id += 1) { + badges.push({ id, ...createDummyBadge() }); + } + store.replaceState({ + ...store.state, + badges, + kind: PROJECT_BADGE, + isLoading: false, + }); + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders a header with the badge count', () => { + const header = vm.$el.querySelector('.panel-heading'); + expect(header).toHaveText(new RegExp(`Your badges\\s+${numberOfDummyBadges}`)); + }); + + it('renders a row for each badge', () => { + const rows = vm.$el.querySelectorAll('.gl-responsive-table-row'); + expect(rows).toHaveLength(numberOfDummyBadges); + }); + + it('renders a message if no badges exist', done => { + store.state.badges = []; + + Vue.nextTick() + .then(() => { + expect(vm.$el).toContainText('This project has no badges'); + }) + .then(done) + .catch(done.fail); + }); + + it('shows a loading icon when loading', done => { + store.state.isLoading = true; + + Vue.nextTick() + .then(() => { + const loadingIcon = vm.$el.querySelector('.fa-spinner'); + expect(loadingIcon).toBeVisible(); + }) + .then(done) + .catch(done.fail); + }); + + describe('for group badges', () => { + beforeEach(done => { + store.state.kind = GROUP_BADGE; + + Vue.nextTick() + .then(done) + .catch(done.fail); + }); + + it('renders a message if no badges exist', done => { + store.state.badges = []; + + Vue.nextTick() + .then(() => { + expect(vm.$el).toContainText('This group has no badges'); + }) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/spec/javascripts/badges/components/badge_settings_spec.js b/spec/javascripts/badges/components/badge_settings_spec.js new file mode 100644 index 00000000000..3db02982ad4 --- /dev/null +++ b/spec/javascripts/badges/components/badge_settings_spec.js @@ -0,0 +1,109 @@ +import $ from 'jquery'; +import Vue from 'vue'; +import store from '~/badges/store'; +import BadgeSettings from '~/badges/components/badge_settings.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { createDummyBadge } from '../dummy_badge'; + +describe('BadgeSettings component', () => { + const Component = Vue.extend(BadgeSettings); + let vm; + + beforeEach(() => { + setFixtures(` + <div id="dummy-element"></div> + <button + id="dummy-modal-button" + type="button" + data-toggle="modal" + data-target="#delete-badge-modal" + >Show modal</button> + `); + vm = mountComponentWithStore(Component, { + el: '#dummy-element', + store, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('displays modal if button is clicked', done => { + const badge = createDummyBadge(); + store.state.badgeInModal = badge; + const modal = vm.$el.querySelector('#delete-badge-modal'); + const button = document.getElementById('dummy-modal-button'); + + $(modal).on('shown.bs.modal', () => { + expect(modal).toContainText('Delete badge?'); + const badgeElement = modal.querySelector('img.project-badge'); + expect(badgeElement).not.toBe(null); + expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl); + + done(); + }); + + Vue.nextTick() + .then(() => { + button.click(); + }) + .catch(done.fail); + }); + + it('displays a form to add a badge', () => { + const form = vm.$el.querySelector('form:nth-of-type(2)'); + expect(form).not.toBe(null); + const button = form.querySelector('.btn-success'); + expect(button).not.toBe(null); + expect(button).toHaveText(/Add badge/); + }); + + it('displays badge list', () => { + const badgeListElement = vm.$el.querySelector('.panel'); + expect(badgeListElement).not.toBe(null); + expect(badgeListElement).toBeVisible(); + expect(badgeListElement).toContainText('Your badges'); + }); + + describe('when editing', () => { + beforeEach(done => { + store.state.isEditing = true; + + Vue.nextTick() + .then(done) + .catch(done.fail); + }); + + it('displays a form to edit a badge', () => { + const form = vm.$el.querySelector('form:nth-of-type(1)'); + expect(form).not.toBe(null); + const submitButton = form.querySelector('.btn-success'); + expect(submitButton).not.toBe(null); + expect(submitButton).toHaveText(/Save changes/); + const cancelButton = form.querySelector('.btn-cancel'); + expect(cancelButton).not.toBe(null); + expect(cancelButton).toHaveText(/Cancel/); + }); + + it('displays no badge list', () => { + const badgeListElement = vm.$el.querySelector('.panel'); + expect(badgeListElement).toBeHidden(); + }); + }); + + describe('methods', () => { + describe('onSubmitModal', () => { + it('triggers ', () => { + spyOn(vm, 'deleteBadge').and.callFake(() => Promise.resolve()); + const modal = vm.$el.querySelector('#delete-badge-modal'); + const deleteButton = modal.querySelector('.btn-danger'); + + deleteButton.click(); + + const badge = store.state.badgeInModal; + expect(vm.deleteBadge).toHaveBeenCalledWith(badge); + }); + }); + }); +}); diff --git a/spec/javascripts/badges/components/badge_spec.js b/spec/javascripts/badges/components/badge_spec.js new file mode 100644 index 00000000000..fd1ecc9cdd8 --- /dev/null +++ b/spec/javascripts/badges/components/badge_spec.js @@ -0,0 +1,147 @@ +import Vue from 'vue'; +import Badge from '~/badges/components/badge.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants'; + +describe('Badge component', () => { + const Component = Vue.extend(Badge); + const dummyProps = { + imageUrl: DUMMY_IMAGE_URL, + linkUrl: `${TEST_HOST}/badge/link/url`, + }; + let vm; + + const findElements = () => { + const buttons = vm.$el.querySelectorAll('button'); + return { + badgeImage: vm.$el.querySelector('img.project-badge'), + loadingIcon: vm.$el.querySelector('.fa-spinner'), + reloadButton: buttons[buttons.length - 1], + }; + }; + + const createComponent = (props, el = null) => { + vm = mountComponent(Component, props, el); + const { badgeImage } = findElements(); + return new Promise(resolve => badgeImage.addEventListener('load', resolve)).then(() => + Vue.nextTick(), + ); + }; + + afterEach(() => { + vm.$destroy(); + }); + + describe('watchers', () => { + describe('imageUrl', () => { + it('sets isLoading and resets numRetries and hasError', done => { + const props = { ...dummyProps }; + createComponent(props) + .then(() => { + expect(vm.isLoading).toBe(false); + vm.hasError = true; + vm.numRetries = 42; + + vm.imageUrl = `${props.imageUrl}#something/else`; + + return Vue.nextTick(); + }) + .then(() => { + expect(vm.isLoading).toBe(true); + expect(vm.numRetries).toBe(0); + expect(vm.hasError).toBe(false); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('methods', () => { + beforeEach(done => { + createComponent({ ...dummyProps }) + .then(done) + .catch(done.fail); + }); + + it('onError resets isLoading and sets hasError', () => { + vm.hasError = false; + vm.isLoading = true; + + vm.onError(); + + expect(vm.hasError).toBe(true); + expect(vm.isLoading).toBe(false); + }); + + it('onLoad sets isLoading', () => { + vm.isLoading = true; + + vm.onLoad(); + + expect(vm.isLoading).toBe(false); + }); + + it('reloadImage resets isLoading and hasError and increases numRetries', () => { + vm.hasError = true; + vm.isLoading = false; + vm.numRetries = 0; + + vm.reloadImage(); + + expect(vm.hasError).toBe(false); + expect(vm.isLoading).toBe(true); + expect(vm.numRetries).toBe(1); + }); + }); + + describe('behavior', () => { + beforeEach(done => { + setFixtures('<div id="dummy-element"></div>'); + createComponent({ ...dummyProps }, '#dummy-element') + .then(done) + .catch(done.fail); + }); + + it('shows a badge image after loading', () => { + expect(vm.isLoading).toBe(false); + expect(vm.hasError).toBe(false); + const { badgeImage, loadingIcon, reloadButton } = findElements(); + expect(badgeImage).toBeVisible(); + expect(loadingIcon).toBeHidden(); + expect(reloadButton).toBeHidden(); + expect(vm.$el.innerText).toBe(''); + }); + + it('shows a loading icon when loading', done => { + vm.isLoading = true; + + Vue.nextTick() + .then(() => { + const { badgeImage, loadingIcon, reloadButton } = findElements(); + expect(badgeImage).toBeHidden(); + expect(loadingIcon).toBeVisible(); + expect(reloadButton).toBeHidden(); + expect(vm.$el.innerText).toBe(''); + }) + .then(done) + .catch(done.fail); + }); + + it('shows an error and reload button if loading failed', done => { + vm.hasError = true; + + Vue.nextTick() + .then(() => { + const { badgeImage, loadingIcon, reloadButton } = findElements(); + expect(badgeImage).toBeHidden(); + expect(loadingIcon).toBeHidden(); + expect(reloadButton).toBeVisible(); + expect(reloadButton).toHaveSpriteIcon('retry'); + expect(vm.$el.innerText.trim()).toBe('No badge image'); + }) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/spec/javascripts/badges/dummy_badge.js b/spec/javascripts/badges/dummy_badge.js new file mode 100644 index 00000000000..6aaff21c503 --- /dev/null +++ b/spec/javascripts/badges/dummy_badge.js @@ -0,0 +1,23 @@ +import { PROJECT_BADGE } from '~/badges/constants'; +import { DUMMY_IMAGE_URL, TEST_HOST } from 'spec/test_constants'; + +export const createDummyBadge = () => { + const id = Math.floor(1000 * Math.random()); + return { + id, + imageUrl: `${TEST_HOST}/badges/${id}/image/url`, + isDeleting: false, + linkUrl: `${TEST_HOST}/badges/${id}/link/url`, + kind: PROJECT_BADGE, + renderedImageUrl: `${DUMMY_IMAGE_URL}?id=${id}`, + renderedLinkUrl: `${TEST_HOST}/badges/${id}/rendered/link/url`, + }; +}; + +export const createDummyBadgeResponse = () => ({ + image_url: `${TEST_HOST}/badge/image/url`, + link_url: `${TEST_HOST}/badge/link/url`, + kind: PROJECT_BADGE, + rendered_image_url: DUMMY_IMAGE_URL, + rendered_link_url: `${TEST_HOST}/rendered/badge/link/url`, +}); diff --git a/spec/javascripts/badges/store/actions_spec.js b/spec/javascripts/badges/store/actions_spec.js new file mode 100644 index 00000000000..bb6263c6de4 --- /dev/null +++ b/spec/javascripts/badges/store/actions_spec.js @@ -0,0 +1,607 @@ +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; +import actions, { transformBackendBadge } from '~/badges/store/actions'; +import mutationTypes from '~/badges/store/mutation_types'; +import createState from '~/badges/store/state'; +import { TEST_HOST } from 'spec/test_constants'; +import testAction from 'spec/helpers/vuex_action_helper'; +import { createDummyBadge, createDummyBadgeResponse } from '../dummy_badge'; + +describe('Badges store actions', () => { + const dummyEndpointUrl = `${TEST_HOST}/badges/endpoint`; + const dummyBadges = [{ ...createDummyBadge(), id: 5 }, { ...createDummyBadge(), id: 6 }]; + + let axiosMock; + let badgeId; + let state; + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + state = { + ...createState(), + apiEndpointUrl: dummyEndpointUrl, + badges: dummyBadges, + }; + badgeId = state.badges[0].id; + }); + + afterEach(() => { + axiosMock.restore(); + }); + + describe('requestNewBadge', () => { + it('commits REQUEST_NEW_BADGE', done => { + testAction( + actions.requestNewBadge, + null, + state, + [{ type: mutationTypes.REQUEST_NEW_BADGE }], + [], + done, + ); + }); + }); + + describe('receiveNewBadge', () => { + it('commits RECEIVE_NEW_BADGE', done => { + const newBadge = createDummyBadge(); + testAction( + actions.receiveNewBadge, + newBadge, + state, + [{ type: mutationTypes.RECEIVE_NEW_BADGE, payload: newBadge }], + [], + done, + ); + }); + }); + + describe('receiveNewBadgeError', () => { + it('commits RECEIVE_NEW_BADGE_ERROR', done => { + testAction( + actions.receiveNewBadgeError, + null, + state, + [{ type: mutationTypes.RECEIVE_NEW_BADGE_ERROR }], + [], + done, + ); + }); + }); + + describe('addBadge', () => { + let badgeInAddForm; + let dispatch; + let endpointMock; + + beforeEach(() => { + endpointMock = axiosMock.onPost(dummyEndpointUrl); + dispatch = jasmine.createSpy('dispatch'); + badgeInAddForm = createDummyBadge(); + state = { + ...state, + badgeInAddForm, + }; + }); + + it('dispatches requestNewBadge and receiveNewBadge for successful response', done => { + const dummyResponse = createDummyBadgeResponse(); + + endpointMock.replyOnce(req => { + expect(req.data).toBe( + JSON.stringify({ + image_url: badgeInAddForm.imageUrl, + link_url: badgeInAddForm.linkUrl, + }), + ); + expect(dispatch.calls.allArgs()).toEqual([['requestNewBadge']]); + dispatch.calls.reset(); + return [200, dummyResponse]; + }); + + const dummyBadge = transformBackendBadge(dummyResponse); + actions + .addBadge({ state, dispatch }) + .then(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveNewBadge', dummyBadge]]); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestNewBadge and receiveNewBadgeError for error response', done => { + endpointMock.replyOnce(req => { + expect(req.data).toBe( + JSON.stringify({ + image_url: badgeInAddForm.imageUrl, + link_url: badgeInAddForm.linkUrl, + }), + ); + expect(dispatch.calls.allArgs()).toEqual([['requestNewBadge']]); + dispatch.calls.reset(); + return [500, '']; + }); + + actions + .addBadge({ state, dispatch }) + .then(() => done.fail('Expected Ajax call to fail!')) + .catch(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveNewBadgeError']]); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('requestDeleteBadge', () => { + it('commits REQUEST_DELETE_BADGE', done => { + testAction( + actions.requestDeleteBadge, + badgeId, + state, + [{ type: mutationTypes.REQUEST_DELETE_BADGE, payload: badgeId }], + [], + done, + ); + }); + }); + + describe('receiveDeleteBadge', () => { + it('commits RECEIVE_DELETE_BADGE', done => { + testAction( + actions.receiveDeleteBadge, + badgeId, + state, + [{ type: mutationTypes.RECEIVE_DELETE_BADGE, payload: badgeId }], + [], + done, + ); + }); + }); + + describe('receiveDeleteBadgeError', () => { + it('commits RECEIVE_DELETE_BADGE_ERROR', done => { + testAction( + actions.receiveDeleteBadgeError, + badgeId, + state, + [{ type: mutationTypes.RECEIVE_DELETE_BADGE_ERROR, payload: badgeId }], + [], + done, + ); + }); + }); + + describe('deleteBadge', () => { + let dispatch; + let endpointMock; + + beforeEach(() => { + endpointMock = axiosMock.onDelete(`${dummyEndpointUrl}/${badgeId}`); + dispatch = jasmine.createSpy('dispatch'); + }); + + it('dispatches requestDeleteBadge and receiveDeleteBadge for successful response', done => { + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestDeleteBadge', badgeId]]); + dispatch.calls.reset(); + return [200, '']; + }); + + actions + .deleteBadge({ state, dispatch }, { id: badgeId }) + .then(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveDeleteBadge', badgeId]]); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestDeleteBadge and receiveDeleteBadgeError for error response', done => { + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestDeleteBadge', badgeId]]); + dispatch.calls.reset(); + return [500, '']; + }); + + actions + .deleteBadge({ state, dispatch }, { id: badgeId }) + .then(() => done.fail('Expected Ajax call to fail!')) + .catch(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveDeleteBadgeError', badgeId]]); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('editBadge', () => { + it('commits START_EDITING', done => { + const dummyBadge = createDummyBadge(); + testAction( + actions.editBadge, + dummyBadge, + state, + [{ type: mutationTypes.START_EDITING, payload: dummyBadge }], + [], + done, + ); + }); + }); + + describe('requestLoadBadges', () => { + it('commits REQUEST_LOAD_BADGES', done => { + const dummyData = 'this is not real data'; + testAction( + actions.requestLoadBadges, + dummyData, + state, + [{ type: mutationTypes.REQUEST_LOAD_BADGES, payload: dummyData }], + [], + done, + ); + }); + }); + + describe('receiveLoadBadges', () => { + it('commits RECEIVE_LOAD_BADGES', done => { + const badges = dummyBadges; + testAction( + actions.receiveLoadBadges, + badges, + state, + [{ type: mutationTypes.RECEIVE_LOAD_BADGES, payload: badges }], + [], + done, + ); + }); + }); + + describe('receiveLoadBadgesError', () => { + it('commits RECEIVE_LOAD_BADGES_ERROR', done => { + testAction( + actions.receiveLoadBadgesError, + null, + state, + [{ type: mutationTypes.RECEIVE_LOAD_BADGES_ERROR }], + [], + done, + ); + }); + }); + + describe('loadBadges', () => { + let dispatch; + let endpointMock; + + beforeEach(() => { + endpointMock = axiosMock.onGet(dummyEndpointUrl); + dispatch = jasmine.createSpy('dispatch'); + }); + + it('dispatches requestLoadBadges and receiveLoadBadges for successful response', done => { + const dummyData = 'this is just some data'; + const dummyReponse = [ + createDummyBadgeResponse(), + createDummyBadgeResponse(), + createDummyBadgeResponse(), + ]; + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestLoadBadges', dummyData]]); + dispatch.calls.reset(); + return [200, dummyReponse]; + }); + + actions + .loadBadges({ state, dispatch }, dummyData) + .then(() => { + const badges = dummyReponse.map(transformBackendBadge); + expect(dispatch.calls.allArgs()).toEqual([['receiveLoadBadges', badges]]); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestLoadBadges and receiveLoadBadgesError for error response', done => { + const dummyData = 'this is just some data'; + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestLoadBadges', dummyData]]); + dispatch.calls.reset(); + return [500, '']; + }); + + actions + .loadBadges({ state, dispatch }, dummyData) + .then(() => done.fail('Expected Ajax call to fail!')) + .catch(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveLoadBadgesError']]); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('requestRenderedBadge', () => { + it('commits REQUEST_RENDERED_BADGE', done => { + testAction( + actions.requestRenderedBadge, + null, + state, + [{ type: mutationTypes.REQUEST_RENDERED_BADGE }], + [], + done, + ); + }); + }); + + describe('receiveRenderedBadge', () => { + it('commits RECEIVE_RENDERED_BADGE', done => { + const dummyBadge = createDummyBadge(); + testAction( + actions.receiveRenderedBadge, + dummyBadge, + state, + [{ type: mutationTypes.RECEIVE_RENDERED_BADGE, payload: dummyBadge }], + [], + done, + ); + }); + }); + + describe('receiveRenderedBadgeError', () => { + it('commits RECEIVE_RENDERED_BADGE_ERROR', done => { + testAction( + actions.receiveRenderedBadgeError, + null, + state, + [{ type: mutationTypes.RECEIVE_RENDERED_BADGE_ERROR }], + [], + done, + ); + }); + }); + + describe('renderBadge', () => { + let dispatch; + let endpointMock; + let badgeInForm; + + beforeEach(() => { + badgeInForm = createDummyBadge(); + state = { + ...state, + badgeInAddForm: badgeInForm, + }; + const urlParameters = [ + `link_url=${encodeURIComponent(badgeInForm.linkUrl)}`, + `image_url=${encodeURIComponent(badgeInForm.imageUrl)}`, + ].join('&'); + endpointMock = axiosMock.onGet(`${dummyEndpointUrl}/render?${urlParameters}`); + dispatch = jasmine.createSpy('dispatch'); + }); + + it('returns immediately if imageUrl is empty', done => { + spyOn(axios, 'get'); + badgeInForm.imageUrl = ''; + + actions + .renderBadge({ state, dispatch }) + .then(() => { + expect(axios.get).not.toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + it('returns immediately if linkUrl is empty', done => { + spyOn(axios, 'get'); + badgeInForm.linkUrl = ''; + + actions + .renderBadge({ state, dispatch }) + .then(() => { + expect(axios.get).not.toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + it('escapes user input', done => { + spyOn(axios, 'get').and.callFake(() => Promise.resolve({ data: createDummyBadgeResponse() })); + badgeInForm.imageUrl = '&make-sandwhich=true'; + badgeInForm.linkUrl = '<script>I am dangerous!</script>'; + + actions + .renderBadge({ state, dispatch }) + .then(() => { + expect(axios.get.calls.count()).toBe(1); + const url = axios.get.calls.argsFor(0)[0]; + expect(url).toMatch(`^${dummyEndpointUrl}/render?`); + expect(url).toMatch('\\?link_url=%3Cscript%3EI%20am%20dangerous!%3C%2Fscript%3E&'); + expect(url).toMatch('&image_url=%26make-sandwhich%3Dtrue$'); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestRenderedBadge and receiveRenderedBadge for successful response', done => { + const dummyReponse = createDummyBadgeResponse(); + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestRenderedBadge']]); + dispatch.calls.reset(); + return [200, dummyReponse]; + }); + + actions + .renderBadge({ state, dispatch }) + .then(() => { + const renderedBadge = transformBackendBadge(dummyReponse); + expect(dispatch.calls.allArgs()).toEqual([['receiveRenderedBadge', renderedBadge]]); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestRenderedBadge and receiveRenderedBadgeError for error response', done => { + endpointMock.replyOnce(() => { + expect(dispatch.calls.allArgs()).toEqual([['requestRenderedBadge']]); + dispatch.calls.reset(); + return [500, '']; + }); + + actions + .renderBadge({ state, dispatch }) + .then(() => done.fail('Expected Ajax call to fail!')) + .catch(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveRenderedBadgeError']]); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('requestUpdatedBadge', () => { + it('commits REQUEST_UPDATED_BADGE', done => { + testAction( + actions.requestUpdatedBadge, + null, + state, + [{ type: mutationTypes.REQUEST_UPDATED_BADGE }], + [], + done, + ); + }); + }); + + describe('receiveUpdatedBadge', () => { + it('commits RECEIVE_UPDATED_BADGE', done => { + const updatedBadge = createDummyBadge(); + testAction( + actions.receiveUpdatedBadge, + updatedBadge, + state, + [{ type: mutationTypes.RECEIVE_UPDATED_BADGE, payload: updatedBadge }], + [], + done, + ); + }); + }); + + describe('receiveUpdatedBadgeError', () => { + it('commits RECEIVE_UPDATED_BADGE_ERROR', done => { + testAction( + actions.receiveUpdatedBadgeError, + null, + state, + [{ type: mutationTypes.RECEIVE_UPDATED_BADGE_ERROR }], + [], + done, + ); + }); + }); + + describe('saveBadge', () => { + let badgeInEditForm; + let dispatch; + let endpointMock; + + beforeEach(() => { + badgeInEditForm = createDummyBadge(); + state = { + ...state, + badgeInEditForm, + }; + endpointMock = axiosMock.onPut(`${dummyEndpointUrl}/${badgeInEditForm.id}`); + dispatch = jasmine.createSpy('dispatch'); + }); + + it('dispatches requestUpdatedBadge and receiveUpdatedBadge for successful response', done => { + const dummyResponse = createDummyBadgeResponse(); + + endpointMock.replyOnce(req => { + expect(req.data).toBe( + JSON.stringify({ + image_url: badgeInEditForm.imageUrl, + link_url: badgeInEditForm.linkUrl, + }), + ); + expect(dispatch.calls.allArgs()).toEqual([['requestUpdatedBadge']]); + dispatch.calls.reset(); + return [200, dummyResponse]; + }); + + const updatedBadge = transformBackendBadge(dummyResponse); + actions + .saveBadge({ state, dispatch }) + .then(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveUpdatedBadge', updatedBadge]]); + }) + .then(done) + .catch(done.fail); + }); + + it('dispatches requestUpdatedBadge and receiveUpdatedBadgeError for error response', done => { + endpointMock.replyOnce(req => { + expect(req.data).toBe( + JSON.stringify({ + image_url: badgeInEditForm.imageUrl, + link_url: badgeInEditForm.linkUrl, + }), + ); + expect(dispatch.calls.allArgs()).toEqual([['requestUpdatedBadge']]); + dispatch.calls.reset(); + return [500, '']; + }); + + actions + .saveBadge({ state, dispatch }) + .then(() => done.fail('Expected Ajax call to fail!')) + .catch(() => { + expect(dispatch.calls.allArgs()).toEqual([['receiveUpdatedBadgeError']]); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('stopEditing', () => { + it('commits STOP_EDITING', done => { + testAction( + actions.stopEditing, + null, + state, + [{ type: mutationTypes.STOP_EDITING }], + [], + done, + ); + }); + }); + + describe('updateBadgeInForm', () => { + it('commits UPDATE_BADGE_IN_FORM', done => { + const dummyBadge = createDummyBadge(); + testAction( + actions.updateBadgeInForm, + dummyBadge, + state, + [{ type: mutationTypes.UPDATE_BADGE_IN_FORM, payload: dummyBadge }], + [], + done, + ); + }); + + describe('updateBadgeInModal', () => { + it('commits UPDATE_BADGE_IN_MODAL', done => { + const dummyBadge = createDummyBadge(); + testAction( + actions.updateBadgeInModal, + dummyBadge, + state, + [{ type: mutationTypes.UPDATE_BADGE_IN_MODAL, payload: dummyBadge }], + [], + done, + ); + }); + }); + }); +}); diff --git a/spec/javascripts/badges/store/mutations_spec.js b/spec/javascripts/badges/store/mutations_spec.js new file mode 100644 index 00000000000..8d26f83339d --- /dev/null +++ b/spec/javascripts/badges/store/mutations_spec.js @@ -0,0 +1,418 @@ +import { GROUP_BADGE, PROJECT_BADGE } from '~/badges/constants'; +import store from '~/badges/store'; +import types from '~/badges/store/mutation_types'; +import createState from '~/badges/store/state'; +import { createDummyBadge } from '../dummy_badge'; + +describe('Badges store mutations', () => { + let dummyBadge; + + beforeEach(() => { + dummyBadge = createDummyBadge(); + store.replaceState(createState()); + }); + + describe('RECEIVE_DELETE_BADGE', () => { + beforeEach(() => { + const badges = [ + { ...dummyBadge, id: dummyBadge.id - 1 }, + dummyBadge, + { ...dummyBadge, id: dummyBadge.id + 1 }, + ]; + + store.replaceState({ + ...store.state, + badges, + }); + }); + + it('removes deleted badge', () => { + const badgeCount = store.state.badges.length; + + store.commit(types.RECEIVE_DELETE_BADGE, dummyBadge.id); + + expect(store.state.badges.length).toBe(badgeCount - 1); + expect(store.state.badges.indexOf(dummyBadge)).toBe(-1); + }); + }); + + describe('RECEIVE_DELETE_BADGE_ERROR', () => { + beforeEach(() => { + const badges = [ + { ...dummyBadge, id: dummyBadge.id - 1, isDeleting: false }, + { ...dummyBadge, isDeleting: true }, + { ...dummyBadge, id: dummyBadge.id + 1, isDeleting: true }, + ]; + + store.replaceState({ + ...store.state, + badges, + }); + }); + + it('sets isDeleting to false', () => { + const badgeCount = store.state.badges.length; + + store.commit(types.RECEIVE_DELETE_BADGE_ERROR, dummyBadge.id); + + expect(store.state.badges.length).toBe(badgeCount); + expect(store.state.badges[0].isDeleting).toBe(false); + expect(store.state.badges[1].isDeleting).toBe(false); + expect(store.state.badges[2].isDeleting).toBe(true); + }); + }); + + describe('RECEIVE_LOAD_BADGES', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isLoading: 'not false', + }); + }); + + it('sets badges and isLoading to false', () => { + const badges = [createDummyBadge()]; + store.commit(types.RECEIVE_LOAD_BADGES, badges); + + expect(store.state.isLoading).toBe(false); + expect(store.state.badges).toBe(badges); + }); + }); + + describe('RECEIVE_LOAD_BADGES_ERROR', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isLoading: 'not false', + }); + }); + + it('sets isLoading to false', () => { + store.commit(types.RECEIVE_LOAD_BADGES_ERROR); + + expect(store.state.isLoading).toBe(false); + }); + }); + + describe('RECEIVE_NEW_BADGE', () => { + beforeEach(() => { + const badges = [ + { ...dummyBadge, id: dummyBadge.id - 1, kind: GROUP_BADGE }, + { ...dummyBadge, id: dummyBadge.id + 1, kind: GROUP_BADGE }, + { ...dummyBadge, id: dummyBadge.id - 1, kind: PROJECT_BADGE }, + { ...dummyBadge, id: dummyBadge.id + 1, kind: PROJECT_BADGE }, + ]; + store.replaceState({ + ...store.state, + badgeInAddForm: createDummyBadge(), + badges, + isSaving: 'dummy value', + renderedBadge: createDummyBadge(), + }); + }); + + it('resets the add form', () => { + store.commit(types.RECEIVE_NEW_BADGE, dummyBadge); + + expect(store.state.badgeInAddForm).toBe(null); + expect(store.state.isSaving).toBe(false); + expect(store.state.renderedBadge).toBe(null); + }); + + it('inserts group badge at correct position', () => { + const badgeCount = store.state.badges.length; + dummyBadge = { ...dummyBadge, kind: GROUP_BADGE }; + + store.commit(types.RECEIVE_NEW_BADGE, dummyBadge); + + expect(store.state.badges.length).toBe(badgeCount + 1); + expect(store.state.badges.indexOf(dummyBadge)).toBe(1); + }); + + it('inserts project badge at correct position', () => { + const badgeCount = store.state.badges.length; + dummyBadge = { ...dummyBadge, kind: PROJECT_BADGE }; + + store.commit(types.RECEIVE_NEW_BADGE, dummyBadge); + + expect(store.state.badges.length).toBe(badgeCount + 1); + expect(store.state.badges.indexOf(dummyBadge)).toBe(3); + }); + }); + + describe('RECEIVE_NEW_BADGE_ERROR', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isSaving: 'dummy value', + }); + }); + + it('sets isSaving to false', () => { + store.commit(types.RECEIVE_NEW_BADGE_ERROR); + + expect(store.state.isSaving).toBe(false); + }); + }); + + describe('RECEIVE_RENDERED_BADGE', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isRendering: 'dummy value', + renderedBadge: 'dummy value', + }); + }); + + it('sets renderedBadge', () => { + store.commit(types.RECEIVE_RENDERED_BADGE, dummyBadge); + + expect(store.state.isRendering).toBe(false); + expect(store.state.renderedBadge).toBe(dummyBadge); + }); + }); + + describe('RECEIVE_RENDERED_BADGE_ERROR', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isRendering: 'dummy value', + }); + }); + + it('sets isRendering to false', () => { + store.commit(types.RECEIVE_RENDERED_BADGE_ERROR); + + expect(store.state.isRendering).toBe(false); + }); + }); + + describe('RECEIVE_UPDATED_BADGE', () => { + beforeEach(() => { + const badges = [ + { ...dummyBadge, id: dummyBadge.id - 1 }, + dummyBadge, + { ...dummyBadge, id: dummyBadge.id + 1 }, + ]; + store.replaceState({ + ...store.state, + badgeInEditForm: createDummyBadge(), + badges, + isEditing: 'dummy value', + isSaving: 'dummy value', + renderedBadge: createDummyBadge(), + }); + }); + + it('resets the edit form', () => { + store.commit(types.RECEIVE_UPDATED_BADGE, dummyBadge); + + expect(store.state.badgeInAddForm).toBe(null); + expect(store.state.isSaving).toBe(false); + expect(store.state.renderedBadge).toBe(null); + }); + + it('replaces the updated badge', () => { + const badgeCount = store.state.badges.length; + const badgeIndex = store.state.badges.indexOf(dummyBadge); + const newBadge = { id: dummyBadge.id, dummy: 'value' }; + + store.commit(types.RECEIVE_UPDATED_BADGE, newBadge); + + expect(store.state.badges.length).toBe(badgeCount); + expect(store.state.badges[badgeIndex]).toBe(newBadge); + }); + }); + + describe('RECEIVE_UPDATED_BADGE_ERROR', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isSaving: 'dummy value', + }); + }); + + it('sets isSaving to false', () => { + store.commit(types.RECEIVE_NEW_BADGE_ERROR); + + expect(store.state.isSaving).toBe(false); + }); + }); + + describe('REQUEST_DELETE_BADGE', () => { + beforeEach(() => { + const badges = [ + { ...dummyBadge, id: dummyBadge.id - 1, isDeleting: false }, + { ...dummyBadge, isDeleting: false }, + { ...dummyBadge, id: dummyBadge.id + 1, isDeleting: true }, + ]; + + store.replaceState({ + ...store.state, + badges, + }); + }); + + it('sets isDeleting to true', () => { + const badgeCount = store.state.badges.length; + + store.commit(types.REQUEST_DELETE_BADGE, dummyBadge.id); + + expect(store.state.badges.length).toBe(badgeCount); + expect(store.state.badges[0].isDeleting).toBe(false); + expect(store.state.badges[1].isDeleting).toBe(true); + expect(store.state.badges[2].isDeleting).toBe(true); + }); + }); + + describe('REQUEST_LOAD_BADGES', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + apiEndpointUrl: 'some endpoint', + docsUrl: 'some url', + isLoading: 'dummy value', + kind: 'some kind', + }); + }); + + it('sets isLoading to true and initializes the store', () => { + const dummyData = { + apiEndpointUrl: 'dummy endpoint', + docsUrl: 'dummy url', + kind: 'dummy kind', + }; + + store.commit(types.REQUEST_LOAD_BADGES, dummyData); + + expect(store.state.isLoading).toBe(true); + expect(store.state.apiEndpointUrl).toBe(dummyData.apiEndpointUrl); + expect(store.state.docsUrl).toBe(dummyData.docsUrl); + expect(store.state.kind).toBe(dummyData.kind); + }); + }); + + describe('REQUEST_NEW_BADGE', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isSaving: 'dummy value', + }); + }); + + it('sets isSaving to true', () => { + store.commit(types.REQUEST_NEW_BADGE); + + expect(store.state.isSaving).toBe(true); + }); + }); + + describe('REQUEST_RENDERED_BADGE', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isRendering: 'dummy value', + }); + }); + + it('sets isRendering to true', () => { + store.commit(types.REQUEST_RENDERED_BADGE); + + expect(store.state.isRendering).toBe(true); + }); + }); + + describe('REQUEST_UPDATED_BADGE', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + isSaving: 'dummy value', + }); + }); + + it('sets isSaving to true', () => { + store.commit(types.REQUEST_NEW_BADGE); + + expect(store.state.isSaving).toBe(true); + }); + }); + + describe('START_EDITING', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + badgeInEditForm: 'dummy value', + isEditing: 'dummy value', + renderedBadge: 'dummy value', + }); + }); + + it('initializes the edit form', () => { + store.commit(types.START_EDITING, dummyBadge); + + expect(store.state.isEditing).toBe(true); + expect(store.state.badgeInEditForm).toEqual(dummyBadge); + expect(store.state.renderedBadge).toEqual(dummyBadge); + }); + }); + + describe('STOP_EDITING', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + badgeInEditForm: 'dummy value', + isEditing: 'dummy value', + renderedBadge: 'dummy value', + }); + }); + + it('resets the edit form', () => { + store.commit(types.STOP_EDITING); + + expect(store.state.isEditing).toBe(false); + expect(store.state.badgeInEditForm).toBe(null); + expect(store.state.renderedBadge).toBe(null); + }); + }); + + describe('UPDATE_BADGE_IN_FORM', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + badgeInAddForm: 'dummy value', + badgeInEditForm: 'dummy value', + }); + }); + + it('sets badgeInEditForm if isEditing is true', () => { + store.state.isEditing = true; + + store.commit(types.UPDATE_BADGE_IN_FORM, dummyBadge); + + expect(store.state.badgeInEditForm).toBe(dummyBadge); + }); + + it('sets badgeInAddForm if isEditing is false', () => { + store.state.isEditing = false; + + store.commit(types.UPDATE_BADGE_IN_FORM, dummyBadge); + + expect(store.state.badgeInAddForm).toBe(dummyBadge); + }); + }); + + describe('UPDATE_BADGE_IN_MODAL', () => { + beforeEach(() => { + store.replaceState({ + ...store.state, + badgeInModal: 'dummy value', + }); + }); + + it('sets badgeInModal', () => { + store.commit(types.UPDATE_BADGE_IN_MODAL, dummyBadge); + + expect(store.state.badgeInModal).toBe(dummyBadge); + }); + }); +}); diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index c37c62c63dd..d03836d10f9 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import '~/behaviors/quick_submit'; -describe('Quick Submit behavior', () => { +describe('Quick Submit behavior', function () { const keydownEvent = (options = { keyCode: 13, metaKey: true }) => $.Event('keydown', options); preloadFixtures('merge_requests/merge_request_with_task_list.html.raw'); diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js index 0b1de504435..346f795c3f5 100644 --- a/spec/javascripts/blob/blob_file_dropzone_spec.js +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import BlobFileDropzone from '~/blob/blob_file_dropzone'; -describe('BlobFileDropzone', () => { +describe('BlobFileDropzone', function () { preloadFixtures('blob/show.html.raw'); beforeEach(() => { diff --git a/spec/javascripts/boards/board_blank_state_spec.js b/spec/javascripts/boards/board_blank_state_spec.js index f757dadfada..664ea202e93 100644 --- a/spec/javascripts/boards/board_blank_state_spec.js +++ b/spec/javascripts/boards/board_blank_state_spec.js @@ -1,7 +1,7 @@ /* global BoardService */ import Vue from 'vue'; import '~/boards/stores/boards_store'; -import boardBlankState from '~/boards/components/board_blank_state'; +import BoardBlankState from '~/boards/components/board_blank_state.vue'; import { mockBoardService } from './mock_data'; describe('Boards blank state', () => { @@ -9,7 +9,7 @@ describe('Boards blank state', () => { let fail = false; beforeEach((done) => { - const Comp = Vue.extend(boardBlankState); + const Comp = Vue.extend(BoardBlankState); gl.issueBoards.BoardsStore.create(); gl.boardService = mockBoardService(); diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index 37088a6421c..be1ea0b57b4 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -41,6 +41,8 @@ describe('Issue card component', () => { confidential: false, labels: [list.label], assignees: [], + reference_path: '#1', + real_path: '/test/1', }); component = new Vue({ diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/javascripts/boards/modal_store_spec.js index e9d77f035e3..797693a21aa 100644 --- a/spec/javascripts/boards/modal_store_spec.js +++ b/spec/javascripts/boards/modal_store_spec.js @@ -4,12 +4,11 @@ import '~/vue_shared/models/label'; import '~/boards/models/issue'; import '~/boards/models/list'; import '~/boards/models/assignee'; -import '~/boards/stores/modal_store'; +import Store from '~/boards/stores/modal_store'; describe('Modal store', () => { let issue; let issue2; - const Store = gl.issueBoards.ModalStore; beforeEach(() => { // Setup default state diff --git a/spec/javascripts/branches/branches_delete_modal_spec.js b/spec/javascripts/branches/branches_delete_modal_spec.js new file mode 100644 index 00000000000..b223b8e2c0a --- /dev/null +++ b/spec/javascripts/branches/branches_delete_modal_spec.js @@ -0,0 +1,40 @@ +import $ from 'jquery'; +import DeleteModal from '~/branches/branches_delete_modal'; + +describe('branches delete modal', () => { + describe('setDisableDeleteButton', () => { + let submitSpy; + let $deleteButton; + + beforeEach(() => { + setFixtures(` + <div id="modal-delete-branch"> + <form> + <button type="submit" class="js-delete-branch">Delete</button> + </form> + </div> + `); + $deleteButton = $('.js-delete-branch'); + submitSpy = jasmine.createSpy('submit').and.callFake(event => event.preventDefault()); + $('#modal-delete-branch form').on('submit', submitSpy); + // eslint-disable-next-line no-new + new DeleteModal(); + }); + + it('does not submit if button is disabled', () => { + $deleteButton.attr('disabled', true); + + $deleteButton.click(); + + expect(submitSpy).not.toHaveBeenCalled(); + }); + + it('submits if button is not disabled', () => { + $deleteButton.attr('disabled', false); + + $deleteButton.click(); + + expect(submitSpy).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js index 2abf52a1676..8427e8a0ba7 100644 --- a/spec/javascripts/collapsed_sidebar_todo_spec.js +++ b/spec/javascripts/collapsed_sidebar_todo_spec.js @@ -85,7 +85,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { setTimeout(() => { expect( document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(), - ).toBe('Mark done'); + ).toBe('Mark todo as done'); done(); }); @@ -97,7 +97,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { setTimeout(() => { expect( document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('data-original-title'), - ).toBe('Mark done'); + ).toBe('Mark todo as done'); done(); }); @@ -128,13 +128,13 @@ describe('Issuable right sidebar collapsed todo toggle', () => { .catch(done.fail); }); - it('updates aria-label to mark done', (done) => { + it('updates aria-label to mark todo as done', (done) => { document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); setTimeout(() => { expect( document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'), - ).toBe('Mark done'); + ).toBe('Mark todo as done'); done(); }); @@ -147,7 +147,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { .then(() => { expect( document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('aria-label'), - ).toBe('Mark done'); + ).toBe('Mark todo as done'); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); }) diff --git a/spec/javascripts/comment_type_toggle_spec.js b/spec/javascripts/comment_type_toggle_spec.js index dfd0810d52e..0ba709298c5 100644 --- a/spec/javascripts/comment_type_toggle_spec.js +++ b/spec/javascripts/comment_type_toggle_spec.js @@ -1,5 +1,4 @@ import CommentTypeToggle from '~/comment_type_toggle'; -import * as dropLabSrc from '~/droplab/drop_lab'; import InputSetter from '~/droplab/plugins/input_setter'; describe('CommentTypeToggle', function () { @@ -59,14 +58,14 @@ describe('CommentTypeToggle', function () { this.droplab = jasmine.createSpyObj('droplab', ['init']); - spyOn(dropLabSrc, 'default').and.returnValue(this.droplab); + this.droplabConstructor = spyOnDependency(CommentTypeToggle, 'DropLab').and.returnValue(this.droplab); spyOn(this.commentTypeToggle, 'setConfig').and.returnValue(this.config); CommentTypeToggle.prototype.initDroplab.call(this.commentTypeToggle); }); it('should instantiate a DropLab instance', function () { - expect(dropLabSrc.default).toHaveBeenCalled(); + expect(this.droplabConstructor).toHaveBeenCalled(); }); it('should set .droplab', function () { diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js index 0afe09d87bc..819ed7896ca 100644 --- a/spec/javascripts/commit/pipelines/pipelines_spec.js +++ b/spec/javascripts/commit/pipelines/pipelines_spec.js @@ -1,113 +1,82 @@ -import _ from 'underscore'; import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import pipelinesTable from '~/commit/pipelines/pipelines_table.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; -describe('Pipelines table in Commits and Merge requests', () => { +describe('Pipelines table in Commits and Merge requests', function () { const jsonFixtureName = 'pipelines/pipelines.json'; let pipeline; let PipelinesTable; + let mock; + let vm; preloadFixtures(jsonFixtureName); beforeEach(() => { + mock = new MockAdapter(axios); + const pipelines = getJSONFixture(jsonFixtureName).pipelines; PipelinesTable = Vue.extend(pipelinesTable); pipeline = pipelines.find(p => p.user !== null && p.commit !== null); }); + afterEach(() => { + vm.$destroy(); + mock.restore(); + }); + describe('successful request', () => { describe('without pipelines', () => { - const pipelinesEmptyResponse = (request, next) => { - next(request.respondWith(JSON.stringify([]), { - status: 200, - })); - }; - beforeEach(function () { - Vue.http.interceptors.push(pipelinesEmptyResponse); - - this.component = new PipelinesTable({ - propsData: { - endpoint: 'endpoint', - helpPagePath: 'foo', - emptyStateSvgPath: 'foo', - errorStateSvgPath: 'foo', - autoDevopsHelpPath: 'foo', - }, - }).$mount(); - }); + mock.onGet('endpoint.json').reply(200, []); - afterEach(function () { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesEmptyResponse, - ); - this.component.$destroy(); + vm = mountComponent(PipelinesTable, { + endpoint: 'endpoint.json', + helpPagePath: 'foo', + emptyStateSvgPath: 'foo', + errorStateSvgPath: 'foo', + autoDevopsHelpPath: 'foo', + }); }); it('should render the empty state', function (done) { setTimeout(() => { - expect(this.component.$el.querySelector('.empty-state')).toBeDefined(); - expect(this.component.$el.querySelector('.realtime-loading')).toBe(null); - expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null); + expect(vm.$el.querySelector('.empty-state')).toBeDefined(); + expect(vm.$el.querySelector('.realtime-loading')).toBe(null); + expect(vm.$el.querySelector('.js-pipelines-error-state')).toBe(null); done(); - }, 1); + }, 0); }); }); describe('with pipelines', () => { - const pipelinesResponse = (request, next) => { - next(request.respondWith(JSON.stringify([pipeline]), { - status: 200, - })); - }; - beforeEach(() => { - Vue.http.interceptors.push(pipelinesResponse); - - this.component = new PipelinesTable({ - propsData: { - endpoint: 'endpoint', - helpPagePath: 'foo', - emptyStateSvgPath: 'foo', - errorStateSvgPath: 'foo', - autoDevopsHelpPath: 'foo', - }, - }).$mount(); - }); - - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesResponse, - ); - this.component.$destroy(); + mock.onGet('endpoint.json').reply(200, [pipeline]); + vm = mountComponent(PipelinesTable, { + endpoint: 'endpoint.json', + helpPagePath: 'foo', + emptyStateSvgPath: 'foo', + errorStateSvgPath: 'foo', + autoDevopsHelpPath: 'foo', + }); }); it('should render a table with the received pipelines', (done) => { setTimeout(() => { - expect(this.component.$el.querySelectorAll('.ci-table .commit').length).toEqual(1); - expect(this.component.$el.querySelector('.realtime-loading')).toBe(null); - expect(this.component.$el.querySelector('.empty-state')).toBe(null); - expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null); + expect(vm.$el.querySelectorAll('.ci-table .commit').length).toEqual(1); + expect(vm.$el.querySelector('.realtime-loading')).toBe(null); + expect(vm.$el.querySelector('.empty-state')).toBe(null); + expect(vm.$el.querySelector('.js-pipelines-error-state')).toBe(null); done(); }, 0); }); }); describe('pipeline badge counts', () => { - const pipelinesResponse = (request, next) => { - next(request.respondWith(JSON.stringify([pipeline]), { - status: 200, - })); - }; - beforeEach(() => { - Vue.http.interceptors.push(pipelinesResponse); - }); - - afterEach(() => { - Vue.http.interceptors = _.without(Vue.http.interceptors, pipelinesResponse); - this.component.$destroy(); + mock.onGet('endpoint.json').reply(200, [pipeline]); }); it('should receive update-pipelines-count event', (done) => { @@ -119,54 +88,38 @@ describe('Pipelines table in Commits and Merge requests', () => { done(); }); - this.component = new PipelinesTable({ - propsData: { - endpoint: 'endpoint', - helpPagePath: 'foo', - emptyStateSvgPath: 'foo', - errorStateSvgPath: 'foo', - autoDevopsHelpPath: 'foo', - }, - }).$mount(); - element.appendChild(this.component.$el); - }); - }); - }); - - describe('unsuccessfull request', () => { - const pipelinesErrorResponse = (request, next) => { - next(request.respondWith(JSON.stringify([]), { - status: 500, - })); - }; - - beforeEach(function () { - Vue.http.interceptors.push(pipelinesErrorResponse); - - this.component = new PipelinesTable({ - propsData: { - endpoint: 'endpoint', + vm = mountComponent(PipelinesTable, { + endpoint: 'endpoint.json', helpPagePath: 'foo', emptyStateSvgPath: 'foo', errorStateSvgPath: 'foo', autoDevopsHelpPath: 'foo', - }, - }).$mount(); + }); + + element.appendChild(vm.$el); + }); }); + }); - afterEach(function () { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesErrorResponse, - ); - this.component.$destroy(); + describe('unsuccessfull request', () => { + beforeEach(() => { + mock.onGet('endpoint.json').reply(500, []); + + vm = mountComponent(PipelinesTable, { + endpoint: 'endpoint.json', + helpPagePath: 'foo', + emptyStateSvgPath: 'foo', + errorStateSvgPath: 'foo', + autoDevopsHelpPath: 'foo', + }); }); it('should render error state', function (done) { setTimeout(() => { - expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBeDefined(); - expect(this.component.$el.querySelector('.realtime-loading')).toBe(null); - expect(this.component.$el.querySelector('.js-empty-state')).toBe(null); - expect(this.component.$el.querySelector('.ci-table')).toBe(null); + expect(vm.$el.querySelector('.js-pipelines-error-state')).toBeDefined(); + expect(vm.$el.querySelector('.realtime-loading')).toBe(null); + expect(vm.$el.querySelector('.js-empty-state')).toBe(null); + expect(vm.$el.querySelector('.ci-table')).toBe(null); done(); }, 0); }); diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js index 977298b9221..60d100e8544 100644 --- a/spec/javascripts/commits_spec.js +++ b/spec/javascripts/commits_spec.js @@ -3,6 +3,7 @@ import 'vendor/jquery.endless-scroll'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import CommitsList from '~/commits'; +import Pager from '~/pager'; describe('Commits List', () => { let commitsList; @@ -14,6 +15,7 @@ describe('Commits List', () => { </form> <ol id="commits-list"></ol> `); + spyOn(Pager, 'init').and.stub(); commitsList = new CommitsList(25); }); @@ -68,9 +70,10 @@ describe('Commits List', () => { mock.restore(); }); - it('should save the last search string', (done) => { + it('should save the last search string', done => { commitsList.searchField.val('GitLab'); - commitsList.filterResults() + commitsList + .filterResults() .then(() => { expect(ajaxSpy).toHaveBeenCalled(); expect(commitsList.lastSearch).toEqual('GitLab'); @@ -80,8 +83,9 @@ describe('Commits List', () => { .catch(done.fail); }); - it('should not make ajax call if the input does not change', (done) => { - commitsList.filterResults() + it('should not make ajax call if the input does not change', done => { + commitsList + .filterResults() .then(() => { expect(ajaxSpy).not.toHaveBeenCalled(); expect(commitsList.lastSearch).toEqual(''); diff --git a/spec/javascripts/droplab/hook_spec.js b/spec/javascripts/droplab/hook_spec.js index 3d39bd0812b..5eed1db2750 100644 --- a/spec/javascripts/droplab/hook_spec.js +++ b/spec/javascripts/droplab/hook_spec.js @@ -1,5 +1,4 @@ import Hook from '~/droplab/hook'; -import * as dropdownSrc from '~/droplab/drop_down'; describe('Hook', function () { describe('class constructor', function () { @@ -10,7 +9,7 @@ describe('Hook', function () { this.config = {}; this.dropdown = {}; - spyOn(dropdownSrc, 'default').and.returnValue(this.dropdown); + this.dropdownConstructor = spyOnDependency(Hook, 'DropDown').and.returnValue(this.dropdown); this.hook = new Hook(this.trigger, this.list, this.plugins, this.config); }); @@ -24,7 +23,7 @@ describe('Hook', function () { }); it('should call DropDown constructor', function () { - expect(dropdownSrc.default).toHaveBeenCalledWith(this.list, this.config); + expect(this.dropdownConstructor).toHaveBeenCalledWith(this.list, this.config); }); it('should set .type', function () { diff --git a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js index 480c138b9db..2ab6a0077b5 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js @@ -3,12 +3,11 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { getSelector, - togglePopover, dismiss, - mouseleave, - mouseenter, inserted, } from '~/feature_highlight/feature_highlight_helper'; +import { togglePopover } from '~/shared/popover'; + import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; describe('feature highlight helper', () => { @@ -19,110 +18,6 @@ describe('feature highlight helper', () => { }); }); - describe('togglePopover', () => { - describe('togglePopover(true)', () => { - it('returns true when popover is shown', () => { - const context = { - hasClass: () => false, - popover: () => {}, - toggleClass: () => {}, - }; - - expect(togglePopover.call(context, true)).toEqual(true); - }); - - it('returns false when popover is already shown', () => { - const context = { - hasClass: () => true, - }; - - expect(togglePopover.call(context, true)).toEqual(false); - }); - - it('shows popover', (done) => { - const context = { - hasClass: () => false, - popover: () => {}, - toggleClass: () => {}, - }; - - spyOn(context, 'popover').and.callFake((method) => { - expect(method).toEqual('show'); - done(); - }); - - togglePopover.call(context, true); - }); - - it('adds disable-animation and js-popover-show class', (done) => { - const context = { - hasClass: () => false, - popover: () => {}, - toggleClass: () => {}, - }; - - spyOn(context, 'toggleClass').and.callFake((classNames, show) => { - expect(classNames).toEqual('disable-animation js-popover-show'); - expect(show).toEqual(true); - done(); - }); - - togglePopover.call(context, true); - }); - }); - - describe('togglePopover(false)', () => { - it('returns true when popover is hidden', () => { - const context = { - hasClass: () => true, - popover: () => {}, - toggleClass: () => {}, - }; - - expect(togglePopover.call(context, false)).toEqual(true); - }); - - it('returns false when popover is already hidden', () => { - const context = { - hasClass: () => false, - }; - - expect(togglePopover.call(context, false)).toEqual(false); - }); - - it('hides popover', (done) => { - const context = { - hasClass: () => true, - popover: () => {}, - toggleClass: () => {}, - }; - - spyOn(context, 'popover').and.callFake((method) => { - expect(method).toEqual('hide'); - done(); - }); - - togglePopover.call(context, false); - }); - - it('removes disable-animation and js-popover-show class', (done) => { - const context = { - hasClass: () => true, - popover: () => {}, - toggleClass: () => {}, - }; - - spyOn(context, 'toggleClass').and.callFake((classNames, show) => { - expect(classNames).toEqual('disable-animation js-popover-show'); - expect(show).toEqual(false); - done(); - }); - - togglePopover.call(context, false); - }); - }); - }); - describe('dismiss', () => { let mock; const context = { @@ -163,56 +58,6 @@ describe('feature highlight helper', () => { }); }); - describe('mouseleave', () => { - it('calls hide popover if .popover:hover is false', () => { - const fakeJquery = { - length: 0, - }; - - spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); - spyOn(togglePopover, 'call'); - mouseleave(); - expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), false); - }); - - it('does not call hide popover if .popover:hover is true', () => { - const fakeJquery = { - length: 1, - }; - - spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); - spyOn(togglePopover, 'call'); - mouseleave(); - expect(togglePopover.call).not.toHaveBeenCalledWith(false); - }); - }); - - describe('mouseenter', () => { - const context = {}; - - it('shows popover', () => { - spyOn(togglePopover, 'call').and.returnValue(false); - mouseenter.call(context); - expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), true); - }); - - it('registers mouseleave event if popover is showed', (done) => { - spyOn(togglePopover, 'call').and.returnValue(true); - spyOn($.fn, 'on').and.callFake((eventName) => { - expect(eventName).toEqual('mouseleave'); - done(); - }); - mouseenter.call(context); - }); - - it('does not register mouseleave event if popover is not showed', () => { - spyOn(togglePopover, 'call').and.returnValue(false); - const spy = spyOn($.fn, 'on').and.callFake(() => {}); - mouseenter.call(context); - expect(spy).not.toHaveBeenCalled(); - }); - }); - describe('inserted', () => { it('registers click event callback', (done) => { const context = { diff --git a/spec/javascripts/feature_highlight/feature_highlight_spec.js b/spec/javascripts/feature_highlight/feature_highlight_spec.js index d2dd39d49d1..ec46d4f905a 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_spec.js @@ -1,6 +1,6 @@ import $ from 'jquery'; -import * as featureHighlightHelper from '~/feature_highlight/feature_highlight_helper'; import * as featureHighlight from '~/feature_highlight/feature_highlight'; +import * as popover from '~/shared/popover'; import axios from '~/lib/utils/axios_utils'; import MockAdapter from 'axios-mock-adapter'; @@ -29,7 +29,6 @@ describe('feature highlight', () => { mock = new MockAdapter(axios); mock.onGet('/test').reply(200); spyOn(window, 'addEventListener'); - spyOn(window, 'removeEventListener'); featureHighlight.setupFeatureHighlightPopover('test', 0); }); @@ -45,14 +44,14 @@ describe('feature highlight', () => { }); it('setup mouseenter', () => { - const toggleSpy = spyOn(featureHighlightHelper.togglePopover, 'call'); + const toggleSpy = spyOn(popover.togglePopover, 'call'); $(selector).trigger('mouseenter'); expect(toggleSpy).toHaveBeenCalledWith(jasmine.any(Object), true); }); it('setup debounced mouseleave', (done) => { - const toggleSpy = spyOn(featureHighlightHelper.togglePopover, 'call'); + const toggleSpy = spyOn(popover.togglePopover, 'call'); $(selector).trigger('mouseleave'); // Even though we've set the debounce to 0ms, setTimeout is needed for the debounce @@ -64,12 +63,7 @@ describe('feature highlight', () => { it('setup show.bs.popover', () => { $(selector).trigger('show.bs.popover'); - expect(window.addEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function)); - }); - - it('setup hide.bs.popover', () => { - $(selector).trigger('hide.bs.popover'); - expect(window.removeEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function)); + expect(window.addEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function), { once: true }); }); it('removes disabled attribute', () => { @@ -85,7 +79,7 @@ describe('feature highlight', () => { it('toggles when clicked', () => { $(selector).trigger('mouseenter'); const popoverId = $(selector).attr('aria-describedby'); - const toggleSpy = spyOn(featureHighlightHelper.togglePopover, 'call'); + const toggleSpy = spyOn(popover.togglePopover, 'call'); $(`#${popoverId} .dismiss-feature-highlight`).click(); diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index 95d02974bdc..8fcee36beb8 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -1,5 +1,3 @@ -import * as urlUtils from '~/lib/utils/url_utility'; -import * as recentSearchesStoreSrc from '~/filtered_search/stores/recent_searches_store'; import RecentSearchesService from '~/filtered_search/services/recent_searches_service'; import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error'; import RecentSearchesRoot from '~/filtered_search/recent_searches_root'; @@ -11,7 +9,7 @@ import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dro import FilteredSearchManager from '~/filtered_search/filtered_search_manager'; import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; -describe('Filtered Search Manager', () => { +describe('Filtered Search Manager', function () { let input; let manager; let tokensContainer; @@ -74,18 +72,19 @@ describe('Filtered Search Manager', () => { describe('class constructor', () => { const isLocalStorageAvailable = 'isLocalStorageAvailable'; + let RecentSearchesStoreSpy; beforeEach(() => { spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable); - spyOn(recentSearchesStoreSrc, 'default'); spyOn(RecentSearchesRoot.prototype, 'render'); + RecentSearchesStoreSpy = spyOnDependency(FilteredSearchManager, 'RecentSearchesStore'); }); it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => { manager = new FilteredSearchManager({ page }); expect(RecentSearchesService.isAvailable).toHaveBeenCalled(); - expect(recentSearchesStoreSrc.default).toHaveBeenCalledWith({ + expect(RecentSearchesStoreSpy).toHaveBeenCalledWith({ isLocalStorageAvailable, allowedKeys: FilteredSearchTokenKeys.getKeys(), }); @@ -164,7 +163,7 @@ describe('Filtered Search Manager', () => { it('should search with a single word', (done) => { input.value = 'searchTerm'; - spyOn(urlUtils, 'visitUrl').and.callFake((url) => { + spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=searchTerm`); done(); }); @@ -175,7 +174,7 @@ describe('Filtered Search Manager', () => { it('should search with multiple words', (done) => { input.value = 'awesome search terms'; - spyOn(urlUtils, 'visitUrl').and.callFake((url) => { + spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`); done(); }); @@ -186,7 +185,7 @@ describe('Filtered Search Manager', () => { it('should search with special characters', (done) => { input.value = '~!@#$%^&*()_+{}:<>,.?/'; - spyOn(urlUtils, 'visitUrl').and.callFake((url) => { + spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`); done(); }); @@ -200,7 +199,7 @@ describe('Filtered Search Manager', () => { ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')} `); - spyOn(urlUtils, 'visitUrl').and.callFake((url) => { + spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&label_name[]=bug`); done(); }); diff --git a/spec/javascripts/filtered_search/recent_searches_root_spec.js b/spec/javascripts/filtered_search/recent_searches_root_spec.js index d8ba6de5f45..1e6272bad0b 100644 --- a/spec/javascripts/filtered_search/recent_searches_root_spec.js +++ b/spec/javascripts/filtered_search/recent_searches_root_spec.js @@ -1,11 +1,11 @@ import RecentSearchesRoot from '~/filtered_search/recent_searches_root'; -import * as vueSrc from 'vue'; describe('RecentSearchesRoot', () => { describe('render', () => { let recentSearchesRoot; let data; let template; + let VueSpy; beforeEach(() => { recentSearchesRoot = { @@ -14,7 +14,7 @@ describe('RecentSearchesRoot', () => { }, }; - spyOn(vueSrc, 'default').and.callFake((options) => { + VueSpy = spyOnDependency(RecentSearchesRoot, 'Vue').and.callFake((options) => { data = options.data; template = options.template; }); @@ -23,7 +23,7 @@ describe('RecentSearchesRoot', () => { }); it('should instantiate Vue', () => { - expect(vueSrc.default).toHaveBeenCalled(); + expect(VueSpy).toHaveBeenCalled(); expect(data()).toBe(recentSearchesRoot.store.state); expect(template).toContain(':is-local-storage-available="isLocalStorageAvailable"'); }); diff --git a/spec/javascripts/fixtures/linked_tabs.html.haml b/spec/javascripts/fixtures/linked_tabs.html.haml index 93c0cf97ff0..c38fe8b1f25 100644 --- a/spec/javascripts/fixtures/linked_tabs.html.haml +++ b/spec/javascripts/fixtures/linked_tabs.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs.linked-tabs +%ul.nav-links.new-session-tabs.linked-tabs %li %a{ href: 'foo/bar/1', data: { target: 'div#tab1', action: 'tab1', toggle: 'tab' } } Tab 1 diff --git a/spec/javascripts/fixtures/one_white_pixel.png b/spec/javascripts/fixtures/one_white_pixel.png Binary files differnew file mode 100644 index 00000000000..073fcf40a18 --- /dev/null +++ b/spec/javascripts/fixtures/one_white_pixel.png diff --git a/spec/javascripts/fixtures/signin_tabs.html.haml b/spec/javascripts/fixtures/signin_tabs.html.haml index 12b8d423cbe..2e00fe7865e 100644 --- a/spec/javascripts/fixtures/signin_tabs.html.haml +++ b/spec/javascripts/fixtures/signin_tabs.html.haml @@ -1,5 +1,5 @@ -%ul.nav-tabs +%ul.nav-links.new-session-tabs + %li.active + %a{ href: '#ldap' } LDAP %li - %a.active{ id: 'standard', href: '#standard'} Standard - %li - %a{ id: 'ldap', href: '#ldap'} Ldap + %a{ href: '#login-pane'} Standard diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 5393502196e..7f9c4811fba 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -1,9 +1,8 @@ /* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */ import $ from 'jquery'; -import '~/gl_dropdown'; +import GLDropdown from '~/gl_dropdown'; import '~/lib/utils/common_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; describe('glDropdown', function describeDropdown() { preloadFixtures('static/gl_dropdown.html.raw'); @@ -138,13 +137,13 @@ describe('glDropdown', function describeDropdown() { expect(this.dropdownContainerElement).toHaveClass('open'); const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0; navigateWithKeys('down', randomIndex, () => { - spyOn(urlUtils, 'visitUrl').and.stub(); + const visitUrl = spyOnDependency(GLDropdown, 'visitUrl').and.stub(); navigateWithKeys('enter', null, () => { expect(this.dropdownContainerElement).not.toHaveClass('open'); const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement); expect(link).toHaveClass('is-active'); const linkedLocation = link.attr('href'); - if (linkedLocation && linkedLocation !== '#') expect(urlUtils.visitUrl).toHaveBeenCalledWith(linkedLocation); + if (linkedLocation && linkedLocation !== '#') expect(visitUrl).toHaveBeenCalledWith(linkedLocation); }); }); }); diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js index d8428bd0e08..2b92c485f41 100644 --- a/spec/javascripts/groups/components/app_spec.js +++ b/spec/javascripts/groups/components/app_spec.js @@ -1,7 +1,6 @@ import $ from 'jquery'; import Vue from 'vue'; -import * as utils from '~/lib/utils/url_utility'; import appComponent from '~/groups/components/app.vue'; import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupItemComponent from '~/groups/components/group_item.vue'; @@ -177,7 +176,7 @@ describe('AppComponent', () => { it('should fetch groups for provided page details and update window state', (done) => { spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise(mockGroups)); spyOn(vm, 'updateGroups').and.callThrough(); - spyOn(utils, 'mergeUrlParams').and.callThrough(); + const mergeUrlParams = spyOnDependency(appComponent, 'mergeUrlParams').and.callThrough(); spyOn(window.history, 'replaceState'); spyOn($, 'scrollTo'); @@ -193,7 +192,7 @@ describe('AppComponent', () => { setTimeout(() => { expect(vm.isLoading).toBe(false); expect($.scrollTo).toHaveBeenCalledWith(0); - expect(utils.mergeUrlParams).toHaveBeenCalledWith({ page: 2 }, jasmine.any(String)); + expect(mergeUrlParams).toHaveBeenCalledWith({ page: 2 }, jasmine.any(String)); expect(window.history.replaceState).toHaveBeenCalledWith({ page: jasmine.any(String), }, jasmine.any(String), jasmine.any(String)); diff --git a/spec/javascripts/groups/components/group_item_spec.js b/spec/javascripts/groups/components/group_item_spec.js index e3c942597a3..49a139855c8 100644 --- a/spec/javascripts/groups/components/group_item_spec.js +++ b/spec/javascripts/groups/components/group_item_spec.js @@ -1,5 +1,4 @@ import Vue from 'vue'; -import * as urlUtils from '~/lib/utils/url_utility'; import groupItemComponent from '~/groups/components/group_item.vue'; import groupFolderComponent from '~/groups/components/group_folder.vue'; import eventHub from '~/groups/event_hub'; @@ -135,13 +134,13 @@ describe('GroupItemComponent', () => { const group = Object.assign({}, mockParentGroupItem); group.childrenCount = 0; const newVm = createComponent(group); - spyOn(urlUtils, 'visitUrl').and.stub(); + const visitUrl = spyOnDependency(groupItemComponent, 'visitUrl').and.stub(); spyOn(eventHub, '$emit'); newVm.onClickRowGroup(event); setTimeout(() => { expect(eventHub.$emit).not.toHaveBeenCalled(); - expect(urlUtils.visitUrl).toHaveBeenCalledWith(newVm.group.relativePath); + expect(visitUrl).toHaveBeenCalledWith(newVm.group.relativePath); done(); }, 0); }); diff --git a/spec/javascripts/helpers/class_spec_helper_spec.js b/spec/javascripts/helpers/class_spec_helper_spec.js index 1415ffb7eb3..fa104ae5bcd 100644 --- a/spec/javascripts/helpers/class_spec_helper_spec.js +++ b/spec/javascripts/helpers/class_spec_helper_spec.js @@ -2,7 +2,7 @@ import './class_spec_helper'; -describe('ClassSpecHelper', () => { +describe('ClassSpecHelper', function () { describe('itShouldBeAStaticMethod', () => { beforeEach(() => { class TestClass { diff --git a/spec/javascripts/helpers/vue_component_helper.js b/spec/javascripts/helpers/vue_component_helper.js index 257c9f5526a..e0fe18e5560 100644 --- a/spec/javascripts/helpers/vue_component_helper.js +++ b/spec/javascripts/helpers/vue_component_helper.js @@ -1,3 +1,18 @@ -export default function removeBreakLine (data) { - return data.replace(/\r?\n|\r/g, ' '); -} +/** + * Replaces line break with an empty space + * @param {*} data + */ +export const removeBreakLine = data => data.replace(/\r?\n|\r/g, ' '); + +/** + * Removes line breaks, spaces and trims the given text + * @param {String} str + * @returns {String} + */ +export const trimText = str => + str + .replace(/\r?\n|\r/g, '') + .replace(/\s\s+/g, ' ') + .trim(); + +export const removeWhitespace = str => str.replace(/\s\s+/g, ' '); diff --git a/spec/javascripts/helpers/vue_mount_component_helper.js b/spec/javascripts/helpers/vue_mount_component_helper.js index 34acdfbfba9..effacbcff4e 100644 --- a/spec/javascripts/helpers/vue_mount_component_helper.js +++ b/spec/javascripts/helpers/vue_mount_component_helper.js @@ -3,6 +3,12 @@ export const createComponentWithStore = (Component, store, propsData = {}) => ne propsData, }); +export const mountComponentWithStore = (Component, { el, props, store }) => + new Component({ + store, + propsData: props || { }, + }).$mount(el); + export default (Component, props = {}, el = null) => new Component({ propsData: props, }).$mount(el); diff --git a/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js new file mode 100644 index 00000000000..53275b78da5 --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js @@ -0,0 +1,63 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import emptyState from '~/ide/components/commit_sidebar/empty_state.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { resetStore } from '../../helpers'; + +describe('IDE commit panel empty state', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(emptyState); + + vm = createComponentWithStore(Component, store, { + noChangesStateSvgPath: 'no-changes', + committedStateSvgPath: 'committed-state', + }); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders no changes text when last commit message is empty', () => { + expect(vm.$el.textContent).toContain('No changes'); + }); + + describe('toggle button', () => { + it('calls store action', () => { + spyOn(vm, 'toggleRightPanelCollapsed'); + + vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); + + expect(vm.toggleRightPanelCollapsed).toHaveBeenCalled(); + }); + + it('renders collapsed class', done => { + vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); + + Vue.nextTick(() => { + expect(vm.$el.querySelector('.is-collapsed')).not.toBeNull(); + + done(); + }); + }); + }); + + describe('collapsed state', () => { + beforeEach(done => { + vm.$store.state.rightPanelCollapsed = true; + + Vue.nextTick(done); + }); + + it('does not render text & svg', () => { + expect(vm.$el.querySelector('img')).toBeNull(); + expect(vm.$el.textContent).not.toContain('No changes'); + }); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/list_collapsed_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_collapsed_spec.js index 5b402886b55..9af3c15a4e3 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_collapsed_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_collapsed_spec.js @@ -3,6 +3,7 @@ import store from '~/ide/stores'; import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { file } from '../../helpers'; +import { removeWhitespace } from '../../../helpers/vue_component_helper'; describe('Multi-file editor commit sidebar list collapsed', () => { let vm; @@ -10,10 +11,17 @@ describe('Multi-file editor commit sidebar list collapsed', () => { beforeEach(() => { const Component = Vue.extend(listCollapsed); - vm = createComponentWithStore(Component, store); - - vm.$store.state.changedFiles.push(file('file1'), file('file2')); - vm.$store.state.changedFiles[0].tempFile = true; + vm = createComponentWithStore(Component, store, { + files: [ + { + ...file('file1'), + tempFile: true, + }, + file('file2'), + ], + iconName: 'staged', + title: 'Staged', + }); vm.$mount(); }); @@ -23,6 +31,42 @@ describe('Multi-file editor commit sidebar list collapsed', () => { }); it('renders added & modified files count', () => { - expect(vm.$el.textContent.replace(/\s+/g, ' ').trim()).toBe('1 1'); + expect(removeWhitespace(vm.$el.textContent).trim()).toBe('1 1'); + }); + + describe('addedFilesLength', () => { + it('returns an length of temp files', () => { + expect(vm.addedFilesLength).toBe(1); + }); + }); + + describe('modifiedFilesLength', () => { + it('returns an length of modified files', () => { + expect(vm.modifiedFilesLength).toBe(1); + }); + }); + + describe('addedFilesIconClass', () => { + it('includes multi-file-addition when addedFiles is not empty', () => { + expect(vm.addedFilesIconClass).toContain('multi-file-addition'); + }); + + it('excludes multi-file-addition when addedFiles is empty', () => { + vm.files = []; + + expect(vm.addedFilesIconClass).not.toContain('multi-file-addition'); + }); + }); + + describe('modifiedFilesClass', () => { + it('includes multi-file-modified when addedFiles is not empty', () => { + expect(vm.modifiedFilesClass).toContain('multi-file-modified'); + }); + + it('excludes multi-file-modified when addedFiles is empty', () => { + vm.files = []; + + expect(vm.modifiedFilesClass).not.toContain('multi-file-modified'); + }); }); }); diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js index 509434e4300..cc7e0a3f26d 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; +import store from '~/ide/stores'; import listItem from '~/ide/components/commit_sidebar/list_item.vue'; import router from '~/ide/ide_router'; -import store from '~/ide/stores'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { file, resetStore } from '../../helpers'; @@ -18,6 +18,7 @@ describe('Multi-file editor commit sidebar list item', () => { vm = createComponentWithStore(Component, store, { file: f, + actionComponent: 'stage-button', }).$mount(); }); @@ -31,22 +32,18 @@ describe('Multi-file editor commit sidebar list item', () => { expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent.trim()).toBe(f.path); }); - it('calls discardFileChanges when clicking discard button', () => { - spyOn(vm, 'discardFileChanges'); - - vm.$el.querySelector('.multi-file-discard-btn').click(); - - expect(vm.discardFileChanges).toHaveBeenCalled(); + it('renders actionn button', () => { + expect(vm.$el.querySelector('.multi-file-discard-btn')).not.toBeNull(); }); it('opens a closed file in the editor when clicking the file path', done => { - spyOn(vm, 'openFileInEditor').and.callThrough(); + spyOn(vm, 'openPendingTab').and.callThrough(); spyOn(router, 'push'); vm.$el.querySelector('.multi-file-commit-list-path').click(); setTimeout(() => { - expect(vm.openFileInEditor).toHaveBeenCalled(); + expect(vm.openPendingTab).toHaveBeenCalled(); expect(router.push).toHaveBeenCalled(); done(); diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js index a62c0a28340..62fc3f90ad1 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js @@ -2,7 +2,7 @@ import Vue from 'vue'; import store from '~/ide/stores'; import commitSidebarList from '~/ide/components/commit_sidebar/list.vue'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import { file } from '../../helpers'; +import { file, resetStore } from '../../helpers'; describe('Multi-file editor commit sidebar list', () => { let vm; @@ -13,6 +13,10 @@ describe('Multi-file editor commit sidebar list', () => { vm = createComponentWithStore(Component, store, { title: 'Staged', fileList: [], + iconName: 'staged', + action: 'stageAllChanges', + actionBtnText: 'stage all', + itemActionComponent: 'stage-button', }); vm.$store.state.rightPanelCollapsed = false; @@ -22,6 +26,8 @@ describe('Multi-file editor commit sidebar list', () => { afterEach(() => { vm.$destroy(); + + resetStore(vm.$store); }); describe('with a list of files', () => { @@ -38,6 +44,12 @@ describe('Multi-file editor commit sidebar list', () => { }); }); + describe('empty files array', () => { + it('renders no changes text when empty', () => { + expect(vm.$el.textContent).toContain('No changes'); + }); + }); + describe('collapsed', () => { beforeEach(done => { vm.$store.state.rightPanelCollapsed = true; @@ -50,4 +62,32 @@ describe('Multi-file editor commit sidebar list', () => { expect(vm.$el.querySelector('.help-block')).toBeNull(); }); }); + + describe('with toggle', () => { + beforeEach(done => { + spyOn(vm, 'toggleRightPanelCollapsed'); + + vm.showToggle = true; + + Vue.nextTick(done); + }); + + it('calls setPanelCollapsedStatus when clickin toggle', () => { + vm.$el.querySelector('.multi-file-commit-panel-collapse-btn').click(); + + expect(vm.toggleRightPanelCollapsed).toHaveBeenCalled(); + }); + }); + + describe('action button', () => { + beforeEach(() => { + spyOn(vm, 'stageAllChanges'); + }); + + it('calls store action when clicked', () => { + vm.$el.querySelector('.ide-staged-action-btn').click(); + + expect(vm.stageAllChanges).toHaveBeenCalled(); + }); + }); }); diff --git a/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js b/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js new file mode 100644 index 00000000000..d62d58101d6 --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/message_field_spec.js @@ -0,0 +1,174 @@ +import Vue from 'vue'; +import CommitMessageField from '~/ide/components/commit_sidebar/message_field.vue'; +import createComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('IDE commit message field', () => { + const Component = Vue.extend(CommitMessageField); + let vm; + + beforeEach(() => { + setFixtures('<div id="app"></div>'); + + vm = createComponent( + Component, + { + text: '', + }, + '#app', + ); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('adds is-focused class on focus', done => { + vm.$el.querySelector('textarea').focus(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.is-focused')).not.toBeNull(); + + done(); + }); + }); + + it('removed is-focused class on blur', done => { + vm.$el.querySelector('textarea').focus(); + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelector('.is-focused')).not.toBeNull(); + + vm.$el.querySelector('textarea').blur(); + + return vm.$nextTick(); + }) + .then(() => { + expect(vm.$el.querySelector('.is-focused')).toBeNull(); + + done(); + }) + .then(done) + .catch(done.fail); + }); + + it('emits input event on input', () => { + spyOn(vm, '$emit'); + + const textarea = vm.$el.querySelector('textarea'); + textarea.value = 'testing'; + + textarea.dispatchEvent(new Event('input')); + + expect(vm.$emit).toHaveBeenCalledWith('input', 'testing'); + }); + + describe('highlights', () => { + describe('subject line', () => { + it('does not highlight less than 50 characters', done => { + vm.text = 'text less than 50 chars'; + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelector('.highlights span').textContent).toContain( + 'text less than 50 chars', + ); + expect(vm.$el.querySelector('mark').style.display).toBe('none'); + }) + .then(done) + .catch(done.fail); + }); + + it('highlights characters over 50 length', done => { + vm.text = + 'text less than 50 chars that should not highlighted. text more than 50 should be highlighted'; + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelector('.highlights span').textContent).toContain( + 'text less than 50 chars that should not highlighte', + ); + expect(vm.$el.querySelector('mark').style.display).not.toBe('none'); + expect(vm.$el.querySelector('mark').textContent).toBe( + 'd. text more than 50 should be highlighted', + ); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('body text', () => { + it('does not highlight body text less tan 72 characters', done => { + vm.text = 'subject line\nbody content'; + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2); + expect(vm.$el.querySelectorAll('mark')[1].style.display).toBe('none'); + }) + .then(done) + .catch(done.fail); + }); + + it('highlights body text more than 72 characters', done => { + vm.text = + 'subject line\nbody content that will be highlighted when it is more than 72 characters in length'; + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2); + expect(vm.$el.querySelectorAll('mark')[1].style.display).not.toBe('none'); + expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length'); + }) + .then(done) + .catch(done.fail); + }); + + it('highlights body text & subject line', done => { + vm.text = + 'text less than 50 chars that should not highlighted\nbody content that will be highlighted when it is more than 72 characters in length'; + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2); + expect(vm.$el.querySelectorAll('mark').length).toBe(2); + + expect(vm.$el.querySelectorAll('mark')[0].textContent).toContain('d'); + expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length'); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('scrolling textarea', () => { + it('updates transform of highlights', done => { + vm.text = 'subject line\n\n\n\n\n\n\n\n\n\n\nbody content'; + + vm + .$nextTick() + .then(() => { + vm.$el.querySelector('textarea').scrollTo(0, 50); + + vm.handleScroll(); + }) + .then(vm.$nextTick) + .then(() => { + expect(vm.scrollTop).toBe(50); + expect(vm.$el.querySelector('.highlights').style.transform).toBe( + 'translate3d(0px, -50px, 0px)', + ); + }) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js b/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js index 4e8243439f3..21bfe4be52f 100644 --- a/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js @@ -69,19 +69,6 @@ describe('IDE commit sidebar radio group', () => { }); }); - it('renders helpText tooltip', done => { - vm.helpText = 'help text'; - - Vue.nextTick(() => { - const help = vm.$el.querySelector('.help-block'); - - expect(help).not.toBeNull(); - expect(help.getAttribute('data-original-title')).toBe('help text'); - - done(); - }); - }); - describe('with input', () => { beforeEach(done => { vm.$destroy(); diff --git a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js new file mode 100644 index 00000000000..6bf8710bda7 --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js @@ -0,0 +1,46 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import stageButton from '~/ide/components/commit_sidebar/stage_button.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { file, resetStore } from '../../helpers'; + +describe('IDE stage file button', () => { + let vm; + let f; + + beforeEach(() => { + const Component = Vue.extend(stageButton); + f = file(); + + vm = createComponentWithStore(Component, store, { + path: f.path, + }); + + spyOn(vm, 'stageChange'); + spyOn(vm, 'discardFileChanges'); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders button to discard & stage', () => { + expect(vm.$el.querySelectorAll('.btn').length).toBe(2); + }); + + it('calls store with stage button', () => { + vm.$el.querySelectorAll('.btn')[0].click(); + + expect(vm.stageChange).toHaveBeenCalledWith(f.path); + }); + + it('calls store with discard button', () => { + vm.$el.querySelectorAll('.btn')[1].click(); + + expect(vm.discardFileChanges).toHaveBeenCalledWith(f.path); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js b/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js new file mode 100644 index 00000000000..e1a432b81be --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import successMessage from '~/ide/components/commit_sidebar/success_message.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { resetStore } from '../../helpers'; + +describe('IDE commit panel successful commit state', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(successMessage); + + vm = createComponentWithStore(Component, store, { + committedStateSvgPath: 'committed-state', + }); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders last commit message when it exists', done => { + vm.$store.state.lastCommitMsg = 'testing commit message'; + + Vue.nextTick(() => { + expect(vm.$el.textContent).toContain('testing commit message'); + + done(); + }); + }); +}); diff --git a/spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js b/spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js new file mode 100644 index 00000000000..917bbb9fb46 --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/unstage_button_spec.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import unstageButton from '~/ide/components/commit_sidebar/unstage_button.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { file, resetStore } from '../../helpers'; + +describe('IDE unstage file button', () => { + let vm; + let f; + + beforeEach(() => { + const Component = Vue.extend(unstageButton); + f = file(); + + vm = createComponentWithStore(Component, store, { + path: f.path, + }); + + spyOn(vm, 'unstageChange'); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders button to unstage', () => { + expect(vm.$el.querySelectorAll('.btn').length).toBe(1); + }); + + it('calls store with unnstage button', () => { + vm.$el.querySelector('.btn').click(); + + expect(vm.unstageChange).toHaveBeenCalledWith(f.path); + }); +}); diff --git a/spec/javascripts/ide/components/file_finder/index_spec.js b/spec/javascripts/ide/components/file_finder/index_spec.js new file mode 100644 index 00000000000..4f208e946d2 --- /dev/null +++ b/spec/javascripts/ide/components/file_finder/index_spec.js @@ -0,0 +1,308 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import FindFileComponent from '~/ide/components/file_finder/index.vue'; +import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes'; +import router from '~/ide/ide_router'; +import { file, resetStore } from '../../helpers'; +import { mountComponentWithStore } from '../../../helpers/vue_mount_component_helper'; + +describe('IDE File finder item spec', () => { + const Component = Vue.extend(FindFileComponent); + let vm; + + beforeEach(done => { + setFixtures('<div id="app"></div>'); + + vm = mountComponentWithStore(Component, { + store, + el: '#app', + props: { + index: 0, + }, + }); + + setTimeout(done); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + describe('with entries', () => { + beforeEach(done => { + Vue.set(vm.$store.state.entries, 'folder', { + ...file('folder'), + path: 'folder', + type: 'folder', + }); + + Vue.set(vm.$store.state.entries, 'index.js', { + ...file('index.js'), + path: 'index.js', + type: 'blob', + url: '/index.jsurl', + }); + + Vue.set(vm.$store.state.entries, 'component.js', { + ...file('component.js'), + path: 'component.js', + type: 'blob', + }); + + setTimeout(done); + }); + + it('renders list of blobs', () => { + expect(vm.$el.textContent).toContain('index.js'); + expect(vm.$el.textContent).toContain('component.js'); + expect(vm.$el.textContent).not.toContain('folder'); + }); + + it('filters entries', done => { + vm.searchText = 'index'; + + vm.$nextTick(() => { + expect(vm.$el.textContent).toContain('index.js'); + expect(vm.$el.textContent).not.toContain('component.js'); + + done(); + }); + }); + + it('shows clear button when searchText is not empty', done => { + vm.searchText = 'index'; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.dropdown-input-clear').classList).toContain('show'); + expect(vm.$el.querySelector('.dropdown-input-search').classList).toContain('hidden'); + + done(); + }); + }); + + it('clear button resets searchText', done => { + vm.searchText = 'index'; + + vm + .$nextTick() + .then(() => { + vm.$el.querySelector('.dropdown-input-clear').click(); + }) + .then(vm.$nextTick) + .then(() => { + expect(vm.searchText).toBe(''); + }) + .then(done) + .catch(done.fail); + }); + + it('clear button focues search input', done => { + spyOn(vm.$refs.searchInput, 'focus'); + vm.searchText = 'index'; + + vm + .$nextTick() + .then(() => { + vm.$el.querySelector('.dropdown-input-clear').click(); + }) + .then(vm.$nextTick) + .then(() => { + expect(vm.$refs.searchInput.focus).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + describe('listShowCount', () => { + it('returns 1 when no filtered entries exist', done => { + vm.searchText = 'testing 123'; + + vm.$nextTick(() => { + expect(vm.listShowCount).toBe(1); + + done(); + }); + }); + + it('returns entries length when not filtered', () => { + expect(vm.listShowCount).toBe(2); + }); + }); + + describe('listHeight', () => { + it('returns 55 when entries exist', () => { + expect(vm.listHeight).toBe(55); + }); + + it('returns 33 when entries dont exist', done => { + vm.searchText = 'testing 123'; + + vm.$nextTick(() => { + expect(vm.listHeight).toBe(33); + + done(); + }); + }); + }); + + describe('filteredBlobsLength', () => { + it('returns length of filtered blobs', done => { + vm.searchText = 'index'; + + vm.$nextTick(() => { + expect(vm.filteredBlobsLength).toBe(1); + + done(); + }); + }); + }); + + describe('watches', () => { + describe('searchText', () => { + it('resets focusedIndex when updated', done => { + vm.focusedIndex = 1; + vm.searchText = 'test'; + + vm.$nextTick(() => { + expect(vm.focusedIndex).toBe(0); + + done(); + }); + }); + }); + + describe('fileFindVisible', () => { + it('returns searchText when false', done => { + vm.searchText = 'test'; + vm.$store.state.fileFindVisible = true; + + vm + .$nextTick() + .then(() => { + vm.$store.state.fileFindVisible = false; + }) + .then(vm.$nextTick) + .then(() => { + expect(vm.searchText).toBe(''); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('openFile', () => { + beforeEach(() => { + spyOn(router, 'push'); + spyOn(vm, 'toggleFileFinder'); + }); + + it('closes file finder', () => { + vm.openFile(vm.$store.state.entries['index.js']); + + expect(vm.toggleFileFinder).toHaveBeenCalled(); + }); + + it('pushes to router', () => { + vm.openFile(vm.$store.state.entries['index.js']); + + expect(router.push).toHaveBeenCalledWith('/project/index.jsurl'); + }); + }); + + describe('onKeyup', () => { + it('opens file on enter key', done => { + const event = new CustomEvent('keyup'); + event.keyCode = ENTER_KEY_CODE; + + spyOn(vm, 'openFile'); + + vm.$refs.searchInput.dispatchEvent(event); + + vm.$nextTick(() => { + expect(vm.openFile).toHaveBeenCalledWith(vm.$store.state.entries['index.js']); + + done(); + }); + }); + + it('closes file finder on esc key', done => { + const event = new CustomEvent('keyup'); + event.keyCode = ESC_KEY_CODE; + + spyOn(vm, 'toggleFileFinder'); + + vm.$refs.searchInput.dispatchEvent(event); + + vm.$nextTick(() => { + expect(vm.toggleFileFinder).toHaveBeenCalled(); + + done(); + }); + }); + }); + + describe('onKeyDown', () => { + let el; + + beforeEach(() => { + el = vm.$refs.searchInput; + }); + + describe('up key', () => { + const event = new CustomEvent('keydown'); + event.keyCode = UP_KEY_CODE; + + it('resets to last index when at top', () => { + el.dispatchEvent(event); + + expect(vm.focusedIndex).toBe(1); + }); + + it('minus 1 from focusedIndex', () => { + vm.focusedIndex = 1; + + el.dispatchEvent(event); + + expect(vm.focusedIndex).toBe(0); + }); + }); + + describe('down key', () => { + const event = new CustomEvent('keydown'); + event.keyCode = DOWN_KEY_CODE; + + it('resets to first index when at bottom', () => { + vm.focusedIndex = 1; + el.dispatchEvent(event); + + expect(vm.focusedIndex).toBe(0); + }); + + it('adds 1 to focusedIndex', () => { + el.dispatchEvent(event); + + expect(vm.focusedIndex).toBe(1); + }); + }); + }); + }); + + describe('without entries', () => { + it('renders loading text when loading', done => { + store.state.loading = true; + + vm.$nextTick(() => { + expect(vm.$el.textContent).toContain('Loading...'); + + done(); + }); + }); + + it('renders no files text', () => { + expect(vm.$el.textContent).toContain('No files found.'); + }); + }); +}); diff --git a/spec/javascripts/ide/components/file_finder/item_spec.js b/spec/javascripts/ide/components/file_finder/item_spec.js new file mode 100644 index 00000000000..0f1116c6912 --- /dev/null +++ b/spec/javascripts/ide/components/file_finder/item_spec.js @@ -0,0 +1,140 @@ +import Vue from 'vue'; +import ItemComponent from '~/ide/components/file_finder/item.vue'; +import { file } from '../../helpers'; +import createComponent from '../../../helpers/vue_mount_component_helper'; + +describe('IDE File finder item spec', () => { + const Component = Vue.extend(ItemComponent); + let vm; + let localFile; + + beforeEach(() => { + localFile = { + ...file(), + name: 'test file', + path: 'test/file', + }; + + vm = createComponent(Component, { + file: localFile, + focused: true, + searchText: '', + index: 0, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders file name & path', () => { + expect(vm.$el.textContent).toContain('test file'); + expect(vm.$el.textContent).toContain('test/file'); + }); + + describe('focused', () => { + it('adds is-focused class', () => { + expect(vm.$el.classList).toContain('is-focused'); + }); + + it('does not have is-focused class when not focused', done => { + vm.focused = false; + + vm.$nextTick(() => { + expect(vm.$el.classList).not.toContain('is-focused'); + + done(); + }); + }); + }); + + describe('changed file icon', () => { + it('does not render when not a changed or temp file', () => { + expect(vm.$el.querySelector('.diff-changed-stats')).toBe(null); + }); + + it('renders when a changed file', done => { + vm.file.changed = true; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.diff-changed-stats')).not.toBe(null); + + done(); + }); + }); + + it('renders when a temp file', done => { + vm.file.tempFile = true; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.diff-changed-stats')).not.toBe(null); + + done(); + }); + }); + }); + + it('emits event when clicked', () => { + spyOn(vm, '$emit'); + + vm.$el.click(); + + expect(vm.$emit).toHaveBeenCalledWith('click', vm.file); + }); + + describe('path', () => { + let el; + + beforeEach(done => { + vm.searchText = 'file'; + + el = vm.$el.querySelector('.diff-changed-file-path'); + + vm.$nextTick(done); + }); + + it('highlights text', () => { + expect(el.querySelectorAll('.highlighted').length).toBe(4); + }); + + it('adds ellipsis to long text', done => { + vm.file.path = new Array(70) + .fill() + .map((_, i) => `${i}-`) + .join(''); + + vm.$nextTick(() => { + expect(el.textContent).toBe(`...${vm.file.path.substr(vm.file.path.length - 60)}`); + done(); + }); + }); + }); + + describe('name', () => { + let el; + + beforeEach(done => { + vm.searchText = 'file'; + + el = vm.$el.querySelector('.diff-changed-file-name'); + + vm.$nextTick(done); + }); + + it('highlights text', () => { + expect(el.querySelectorAll('.highlighted').length).toBe(4); + }); + + it('does not add ellipsis to long text', done => { + vm.file.name = new Array(70) + .fill() + .map((_, i) => `${i}-`) + .join(''); + + vm.$nextTick(() => { + expect(el.textContent).not.toBe(`...${vm.file.name.substr(vm.file.name.length - 60)}`); + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/components/repo_file_buttons_spec.js b/spec/javascripts/ide/components/ide_file_buttons_spec.js index c86bdb132b4..8ac8d1b2acf 100644 --- a/spec/javascripts/ide/components/repo_file_buttons_spec.js +++ b/spec/javascripts/ide/components/ide_file_buttons_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import repoFileButtons from '~/ide/components/repo_file_buttons.vue'; +import repoFileButtons from '~/ide/components/ide_file_buttons.vue'; import createVueComponent from '../../helpers/vue_mount_component_helper'; import { file } from '../helpers'; @@ -23,7 +23,7 @@ describe('RepoFileButtons', () => { vm.$destroy(); }); - it('renders Raw, Blame, History, Permalink and Preview toggle', done => { + it('renders Raw, Blame, History and Permalink', done => { vm = createComponent(); vm.$nextTick(() => { @@ -32,16 +32,30 @@ describe('RepoFileButtons', () => { const history = vm.$el.querySelector('.history'); expect(raw.href).toMatch(`/${activeFile.rawPath}`); - expect(raw.textContent.trim()).toEqual('Raw'); + expect(raw.getAttribute('data-original-title')).toEqual('Raw'); expect(blame.href).toMatch(`/${activeFile.blamePath}`); - expect(blame.textContent.trim()).toEqual('Blame'); + expect(blame.getAttribute('data-original-title')).toEqual('Blame'); expect(history.href).toMatch(`/${activeFile.commitsPath}`); - expect(history.textContent.trim()).toEqual('History'); - expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual( + expect(history.getAttribute('data-original-title')).toEqual('History'); + expect(vm.$el.querySelector('.permalink').getAttribute('data-original-title')).toEqual( 'Permalink', ); done(); }); }); + + it('renders Download', done => { + activeFile.binary = true; + vm = createComponent(); + + vm.$nextTick(() => { + const raw = vm.$el.querySelector('.raw'); + + expect(raw.href).toMatch(`/${activeFile.rawPath}`); + expect(raw.getAttribute('data-original-title')).toEqual('Download'); + + done(); + }); + }); }); diff --git a/spec/javascripts/ide/components/ide_spec.js b/spec/javascripts/ide/components/ide_spec.js index 5bd890094cc..7bfcfc90572 100644 --- a/spec/javascripts/ide/components/ide_spec.js +++ b/spec/javascripts/ide/components/ide_spec.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import Mousetrap from 'mousetrap'; import store from '~/ide/stores'; import ide from '~/ide/components/ide.vue'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; @@ -38,4 +39,68 @@ describe('ide component', () => { done(); }); }); + + describe('file finder', () => { + beforeEach(done => { + spyOn(vm, 'toggleFileFinder'); + + vm.$store.state.fileFindVisible = true; + + vm.$nextTick(done); + }); + + it('calls toggleFileFinder on `t` key press', done => { + Mousetrap.trigger('t'); + + vm + .$nextTick() + .then(() => { + expect(vm.toggleFileFinder).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + it('calls toggleFileFinder on `command+p` key press', done => { + Mousetrap.trigger('command+p'); + + vm + .$nextTick() + .then(() => { + expect(vm.toggleFileFinder).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + it('calls toggleFileFinder on `ctrl+p` key press', done => { + Mousetrap.trigger('ctrl+p'); + + vm + .$nextTick() + .then(() => { + expect(vm.toggleFileFinder).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + + it('always allows `command+p` to trigger toggleFileFinder', () => { + expect( + vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 'command+p'), + ).toBe(false); + }); + + it('always allows `ctrl+p` to trigger toggleFileFinder', () => { + expect( + vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 'ctrl+p'), + ).toBe(false); + }); + + it('onlys handles `t` when focused in input-field', () => { + expect( + vm.mousetrapStopCallback(null, vm.$el.querySelector('.dropdown-input-field'), 't'), + ).toBe(true); + }); + }); }); diff --git a/spec/javascripts/ide/components/new_dropdown/index_spec.js b/spec/javascripts/ide/components/new_dropdown/index_spec.js index e08abe7d849..7b637f37eba 100644 --- a/spec/javascripts/ide/components/new_dropdown/index_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/index_spec.js @@ -32,12 +32,8 @@ describe('new dropdown component', () => { it('renders new file, upload and new directory links', () => { expect(vm.$el.querySelectorAll('a')[0].textContent.trim()).toBe('New file'); - expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe( - 'Upload file', - ); - expect(vm.$el.querySelectorAll('a')[2].textContent.trim()).toBe( - 'New directory', - ); + expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe('Upload file'); + expect(vm.$el.querySelectorAll('a')[2].textContent.trim()).toBe('New directory'); }); describe('createNewItem', () => { @@ -81,4 +77,18 @@ describe('new dropdown component', () => { .catch(done.fail); }); }); + + describe('dropdownOpen', () => { + it('scrolls dropdown into view', done => { + spyOn(vm.$refs.dropdownMenu, 'scrollIntoView'); + + vm.dropdownOpen = true; + + setTimeout(() => { + expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalled(); + + done(); + }); + }); + }); }); diff --git a/spec/javascripts/ide/components/new_dropdown/modal_spec.js b/spec/javascripts/ide/components/new_dropdown/modal_spec.js index a6e1e5a0d35..f362ed4db65 100644 --- a/spec/javascripts/ide/components/new_dropdown/modal_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/modal_spec.js @@ -25,25 +25,17 @@ describe('new file modal component', () => { it(`sets modal title as ${type}`, () => { const title = type === 'tree' ? 'directory' : 'file'; - expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe( - `Create new ${title}`, - ); + expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Create new ${title}`); }); it(`sets button label as ${type}`, () => { const title = type === 'tree' ? 'directory' : 'file'; - expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe( - `Create ${title}`, - ); + expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Create ${title}`); }); it(`sets form label as ${type}`, () => { - const title = type === 'tree' ? 'Directory' : 'File'; - - expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe( - `${title} name`, - ); + expect(vm.$el.querySelector('.label-light').textContent.trim()).toBe('Name'); }); describe('createEntryInStore', () => { diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 113ade269e9..768f6e99bf1 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -28,16 +28,34 @@ describe('RepoCommitSection', () => { }, }; + const files = [file('file1'), file('file2')].map(f => + Object.assign(f, { + type: 'blob', + }), + ); + vm.$store.state.rightPanelCollapsed = false; vm.$store.state.currentBranch = 'master'; - vm.$store.state.changedFiles = [file('file1'), file('file2')]; + vm.$store.state.changedFiles = [...files]; vm.$store.state.changedFiles.forEach(f => Object.assign(f, { changed: true, + content: 'changedFile testing', + }), + ); + + vm.$store.state.stagedFiles = [{ ...files[0] }, { ...files[1] }]; + vm.$store.state.stagedFiles.forEach(f => + Object.assign(f, { + changed: true, content: 'testing', }), ); + vm.$store.state.changedFiles.forEach(f => { + vm.$store.state.entries[f.path] = f; + }); + return vm.$mount(); } @@ -94,20 +112,93 @@ describe('RepoCommitSection', () => { ...vm.$el.querySelectorAll('.multi-file-commit-list li'), ]; const submitCommit = vm.$el.querySelector('form .btn'); + const allFiles = vm.$store.state.changedFiles.concat( + vm.$store.state.stagedFiles, + ); expect(vm.$el.querySelector('.multi-file-commit-form')).not.toBeNull(); - expect(changedFileElements.length).toEqual(2); + expect(changedFileElements.length).toEqual(4); changedFileElements.forEach((changedFile, i) => { - expect(changedFile.textContent.trim()).toContain( - vm.$store.state.changedFiles[i].path, - ); + expect(changedFile.textContent.trim()).toContain(allFiles[i].path); }); expect(submitCommit.disabled).toBeTruthy(); expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeNull(); }); + it('adds changed files into staged files', done => { + vm.$el.querySelector('.ide-staged-action-btn').click(); + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('.ide-commit-list-container').textContent, + ).toContain('No changes'); + + done(); + }); + }); + + it('stages a single file', done => { + vm.$el.querySelector('.multi-file-discard-btn .btn').click(); + + Vue.nextTick(() => { + expect( + vm.$el + .querySelector('.ide-commit-list-container') + .querySelectorAll('li').length, + ).toBe(1); + + done(); + }); + }); + + it('discards a single file', done => { + vm.$el.querySelectorAll('.multi-file-discard-btn .btn')[1].click(); + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('.ide-commit-list-container').textContent, + ).not.toContain('file1'); + expect( + vm.$el + .querySelector('.ide-commit-list-container') + .querySelectorAll('li').length, + ).toBe(1); + + done(); + }); + }); + + it('removes all staged files', done => { + vm.$el.querySelectorAll('.ide-staged-action-btn')[1].click(); + + Vue.nextTick(() => { + expect( + vm.$el.querySelectorAll('.ide-commit-list-container')[1].textContent, + ).toContain('No changes'); + + done(); + }); + }); + + it('unstages a single file', done => { + vm.$el + .querySelectorAll('.multi-file-discard-btn')[2] + .querySelector('.btn') + .click(); + + Vue.nextTick(() => { + expect( + vm.$el + .querySelectorAll('.ide-commit-list-container')[1] + .querySelectorAll('li').length, + ).toBe(1); + + done(); + }); + }); + it('updates commitMessage in store on input', done => { const textarea = vm.$el.querySelector('textarea'); diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js index 9d3fa1280f4..b06a6c62a1c 100644 --- a/spec/javascripts/ide/components/repo_editor_spec.js +++ b/spec/javascripts/ide/components/repo_editor_spec.js @@ -1,9 +1,12 @@ import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import store from '~/ide/stores'; import repoEditor from '~/ide/components/repo_editor.vue'; import monacoLoader from '~/ide/monaco_loader'; import Editor from '~/ide/lib/editor'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; +import setTimeoutPromise from '../../helpers/set_timeout_promise_helper'; import { file, resetStore } from '../helpers'; describe('RepoEditor', () => { @@ -19,7 +22,6 @@ describe('RepoEditor', () => { f.active = true; f.tempFile = true; - f.html = 'testing'; vm.$store.state.openFiles.push(f); vm.$store.state.entries[f.path] = f; vm.monaco = true; @@ -36,7 +38,7 @@ describe('RepoEditor', () => { resetStore(vm.$store); - Editor.editorInstance.modelManager.dispose(); + Editor.editorInstance.dispose(); }); it('renders an ide container', done => { @@ -47,6 +49,95 @@ describe('RepoEditor', () => { }); }); + it('renders only an edit tab', done => { + Vue.nextTick(() => { + const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li'); + expect(tabs.length).toBe(1); + expect(tabs[0].textContent.trim()).toBe('Edit'); + + done(); + }); + }); + + describe('when file is markdown', () => { + beforeEach(done => { + vm.file.previewMode = { + id: 'markdown', + previewTitle: 'Preview Markdown', + }; + + vm.$nextTick(done); + }); + + it('renders an Edit and a Preview Tab', done => { + Vue.nextTick(() => { + const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li'); + expect(tabs.length).toBe(2); + expect(tabs[0].textContent.trim()).toBe('Edit'); + expect(tabs[1].textContent.trim()).toBe('Preview Markdown'); + + done(); + }); + }); + }); + + describe('when file is markdown and viewer mode is review', () => { + let mock; + + beforeEach(done => { + mock = new MockAdapter(axios); + + vm.file.projectId = 'namespace/project'; + vm.file.previewMode = { + id: 'markdown', + previewTitle: 'Preview Markdown', + }; + vm.file.content = 'testing 123'; + vm.$store.state.viewer = 'diff'; + + mock.onPost(/(.*)\/preview_markdown/).reply(200, { + body: '<p>testing 123</p>', + }); + + vm.$nextTick(done); + }); + + afterEach(() => { + mock.restore(); + }); + + it('renders an Edit and a Preview Tab', done => { + Vue.nextTick(() => { + const tabs = vm.$el.querySelectorAll('.ide-mode-tabs .nav-links li'); + expect(tabs.length).toBe(2); + expect(tabs[0].textContent.trim()).toBe('Review'); + expect(tabs[1].textContent.trim()).toBe('Preview Markdown'); + + done(); + }); + }); + + it('renders markdown for tempFile', done => { + vm.file.tempFile = true; + vm.file.path = `${vm.file.path}.md`; + vm.$store.state.entries[vm.file.path] = vm.file; + + vm + .$nextTick() + .then(() => { + vm.$el.querySelectorAll('.ide-mode-tabs .nav-links a')[1].click(); + }) + .then(setTimeoutPromise) + .then(() => { + expect(vm.$el.querySelector('.preview-container').innerHTML).toContain( + '<p>testing 123</p>', + ); + }) + .then(done) + .catch(done.fail); + }); + }); + describe('when open file is binary and not raw', () => { beforeEach(done => { vm.file.binary = true; @@ -57,10 +148,6 @@ describe('RepoEditor', () => { it('does not render the IDE', () => { expect(vm.shouldHideEditor).toBeTruthy(); }); - - it('shows activeFile html', () => { - expect(vm.$el.textContent).toContain('testing'); - }); }); describe('createEditorInstance', () => { @@ -113,7 +200,7 @@ describe('RepoEditor', () => { vm.setupEditor(); - expect(vm.editor.createModel).toHaveBeenCalledWith(vm.file); + expect(vm.editor.createModel).toHaveBeenCalledWith(vm.file, null); expect(vm.model).not.toBeNull(); }); @@ -135,7 +222,7 @@ describe('RepoEditor', () => { vm.setupEditor(); expect(vm.editor.onPositionChange).toHaveBeenCalled(); - expect(vm.model.events.size).toBe(1); + expect(vm.model.events.size).toBe(2); }); it('updates state when model content changed', done => { @@ -147,49 +234,65 @@ describe('RepoEditor', () => { done(); }); }); - }); - describe('setup editor for merge request viewing', () => { - beforeEach(done => { - // Resetting as the main test setup has already done it - vm.$destroy(); - resetStore(vm.$store); + it('sets head model as staged file', () => { + spyOn(vm.editor, 'createModel').and.callThrough(); + Editor.editorInstance.modelManager.dispose(); - const f = { - ...file(), - active: true, - tempFile: true, - html: 'testing', - mrChange: { diff: 'ABC' }, - baseRaw: 'testing', - content: 'test', - }; - const RepoEditor = Vue.extend(repoEditor); - vm = createComponentWithStore(RepoEditor, store, { - file: f, - }); + vm.$store.state.stagedFiles.push({ ...vm.file, key: 'staged' }); + vm.file.staged = true; + vm.file.key = `unstaged-${vm.file.key}`; - vm.$store.state.openFiles.push(f); - vm.$store.state.entries[f.path] = f; + vm.setupEditor(); - vm.$store.state.viewer = 'mrdiff'; + expect(vm.editor.createModel).toHaveBeenCalledWith(vm.file, vm.$store.state.stagedFiles[0]); + }); + }); + + describe('editor updateDimensions', () => { + beforeEach(() => { + spyOn(vm.editor, 'updateDimensions').and.callThrough(); + spyOn(vm.editor, 'updateDiffView'); + }); - vm.monaco = true; + it('calls updateDimensions when rightPanelCollapsed is changed', done => { + vm.$store.state.rightPanelCollapsed = true; - vm.$mount(); + vm.$nextTick(() => { + expect(vm.editor.updateDimensions).toHaveBeenCalled(); + expect(vm.editor.updateDiffView).toHaveBeenCalled(); - monacoLoader(['vs/editor/editor.main'], () => { - setTimeout(done, 0); + done(); }); }); - it('attaches merge request model to editor when merge request diff', () => { - spyOn(vm.editor, 'attachMergeRequestModel').and.callThrough(); + it('calls updateDimensions when panelResizing is false', done => { + vm.$store.state.panelResizing = true; + + vm + .$nextTick() + .then(() => { + vm.$store.state.panelResizing = false; + }) + .then(vm.$nextTick) + .then(() => { + expect(vm.editor.updateDimensions).toHaveBeenCalled(); + expect(vm.editor.updateDiffView).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); - vm.setupEditor(); + it('does not call updateDimensions when panelResizing is true', done => { + vm.$store.state.panelResizing = true; - expect(vm.editor.attachMergeRequestModel).toHaveBeenCalledWith(vm.model); + vm.$nextTick(() => { + expect(vm.editor.updateDimensions).not.toHaveBeenCalled(); + expect(vm.editor.updateDiffView).not.toHaveBeenCalled(); + + done(); + }); }); }); }); diff --git a/spec/javascripts/ide/components/repo_file_spec.js b/spec/javascripts/ide/components/repo_file_spec.js index ff391cb4351..28ff06e1f80 100644 --- a/spec/javascripts/ide/components/repo_file_spec.js +++ b/spec/javascripts/ide/components/repo_file_spec.js @@ -48,6 +48,33 @@ describe('RepoFile', () => { }); }); + describe('folder', () => { + it('renders changes count inside folder', () => { + const f = { + ...file('folder'), + path: 'testing', + type: 'tree', + branchId: 'master', + projectId: 'project', + }; + + store.state.changedFiles.push({ + ...file('fileName'), + path: 'testing/fileName', + }); + + createComponent({ + file: f, + level: 0, + }); + + const treeChangesEl = vm.$el.querySelector('.ide-tree-changes'); + + expect(treeChangesEl).not.toBeNull(); + expect(treeChangesEl.textContent).toContain('1'); + }); + }); + describe('locked file', () => { let f; @@ -72,8 +99,7 @@ describe('RepoFile', () => { it('renders a tooltip', () => { expect( - vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset - .originalTitle, + vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset.originalTitle, ).toContain('Locked by testuser'); }); }); diff --git a/spec/javascripts/ide/components/repo_loading_file_spec.js b/spec/javascripts/ide/components/repo_loading_file_spec.js index 8f9644216bc..7c20b8302f9 100644 --- a/spec/javascripts/ide/components/repo_loading_file_spec.js +++ b/spec/javascripts/ide/components/repo_loading_file_spec.js @@ -27,7 +27,7 @@ describe('RepoLoadingFile', () => { const lines = [...container.querySelectorAll(':scope > div')]; expect(container).toBeTruthy(); - expect(lines.length).toEqual(6); + expect(lines.length).toEqual(3); assertLines(lines); }); } diff --git a/spec/javascripts/ide/lib/common/model_spec.js b/spec/javascripts/ide/lib/common/model_spec.js index 8fc2fccb64c..7a6c22b6d27 100644 --- a/spec/javascripts/ide/lib/common/model_spec.js +++ b/spec/javascripts/ide/lib/common/model_spec.js @@ -30,6 +30,19 @@ describe('Multi-file editor library model', () => { expect(model.baseModel).not.toBeNull(); }); + it('creates model with head file to compare against', () => { + const f = file('path'); + model.dispose(); + + model = new Model(monaco, f, { + ...f, + content: '123 testing', + }); + + expect(model.head).not.toBeNull(); + expect(model.getOriginalModel().getValue()).toBe('123 testing'); + }); + it('adds eventHub listener', () => { expect(eventHub.$on).toHaveBeenCalledWith( `editor.update.model.dispose.${model.file.key}`, @@ -70,13 +83,6 @@ describe('Multi-file editor library model', () => { }); describe('onChange', () => { - it('caches event by path', () => { - model.onChange(() => {}); - - expect(model.events.size).toBe(1); - expect(model.events.keys().next().value).toBe(model.file.key); - }); - it('calls callback on change', done => { const spy = jasmine.createSpy(); model.onChange(spy); @@ -119,5 +125,15 @@ describe('Multi-file editor library model', () => { jasmine.anything(), ); }); + + it('calls onDispose callback', () => { + const disposeSpy = jasmine.createSpy(); + + model.onDispose(disposeSpy); + + model.dispose(); + + expect(disposeSpy).toHaveBeenCalled(); + }); }); }); diff --git a/spec/javascripts/ide/lib/decorations/controller_spec.js b/spec/javascripts/ide/lib/decorations/controller_spec.js index aec325e26a9..e1c4ca570b6 100644 --- a/spec/javascripts/ide/lib/decorations/controller_spec.js +++ b/spec/javascripts/ide/lib/decorations/controller_spec.js @@ -117,4 +117,33 @@ describe('Multi-file editor library decorations controller', () => { expect(controller.editorDecorations.size).toBe(0); }); }); + + describe('hasDecorations', () => { + it('returns true when decorations are cached', () => { + controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); + + expect(controller.hasDecorations(model)).toBe(true); + }); + + it('returns false when no model decorations exist', () => { + expect(controller.hasDecorations(model)).toBe(false); + }); + }); + + describe('removeDecorations', () => { + beforeEach(() => { + controller.addDecorations(model, 'key', [{ decoration: 'decorationValue' }]); + controller.decorate(model); + }); + + it('removes cached decorations', () => { + expect(controller.decorations.size).not.toBe(0); + expect(controller.editorDecorations.size).not.toBe(0); + + controller.removeDecorations(model); + + expect(controller.decorations.size).toBe(0); + expect(controller.editorDecorations.size).toBe(0); + }); + }); }); diff --git a/spec/javascripts/ide/lib/diff/controller_spec.js b/spec/javascripts/ide/lib/diff/controller_spec.js index ff73240734e..fd8ab3b4f1d 100644 --- a/spec/javascripts/ide/lib/diff/controller_spec.js +++ b/spec/javascripts/ide/lib/diff/controller_spec.js @@ -3,10 +3,7 @@ import monacoLoader from '~/ide/monaco_loader'; import editor from '~/ide/lib/editor'; import ModelManager from '~/ide/lib/common/model_manager'; import DecorationsController from '~/ide/lib/decorations/controller'; -import DirtyDiffController, { - getDiffChangeType, - getDecorator, -} from '~/ide/lib/diff/controller'; +import DirtyDiffController, { getDiffChangeType, getDecorator } from '~/ide/lib/diff/controller'; import { computeDiff } from '~/ide/lib/diff/diff'; import { file } from '../../helpers'; @@ -90,6 +87,14 @@ describe('Multi-file editor library dirty diff controller', () => { expect(model.onChange).toHaveBeenCalled(); }); + it('adds dispose event callback', () => { + spyOn(model, 'onDispose'); + + controller.attachModel(model); + + expect(model.onDispose).toHaveBeenCalled(); + }); + it('calls throttledComputeDiff on change', () => { spyOn(controller, 'throttledComputeDiff'); @@ -99,6 +104,12 @@ describe('Multi-file editor library dirty diff controller', () => { expect(controller.throttledComputeDiff).toHaveBeenCalled(); }); + + it('caches model', () => { + controller.attachModel(model); + + expect(controller.models.has(model.url)).toBe(true); + }); }); describe('computeDiff', () => { @@ -116,14 +127,22 @@ describe('Multi-file editor library dirty diff controller', () => { }); describe('reDecorate', () => { - it('calls decorations controller decorate', () => { + it('calls computeDiff when no decorations are cached', () => { + spyOn(controller, 'computeDiff'); + + controller.reDecorate(model); + + expect(controller.computeDiff).toHaveBeenCalledWith(model); + }); + + it('calls decorate when decorations are cached', () => { spyOn(controller.decorationsController, 'decorate'); + controller.decorationsController.decorations.set(model.url, 'test'); + controller.reDecorate(model); - expect(controller.decorationsController.decorate).toHaveBeenCalledWith( - model, - ); + expect(controller.decorationsController.decorate).toHaveBeenCalledWith(model); }); }); @@ -133,16 +152,15 @@ describe('Multi-file editor library dirty diff controller', () => { controller.decorate({ data: { changes: [], path: model.path } }); - expect( - controller.decorationsController.addDecorations, - ).toHaveBeenCalledWith(model, 'dirtyDiff', jasmine.anything()); + expect(controller.decorationsController.addDecorations).toHaveBeenCalledWith( + model, + 'dirtyDiff', + jasmine.anything(), + ); }); it('adds decorations into editor', () => { - const spy = spyOn( - controller.decorationsController.editor.instance, - 'deltaDecorations', - ); + const spy = spyOn(controller.decorationsController.editor.instance, 'deltaDecorations'); controller.decorate({ data: { changes: computeDiff('123', '1234'), path: model.path }, @@ -181,16 +199,22 @@ describe('Multi-file editor library dirty diff controller', () => { }); it('removes worker event listener', () => { - spyOn( - controller.dirtyDiffWorker, - 'removeEventListener', - ).and.callThrough(); + spyOn(controller.dirtyDiffWorker, 'removeEventListener').and.callThrough(); controller.dispose(); - expect( - controller.dirtyDiffWorker.removeEventListener, - ).toHaveBeenCalledWith('message', jasmine.anything()); + expect(controller.dirtyDiffWorker.removeEventListener).toHaveBeenCalledWith( + 'message', + jasmine.anything(), + ); + }); + + it('clears cached models', () => { + controller.attachModel(model); + + model.dispose(); + + expect(controller.models.size).toBe(0); }); }); }); diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js index ec56ebc0341..530bdfa2759 100644 --- a/spec/javascripts/ide/lib/editor_spec.js +++ b/spec/javascripts/ide/lib/editor_spec.js @@ -76,7 +76,8 @@ describe('Multi-file editor library', () => { occurrencesHighlight: false, renderLineHighlight: 'none', hideCursorInOverviewRuler: true, - wordWrap: 'bounded', + wordWrap: 'on', + renderSideBySide: true, }); }); }); @@ -87,7 +88,7 @@ describe('Multi-file editor library', () => { instance.createModel('FILE'); - expect(instance.modelManager.addModel).toHaveBeenCalledWith('FILE'); + expect(instance.modelManager.addModel).toHaveBeenCalledWith('FILE', null); }); }); @@ -215,4 +216,56 @@ describe('Multi-file editor library', () => { expect(instance.decorationsController.dispose).not.toHaveBeenCalled(); }); }); + + describe('updateDiffView', () => { + describe('edit mode', () => { + it('does not update options', () => { + instance.createInstance(holder); + + spyOn(instance.instance, 'updateOptions'); + + instance.updateDiffView(); + + expect(instance.instance.updateOptions).not.toHaveBeenCalled(); + }); + }); + + describe('diff mode', () => { + beforeEach(() => { + instance.createDiffInstance(holder); + + spyOn(instance.instance, 'updateOptions').and.callThrough(); + }); + + it('sets renderSideBySide to false if el is less than 700 pixels', () => { + spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(600); + + expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ + renderSideBySide: false, + }); + }); + + it('sets renderSideBySide to false if el is more than 700 pixels', () => { + spyOnProperty(instance.instance.getDomNode(), 'offsetWidth').and.returnValue(800); + + expect(instance.instance.updateOptions).not.toHaveBeenCalledWith({ + renderSideBySide: true, + }); + }); + }); + }); + + describe('isDiffEditorType', () => { + it('returns true when diff editor', () => { + instance.createDiffInstance(holder); + + expect(instance.isDiffEditorType).toBe(true); + }); + + it('returns false when not diff editor', () => { + instance.createInstance(holder); + + expect(instance.isDiffEditorType).toBe(false); + }); + }); }); diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js index 479ed7ce49e..3ee11bd2f03 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/javascripts/ide/stores/actions/file_spec.js @@ -1,9 +1,12 @@ import Vue from 'vue'; import store from '~/ide/stores'; +import * as actions from '~/ide/stores/actions/file'; +import * as types from '~/ide/stores/mutation_types'; import service from '~/ide/services'; import router from '~/ide/ide_router'; import eventHub from '~/ide/eventhub'; import { file, resetStore } from '../../helpers'; +import testAction from '../../../helpers/vuex_action_helper'; describe('IDE store file actions', () => { beforeEach(() => { @@ -395,6 +398,20 @@ describe('IDE store file actions', () => { }) .catch(done.fail); }); + + it('bursts unused seal', done => { + store + .dispatch('changeFileContent', { + path: tmpFile.path, + content: 'content', + }) + .then(() => { + expect(store.state.unusedSeal).toBe(false); + + done(); + }) + .catch(done.fail); + }); }); describe('discardFileChanges', () => { @@ -402,6 +419,7 @@ describe('IDE store file actions', () => { beforeEach(() => { spyOn(eventHub, '$on'); + spyOn(eventHub, '$emit'); tmpFile = file(); tmpFile.content = 'testing'; @@ -460,6 +478,57 @@ describe('IDE store file actions', () => { }) .catch(done.fail); }); + + it('pushes route for active file', done => { + tmpFile.active = true; + store.state.openFiles.push(tmpFile); + + store + .dispatch('discardFileChanges', tmpFile.path) + .then(() => { + expect(router.push).toHaveBeenCalledWith(`/project${tmpFile.url}`); + + done(); + }) + .catch(done.fail); + }); + + it('emits eventHub event to dispose cached model', done => { + store + .dispatch('discardFileChanges', tmpFile.path) + .then(() => { + expect(eventHub.$emit).toHaveBeenCalled(); + + done(); + }) + .catch(done.fail); + }); + }); + + describe('stageChange', () => { + it('calls STAGE_CHANGE with file path', done => { + testAction( + actions.stageChange, + 'path', + store.state, + [{ type: types.STAGE_CHANGE, payload: 'path' }], + [], + done, + ); + }); + }); + + describe('unstageChange', () => { + it('calls UNSTAGE_CHANGE with file path', done => { + testAction( + actions.unstageChange, + 'path', + store.state, + [{ type: types.UNSTAGE_CHANGE, payload: 'path' }], + [], + done, + ); + }); }); describe('openPendingTab', () => { @@ -476,7 +545,7 @@ describe('IDE store file actions', () => { it('makes file pending in openFiles', done => { store - .dispatch('openPendingTab', f) + .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) .then(() => { expect(store.state.openFiles[0].pending).toBe(true); }) @@ -486,7 +555,7 @@ describe('IDE store file actions', () => { it('returns true when opened', done => { store - .dispatch('openPendingTab', f) + .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) .then(added => { expect(added).toBe(true); }) @@ -498,7 +567,7 @@ describe('IDE store file actions', () => { store.state.currentBranchId = 'master'; store - .dispatch('openPendingTab', f) + .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) .then(() => { expect(router.push).toHaveBeenCalledWith('/project/123/tree/master/'); }) @@ -512,7 +581,7 @@ describe('IDE store file actions', () => { store._actions.scrollToTab = [scrollToTabSpy]; // eslint-disable-line store - .dispatch('openPendingTab', f) + .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) .then(() => { expect(scrollToTabSpy).toHaveBeenCalled(); store._actions.scrollToTab = oldScrollToTab; // eslint-disable-line @@ -527,7 +596,7 @@ describe('IDE store file actions', () => { store.state.viewer = 'diff'; store - .dispatch('openPendingTab', f) + .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' }) .then(added => { expect(added).toBe(false); }) diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js index cec572f4507..a64af5b941b 100644 --- a/spec/javascripts/ide/stores/actions_spec.js +++ b/spec/javascripts/ide/stores/actions_spec.js @@ -1,7 +1,14 @@ -import * as urlUtils from '~/lib/utils/url_utility'; +import actions, { + stageAllChanges, + unstageAllChanges, + toggleFileFinder, + updateTempFlagForEntry, +} from '~/ide/stores/actions'; import store from '~/ide/stores'; +import * as types from '~/ide/stores/mutation_types'; import router from '~/ide/ide_router'; import { resetStore, file } from '../helpers'; +import testAction from '../../helpers/vuex_action_helper'; describe('Multi-file store actions', () => { beforeEach(() => { @@ -14,12 +21,12 @@ describe('Multi-file store actions', () => { describe('redirectToUrl', () => { it('calls visitUrl', done => { - spyOn(urlUtils, 'visitUrl'); + const visitUrl = spyOnDependency(actions, 'visitUrl'); store .dispatch('redirectToUrl', 'test') .then(() => { - expect(urlUtils.visitUrl).toHaveBeenCalledWith('test'); + expect(visitUrl).toHaveBeenCalledWith('test'); done(); }) @@ -191,9 +198,7 @@ describe('Multi-file store actions', () => { }) .then(f => { expect(f.tempFile).toBeTruthy(); - expect(store.state.trees['abcproject/mybranch'].tree.length).toBe( - 1, - ); + expect(store.state.trees['abcproject/mybranch'].tree.length).toBe(1); done(); }) @@ -292,6 +297,42 @@ describe('Multi-file store actions', () => { }); }); + describe('stageAllChanges', () => { + it('adds all files from changedFiles to stagedFiles', done => { + store.state.changedFiles.push(file(), file('new')); + + testAction( + stageAllChanges, + null, + store.state, + [ + { type: types.STAGE_CHANGE, payload: store.state.changedFiles[0].path }, + { type: types.STAGE_CHANGE, payload: store.state.changedFiles[1].path }, + ], + [], + done, + ); + }); + }); + + describe('unstageAllChanges', () => { + it('removes all files from stagedFiles after unstaging', done => { + store.state.stagedFiles.push(file(), file('new')); + + testAction( + unstageAllChanges, + null, + store.state, + [ + { type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[0].path }, + { type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[1].path }, + ], + [], + done, + ); + }); + }); + describe('updateViewer', () => { it('updates viewer state', done => { store @@ -303,4 +344,60 @@ describe('Multi-file store actions', () => { .catch(done.fail); }); }); + + describe('updateTempFlagForEntry', () => { + it('commits UPDATE_TEMP_FLAG', done => { + const f = { + ...file(), + path: 'test', + tempFile: true, + }; + store.state.entries[f.path] = f; + + testAction( + updateTempFlagForEntry, + { file: f, tempFile: false }, + store.state, + [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }], + [], + done, + ); + }); + + it('commits UPDATE_TEMP_FLAG and dispatches for parent', done => { + const parent = { + ...file(), + path: 'testing', + }; + const f = { + ...file(), + path: 'test', + parentPath: 'testing', + }; + store.state.entries[parent.path] = parent; + store.state.entries[f.path] = f; + + testAction( + updateTempFlagForEntry, + { file: f, tempFile: false }, + store.state, + [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }], + [{ type: 'updateTempFlagForEntry', payload: { file: parent, tempFile: false } }], + done, + ); + }); + }); + + describe('toggleFileFinder', () => { + it('commits TOGGLE_FILE_FINDER', done => { + testAction( + toggleFileFinder, + true, + null, + [{ type: 'TOGGLE_FILE_FINDER', payload: true }], + [], + done, + ); + }); + }); }); diff --git a/spec/javascripts/ide/stores/getters_spec.js b/spec/javascripts/ide/stores/getters_spec.js index 33733b97dff..bd834443730 100644 --- a/spec/javascripts/ide/stores/getters_spec.js +++ b/spec/javascripts/ide/stores/getters_spec.js @@ -37,19 +37,11 @@ describe('IDE store getters', () => { expect(modifiedFiles.length).toBe(1); expect(modifiedFiles[0].name).toBe('changed'); }); - }); - describe('addedFiles', () => { - it('returns a list of added files', () => { - localState.openFiles.push(file()); - localState.changedFiles.push(file('added')); - localState.changedFiles[0].changed = true; - localState.changedFiles[0].tempFile = true; + it('returns angle left when collapsed', () => { + localState.rightPanelCollapsed = true; - const modifiedFiles = getters.addedFiles(localState); - - expect(modifiedFiles.length).toBe(1); - expect(modifiedFiles[0].name).toBe('added'); + expect(getters.collapseButtonIcon(localState)).toBe('angle-double-left'); }); }); @@ -72,4 +64,87 @@ describe('IDE store getters', () => { expect(getters.currentMergeRequest(localState)).toBeNull(); }); }); + + describe('allBlobs', () => { + beforeEach(() => { + Object.assign(localState.entries, { + index: { type: 'blob', name: 'index', lastOpenedAt: 0 }, + app: { type: 'blob', name: 'blob', lastOpenedAt: 0 }, + folder: { type: 'folder', name: 'folder', lastOpenedAt: 0 }, + }); + }); + + it('returns only blobs', () => { + expect(getters.allBlobs(localState).length).toBe(2); + }); + + it('returns list sorted by lastOpenedAt', () => { + localState.entries.app.lastOpenedAt = new Date().getTime(); + + expect(getters.allBlobs(localState)[0].name).toBe('blob'); + }); + }); + + describe('getChangesInFolder', () => { + it('returns length of changed files for a path', () => { + localState.changedFiles.push( + { + path: 'test/index', + name: 'index', + }, + { + path: 'app/123', + name: '123', + }, + ); + + expect(getters.getChangesInFolder(localState)('test')).toBe(1); + }); + + it('returns length of changed & staged files for a path', () => { + localState.changedFiles.push( + { + path: 'test/index', + name: 'index', + }, + { + path: 'testing/123', + name: '123', + }, + ); + + localState.stagedFiles.push( + { + path: 'test/123', + name: '123', + }, + { + path: 'test/index', + name: 'index', + }, + { + path: 'testing/12345', + name: '12345', + }, + ); + + expect(getters.getChangesInFolder(localState)('test')).toBe(2); + }); + + it('returns length of changed & tempFiles files for a path', () => { + localState.changedFiles.push( + { + path: 'test/index', + name: 'index', + }, + { + path: 'test/newfile', + name: 'newfile', + tempFile: true, + }, + ); + + expect(getters.getChangesInFolder(localState)('test')).toBe(2); + }); + }); }); diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js index 90ded940227..b2b4b85ca42 100644 --- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js @@ -1,7 +1,7 @@ +import actions from '~/ide/stores/actions'; import store from '~/ide/stores'; import service from '~/ide/services'; import router from '~/ide/ide_router'; -import * as urlUtils from '~/lib/utils/url_utility'; import eventHub from '~/ide/eventhub'; import * as consts from '~/ide/stores/modules/commit/constants'; import { resetStore, file } from 'spec/ide/helpers'; @@ -133,10 +133,7 @@ describe('IDE commit module actions', () => { store .dispatch('commit/checkCommitStatus') .then(() => { - expect(service.getBranchData).toHaveBeenCalledWith( - 'abcproject', - 'master', - ); + expect(service.getBranchData).toHaveBeenCalledWith('abcproject', 'master'); done(); }) @@ -212,14 +209,14 @@ describe('IDE commit module actions', () => { }, }, }; - store.state.changedFiles.push(f, { + store.state.stagedFiles.push(f, { ...file('changedFile2'), changed: true, }); - store.state.openFiles = store.state.changedFiles; + store.state.openFiles = store.state.stagedFiles; - store.state.changedFiles.forEach(changedFile => { - store.state.entries[changedFile.path] = changedFile; + store.state.stagedFiles.forEach(stagedFile => { + store.state.entries[stagedFile.path] = stagedFile; }); }); @@ -230,9 +227,7 @@ describe('IDE commit module actions', () => { branch, }) .then(() => { - expect( - store.state.projects.abcproject.branches.master.workingReference, - ).toBe(data.id); + expect(store.state.projects.abcproject.branches.master.workingReference).toBe(data.id); }) .then(done) .catch(done.fail); @@ -253,19 +248,6 @@ describe('IDE commit module actions', () => { .catch(done.fail); }); - it('removes all changed files', done => { - store - .dispatch('commit/updateFilesAfterCommit', { - data, - branch, - }) - .then(() => { - expect(store.state.changedFiles.length).toBe(0); - }) - .then(done) - .catch(done.fail); - }); - it('sets files commit data', done => { store .dispatch('commit/updateFilesAfterCommit', { @@ -299,10 +281,10 @@ describe('IDE commit module actions', () => { branch, }) .then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith( - `editor.update.model.content.${f.path}`, - f.content, - ); + expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.content.${f.key}`, { + content: f.content, + changed: false, + }); }) .then(done) .catch(done.fail); @@ -317,26 +299,7 @@ describe('IDE commit module actions', () => { branch, }) .then(() => { - expect(router.push).toHaveBeenCalledWith( - `/project/abcproject/blob/master/${f.path}`, - ); - }) - .then(done) - .catch(done.fail); - }); - - it('resets stores commit actions', done => { - store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH; - - store - .dispatch('commit/updateFilesAfterCommit', { - data, - branch, - }) - .then(() => { - expect(store.state.commit.commitAction).not.toBe( - consts.COMMIT_TO_NEW_BRANCH, - ); + expect(router.push).toHaveBeenCalledWith(`/project/abcproject/blob/master/${f.path}`); }) .then(done) .catch(done.fail); @@ -344,8 +307,10 @@ describe('IDE commit module actions', () => { }); describe('commitChanges', () => { + let visitUrl; + beforeEach(() => { - spyOn(urlUtils, 'visitUrl'); + visitUrl = spyOnDependency(actions, 'visitUrl'); document.body.innerHTML += '<div class="flash-container"></div>'; @@ -359,12 +324,22 @@ describe('IDE commit module actions', () => { }, }, }; - store.state.changedFiles.push(file('changed')); - store.state.changedFiles[0].active = true; + + const f = { + ...file('changed'), + type: 'blob', + active: true, + }; + store.state.stagedFiles.push(f); + store.state.changedFiles = [ + { + ...f, + }, + ]; store.state.openFiles = store.state.changedFiles; - store.state.openFiles.forEach(f => { - store.state.entries[f.path] = f; + store.state.openFiles.forEach(localF => { + store.state.entries[localF.path] = localF; }); store.state.commit.commitAction = '2'; @@ -444,11 +419,11 @@ describe('IDE commit module actions', () => { .catch(done.fail); }); - it('adds commit data to changed files', done => { + it('adds commit data to files', done => { store .dispatch('commit/commitChanges') .then(() => { - expect(store.state.openFiles[0].lastCommit.message).toBe( + expect(store.state.entries[store.state.openFiles[0].path].lastCommit.message).toBe( 'test message', ); @@ -457,24 +432,63 @@ describe('IDE commit module actions', () => { .catch(done.fail); }); - it('redirects to new merge request page', done => { - spyOn(eventHub, '$on'); - - store.state.commit.commitAction = '3'; + it('resets stores commit actions', done => { + store.state.commit.commitAction = consts.COMMIT_TO_NEW_BRANCH; store .dispatch('commit/commitChanges') .then(() => { - expect(urlUtils.visitUrl).toHaveBeenCalledWith( - `webUrl/merge_requests/new?merge_request[source_branch]=${ - store.getters['commit/newBranchName'] - }&merge_request[target_branch]=master`, - ); + expect(store.state.commit.commitAction).not.toBe(consts.COMMIT_TO_NEW_BRANCH); + }) + .then(done) + .catch(done.fail); + }); - done(); + it('removes all staged files', done => { + store + .dispatch('commit/commitChanges') + .then(() => { + expect(store.state.stagedFiles.length).toBe(0); }) + .then(done) .catch(done.fail); }); + + describe('merge request', () => { + it('redirects to new merge request page', done => { + spyOn(eventHub, '$on'); + + store.state.commit.commitAction = '3'; + + store + .dispatch('commit/commitChanges') + .then(() => { + expect(visitUrl).toHaveBeenCalledWith( + `webUrl/merge_requests/new?merge_request[source_branch]=${ + store.getters['commit/newBranchName'] + }&merge_request[target_branch]=master`, + ); + + done(); + }) + .catch(done.fail); + }); + + it('resets changed files before redirecting', done => { + spyOn(eventHub, '$on'); + + store.state.commit.commitAction = '3'; + + store + .dispatch('commit/commitChanges') + .then(() => { + expect(store.state.stagedFiles.length).toBe(0); + + done(); + }) + .catch(done.fail); + }); + }); }); describe('failed', () => { diff --git a/spec/javascripts/ide/stores/modules/commit/getters_spec.js b/spec/javascripts/ide/stores/modules/commit/getters_spec.js index e396284ec2c..55580f046ad 100644 --- a/spec/javascripts/ide/stores/modules/commit/getters_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/getters_spec.js @@ -34,17 +34,17 @@ describe('IDE commit module getters', () => { discardDraftButtonDisabled: false, }; const rootState = { - changedFiles: ['a'], + stagedFiles: ['a'], }; - it('returns false when discardDraftButtonDisabled is false & changedFiles is not empty', () => { + it('returns false when discardDraftButtonDisabled is false & stagedFiles is not empty', () => { expect( getters.commitButtonDisabled(state, localGetters, rootState), ).toBeFalsy(); }); - it('returns true when discardDraftButtonDisabled is false & changedFiles is empty', () => { - rootState.changedFiles.length = 0; + it('returns true when discardDraftButtonDisabled is false & stagedFiles is empty', () => { + rootState.stagedFiles.length = 0; expect( getters.commitButtonDisabled(state, localGetters, rootState), @@ -61,7 +61,7 @@ describe('IDE commit module getters', () => { it('returns true when discardDraftButtonDisabled is false & changedFiles is not empty', () => { localGetters.discardDraftButtonDisabled = false; - rootState.changedFiles.length = 0; + rootState.stagedFiles.length = 0; expect( getters.commitButtonDisabled(state, localGetters, rootState), diff --git a/spec/javascripts/ide/stores/mutations/file_spec.js b/spec/javascripts/ide/stores/mutations/file_spec.js index 88285ee409f..6fba934810d 100644 --- a/spec/javascripts/ide/stores/mutations/file_spec.js +++ b/spec/javascripts/ide/stores/mutations/file_spec.js @@ -8,7 +8,10 @@ describe('IDE store file mutations', () => { beforeEach(() => { localState = state(); - localFile = file(); + localFile = { + ...file(), + type: 'blob', + }; localState.entries[localFile.path] = localFile; }); @@ -183,6 +186,49 @@ describe('IDE store file mutations', () => { }); }); + describe('STAGE_CHANGE', () => { + it('adds file into stagedFiles array', () => { + mutations.STAGE_CHANGE(localState, localFile.path); + + expect(localState.stagedFiles.length).toBe(1); + expect(localState.stagedFiles[0]).toEqual(localFile); + }); + + it('updates stagedFile if it is already staged', () => { + mutations.STAGE_CHANGE(localState, localFile.path); + + localFile.raw = 'testing 123'; + + mutations.STAGE_CHANGE(localState, localFile.path); + + expect(localState.stagedFiles.length).toBe(1); + expect(localState.stagedFiles[0].raw).toEqual('testing 123'); + }); + }); + + describe('UNSTAGE_CHANGE', () => { + let f; + + beforeEach(() => { + f = { + ...file(), + type: 'blob', + staged: true, + }; + + localState.stagedFiles.push(f); + localState.changedFiles.push(f); + localState.entries[f.path] = f; + }); + + it('removes from stagedFiles array', () => { + mutations.UNSTAGE_CHANGE(localState, f.path); + + expect(localState.stagedFiles.length).toBe(0); + expect(localState.changedFiles.length).toBe(1); + }); + }); + describe('TOGGLE_FILE_CHANGED', () => { it('updates file changed status', () => { mutations.TOGGLE_FILE_CHANGED(localState, { @@ -194,6 +240,17 @@ describe('IDE store file mutations', () => { }); }); + describe('SET_FILE_VIEWMODE', () => { + it('updates file view mode', () => { + mutations.SET_FILE_VIEWMODE(localState, { + file: localFile, + viewMode: 'preview', + }); + + expect(localFile.viewMode).toBe('preview'); + }); + }); + describe('ADD_PENDING_TAB', () => { beforeEach(() => { const f = { diff --git a/spec/javascripts/ide/stores/mutations/tree_spec.js b/spec/javascripts/ide/stores/mutations/tree_spec.js index e6c085eaff6..67e9f7509da 100644 --- a/spec/javascripts/ide/stores/mutations/tree_spec.js +++ b/spec/javascripts/ide/stores/mutations/tree_spec.js @@ -55,6 +55,16 @@ describe('Multi-file store tree mutations', () => { expect(tree.tree[1].name).toBe('submodule'); expect(tree.tree[2].name).toBe('blob'); }); + + it('keeps loading state', () => { + mutations.CREATE_TREE(localState, { treePath: 'project/master' }); + mutations.SET_DIRECTORY_DATA(localState, { + data, + treePath: 'project/master', + }); + + expect(localState.trees['project/master'].loading).toBe(true); + }); }); describe('REMOVE_ALL_CHANGES_FILES', () => { diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js index 38162a470ad..61efb6372c9 100644 --- a/spec/javascripts/ide/stores/mutations_spec.js +++ b/spec/javascripts/ide/stores/mutations_spec.js @@ -69,6 +69,16 @@ describe('Multi-file store mutations', () => { }); }); + describe('CLEAR_STAGED_CHANGES', () => { + it('clears stagedFiles array', () => { + localState.stagedFiles.push('a'); + + mutations.CLEAR_STAGED_CHANGES(localState); + + expect(localState.stagedFiles.length).toBe(0); + }); + }); + describe('UPDATE_VIEWER', () => { it('sets viewer state', () => { mutations.UPDATE_VIEWER(localState, 'diff'); @@ -76,4 +86,44 @@ describe('Multi-file store mutations', () => { expect(localState.viewer).toBe('diff'); }); }); + + describe('UPDATE_TEMP_FLAG', () => { + beforeEach(() => { + localState.entries.test = { + ...file(), + tempFile: true, + changed: true, + }; + }); + + it('updates tempFile flag', () => { + mutations.UPDATE_TEMP_FLAG(localState, { path: 'test', tempFile: false }); + + expect(localState.entries.test.tempFile).toBe(false); + }); + + it('updates changed flag', () => { + mutations.UPDATE_TEMP_FLAG(localState, { path: 'test', tempFile: false }); + + expect(localState.entries.test.changed).toBe(false); + }); + }); + + describe('TOGGLE_FILE_FINDER', () => { + it('updates fileFindVisible', () => { + mutations.TOGGLE_FILE_FINDER(localState, true); + + expect(localState.fileFindVisible).toBe(true); + }); + }); + + describe('BURST_UNUSED_SEAL', () => { + it('updates unusedSeal', () => { + expect(localState.unusedSeal).toBe(true); + + mutations.BURST_UNUSED_SEAL(localState); + + expect(localState.unusedSeal).toBe(false); + }); + }); }); diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index d5a87b5ce20..bf1f0c822fe 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -2,7 +2,6 @@ import Vue from 'vue'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import '~/behaviors/markdown/render_gfm'; -import * as urlUtils from '~/lib/utils/url_utility'; import issuableApp from '~/issue_show/components/app.vue'; import eventHub from '~/issue_show/event_hub'; import setTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; @@ -174,7 +173,7 @@ describe('Issuable output', () => { }); it('does not redirect if issue has not moved', (done) => { - spyOn(urlUtils, 'visitUrl'); + const visitUrl = spyOnDependency(issuableApp, 'visitUrl'); spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { resolve({ data: { @@ -187,16 +186,13 @@ describe('Issuable output', () => { vm.updateIssuable(); setTimeout(() => { - expect( - urlUtils.visitUrl, - ).not.toHaveBeenCalled(); - + expect(visitUrl).not.toHaveBeenCalled(); done(); }); }); it('redirects if returned web_url has changed', (done) => { - spyOn(urlUtils, 'visitUrl'); + const visitUrl = spyOnDependency(issuableApp, 'visitUrl'); spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => { resolve({ data: { @@ -209,10 +205,7 @@ describe('Issuable output', () => { vm.updateIssuable(); setTimeout(() => { - expect( - urlUtils.visitUrl, - ).toHaveBeenCalledWith('/testing-issue-move'); - + expect(visitUrl).toHaveBeenCalledWith('/testing-issue-move'); done(); }); }); @@ -340,7 +333,7 @@ describe('Issuable output', () => { describe('deleteIssuable', () => { it('changes URL when deleted', (done) => { - spyOn(urlUtils, 'visitUrl'); + const visitUrl = spyOnDependency(issuableApp, 'visitUrl'); spyOn(vm.service, 'deleteIssuable').and.callFake(() => new Promise((resolve) => { resolve({ data: { @@ -352,16 +345,13 @@ describe('Issuable output', () => { vm.deleteIssuable(); setTimeout(() => { - expect( - urlUtils.visitUrl, - ).toHaveBeenCalledWith('/test'); - + expect(visitUrl).toHaveBeenCalledWith('/test'); done(); }); }); it('stops polling when deleting', (done) => { - spyOn(urlUtils, 'visitUrl'); + spyOnDependency(issuableApp, 'visitUrl'); spyOn(vm.poll, 'stop').and.callThrough(); spyOn(vm.service, 'deleteIssuable').and.callFake(() => new Promise((resolve) => { resolve({ @@ -377,7 +367,6 @@ describe('Issuable output', () => { expect( vm.poll.stop, ).toHaveBeenCalledWith(); - done(); }); }); diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js index d96151a8a3a..889c8545faa 100644 --- a/spec/javascripts/issue_show/components/description_spec.js +++ b/spec/javascripts/issue_show/components/description_spec.js @@ -1,7 +1,6 @@ import $ from 'jquery'; import Vue from 'vue'; -import descriptionComponent from '~/issue_show/components/description.vue'; -import * as taskList from '~/task_list'; +import Description from '~/issue_show/components/description.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('Description component', () => { @@ -17,7 +16,7 @@ describe('Description component', () => { }; beforeEach(() => { - DescriptionComponent = Vue.extend(descriptionComponent); + DescriptionComponent = Vue.extend(Description); if (!document.querySelector('.issuable-meta')) { const metaData = document.createElement('div'); @@ -82,18 +81,20 @@ describe('Description component', () => { }); describe('TaskList', () => { + let TaskList; + beforeEach(() => { vm = mountComponent(DescriptionComponent, Object.assign({}, props, { issuableType: 'issuableType', })); - spyOn(taskList, 'default'); + TaskList = spyOnDependency(Description, 'TaskList'); }); it('re-inits the TaskList when description changed', (done) => { vm.descriptionHtml = 'changed'; setTimeout(() => { - expect(taskList.default).toHaveBeenCalled(); + expect(TaskList).toHaveBeenCalled(); done(); }); }); @@ -103,7 +104,7 @@ describe('Description component', () => { vm.descriptionHtml = 'changed'; setTimeout(() => { - expect(taskList.default).not.toHaveBeenCalled(); + expect(TaskList).not.toHaveBeenCalled(); done(); }); }); @@ -112,7 +113,7 @@ describe('Description component', () => { vm.descriptionHtml = 'changed'; setTimeout(() => { - expect(taskList.default).toHaveBeenCalledWith({ + expect(TaskList).toHaveBeenCalledWith({ dataType: 'issuableType', fieldName: 'description', selector: '.detail-page-description', diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index f37426a72d4..047ecab27db 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -92,6 +92,7 @@ describe('Issue', function() { function mockCanCreateBranch(canCreateBranch) { mock.onGet(/(.*)\/can_create_branch$/).reply(200, { can_create_branch: canCreateBranch, + suggested_branch_name: 'foo-99', }); } diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index c6bbacf237a..da00b615c9b 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -2,7 +2,6 @@ import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; import '~/lib/utils/datetime_utility'; import Job from '~/job'; import '~/breakpoints'; @@ -22,7 +21,7 @@ describe('Job', () => { beforeEach(() => { loadFixtures('builds/build-with-artifacts.html.raw'); - spyOn(urlUtils, 'visitUrl'); + spyOnDependency(Job, 'visitUrl'); response = {}; diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js index 0961605ce5c..4f861c39d3f 100644 --- a/spec/javascripts/jobs/header_spec.js +++ b/spec/javascripts/jobs/header_spec.js @@ -36,14 +36,28 @@ describe('Job details header', () => { }, isLoading: false, }; - - vm = mountComponent(HeaderComponent, props); }); afterEach(() => { vm.$destroy(); }); + describe('job reason', () => { + it('should not render the reason when reason is absent', () => { + vm = mountComponent(HeaderComponent, props); + + expect(vm.shouldRenderReason).toBe(false); + }); + + it('should render the reason when reason is present', () => { + props.job.callout_message = 'There is an unknown failure, please try again'; + + vm = mountComponent(HeaderComponent, props); + + expect(vm.shouldRenderReason).toBe(true); + }); + }); + describe('triggered job', () => { beforeEach(() => { vm = mountComponent(HeaderComponent, props); @@ -51,14 +65,17 @@ describe('Job details header', () => { it('should render provided job information', () => { expect( - vm.$el.querySelector('.header-main-content').textContent.replace(/\s+/g, ' ').trim(), + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), ).toEqual('failed Job #123 triggered 3 weeks ago by Foo'); }); it('should render new issue link', () => { - expect( - vm.$el.querySelector('.js-new-issue').getAttribute('href'), - ).toEqual(props.job.new_issue_path); + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + props.job.new_issue_path, + ); }); }); @@ -68,7 +85,10 @@ describe('Job details header', () => { vm = mountComponent(HeaderComponent, props); expect( - vm.$el.querySelector('.header-main-content').textContent.replace(/\s+/g, ' ').trim(), + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), ).toEqual('failed Job #123 created 3 weeks ago by Foo'); }); }); diff --git a/spec/javascripts/jobs/sidebar_details_block_spec.js b/spec/javascripts/jobs/sidebar_details_block_spec.js index 602dae514b1..9c4454252ce 100644 --- a/spec/javascripts/jobs/sidebar_details_block_spec.js +++ b/spec/javascripts/jobs/sidebar_details_block_spec.js @@ -31,10 +31,25 @@ describe('Sidebar details block', () => { }); }); + describe("when user can't retry", () => { + it('should not render a retry button', () => { + vm = new SidebarComponent({ + propsData: { + job: {}, + canUserRetry: false, + isLoading: true, + }, + }).$mount(); + + expect(vm.$el.querySelector('.js-retry-job')).toBeNull(); + }); + }); + beforeEach(() => { vm = new SidebarComponent({ propsData: { job, + canUserRetry: true, isLoading: false, }, }).$mount(); @@ -42,7 +57,9 @@ describe('Sidebar details block', () => { describe('actions', () => { it('should render link to new issue', () => { - expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual(job.new_issue_path); + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + job.new_issue_path, + ); expect(vm.$el.querySelector('.js-new-issue').textContent.trim()).toEqual('New issue'); }); @@ -57,43 +74,35 @@ describe('Sidebar details block', () => { describe('information', () => { it('should render merge request link', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-mr')), - ).toEqual('Merge Request: !2'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-mr'))).toEqual('Merge Request: !2'); - expect( - vm.$el.querySelector('.js-job-mr a').getAttribute('href'), - ).toEqual(job.merge_request.path); + expect(vm.$el.querySelector('.js-job-mr a').getAttribute('href')).toEqual( + job.merge_request.path, + ); }); it('should render job duration', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-duration')), - ).toEqual('Duration: 6 seconds'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-duration'))).toEqual( + 'Duration: 6 seconds', + ); }); it('should render erased date', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-erased')), - ).toEqual('Erased: 3 weeks ago'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-erased'))).toEqual('Erased: 3 weeks ago'); }); it('should render finished date', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-finished')), - ).toEqual('Finished: 3 weeks ago'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-finished'))).toEqual( + 'Finished: 3 weeks ago', + ); }); it('should render queued date', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-queued')), - ).toEqual('Queued: 9 seconds'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-queued'))).toEqual('Queued: 9 seconds'); }); it('should render runner ID', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-runner')), - ).toEqual('Runner: #1'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-runner'))).toEqual('Runner: local ci runner (#1)'); }); it('should render timeout information', () => { @@ -103,15 +112,11 @@ describe('Sidebar details block', () => { }); it('should render coverage', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-coverage')), - ).toEqual('Coverage: 20%'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-coverage'))).toEqual('Coverage: 20%'); }); it('should render tags', () => { - expect( - trimWhitespace(vm.$el.querySelector('.js-job-tags')), - ).toEqual('Tags: tag'); + expect(trimWhitespace(vm.$el.querySelector('.js-job-tags'))).toEqual('Tags: tag'); }); }); }); diff --git a/spec/javascripts/lib/utils/csrf_token_spec.js b/spec/javascripts/lib/utils/csrf_token_spec.js index c484213df8e..81a39a97a84 100644 --- a/spec/javascripts/lib/utils/csrf_token_spec.js +++ b/spec/javascripts/lib/utils/csrf_token_spec.js @@ -1,6 +1,6 @@ import csrf from '~/lib/utils/csrf'; -describe('csrf', () => { +describe('csrf', function () { beforeEach(() => { this.tokenKey = 'X-CSRF-Token'; this.token = 'pH1cvjnP9grx2oKlhWEDvUZnJ8x2eXsIs1qzyHkF3DugSG5yTxR76CWeEZRhML2D1IeVB7NEW0t5l/axE4iJpQ=='; diff --git a/spec/javascripts/lib/utils/image_utility_spec.js b/spec/javascripts/lib/utils/image_utility_spec.js index 75addfcc833..a7eff419fba 100644 --- a/spec/javascripts/lib/utils/image_utility_spec.js +++ b/spec/javascripts/lib/utils/image_utility_spec.js @@ -1,4 +1,4 @@ -import * as imageUtility from '~/lib/utils/image_utility'; +import { isImageLoaded } from '~/lib/utils/image_utility'; describe('imageUtility', () => { describe('isImageLoaded', () => { @@ -8,7 +8,7 @@ describe('imageUtility', () => { naturalHeight: 100, }; - expect(imageUtility.isImageLoaded(element)).toEqual(false); + expect(isImageLoaded(element)).toEqual(false); }); it('should return false when naturalHeight = 0', () => { @@ -17,7 +17,7 @@ describe('imageUtility', () => { naturalHeight: 0, }; - expect(imageUtility.isImageLoaded(element)).toEqual(false); + expect(isImageLoaded(element)).toEqual(false); }); it('should return true when image.complete and naturalHeight != 0', () => { @@ -26,7 +26,7 @@ describe('imageUtility', () => { naturalHeight: 100, }; - expect(imageUtility.isImageLoaded(element)).toEqual(true); + expect(isImageLoaded(element)).toEqual(true); }); }); }); diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index e57a55fa71a..eab5c24406a 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -65,11 +65,23 @@ describe('text_utility', () => { describe('stripHtml', () => { it('replaces html tag with the default replacement', () => { - expect(textUtils.stripHtml('This is a text with <p>html</p>.')).toEqual('This is a text with html.'); + expect(textUtils.stripHtml('This is a text with <p>html</p>.')).toEqual( + 'This is a text with html.', + ); }); it('replaces html tags with the provided replacement', () => { - expect(textUtils.stripHtml('This is a text with <p>html</p>.', ' ')).toEqual('This is a text with html .'); + expect(textUtils.stripHtml('This is a text with <p>html</p>.', ' ')).toEqual( + 'This is a text with html .', + ); + }); + + it('passes through with null string input', () => { + expect(textUtils.stripHtml(null, ' ')).toEqual(null); + }); + + it('passes through with undefined string input', () => { + expect(textUtils.stripHtml(undefined, ' ')).toEqual(undefined); }); }); @@ -78,4 +90,10 @@ describe('text_utility', () => { expect(textUtils.convertToCamelCase('snake_case')).toBe('snakeCase'); }); }); + + describe('convertToSentenceCase', () => { + it('converts Sentence Case to Sentence case', () => { + expect(textUtils.convertToSentenceCase('Hello World')).toBe('Hello world'); + }); + }); }); diff --git a/spec/javascripts/matchers.js b/spec/javascripts/matchers.js new file mode 100644 index 00000000000..7cc5e753c22 --- /dev/null +++ b/spec/javascripts/matchers.js @@ -0,0 +1,35 @@ +export default { + toHaveSpriteIcon: () => ({ + compare(element, iconName) { + if (!iconName) { + throw new Error('toHaveSpriteIcon is missing iconName argument!'); + } + + if (!(element instanceof HTMLElement)) { + throw new Error(`${element} is not a DOM element!`); + } + + const iconReferences = [].slice.apply(element.querySelectorAll('svg use')); + const matchingIcon = iconReferences.find(reference => reference.getAttribute('xlink:href').endsWith(`#${iconName}`)); + const result = { + pass: !!matchingIcon, + }; + + if (result.pass) { + result.message = `${element.outerHTML} contains the sprite icon "${iconName}"!`; + } else { + result.message = `${element.outerHTML} does not contain the sprite icon "${iconName}"!`; + + const existingIcons = iconReferences.map((reference) => { + const iconUrl = reference.getAttribute('xlink:href'); + return `"${iconUrl.replace(/^.+#/, '')}"`; + }); + if (existingIcons.length > 0) { + result.message += ` (only found ${existingIcons.join(',')})`; + } + } + + return result; + }, + }), +}; diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 79c8cf0ba32..3dbd9756cd2 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -3,7 +3,6 @@ import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; import MergeRequestTabs from '~/merge_request_tabs'; import '~/commit/pipelines/pipelines_bundle'; import '~/breakpoints'; @@ -356,7 +355,7 @@ import 'vendor/jquery.scrollTo'; describe('with note fragment hash', () => { it('should expand and scroll to linked fragment hash #note_xxx', function (done) { - spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue(noteId); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); setTimeout(() => { @@ -372,7 +371,7 @@ import 'vendor/jquery.scrollTo'; }); it('should gracefully ignore non-existant fragment hash', function (done) { - spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); setTimeout(() => { @@ -385,7 +384,7 @@ import 'vendor/jquery.scrollTo'; describe('with line number fragment hash', () => { it('should gracefully ignore line number fragment hash', function () { - spyOn(urlUtils, 'getLocationHash').and.returnValue(noteLineNumId); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue(noteLineNumId); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); expect(noteLineNumId.length).toBeGreaterThan(0); @@ -422,7 +421,7 @@ import 'vendor/jquery.scrollTo'; describe('with note fragment hash', () => { it('should expand and scroll to linked fragment hash #note_xxx', function (done) { - spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue(noteId); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); @@ -439,7 +438,7 @@ import 'vendor/jquery.scrollTo'; }); it('should gracefully ignore non-existant fragment hash', function (done) { - spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); setTimeout(() => { @@ -451,7 +450,7 @@ import 'vendor/jquery.scrollTo'; describe('with line number fragment hash', () => { it('should gracefully ignore line number fragment hash', function () { - spyOn(urlUtils, 'getLocationHash').and.returnValue(noteLineNumId); + spyOnDependency(MergeRequestTabs, 'getLocationHash').and.returnValue(noteLineNumId); this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); expect(noteLineNumId.length).toBeGreaterThan(0); diff --git a/spec/javascripts/monitoring/graph/axis_spec.js b/spec/javascripts/monitoring/graph/axis_spec.js new file mode 100644 index 00000000000..c7adba00637 --- /dev/null +++ b/spec/javascripts/monitoring/graph/axis_spec.js @@ -0,0 +1,65 @@ +import Vue from 'vue'; +import GraphAxis from '~/monitoring/components/graph/axis.vue'; +import measurements from '~/monitoring/utils/measurements'; + +const createComponent = propsData => { + const Component = Vue.extend(GraphAxis); + + return new Component({ + propsData, + }).$mount(); +}; + +const defaultValuesComponent = { + graphWidth: 500, + graphHeight: 300, + graphHeightOffset: 120, + margin: measurements.large.margin, + measurements: measurements.large, + yAxisLabel: 'Values', + unitOfDisplay: 'MB', +}; + +function getTextFromNode(component, selector) { + return component.$el.querySelector(selector).firstChild.nodeValue.trim(); +} + +describe('Axis', () => { + describe('Computed props', () => { + it('textTransform', () => { + const component = createComponent(defaultValuesComponent); + + expect(component.textTransform).toContain('translate(15, 120) rotate(-90)'); + }); + + it('xPosition', () => { + const component = createComponent(defaultValuesComponent); + + expect(component.xPosition).toEqual(180); + }); + + it('yPosition', () => { + const component = createComponent(defaultValuesComponent); + + expect(component.yPosition).toEqual(240); + }); + + it('rectTransform', () => { + const component = createComponent(defaultValuesComponent); + + expect(component.rectTransform).toContain('translate(0, 120) rotate(-90)'); + }); + }); + + it('has 2 rect-axis-text rect svg elements', () => { + const component = createComponent(defaultValuesComponent); + + expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2); + }); + + it('contains text to signal the usage, title and time with multiple time series', () => { + const component = createComponent(defaultValuesComponent); + + expect(getTextFromNode(component, '.y-label-text')).toEqual('Values (MB)'); + }); +}); diff --git a/spec/javascripts/monitoring/graph/legend_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index 145c8db28d5..abcc51aa077 100644 --- a/spec/javascripts/monitoring/graph/legend_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -1,106 +1,44 @@ import Vue from 'vue'; import GraphLegend from '~/monitoring/components/graph/legend.vue'; -import measurements from '~/monitoring/utils/measurements'; import createTimeSeries from '~/monitoring/utils/multiple_time_series'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from '../mock_data'; -const createComponent = (propsData) => { - const Component = Vue.extend(GraphLegend); - - return new Component({ - propsData, - }).$mount(); -}; - const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); -const defaultValuesComponent = { - graphWidth: 500, - graphHeight: 300, - graphHeightOffset: 120, - margin: measurements.large.margin, - measurements: measurements.large, - areaColorRgb: '#f0f0f0', - legendTitle: 'Title', - yAxisLabel: 'Values', - metricUsage: 'Value', - unitOfDisplay: 'Req/Sec', - currentDataIndex: 0, -}; +const defaultValuesComponent = {}; -const timeSeries = createTimeSeries(convertedMetrics[0].queries, - defaultValuesComponent.graphWidth, defaultValuesComponent.graphHeight, - defaultValuesComponent.graphHeightOffset); +const timeSeries = createTimeSeries(convertedMetrics[0].queries, 500, 300, 120); defaultValuesComponent.timeSeries = timeSeries; -function getTextFromNode(component, selector) { - return component.$el.querySelector(selector).firstChild.nodeValue.trim(); -} - -describe('GraphLegend', () => { - describe('Computed props', () => { - it('textTransform', () => { - const component = createComponent(defaultValuesComponent); - - expect(component.textTransform).toContain('translate(15, 120) rotate(-90)'); - }); - - it('xPosition', () => { - const component = createComponent(defaultValuesComponent); - - expect(component.xPosition).toEqual(180); - }); - - it('yPosition', () => { - const component = createComponent(defaultValuesComponent); - - expect(component.yPosition).toEqual(240); - }); - - it('rectTransform', () => { - const component = createComponent(defaultValuesComponent); +describe('Legend Component', () => { + let vm; + let Legend; - expect(component.rectTransform).toContain('translate(0, 120) rotate(-90)'); - }); + beforeEach(() => { + Legend = Vue.extend(GraphLegend); }); - describe('methods', () => { - it('translateLegendGroup should only change Y direction', () => { - const component = createComponent(defaultValuesComponent); - - const translatedCoordinate = component.translateLegendGroup(1); - expect(translatedCoordinate.indexOf('translate(0, ')).not.toEqual(-1); + describe('View', () => { + beforeEach(() => { + vm = mountComponent(Legend, { + legendTitle: 'legend', + timeSeries, + currentDataIndex: 0, + unitOfDisplay: 'Req/Sec', + }); }); - it('formatMetricUsage should contain the unit of display and the current value selected via "currentDataIndex"', () => { - const component = createComponent(defaultValuesComponent); + it('should render the usage, title and time with multiple time series', () => { + const titles = vm.$el.querySelectorAll('.legend-metric-title'); - const formattedMetricUsage = component.formatMetricUsage(timeSeries[0]); - const valueFromSeries = timeSeries[0].values[component.currentDataIndex].value; - expect(formattedMetricUsage.indexOf(component.unitOfDisplay)).not.toEqual(-1); - expect(formattedMetricUsage.indexOf(valueFromSeries)).not.toEqual(-1); + expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1); + expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1); }); - }); - - it('has 2 rect-axis-text rect svg elements', () => { - const component = createComponent(defaultValuesComponent); - - expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2); - }); - it('contains text to signal the usage, title and time with multiple time series', () => { - const component = createComponent(defaultValuesComponent); - const titles = component.$el.querySelectorAll('.legend-metric-title'); - - expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1); - expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1); - expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel); - }); - - it('should contain the same number of legend groups as the timeSeries length', () => { - const component = createComponent(defaultValuesComponent); - - expect(component.$el.querySelectorAll('.legend-group').length).toEqual(component.timeSeries.length); + it('should container the same number of rows in the table as time series', () => { + expect(vm.$el.querySelectorAll('.prometheus-table tr').length).toEqual(vm.timeSeries.length); + }); }); }); diff --git a/spec/javascripts/monitoring/graph/track_info_spec.js b/spec/javascripts/monitoring/graph/track_info_spec.js new file mode 100644 index 00000000000..d3121d553f9 --- /dev/null +++ b/spec/javascripts/monitoring/graph/track_info_spec.js @@ -0,0 +1,44 @@ +import Vue from 'vue'; +import TrackInfo from '~/monitoring/components/graph/track_info.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import createTimeSeries from '~/monitoring/utils/multiple_time_series'; +import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from '../mock_data'; + +const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); +const timeSeries = createTimeSeries(convertedMetrics[0].queries, 500, 300, 120); + +describe('TrackInfo component', () => { + let vm; + let Component; + + beforeEach(() => { + Component = Vue.extend(TrackInfo); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('Computed props', () => { + beforeEach(() => { + vm = mountComponent(Component, { track: timeSeries[0] }); + }); + + it('summaryMetrics', () => { + expect(vm.summaryMetrics).toEqual('Avg: 0.000 · Max: 0.000'); + }); + }); + + describe('Rendered output', () => { + beforeEach(() => { + vm = mountComponent(Component, { track: timeSeries[0] }); + }); + + it('contains metric tag and the summary metrics', () => { + const metricTag = vm.$el.querySelector('strong'); + + expect(metricTag.textContent.trim()).toEqual(vm.track.metricTag); + expect(vm.$el.textContent).toContain('Avg: 0.000 · Max: 0.000'); + }); + }); +}); diff --git a/spec/javascripts/monitoring/graph/track_line_spec.js b/spec/javascripts/monitoring/graph/track_line_spec.js new file mode 100644 index 00000000000..45106830a67 --- /dev/null +++ b/spec/javascripts/monitoring/graph/track_line_spec.js @@ -0,0 +1,52 @@ +import Vue from 'vue'; +import TrackLine from '~/monitoring/components/graph/track_line.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import createTimeSeries from '~/monitoring/utils/multiple_time_series'; +import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from '../mock_data'; + +const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); +const timeSeries = createTimeSeries(convertedMetrics[0].queries, 500, 300, 120); + +describe('TrackLine component', () => { + let vm; + let Component; + + beforeEach(() => { + Component = Vue.extend(TrackLine); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('Computed props', () => { + it('stylizedLine for dashed lineStyles', () => { + vm = mountComponent(Component, { track: { ...timeSeries[0], lineStyle: 'dashed' } }); + + expect(vm.stylizedLine).toEqual('6, 3'); + }); + + it('stylizedLine for dotted lineStyles', () => { + vm = mountComponent(Component, { track: { ...timeSeries[0], lineStyle: 'dotted' } }); + + expect(vm.stylizedLine).toEqual('3, 3'); + }); + }); + + describe('Rendered output', () => { + it('has an svg with a line', () => { + vm = mountComponent(Component, { track: { ...timeSeries[0] } }); + const svgEl = vm.$el.querySelector('svg'); + const lineEl = vm.$el.querySelector('svg line'); + + expect(svgEl.getAttribute('width')).toEqual('15'); + expect(svgEl.getAttribute('height')).toEqual('6'); + + expect(lineEl.getAttribute('stroke-width')).toEqual('4'); + expect(lineEl.getAttribute('x1')).toEqual('0'); + expect(lineEl.getAttribute('x2')).toEqual('15'); + expect(lineEl.getAttribute('y1')).toEqual('2'); + expect(lineEl.getAttribute('y2')).toEqual('2'); + }); + }); +}); diff --git a/spec/javascripts/monitoring/graph_spec.js b/spec/javascripts/monitoring/graph_spec.js index b1d69752bad..1213c80ba3a 100644 --- a/spec/javascripts/monitoring/graph_spec.js +++ b/spec/javascripts/monitoring/graph_spec.js @@ -2,11 +2,15 @@ import Vue from 'vue'; import Graph from '~/monitoring/components/graph.vue'; import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins'; import eventHub from '~/monitoring/event_hub'; -import { deploymentData, convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from './mock_data'; +import { + deploymentData, + convertDatesMultipleSeries, + singleRowMetricsMultipleSeries, +} from './mock_data'; const tagsPath = 'http://test.host/frontend-fixtures/environments-project/tags'; const projectPath = 'http://test.host/frontend-fixtures/environments-project'; -const createComponent = (propsData) => { +const createComponent = propsData => { const Component = Vue.extend(Graph); return new Component({ @@ -14,7 +18,9 @@ const createComponent = (propsData) => { }).$mount(); }; -const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); +const convertedMetrics = convertDatesMultipleSeries( + singleRowMetricsMultipleSeries, +); describe('Graph', () => { beforeEach(() => { @@ -31,7 +37,9 @@ describe('Graph', () => { projectPath, }); - expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.graphData.title); + expect(component.$el.querySelector('.text-center').innerText.trim()).toBe( + component.graphData.title, + ); }); describe('Computed props', () => { @@ -46,8 +54,9 @@ describe('Graph', () => { }); const transformedHeight = `${component.graphHeight - 100}`; - expect(component.axisTransform.indexOf(transformedHeight)) - .not.toEqual(-1); + expect(component.axisTransform.indexOf(transformedHeight)).not.toEqual( + -1, + ); }); it('outerViewBox gets a width and height property based on the DOM size of the element', () => { @@ -63,11 +72,11 @@ describe('Graph', () => { const viewBoxArray = component.outerViewBox.split(' '); expect(typeof component.outerViewBox).toEqual('string'); expect(viewBoxArray[2]).toEqual(component.graphWidth.toString()); - expect(viewBoxArray[3]).toEqual(component.graphHeight.toString()); + expect(viewBoxArray[3]).toEqual((component.graphHeight - 50).toString()); }); }); - it('sends an event to the eventhub when it has finished resizing', (done) => { + it('sends an event to the eventhub when it has finished resizing', done => { const component = createComponent({ graphData: convertedMetrics[1], classType: 'col-md-6', diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index f30208b27b6..50da6da2e07 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -3,2426 +3,645 @@ export const mockApiEndpoint = `${gl.TEST_HOST}/monitoring/mock`; export const metricsGroupsAPIResponse = { - 'success': true, - 'data': [ + success: true, + data: [ { - 'group': 'Kubernetes', - 'priority': 1, - 'metrics': [ - { - 'title': 'Memory usage', - 'weight': 1, - 'queries': [ + group: 'Kubernetes', + priority: 1, + metrics: [ + { + title: 'Memory usage', + weight: 1, + queries: [ + { + query_range: 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20', + y_label: 'Memory', + unit: 'MiB', + result: [ { - 'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20', - 'y_label': 'Memory', - 'unit': 'MiB', - 'result': [ - { - 'metric': {}, - 'values': [ - [ - 1495700554.925, - '8.0390625' - ], - [ - 1495700614.925, - '8.0390625' - ], - [ - 1495700674.925, - '8.0390625' - ], - [ - 1495700734.925, - '8.0390625' - ], - [ - 1495700794.925, - '8.0390625' - ], - [ - 1495700854.925, - '8.0390625' - ], - [ - 1495700914.925, - '8.0390625' - ], - [ - 1495700974.925, - '8.0390625' - ], - [ - 1495701034.925, - '8.0390625' - ], - [ - 1495701094.925, - '8.0390625' - ], - [ - 1495701154.925, - '8.0390625' - ], - [ - 1495701214.925, - '8.0390625' - ], - [ - 1495701274.925, - '8.0390625' - ], - [ - 1495701334.925, - '8.0390625' - ], - [ - 1495701394.925, - '8.0390625' - ], - [ - 1495701454.925, - '8.0390625' - ], - [ - 1495701514.925, - '8.0390625' - ], - [ - 1495701574.925, - '8.0390625' - ], - [ - 1495701634.925, - '8.0390625' - ], - [ - 1495701694.925, - '8.0390625' - ], - [ - 1495701754.925, - '8.0390625' - ], - [ - 1495701814.925, - '8.0390625' - ], - [ - 1495701874.925, - '8.0390625' - ], - [ - 1495701934.925, - '8.0390625' - ], - [ - 1495701994.925, - '8.0390625' - ], - [ - 1495702054.925, - '8.0390625' - ], - [ - 1495702114.925, - '8.0390625' - ], - [ - 1495702174.925, - '8.0390625' - ], - [ - 1495702234.925, - '8.0390625' - ], - [ - 1495702294.925, - '8.0390625' - ], - [ - 1495702354.925, - '8.0390625' - ], - [ - 1495702414.925, - '8.0390625' - ], - [ - 1495702474.925, - '8.0390625' - ], - [ - 1495702534.925, - '8.0390625' - ], - [ - 1495702594.925, - '8.0390625' - ], - [ - 1495702654.925, - '8.0390625' - ], - [ - 1495702714.925, - '8.0390625' - ], - [ - 1495702774.925, - '8.0390625' - ], - [ - 1495702834.925, - '8.0390625' - ], - [ - 1495702894.925, - '8.0390625' - ], - [ - 1495702954.925, - '8.0390625' - ], - [ - 1495703014.925, - '8.0390625' - ], - [ - 1495703074.925, - '8.0390625' - ], - [ - 1495703134.925, - '8.0390625' - ], - [ - 1495703194.925, - '8.0390625' - ], - [ - 1495703254.925, - '8.03515625' - ], - [ - 1495703314.925, - '8.03515625' - ], - [ - 1495703374.925, - '8.03515625' - ], - [ - 1495703434.925, - '8.03515625' - ], - [ - 1495703494.925, - '8.03515625' - ], - [ - 1495703554.925, - '8.03515625' - ], - [ - 1495703614.925, - '8.03515625' - ], - [ - 1495703674.925, - '8.03515625' - ], - [ - 1495703734.925, - '8.03515625' - ], - [ - 1495703794.925, - '8.03515625' - ], - [ - 1495703854.925, - '8.03515625' - ], - [ - 1495703914.925, - '8.03515625' - ], - [ - 1495703974.925, - '8.03515625' - ], - [ - 1495704034.925, - '8.03515625' - ], - [ - 1495704094.925, - '8.03515625' - ], - [ - 1495704154.925, - '8.03515625' - ], - [ - 1495704214.925, - '7.9296875' - ], - [ - 1495704274.925, - '7.9296875' - ], - [ - 1495704334.925, - '7.9296875' - ], - [ - 1495704394.925, - '7.9296875' - ], - [ - 1495704454.925, - '7.9296875' - ], - [ - 1495704514.925, - '7.9296875' - ], - [ - 1495704574.925, - '7.9296875' - ], - [ - 1495704634.925, - '7.9296875' - ], - [ - 1495704694.925, - '7.9296875' - ], - [ - 1495704754.925, - '7.9296875' - ], - [ - 1495704814.925, - '7.9296875' - ], - [ - 1495704874.925, - '7.9296875' - ], - [ - 1495704934.925, - '7.9296875' - ], - [ - 1495704994.925, - '7.9296875' - ], - [ - 1495705054.925, - '7.9296875' - ], - [ - 1495705114.925, - '7.9296875' - ], - [ - 1495705174.925, - '7.9296875' - ], - [ - 1495705234.925, - '7.9296875' - ], - [ - 1495705294.925, - '7.9296875' - ], - [ - 1495705354.925, - '7.9296875' - ], - [ - 1495705414.925, - '7.9296875' - ], - [ - 1495705474.925, - '7.9296875' - ], - [ - 1495705534.925, - '7.9296875' - ], - [ - 1495705594.925, - '7.9296875' - ], - [ - 1495705654.925, - '7.9296875' - ], - [ - 1495705714.925, - '7.9296875' - ], - [ - 1495705774.925, - '7.9296875' - ], - [ - 1495705834.925, - '7.9296875' - ], - [ - 1495705894.925, - '7.9296875' - ], - [ - 1495705954.925, - '7.9296875' - ], - [ - 1495706014.925, - '7.9296875' - ], - [ - 1495706074.925, - '7.9296875' - ], - [ - 1495706134.925, - '7.9296875' - ], - [ - 1495706194.925, - '7.9296875' - ], - [ - 1495706254.925, - '7.9296875' - ], - [ - 1495706314.925, - '7.9296875' - ], - [ - 1495706374.925, - '7.9296875' - ], - [ - 1495706434.925, - '7.9296875' - ], - [ - 1495706494.925, - '7.9296875' - ], - [ - 1495706554.925, - '7.9296875' - ], - [ - 1495706614.925, - '7.9296875' - ], - [ - 1495706674.925, - '7.9296875' - ], - [ - 1495706734.925, - '7.9296875' - ], - [ - 1495706794.925, - '7.9296875' - ], - [ - 1495706854.925, - '7.9296875' - ], - [ - 1495706914.925, - '7.9296875' - ], - [ - 1495706974.925, - '7.9296875' - ], - [ - 1495707034.925, - '7.9296875' - ], - [ - 1495707094.925, - '7.9296875' - ], - [ - 1495707154.925, - '7.9296875' - ], - [ - 1495707214.925, - '7.9296875' - ], - [ - 1495707274.925, - '7.9296875' - ], - [ - 1495707334.925, - '7.9296875' - ], - [ - 1495707394.925, - '7.9296875' - ], - [ - 1495707454.925, - '7.9296875' - ], - [ - 1495707514.925, - '7.9296875' - ], - [ - 1495707574.925, - '7.9296875' - ], - [ - 1495707634.925, - '7.9296875' - ], - [ - 1495707694.925, - '7.9296875' - ], - [ - 1495707754.925, - '7.9296875' - ], - [ - 1495707814.925, - '7.9296875' - ], - [ - 1495707874.925, - '7.9296875' - ], - [ - 1495707934.925, - '7.9296875' - ], - [ - 1495707994.925, - '7.9296875' - ], - [ - 1495708054.925, - '7.9296875' - ], - [ - 1495708114.925, - '7.9296875' - ], - [ - 1495708174.925, - '7.9296875' - ], - [ - 1495708234.925, - '7.9296875' - ], - [ - 1495708294.925, - '7.9296875' - ], - [ - 1495708354.925, - '7.9296875' - ], - [ - 1495708414.925, - '7.9296875' - ], - [ - 1495708474.925, - '7.9296875' - ], - [ - 1495708534.925, - '7.9296875' - ], - [ - 1495708594.925, - '7.9296875' - ], - [ - 1495708654.925, - '7.9296875' - ], - [ - 1495708714.925, - '7.9296875' - ], - [ - 1495708774.925, - '7.9296875' - ], - [ - 1495708834.925, - '7.9296875' - ], - [ - 1495708894.925, - '7.9296875' - ], - [ - 1495708954.925, - '7.8984375' - ], - [ - 1495709014.925, - '7.8984375' - ], - [ - 1495709074.925, - '7.8984375' - ], - [ - 1495709134.925, - '7.8984375' - ], - [ - 1495709194.925, - '7.8984375' - ], - [ - 1495709254.925, - '7.89453125' - ], - [ - 1495709314.925, - '7.89453125' - ], - [ - 1495709374.925, - '7.89453125' - ], - [ - 1495709434.925, - '7.89453125' - ], - [ - 1495709494.925, - '7.89453125' - ], - [ - 1495709554.925, - '7.89453125' - ], - [ - 1495709614.925, - '7.89453125' - ], - [ - 1495709674.925, - '7.89453125' - ], - [ - 1495709734.925, - '7.89453125' - ], - [ - 1495709794.925, - '7.89453125' - ], - [ - 1495709854.925, - '7.89453125' - ], - [ - 1495709914.925, - '7.89453125' - ], - [ - 1495709974.925, - '7.89453125' - ], - [ - 1495710034.925, - '7.89453125' - ], - [ - 1495710094.925, - '7.89453125' - ], - [ - 1495710154.925, - '7.89453125' - ], - [ - 1495710214.925, - '7.89453125' - ], - [ - 1495710274.925, - '7.89453125' - ], - [ - 1495710334.925, - '7.89453125' - ], - [ - 1495710394.925, - '7.89453125' - ], - [ - 1495710454.925, - '7.89453125' - ], - [ - 1495710514.925, - '7.89453125' - ], - [ - 1495710574.925, - '7.89453125' - ], - [ - 1495710634.925, - '7.89453125' - ], - [ - 1495710694.925, - '7.89453125' - ], - [ - 1495710754.925, - '7.89453125' - ], - [ - 1495710814.925, - '7.89453125' - ], - [ - 1495710874.925, - '7.89453125' - ], - [ - 1495710934.925, - '7.89453125' - ], - [ - 1495710994.925, - '7.89453125' - ], - [ - 1495711054.925, - '7.89453125' - ], - [ - 1495711114.925, - '7.89453125' - ], - [ - 1495711174.925, - '7.8515625' - ], - [ - 1495711234.925, - '7.8515625' - ], - [ - 1495711294.925, - '7.8515625' - ], - [ - 1495711354.925, - '7.8515625' - ], - [ - 1495711414.925, - '7.8515625' - ], - [ - 1495711474.925, - '7.8515625' - ], - [ - 1495711534.925, - '7.8515625' - ], - [ - 1495711594.925, - '7.8515625' - ], - [ - 1495711654.925, - '7.8515625' - ], - [ - 1495711714.925, - '7.8515625' - ], - [ - 1495711774.925, - '7.8515625' - ], - [ - 1495711834.925, - '7.8515625' - ], - [ - 1495711894.925, - '7.8515625' - ], - [ - 1495711954.925, - '7.8515625' - ], - [ - 1495712014.925, - '7.8515625' - ], - [ - 1495712074.925, - '7.8515625' - ], - [ - 1495712134.925, - '7.8515625' - ], - [ - 1495712194.925, - '7.8515625' - ], - [ - 1495712254.925, - '7.8515625' - ], - [ - 1495712314.925, - '7.8515625' - ], - [ - 1495712374.925, - '7.8515625' - ], - [ - 1495712434.925, - '7.83203125' - ], - [ - 1495712494.925, - '7.83203125' - ], - [ - 1495712554.925, - '7.83203125' - ], - [ - 1495712614.925, - '7.83203125' - ], - [ - 1495712674.925, - '7.83203125' - ], - [ - 1495712734.925, - '7.83203125' - ], - [ - 1495712794.925, - '7.83203125' - ], - [ - 1495712854.925, - '7.83203125' - ], - [ - 1495712914.925, - '7.83203125' - ], - [ - 1495712974.925, - '7.83203125' - ], - [ - 1495713034.925, - '7.83203125' - ], - [ - 1495713094.925, - '7.83203125' - ], - [ - 1495713154.925, - '7.83203125' - ], - [ - 1495713214.925, - '7.83203125' - ], - [ - 1495713274.925, - '7.83203125' - ], - [ - 1495713334.925, - '7.83203125' - ], - [ - 1495713394.925, - '7.8125' - ], - [ - 1495713454.925, - '7.8125' - ], - [ - 1495713514.925, - '7.8125' - ], - [ - 1495713574.925, - '7.8125' - ], - [ - 1495713634.925, - '7.8125' - ], - [ - 1495713694.925, - '7.8125' - ], - [ - 1495713754.925, - '7.8125' - ], - [ - 1495713814.925, - '7.8125' - ], - [ - 1495713874.925, - '7.8125' - ], - [ - 1495713934.925, - '7.8125' - ], - [ - 1495713994.925, - '7.8125' - ], - [ - 1495714054.925, - '7.8125' - ], - [ - 1495714114.925, - '7.8125' - ], - [ - 1495714174.925, - '7.8125' - ], - [ - 1495714234.925, - '7.8125' - ], - [ - 1495714294.925, - '7.8125' - ], - [ - 1495714354.925, - '7.80859375' - ], - [ - 1495714414.925, - '7.80859375' - ], - [ - 1495714474.925, - '7.80859375' - ], - [ - 1495714534.925, - '7.80859375' - ], - [ - 1495714594.925, - '7.80859375' - ], - [ - 1495714654.925, - '7.80859375' - ], - [ - 1495714714.925, - '7.80859375' - ], - [ - 1495714774.925, - '7.80859375' - ], - [ - 1495714834.925, - '7.80859375' - ], - [ - 1495714894.925, - '7.80859375' - ], - [ - 1495714954.925, - '7.80859375' - ], - [ - 1495715014.925, - '7.80859375' - ], - [ - 1495715074.925, - '7.80859375' - ], - [ - 1495715134.925, - '7.80859375' - ], - [ - 1495715194.925, - '7.80859375' - ], - [ - 1495715254.925, - '7.80859375' - ], - [ - 1495715314.925, - '7.80859375' - ], - [ - 1495715374.925, - '7.80859375' - ], - [ - 1495715434.925, - '7.80859375' - ], - [ - 1495715494.925, - '7.80859375' - ], - [ - 1495715554.925, - '7.80859375' - ], - [ - 1495715614.925, - '7.80859375' - ], - [ - 1495715674.925, - '7.80859375' - ], - [ - 1495715734.925, - '7.80859375' - ], - [ - 1495715794.925, - '7.80859375' - ], - [ - 1495715854.925, - '7.80859375' - ], - [ - 1495715914.925, - '7.80078125' - ], - [ - 1495715974.925, - '7.80078125' - ], - [ - 1495716034.925, - '7.80078125' - ], - [ - 1495716094.925, - '7.80078125' - ], - [ - 1495716154.925, - '7.80078125' - ], - [ - 1495716214.925, - '7.796875' - ], - [ - 1495716274.925, - '7.796875' - ], - [ - 1495716334.925, - '7.796875' - ], - [ - 1495716394.925, - '7.796875' - ], - [ - 1495716454.925, - '7.796875' - ], - [ - 1495716514.925, - '7.796875' - ], - [ - 1495716574.925, - '7.796875' - ], - [ - 1495716634.925, - '7.796875' - ], - [ - 1495716694.925, - '7.796875' - ], - [ - 1495716754.925, - '7.796875' - ], - [ - 1495716814.925, - '7.796875' - ], - [ - 1495716874.925, - '7.79296875' - ], - [ - 1495716934.925, - '7.79296875' - ], - [ - 1495716994.925, - '7.79296875' - ], - [ - 1495717054.925, - '7.79296875' - ], - [ - 1495717114.925, - '7.79296875' - ], - [ - 1495717174.925, - '7.7890625' - ], - [ - 1495717234.925, - '7.7890625' - ], - [ - 1495717294.925, - '7.7890625' - ], - [ - 1495717354.925, - '7.7890625' - ], - [ - 1495717414.925, - '7.7890625' - ], - [ - 1495717474.925, - '7.7890625' - ], - [ - 1495717534.925, - '7.7890625' - ], - [ - 1495717594.925, - '7.7890625' - ], - [ - 1495717654.925, - '7.7890625' - ], - [ - 1495717714.925, - '7.7890625' - ], - [ - 1495717774.925, - '7.7890625' - ], - [ - 1495717834.925, - '7.77734375' - ], - [ - 1495717894.925, - '7.77734375' - ], - [ - 1495717954.925, - '7.77734375' - ], - [ - 1495718014.925, - '7.77734375' - ], - [ - 1495718074.925, - '7.77734375' - ], - [ - 1495718134.925, - '7.7421875' - ], - [ - 1495718194.925, - '7.7421875' - ], - [ - 1495718254.925, - '7.7421875' - ], - [ - 1495718314.925, - '7.7421875' - ] - ] - } - ] - } - ] + metric: {}, + values: [ + [1495700554.925, '8.0390625'], + [1495700614.925, '8.0390625'], + [1495700674.925, '8.0390625'], + [1495700734.925, '8.0390625'], + [1495700794.925, '8.0390625'], + [1495700854.925, '8.0390625'], + [1495700914.925, '8.0390625'], + [1495700974.925, '8.0390625'], + [1495701034.925, '8.0390625'], + [1495701094.925, '8.0390625'], + [1495701154.925, '8.0390625'], + [1495701214.925, '8.0390625'], + [1495701274.925, '8.0390625'], + [1495701334.925, '8.0390625'], + [1495701394.925, '8.0390625'], + [1495701454.925, '8.0390625'], + [1495701514.925, '8.0390625'], + [1495701574.925, '8.0390625'], + [1495701634.925, '8.0390625'], + [1495701694.925, '8.0390625'], + [1495701754.925, '8.0390625'], + [1495701814.925, '8.0390625'], + [1495701874.925, '8.0390625'], + [1495701934.925, '8.0390625'], + [1495701994.925, '8.0390625'], + [1495702054.925, '8.0390625'], + [1495702114.925, '8.0390625'], + [1495702174.925, '8.0390625'], + [1495702234.925, '8.0390625'], + [1495702294.925, '8.0390625'], + [1495702354.925, '8.0390625'], + [1495702414.925, '8.0390625'], + [1495702474.925, '8.0390625'], + [1495702534.925, '8.0390625'], + [1495702594.925, '8.0390625'], + [1495702654.925, '8.0390625'], + [1495702714.925, '8.0390625'], + [1495702774.925, '8.0390625'], + [1495702834.925, '8.0390625'], + [1495702894.925, '8.0390625'], + [1495702954.925, '8.0390625'], + [1495703014.925, '8.0390625'], + [1495703074.925, '8.0390625'], + [1495703134.925, '8.0390625'], + [1495703194.925, '8.0390625'], + [1495703254.925, '8.03515625'], + [1495703314.925, '8.03515625'], + [1495703374.925, '8.03515625'], + [1495703434.925, '8.03515625'], + [1495703494.925, '8.03515625'], + [1495703554.925, '8.03515625'], + [1495703614.925, '8.03515625'], + [1495703674.925, '8.03515625'], + [1495703734.925, '8.03515625'], + [1495703794.925, '8.03515625'], + [1495703854.925, '8.03515625'], + [1495703914.925, '8.03515625'], + [1495703974.925, '8.03515625'], + [1495704034.925, '8.03515625'], + [1495704094.925, '8.03515625'], + [1495704154.925, '8.03515625'], + [1495704214.925, '7.9296875'], + [1495704274.925, '7.9296875'], + [1495704334.925, '7.9296875'], + [1495704394.925, '7.9296875'], + [1495704454.925, '7.9296875'], + [1495704514.925, '7.9296875'], + [1495704574.925, '7.9296875'], + [1495704634.925, '7.9296875'], + [1495704694.925, '7.9296875'], + [1495704754.925, '7.9296875'], + [1495704814.925, '7.9296875'], + [1495704874.925, '7.9296875'], + [1495704934.925, '7.9296875'], + [1495704994.925, '7.9296875'], + [1495705054.925, '7.9296875'], + [1495705114.925, '7.9296875'], + [1495705174.925, '7.9296875'], + [1495705234.925, '7.9296875'], + [1495705294.925, '7.9296875'], + [1495705354.925, '7.9296875'], + [1495705414.925, '7.9296875'], + [1495705474.925, '7.9296875'], + [1495705534.925, '7.9296875'], + [1495705594.925, '7.9296875'], + [1495705654.925, '7.9296875'], + [1495705714.925, '7.9296875'], + [1495705774.925, '7.9296875'], + [1495705834.925, '7.9296875'], + [1495705894.925, '7.9296875'], + [1495705954.925, '7.9296875'], + [1495706014.925, '7.9296875'], + [1495706074.925, '7.9296875'], + [1495706134.925, '7.9296875'], + [1495706194.925, '7.9296875'], + [1495706254.925, '7.9296875'], + [1495706314.925, '7.9296875'], + [1495706374.925, '7.9296875'], + [1495706434.925, '7.9296875'], + [1495706494.925, '7.9296875'], + [1495706554.925, '7.9296875'], + [1495706614.925, '7.9296875'], + [1495706674.925, '7.9296875'], + [1495706734.925, '7.9296875'], + [1495706794.925, '7.9296875'], + [1495706854.925, '7.9296875'], + [1495706914.925, '7.9296875'], + [1495706974.925, '7.9296875'], + [1495707034.925, '7.9296875'], + [1495707094.925, '7.9296875'], + [1495707154.925, '7.9296875'], + [1495707214.925, '7.9296875'], + [1495707274.925, '7.9296875'], + [1495707334.925, '7.9296875'], + [1495707394.925, '7.9296875'], + [1495707454.925, '7.9296875'], + [1495707514.925, '7.9296875'], + [1495707574.925, '7.9296875'], + [1495707634.925, '7.9296875'], + [1495707694.925, '7.9296875'], + [1495707754.925, '7.9296875'], + [1495707814.925, '7.9296875'], + [1495707874.925, '7.9296875'], + [1495707934.925, '7.9296875'], + [1495707994.925, '7.9296875'], + [1495708054.925, '7.9296875'], + [1495708114.925, '7.9296875'], + [1495708174.925, '7.9296875'], + [1495708234.925, '7.9296875'], + [1495708294.925, '7.9296875'], + [1495708354.925, '7.9296875'], + [1495708414.925, '7.9296875'], + [1495708474.925, '7.9296875'], + [1495708534.925, '7.9296875'], + [1495708594.925, '7.9296875'], + [1495708654.925, '7.9296875'], + [1495708714.925, '7.9296875'], + [1495708774.925, '7.9296875'], + [1495708834.925, '7.9296875'], + [1495708894.925, '7.9296875'], + [1495708954.925, '7.8984375'], + [1495709014.925, '7.8984375'], + [1495709074.925, '7.8984375'], + [1495709134.925, '7.8984375'], + [1495709194.925, '7.8984375'], + [1495709254.925, '7.89453125'], + [1495709314.925, '7.89453125'], + [1495709374.925, '7.89453125'], + [1495709434.925, '7.89453125'], + [1495709494.925, '7.89453125'], + [1495709554.925, '7.89453125'], + [1495709614.925, '7.89453125'], + [1495709674.925, '7.89453125'], + [1495709734.925, '7.89453125'], + [1495709794.925, '7.89453125'], + [1495709854.925, '7.89453125'], + [1495709914.925, '7.89453125'], + [1495709974.925, '7.89453125'], + [1495710034.925, '7.89453125'], + [1495710094.925, '7.89453125'], + [1495710154.925, '7.89453125'], + [1495710214.925, '7.89453125'], + [1495710274.925, '7.89453125'], + [1495710334.925, '7.89453125'], + [1495710394.925, '7.89453125'], + [1495710454.925, '7.89453125'], + [1495710514.925, '7.89453125'], + [1495710574.925, '7.89453125'], + [1495710634.925, '7.89453125'], + [1495710694.925, '7.89453125'], + [1495710754.925, '7.89453125'], + [1495710814.925, '7.89453125'], + [1495710874.925, '7.89453125'], + [1495710934.925, '7.89453125'], + [1495710994.925, '7.89453125'], + [1495711054.925, '7.89453125'], + [1495711114.925, '7.89453125'], + [1495711174.925, '7.8515625'], + [1495711234.925, '7.8515625'], + [1495711294.925, '7.8515625'], + [1495711354.925, '7.8515625'], + [1495711414.925, '7.8515625'], + [1495711474.925, '7.8515625'], + [1495711534.925, '7.8515625'], + [1495711594.925, '7.8515625'], + [1495711654.925, '7.8515625'], + [1495711714.925, '7.8515625'], + [1495711774.925, '7.8515625'], + [1495711834.925, '7.8515625'], + [1495711894.925, '7.8515625'], + [1495711954.925, '7.8515625'], + [1495712014.925, '7.8515625'], + [1495712074.925, '7.8515625'], + [1495712134.925, '7.8515625'], + [1495712194.925, '7.8515625'], + [1495712254.925, '7.8515625'], + [1495712314.925, '7.8515625'], + [1495712374.925, '7.8515625'], + [1495712434.925, '7.83203125'], + [1495712494.925, '7.83203125'], + [1495712554.925, '7.83203125'], + [1495712614.925, '7.83203125'], + [1495712674.925, '7.83203125'], + [1495712734.925, '7.83203125'], + [1495712794.925, '7.83203125'], + [1495712854.925, '7.83203125'], + [1495712914.925, '7.83203125'], + [1495712974.925, '7.83203125'], + [1495713034.925, '7.83203125'], + [1495713094.925, '7.83203125'], + [1495713154.925, '7.83203125'], + [1495713214.925, '7.83203125'], + [1495713274.925, '7.83203125'], + [1495713334.925, '7.83203125'], + [1495713394.925, '7.8125'], + [1495713454.925, '7.8125'], + [1495713514.925, '7.8125'], + [1495713574.925, '7.8125'], + [1495713634.925, '7.8125'], + [1495713694.925, '7.8125'], + [1495713754.925, '7.8125'], + [1495713814.925, '7.8125'], + [1495713874.925, '7.8125'], + [1495713934.925, '7.8125'], + [1495713994.925, '7.8125'], + [1495714054.925, '7.8125'], + [1495714114.925, '7.8125'], + [1495714174.925, '7.8125'], + [1495714234.925, '7.8125'], + [1495714294.925, '7.8125'], + [1495714354.925, '7.80859375'], + [1495714414.925, '7.80859375'], + [1495714474.925, '7.80859375'], + [1495714534.925, '7.80859375'], + [1495714594.925, '7.80859375'], + [1495714654.925, '7.80859375'], + [1495714714.925, '7.80859375'], + [1495714774.925, '7.80859375'], + [1495714834.925, '7.80859375'], + [1495714894.925, '7.80859375'], + [1495714954.925, '7.80859375'], + [1495715014.925, '7.80859375'], + [1495715074.925, '7.80859375'], + [1495715134.925, '7.80859375'], + [1495715194.925, '7.80859375'], + [1495715254.925, '7.80859375'], + [1495715314.925, '7.80859375'], + [1495715374.925, '7.80859375'], + [1495715434.925, '7.80859375'], + [1495715494.925, '7.80859375'], + [1495715554.925, '7.80859375'], + [1495715614.925, '7.80859375'], + [1495715674.925, '7.80859375'], + [1495715734.925, '7.80859375'], + [1495715794.925, '7.80859375'], + [1495715854.925, '7.80859375'], + [1495715914.925, '7.80078125'], + [1495715974.925, '7.80078125'], + [1495716034.925, '7.80078125'], + [1495716094.925, '7.80078125'], + [1495716154.925, '7.80078125'], + [1495716214.925, '7.796875'], + [1495716274.925, '7.796875'], + [1495716334.925, '7.796875'], + [1495716394.925, '7.796875'], + [1495716454.925, '7.796875'], + [1495716514.925, '7.796875'], + [1495716574.925, '7.796875'], + [1495716634.925, '7.796875'], + [1495716694.925, '7.796875'], + [1495716754.925, '7.796875'], + [1495716814.925, '7.796875'], + [1495716874.925, '7.79296875'], + [1495716934.925, '7.79296875'], + [1495716994.925, '7.79296875'], + [1495717054.925, '7.79296875'], + [1495717114.925, '7.79296875'], + [1495717174.925, '7.7890625'], + [1495717234.925, '7.7890625'], + [1495717294.925, '7.7890625'], + [1495717354.925, '7.7890625'], + [1495717414.925, '7.7890625'], + [1495717474.925, '7.7890625'], + [1495717534.925, '7.7890625'], + [1495717594.925, '7.7890625'], + [1495717654.925, '7.7890625'], + [1495717714.925, '7.7890625'], + [1495717774.925, '7.7890625'], + [1495717834.925, '7.77734375'], + [1495717894.925, '7.77734375'], + [1495717954.925, '7.77734375'], + [1495718014.925, '7.77734375'], + [1495718074.925, '7.77734375'], + [1495718134.925, '7.7421875'], + [1495718194.925, '7.7421875'], + [1495718254.925, '7.7421875'], + [1495718314.925, '7.7421875'], + ], + }, + ], + }, + ], }, { - 'title': 'CPU usage', - 'weight': 1, - 'queries': [ + title: 'CPU usage', + weight: 1, + queries: [ + { + query_range: + 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', + result: [ { - 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', - 'result': [ - { - 'metric': {}, - 'values': [ - [ - 1495700554.925, - '0.0010794445585559514' - ], - [ - 1495700614.925, - '0.003927214935433527' - ], - [ - 1495700674.925, - '0.0053045219047619975' - ], - [ - 1495700734.925, - '0.0048892095238097155' - ], - [ - 1495700794.925, - '0.005827140952381137' - ], - [ - 1495700854.925, - '0.00569846906219937' - ], - [ - 1495700914.925, - '0.004972616802849382' - ], - [ - 1495700974.925, - '0.005117509523809902' - ], - [ - 1495701034.925, - '0.00512389061919564' - ], - [ - 1495701094.925, - '0.005199100501890691' - ], - [ - 1495701154.925, - '0.005415746394885837' - ], - [ - 1495701214.925, - '0.005607682788146286' - ], - [ - 1495701274.925, - '0.005641300000000118' - ], - [ - 1495701334.925, - '0.0071166279368766495' - ], - [ - 1495701394.925, - '0.0063242138095234044' - ], - [ - 1495701454.925, - '0.005793314698235304' - ], - [ - 1495701514.925, - '0.00703934942237556' - ], - [ - 1495701574.925, - '0.006357007076123191' - ], - [ - 1495701634.925, - '0.003753167300126738' - ], - [ - 1495701694.925, - '0.005018469678430698' - ], - [ - 1495701754.925, - '0.0045217153371887' - ], - [ - 1495701814.925, - '0.006140104285714119' - ], - [ - 1495701874.925, - '0.004818684285714102' - ], - [ - 1495701934.925, - '0.005079509718955242' - ], - [ - 1495701994.925, - '0.005059981142498263' - ], - [ - 1495702054.925, - '0.005269098389538773' - ], - [ - 1495702114.925, - '0.005269954285714175' - ], - [ - 1495702174.925, - '0.014199241435795856' - ], - [ - 1495702234.925, - '0.01511936843111017' - ], - [ - 1495702294.925, - '0.0060933692920682875' - ], - [ - 1495702354.925, - '0.004945682380952493' - ], - [ - 1495702414.925, - '0.005641266666666565' - ], - [ - 1495702474.925, - '0.005223752857142996' - ], - [ - 1495702534.925, - '0.005743098505699831' - ], - [ - 1495702594.925, - '0.00538493380952391' - ], - [ - 1495702654.925, - '0.005507793883751339' - ], - [ - 1495702714.925, - '0.005666705714285466' - ], - [ - 1495702774.925, - '0.006231530000000112' - ], - [ - 1495702834.925, - '0.006570768635394899' - ], - [ - 1495702894.925, - '0.005551146666666895' - ], - [ - 1495702954.925, - '0.005602604737098058' - ], - [ - 1495703014.925, - '0.00613993580402159' - ], - [ - 1495703074.925, - '0.004770258764368832' - ], - [ - 1495703134.925, - '0.005512376671364914' - ], - [ - 1495703194.925, - '0.005254436666666674' - ], - [ - 1495703254.925, - '0.0050109839141320505' - ], - [ - 1495703314.925, - '0.0049478019256960016' - ], - [ - 1495703374.925, - '0.0037666860965123463' - ], - [ - 1495703434.925, - '0.004813526061656314' - ], - [ - 1495703494.925, - '0.005047748095238278' - ], - [ - 1495703554.925, - '0.00386494081008772' - ], - [ - 1495703614.925, - '0.004304037408111405' - ], - [ - 1495703674.925, - '0.004999466661587168' - ], - [ - 1495703734.925, - '0.004689140476190834' - ], - [ - 1495703794.925, - '0.004746126153582475' - ], - [ - 1495703854.925, - '0.004482706382572302' - ], - [ - 1495703914.925, - '0.004032808931864524' - ], - [ - 1495703974.925, - '0.005728319047618988' - ], - [ - 1495704034.925, - '0.004436139179627006' - ], - [ - 1495704094.925, - '0.004553455714285617' - ], - [ - 1495704154.925, - '0.003455244285714341' - ], - [ - 1495704214.925, - '0.004742244761904621' - ], - [ - 1495704274.925, - '0.005366978571428422' - ], - [ - 1495704334.925, - '0.004257954837665058' - ], - [ - 1495704394.925, - '0.005431603259831257' - ], - [ - 1495704454.925, - '0.0052009214498621986' - ], - [ - 1495704514.925, - '0.004317201904761618' - ], - [ - 1495704574.925, - '0.004307384285714157' - ], - [ - 1495704634.925, - '0.004789801146644822' - ], - [ - 1495704694.925, - '0.0051429795906706485' - ], - [ - 1495704754.925, - '0.005322495714285479' - ], - [ - 1495704814.925, - '0.004512809333244233' - ], - [ - 1495704874.925, - '0.004953843582568726' - ], - [ - 1495704934.925, - '0.005812690120858119' - ], - [ - 1495704994.925, - '0.004997024285714838' - ], - [ - 1495705054.925, - '0.005246216154439592' - ], - [ - 1495705114.925, - '0.0063494966618726795' - ], - [ - 1495705174.925, - '0.005306004342898225' - ], - [ - 1495705234.925, - '0.005081412857142978' - ], - [ - 1495705294.925, - '0.00511409523809522' - ], - [ - 1495705354.925, - '0.0047861001481192' - ], - [ - 1495705414.925, - '0.005107688228042962' - ], - [ - 1495705474.925, - '0.005271929582294012' - ], - [ - 1495705534.925, - '0.004453254502681249' - ], - [ - 1495705594.925, - '0.005799134293959226' - ], - [ - 1495705654.925, - '0.005340865929502478' - ], - [ - 1495705714.925, - '0.004911654761904942' - ], - [ - 1495705774.925, - '0.005888234873953261' - ], - [ - 1495705834.925, - '0.005565283333332954' - ], - [ - 1495705894.925, - '0.005522869047618869' - ], - [ - 1495705954.925, - '0.005177549737621646' - ], - [ - 1495706014.925, - '0.0053145810232096465' - ], - [ - 1495706074.925, - '0.004751095238095275' - ], - [ - 1495706134.925, - '0.006242077142856976' - ], - [ - 1495706194.925, - '0.00621034406957871' - ], - [ - 1495706254.925, - '0.006887592738978596' - ], - [ - 1495706314.925, - '0.006328128779726213' - ], - [ - 1495706374.925, - '0.007488363809523927' - ], - [ - 1495706434.925, - '0.006193758571428157' - ], - [ - 1495706494.925, - '0.0068798371839706935' - ], - [ - 1495706554.925, - '0.005757034340423128' - ], - [ - 1495706614.925, - '0.004571388497294698' - ], - [ - 1495706674.925, - '0.00620283044923395' - ], - [ - 1495706734.925, - '0.005607562380952455' - ], - [ - 1495706794.925, - '0.005506969933620308' - ], - [ - 1495706854.925, - '0.005621118095238131' - ], - [ - 1495706914.925, - '0.004876606098698849' - ], - [ - 1495706974.925, - '0.0047871205988517206' - ], - [ - 1495707034.925, - '0.00526405939458784' - ], - [ - 1495707094.925, - '0.005716323800605852' - ], - [ - 1495707154.925, - '0.005301459523809575' - ], - [ - 1495707214.925, - '0.0051613042857144905' - ], - [ - 1495707274.925, - '0.005384792857142714' - ], - [ - 1495707334.925, - '0.005259719047619222' - ], - [ - 1495707394.925, - '0.00584101142857182' - ], - [ - 1495707454.925, - '0.0060066121920326326' - ], - [ - 1495707514.925, - '0.006359978571428453' - ], - [ - 1495707574.925, - '0.006315876322151109' - ], - [ - 1495707634.925, - '0.005590012517198831' - ], - [ - 1495707694.925, - '0.005517419877137072' - ], - [ - 1495707754.925, - '0.006089813430348506' - ], - [ - 1495707814.925, - '0.00466754476190479' - ], - [ - 1495707874.925, - '0.006059954380517721' - ], - [ - 1495707934.925, - '0.005085657142856972' - ], - [ - 1495707994.925, - '0.005897665238095296' - ], - [ - 1495708054.925, - '0.0062282023199555885' - ], - [ - 1495708114.925, - '0.00526214553236979' - ], - [ - 1495708174.925, - '0.0044803300000000644' - ], - [ - 1495708234.925, - '0.005421443333333592' - ], - [ - 1495708294.925, - '0.005694326244512144' - ], - [ - 1495708354.925, - '0.005527721904761457' - ], - [ - 1495708414.925, - '0.005988819523809819' - ], - [ - 1495708474.925, - '0.005484704285714448' - ], - [ - 1495708534.925, - '0.005041123649230085' - ], - [ - 1495708594.925, - '0.005717767639612059' - ], - [ - 1495708654.925, - '0.005412954417342863' - ], - [ - 1495708714.925, - '0.005833343333333254' - ], - [ - 1495708774.925, - '0.005448135238094969' - ], - [ - 1495708834.925, - '0.005117341428571432' - ], - [ - 1495708894.925, - '0.005888345825277833' - ], - [ - 1495708954.925, - '0.005398543809524135' - ], - [ - 1495709014.925, - '0.005325611428571416' - ], - [ - 1495709074.925, - '0.005848668571428527' - ], - [ - 1495709134.925, - '0.005135003105145044' - ], - [ - 1495709194.925, - '0.0054551400000003' - ], - [ - 1495709254.925, - '0.005319472937322171' - ], - [ - 1495709314.925, - '0.00585677857142792' - ], - [ - 1495709374.925, - '0.0062146261904759215' - ], - [ - 1495709434.925, - '0.0067105060904182265' - ], - [ - 1495709494.925, - '0.005829691904762108' - ], - [ - 1495709554.925, - '0.005719280952381261' - ], - [ - 1495709614.925, - '0.005682603793416407' - ], - [ - 1495709674.925, - '0.0055272846277326934' - ], - [ - 1495709734.925, - '0.0057123680952386735' - ], - [ - 1495709794.925, - '0.00520597958075818' - ], - [ - 1495709854.925, - '0.005584358957263837' - ], - [ - 1495709914.925, - '0.005601104275197466' - ], - [ - 1495709974.925, - '0.005991657142857066' - ], - [ - 1495710034.925, - '0.00553722238095218' - ], - [ - 1495710094.925, - '0.005127883122696293' - ], - [ - 1495710154.925, - '0.005498111927534584' - ], - [ - 1495710214.925, - '0.005609934069084202' - ], - [ - 1495710274.925, - '0.00459206285714307' - ], - [ - 1495710334.925, - '0.0047910828571428084' - ], - [ - 1495710394.925, - '0.0056014671288845685' - ], - [ - 1495710454.925, - '0.005686936791078528' - ], - [ - 1495710514.925, - '0.00444480476190448' - ], - [ - 1495710574.925, - '0.005780394696738921' - ], - [ - 1495710634.925, - '0.0053107227550210365' - ], - [ - 1495710694.925, - '0.005096031495761817' - ], - [ - 1495710754.925, - '0.005451377979091524' - ], - [ - 1495710814.925, - '0.005328136666667083' - ], - [ - 1495710874.925, - '0.006020612857143043' - ], - [ - 1495710934.925, - '0.0061063585714285365' - ], - [ - 1495710994.925, - '0.006018346015752312' - ], - [ - 1495711054.925, - '0.005069130952381193' - ], - [ - 1495711114.925, - '0.005458406190476052' - ], - [ - 1495711174.925, - '0.00577219190476179' - ], - [ - 1495711234.925, - '0.005760814645658314' - ], - [ - 1495711294.925, - '0.005371875716579101' - ], - [ - 1495711354.925, - '0.0064232666666665834' - ], - [ - 1495711414.925, - '0.009369806836906667' - ], - [ - 1495711474.925, - '0.008956864761904692' - ], - [ - 1495711534.925, - '0.005266849368559271' - ], - [ - 1495711594.925, - '0.005335111364934262' - ], - [ - 1495711654.925, - '0.006461778319586945' - ], - [ - 1495711714.925, - '0.004687939890762393' - ], - [ - 1495711774.925, - '0.004438831245760684' - ], - [ - 1495711834.925, - '0.005142786666666613' - ], - [ - 1495711894.925, - '0.007257734212054963' - ], - [ - 1495711954.925, - '0.005621991904761494' - ], - [ - 1495712014.925, - '0.007868689999999862' - ], - [ - 1495712074.925, - '0.00910970215275738' - ], - [ - 1495712134.925, - '0.006151004285714278' - ], - [ - 1495712194.925, - '0.005447120924961522' - ], - [ - 1495712254.925, - '0.005150705153929503' - ], - [ - 1495712314.925, - '0.006358108714969314' - ], - [ - 1495712374.925, - '0.0057725354795696475' - ], - [ - 1495712434.925, - '0.005232139047619015' - ], - [ - 1495712494.925, - '0.004932809617949037' - ], - [ - 1495712554.925, - '0.004511607508499662' - ], - [ - 1495712614.925, - '0.00440487701522666' - ], - [ - 1495712674.925, - '0.005479113333333174' - ], - [ - 1495712734.925, - '0.004726317619047547' - ], - [ - 1495712794.925, - '0.005582041102958029' - ], - [ - 1495712854.925, - '0.006381481216082099' - ], - [ - 1495712914.925, - '0.005474260014095208' - ], - [ - 1495712974.925, - '0.00567597142857188' - ], - [ - 1495713034.925, - '0.0064741233333332985' - ], - [ - 1495713094.925, - '0.005467475714285271' - ], - [ - 1495713154.925, - '0.004868648393824457' - ], - [ - 1495713214.925, - '0.005254923286444893' - ], - [ - 1495713274.925, - '0.005599217150312865' - ], - [ - 1495713334.925, - '0.005105413720618919' - ], - [ - 1495713394.925, - '0.007246073333333279' - ], - [ - 1495713454.925, - '0.005990312380952272' - ], - [ - 1495713514.925, - '0.005594601853351101' - ], - [ - 1495713574.925, - '0.004739258673727054' - ], - [ - 1495713634.925, - '0.003932121428571783' - ], - [ - 1495713694.925, - '0.005018188268459395' - ], - [ - 1495713754.925, - '0.004538238095237985' - ], - [ - 1495713814.925, - '0.00561816643265435' - ], - [ - 1495713874.925, - '0.0063132584495033586' - ], - [ - 1495713934.925, - '0.00442385238095213' - ], - [ - 1495713994.925, - '0.004181795887658453' - ], - [ - 1495714054.925, - '0.004437759047619037' - ], - [ - 1495714114.925, - '0.006421748157178241' - ], - [ - 1495714174.925, - '0.006525143809523842' - ], - [ - 1495714234.925, - '0.004715904935144247' - ], - [ - 1495714294.925, - '0.005966040152763461' - ], - [ - 1495714354.925, - '0.005614535466921674' - ], - [ - 1495714414.925, - '0.004934375119415906' - ], - [ - 1495714474.925, - '0.0054122933333327385' - ], - [ - 1495714534.925, - '0.004926540699612279' - ], - [ - 1495714594.925, - '0.006124649517134237' - ], - [ - 1495714654.925, - '0.004629427092013995' - ], - [ - 1495714714.925, - '0.005117951257607005' - ], - [ - 1495714774.925, - '0.004868774512685422' - ], - [ - 1495714834.925, - '0.005310093333333399' - ], - [ - 1495714894.925, - '0.0054907752286127345' - ], - [ - 1495714954.925, - '0.004597678117351089' - ], - [ - 1495715014.925, - '0.0059622552380952' - ], - [ - 1495715074.925, - '0.005352457072655368' - ], - [ - 1495715134.925, - '0.005491630952381143' - ], - [ - 1495715194.925, - '0.006391770078379791' - ], - [ - 1495715254.925, - '0.005933472857142518' - ], - [ - 1495715314.925, - '0.005301314285714163' - ], - [ - 1495715374.925, - '0.0058352959724814165' - ], - [ - 1495715434.925, - '0.006154755147867044' - ], - [ - 1495715494.925, - '0.009391935637482038' - ], - [ - 1495715554.925, - '0.007846462857142592' - ], - [ - 1495715614.925, - '0.00477608215316353' - ], - [ - 1495715674.925, - '0.006132865238094998' - ], - [ - 1495715734.925, - '0.006159762457649516' - ], - [ - 1495715794.925, - '0.005957307073265968' - ], - [ - 1495715854.925, - '0.006652319091792501' - ], - [ - 1495715914.925, - '0.005493557402895287' - ], - [ - 1495715974.925, - '0.0058652434829145166' - ], - [ - 1495716034.925, - '0.005627400430468021' - ], - [ - 1495716094.925, - '0.006240656190475609' - ], - [ - 1495716154.925, - '0.006305997676168624' - ], - [ - 1495716214.925, - '0.005388057732783248' - ], - [ - 1495716274.925, - '0.0052814916048421244' - ], - [ - 1495716334.925, - '0.00699498614272497' - ], - [ - 1495716394.925, - '0.00627768693035141' - ], - [ - 1495716454.925, - '0.0042411487048161145' - ], - [ - 1495716514.925, - '0.005348647473627653' - ], - [ - 1495716574.925, - '0.0047176657142853975' - ], - [ - 1495716634.925, - '0.004437898571428686' - ], - [ - 1495716694.925, - '0.004923527366927261' - ], - [ - 1495716754.925, - '0.005131935066048421' - ], - [ - 1495716814.925, - '0.005046949523809611' - ], - [ - 1495716874.925, - '0.00547184095238092' - ], - [ - 1495716934.925, - '0.005224140016380444' - ], - [ - 1495716994.925, - '0.005297991171665292' - ], - [ - 1495717054.925, - '0.005492965995623498' - ], - [ - 1495717114.925, - '0.005754660000000403' - ], - [ - 1495717174.925, - '0.005949557138639285' - ], - [ - 1495717234.925, - '0.006091816112534666' - ], - [ - 1495717294.925, - '0.005554210080192063' - ], - [ - 1495717354.925, - '0.006411504395279871' - ], - [ - 1495717414.925, - '0.006319643996609606' - ], - [ - 1495717474.925, - '0.005539174405717675' - ], - [ - 1495717534.925, - '0.0053157078842772255' - ], - [ - 1495717594.925, - '0.005247480952381066' - ], - [ - 1495717654.925, - '0.004820141620396252' - ], - [ - 1495717714.925, - '0.005906173868322844' - ], - [ - 1495717774.925, - '0.006173117219570961' - ], - [ - 1495717834.925, - '0.005963340952380661' - ], - [ - 1495717894.925, - '0.005698976627681527' - ], - [ - 1495717954.925, - '0.004751279096346378' - ], - [ - 1495718014.925, - '0.005733142379359711' - ], - [ - 1495718074.925, - '0.004831689010348035' - ], - [ - 1495718134.925, - '0.005188370476191092' - ], - [ - 1495718194.925, - '0.004793227554547938' - ], - [ - 1495718254.925, - '0.003997442857142731' - ], - [ - 1495718314.925, - '0.004386040132951264' - ] - ] - } - ] - } - ] - } - ] - } + metric: {}, + values: [ + [1495700554.925, '0.0010794445585559514'], + [1495700614.925, '0.003927214935433527'], + [1495700674.925, '0.0053045219047619975'], + [1495700734.925, '0.0048892095238097155'], + [1495700794.925, '0.005827140952381137'], + [1495700854.925, '0.00569846906219937'], + [1495700914.925, '0.004972616802849382'], + [1495700974.925, '0.005117509523809902'], + [1495701034.925, '0.00512389061919564'], + [1495701094.925, '0.005199100501890691'], + [1495701154.925, '0.005415746394885837'], + [1495701214.925, '0.005607682788146286'], + [1495701274.925, '0.005641300000000118'], + [1495701334.925, '0.0071166279368766495'], + [1495701394.925, '0.0063242138095234044'], + [1495701454.925, '0.005793314698235304'], + [1495701514.925, '0.00703934942237556'], + [1495701574.925, '0.006357007076123191'], + [1495701634.925, '0.003753167300126738'], + [1495701694.925, '0.005018469678430698'], + [1495701754.925, '0.0045217153371887'], + [1495701814.925, '0.006140104285714119'], + [1495701874.925, '0.004818684285714102'], + [1495701934.925, '0.005079509718955242'], + [1495701994.925, '0.005059981142498263'], + [1495702054.925, '0.005269098389538773'], + [1495702114.925, '0.005269954285714175'], + [1495702174.925, '0.014199241435795856'], + [1495702234.925, '0.01511936843111017'], + [1495702294.925, '0.0060933692920682875'], + [1495702354.925, '0.004945682380952493'], + [1495702414.925, '0.005641266666666565'], + [1495702474.925, '0.005223752857142996'], + [1495702534.925, '0.005743098505699831'], + [1495702594.925, '0.00538493380952391'], + [1495702654.925, '0.005507793883751339'], + [1495702714.925, '0.005666705714285466'], + [1495702774.925, '0.006231530000000112'], + [1495702834.925, '0.006570768635394899'], + [1495702894.925, '0.005551146666666895'], + [1495702954.925, '0.005602604737098058'], + [1495703014.925, '0.00613993580402159'], + [1495703074.925, '0.004770258764368832'], + [1495703134.925, '0.005512376671364914'], + [1495703194.925, '0.005254436666666674'], + [1495703254.925, '0.0050109839141320505'], + [1495703314.925, '0.0049478019256960016'], + [1495703374.925, '0.0037666860965123463'], + [1495703434.925, '0.004813526061656314'], + [1495703494.925, '0.005047748095238278'], + [1495703554.925, '0.00386494081008772'], + [1495703614.925, '0.004304037408111405'], + [1495703674.925, '0.004999466661587168'], + [1495703734.925, '0.004689140476190834'], + [1495703794.925, '0.004746126153582475'], + [1495703854.925, '0.004482706382572302'], + [1495703914.925, '0.004032808931864524'], + [1495703974.925, '0.005728319047618988'], + [1495704034.925, '0.004436139179627006'], + [1495704094.925, '0.004553455714285617'], + [1495704154.925, '0.003455244285714341'], + [1495704214.925, '0.004742244761904621'], + [1495704274.925, '0.005366978571428422'], + [1495704334.925, '0.004257954837665058'], + [1495704394.925, '0.005431603259831257'], + [1495704454.925, '0.0052009214498621986'], + [1495704514.925, '0.004317201904761618'], + [1495704574.925, '0.004307384285714157'], + [1495704634.925, '0.004789801146644822'], + [1495704694.925, '0.0051429795906706485'], + [1495704754.925, '0.005322495714285479'], + [1495704814.925, '0.004512809333244233'], + [1495704874.925, '0.004953843582568726'], + [1495704934.925, '0.005812690120858119'], + [1495704994.925, '0.004997024285714838'], + [1495705054.925, '0.005246216154439592'], + [1495705114.925, '0.0063494966618726795'], + [1495705174.925, '0.005306004342898225'], + [1495705234.925, '0.005081412857142978'], + [1495705294.925, '0.00511409523809522'], + [1495705354.925, '0.0047861001481192'], + [1495705414.925, '0.005107688228042962'], + [1495705474.925, '0.005271929582294012'], + [1495705534.925, '0.004453254502681249'], + [1495705594.925, '0.005799134293959226'], + [1495705654.925, '0.005340865929502478'], + [1495705714.925, '0.004911654761904942'], + [1495705774.925, '0.005888234873953261'], + [1495705834.925, '0.005565283333332954'], + [1495705894.925, '0.005522869047618869'], + [1495705954.925, '0.005177549737621646'], + [1495706014.925, '0.0053145810232096465'], + [1495706074.925, '0.004751095238095275'], + [1495706134.925, '0.006242077142856976'], + [1495706194.925, '0.00621034406957871'], + [1495706254.925, '0.006887592738978596'], + [1495706314.925, '0.006328128779726213'], + [1495706374.925, '0.007488363809523927'], + [1495706434.925, '0.006193758571428157'], + [1495706494.925, '0.0068798371839706935'], + [1495706554.925, '0.005757034340423128'], + [1495706614.925, '0.004571388497294698'], + [1495706674.925, '0.00620283044923395'], + [1495706734.925, '0.005607562380952455'], + [1495706794.925, '0.005506969933620308'], + [1495706854.925, '0.005621118095238131'], + [1495706914.925, '0.004876606098698849'], + [1495706974.925, '0.0047871205988517206'], + [1495707034.925, '0.00526405939458784'], + [1495707094.925, '0.005716323800605852'], + [1495707154.925, '0.005301459523809575'], + [1495707214.925, '0.0051613042857144905'], + [1495707274.925, '0.005384792857142714'], + [1495707334.925, '0.005259719047619222'], + [1495707394.925, '0.00584101142857182'], + [1495707454.925, '0.0060066121920326326'], + [1495707514.925, '0.006359978571428453'], + [1495707574.925, '0.006315876322151109'], + [1495707634.925, '0.005590012517198831'], + [1495707694.925, '0.005517419877137072'], + [1495707754.925, '0.006089813430348506'], + [1495707814.925, '0.00466754476190479'], + [1495707874.925, '0.006059954380517721'], + [1495707934.925, '0.005085657142856972'], + [1495707994.925, '0.005897665238095296'], + [1495708054.925, '0.0062282023199555885'], + [1495708114.925, '0.00526214553236979'], + [1495708174.925, '0.0044803300000000644'], + [1495708234.925, '0.005421443333333592'], + [1495708294.925, '0.005694326244512144'], + [1495708354.925, '0.005527721904761457'], + [1495708414.925, '0.005988819523809819'], + [1495708474.925, '0.005484704285714448'], + [1495708534.925, '0.005041123649230085'], + [1495708594.925, '0.005717767639612059'], + [1495708654.925, '0.005412954417342863'], + [1495708714.925, '0.005833343333333254'], + [1495708774.925, '0.005448135238094969'], + [1495708834.925, '0.005117341428571432'], + [1495708894.925, '0.005888345825277833'], + [1495708954.925, '0.005398543809524135'], + [1495709014.925, '0.005325611428571416'], + [1495709074.925, '0.005848668571428527'], + [1495709134.925, '0.005135003105145044'], + [1495709194.925, '0.0054551400000003'], + [1495709254.925, '0.005319472937322171'], + [1495709314.925, '0.00585677857142792'], + [1495709374.925, '0.0062146261904759215'], + [1495709434.925, '0.0067105060904182265'], + [1495709494.925, '0.005829691904762108'], + [1495709554.925, '0.005719280952381261'], + [1495709614.925, '0.005682603793416407'], + [1495709674.925, '0.0055272846277326934'], + [1495709734.925, '0.0057123680952386735'], + [1495709794.925, '0.00520597958075818'], + [1495709854.925, '0.005584358957263837'], + [1495709914.925, '0.005601104275197466'], + [1495709974.925, '0.005991657142857066'], + [1495710034.925, '0.00553722238095218'], + [1495710094.925, '0.005127883122696293'], + [1495710154.925, '0.005498111927534584'], + [1495710214.925, '0.005609934069084202'], + [1495710274.925, '0.00459206285714307'], + [1495710334.925, '0.0047910828571428084'], + [1495710394.925, '0.0056014671288845685'], + [1495710454.925, '0.005686936791078528'], + [1495710514.925, '0.00444480476190448'], + [1495710574.925, '0.005780394696738921'], + [1495710634.925, '0.0053107227550210365'], + [1495710694.925, '0.005096031495761817'], + [1495710754.925, '0.005451377979091524'], + [1495710814.925, '0.005328136666667083'], + [1495710874.925, '0.006020612857143043'], + [1495710934.925, '0.0061063585714285365'], + [1495710994.925, '0.006018346015752312'], + [1495711054.925, '0.005069130952381193'], + [1495711114.925, '0.005458406190476052'], + [1495711174.925, '0.00577219190476179'], + [1495711234.925, '0.005760814645658314'], + [1495711294.925, '0.005371875716579101'], + [1495711354.925, '0.0064232666666665834'], + [1495711414.925, '0.009369806836906667'], + [1495711474.925, '0.008956864761904692'], + [1495711534.925, '0.005266849368559271'], + [1495711594.925, '0.005335111364934262'], + [1495711654.925, '0.006461778319586945'], + [1495711714.925, '0.004687939890762393'], + [1495711774.925, '0.004438831245760684'], + [1495711834.925, '0.005142786666666613'], + [1495711894.925, '0.007257734212054963'], + [1495711954.925, '0.005621991904761494'], + [1495712014.925, '0.007868689999999862'], + [1495712074.925, '0.00910970215275738'], + [1495712134.925, '0.006151004285714278'], + [1495712194.925, '0.005447120924961522'], + [1495712254.925, '0.005150705153929503'], + [1495712314.925, '0.006358108714969314'], + [1495712374.925, '0.0057725354795696475'], + [1495712434.925, '0.005232139047619015'], + [1495712494.925, '0.004932809617949037'], + [1495712554.925, '0.004511607508499662'], + [1495712614.925, '0.00440487701522666'], + [1495712674.925, '0.005479113333333174'], + [1495712734.925, '0.004726317619047547'], + [1495712794.925, '0.005582041102958029'], + [1495712854.925, '0.006381481216082099'], + [1495712914.925, '0.005474260014095208'], + [1495712974.925, '0.00567597142857188'], + [1495713034.925, '0.0064741233333332985'], + [1495713094.925, '0.005467475714285271'], + [1495713154.925, '0.004868648393824457'], + [1495713214.925, '0.005254923286444893'], + [1495713274.925, '0.005599217150312865'], + [1495713334.925, '0.005105413720618919'], + [1495713394.925, '0.007246073333333279'], + [1495713454.925, '0.005990312380952272'], + [1495713514.925, '0.005594601853351101'], + [1495713574.925, '0.004739258673727054'], + [1495713634.925, '0.003932121428571783'], + [1495713694.925, '0.005018188268459395'], + [1495713754.925, '0.004538238095237985'], + [1495713814.925, '0.00561816643265435'], + [1495713874.925, '0.0063132584495033586'], + [1495713934.925, '0.00442385238095213'], + [1495713994.925, '0.004181795887658453'], + [1495714054.925, '0.004437759047619037'], + [1495714114.925, '0.006421748157178241'], + [1495714174.925, '0.006525143809523842'], + [1495714234.925, '0.004715904935144247'], + [1495714294.925, '0.005966040152763461'], + [1495714354.925, '0.005614535466921674'], + [1495714414.925, '0.004934375119415906'], + [1495714474.925, '0.0054122933333327385'], + [1495714534.925, '0.004926540699612279'], + [1495714594.925, '0.006124649517134237'], + [1495714654.925, '0.004629427092013995'], + [1495714714.925, '0.005117951257607005'], + [1495714774.925, '0.004868774512685422'], + [1495714834.925, '0.005310093333333399'], + [1495714894.925, '0.0054907752286127345'], + [1495714954.925, '0.004597678117351089'], + [1495715014.925, '0.0059622552380952'], + [1495715074.925, '0.005352457072655368'], + [1495715134.925, '0.005491630952381143'], + [1495715194.925, '0.006391770078379791'], + [1495715254.925, '0.005933472857142518'], + [1495715314.925, '0.005301314285714163'], + [1495715374.925, '0.0058352959724814165'], + [1495715434.925, '0.006154755147867044'], + [1495715494.925, '0.009391935637482038'], + [1495715554.925, '0.007846462857142592'], + [1495715614.925, '0.00477608215316353'], + [1495715674.925, '0.006132865238094998'], + [1495715734.925, '0.006159762457649516'], + [1495715794.925, '0.005957307073265968'], + [1495715854.925, '0.006652319091792501'], + [1495715914.925, '0.005493557402895287'], + [1495715974.925, '0.0058652434829145166'], + [1495716034.925, '0.005627400430468021'], + [1495716094.925, '0.006240656190475609'], + [1495716154.925, '0.006305997676168624'], + [1495716214.925, '0.005388057732783248'], + [1495716274.925, '0.0052814916048421244'], + [1495716334.925, '0.00699498614272497'], + [1495716394.925, '0.00627768693035141'], + [1495716454.925, '0.0042411487048161145'], + [1495716514.925, '0.005348647473627653'], + [1495716574.925, '0.0047176657142853975'], + [1495716634.925, '0.004437898571428686'], + [1495716694.925, '0.004923527366927261'], + [1495716754.925, '0.005131935066048421'], + [1495716814.925, '0.005046949523809611'], + [1495716874.925, '0.00547184095238092'], + [1495716934.925, '0.005224140016380444'], + [1495716994.925, '0.005297991171665292'], + [1495717054.925, '0.005492965995623498'], + [1495717114.925, '0.005754660000000403'], + [1495717174.925, '0.005949557138639285'], + [1495717234.925, '0.006091816112534666'], + [1495717294.925, '0.005554210080192063'], + [1495717354.925, '0.006411504395279871'], + [1495717414.925, '0.006319643996609606'], + [1495717474.925, '0.005539174405717675'], + [1495717534.925, '0.0053157078842772255'], + [1495717594.925, '0.005247480952381066'], + [1495717654.925, '0.004820141620396252'], + [1495717714.925, '0.005906173868322844'], + [1495717774.925, '0.006173117219570961'], + [1495717834.925, '0.005963340952380661'], + [1495717894.925, '0.005698976627681527'], + [1495717954.925, '0.004751279096346378'], + [1495718014.925, '0.005733142379359711'], + [1495718074.925, '0.004831689010348035'], + [1495718134.925, '0.005188370476191092'], + [1495718194.925, '0.004793227554547938'], + [1495718254.925, '0.003997442857142731'], + [1495718314.925, '0.004386040132951264'], + ], + }, + ], + }, + ], + }, + ], + }, ], - 'last_update': '2017-05-25T13:18:34.949Z' + last_update: '2017-05-25T13:18:34.949Z', }; export default metricsGroupsAPIResponse; @@ -2432,41 +651,44 @@ export const deploymentData = [ id: 111, iid: 3, sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', - commitUrl: 'http://test.host/frontend-fixtures/environments-project/commit/f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', + commitUrl: + 'http://test.host/frontend-fixtures/environments-project/commit/f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', ref: { - name: 'master' + name: 'master', }, created_at: '2017-05-31T21:23:37.881Z', tag: false, tagUrl: 'http://test.host/frontend-fixtures/environments-project/tags/false', - 'last?': true + 'last?': true, }, { id: 110, iid: 2, sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', - commitUrl: 'http://test.host/frontend-fixtures/environments-project/commit/f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', + commitUrl: + 'http://test.host/frontend-fixtures/environments-project/commit/f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187', ref: { - name: 'master' + name: 'master', }, created_at: '2017-05-30T20:08:04.629Z', tag: false, - tagUrl: 'http://test.host/frontend-fixtures/environments-project/tags/false', - 'last?': false + tagUrl: 'http://test.host/frontend-fixtures/environments-project/tags/false', + 'last?': false, }, { id: 109, iid: 1, sha: '6511e58faafaa7ad2228990ec57f19d66f7db7c2', - commitUrl: 'http://test.host/frontend-fixtures/environments-project/commit/6511e58faafaa7ad2228990ec57f19d66f7db7c2', + commitUrl: + 'http://test.host/frontend-fixtures/environments-project/commit/6511e58faafaa7ad2228990ec57f19d66f7db7c2', ref: { - name: 'update2-readme' + name: 'update2-readme', }, created_at: '2017-05-30T17:42:38.409Z', tag: false, tagUrl: 'http://test.host/frontend-fixtures/environments-project/tags/false', - 'last?': false - } + 'last?': false, + }, ]; export const statePaths = { @@ -2476,5844 +698,5844 @@ export const statePaths = { }; export const singleRowMetricsMultipleSeries = [ - { - 'title': 'Multiple Time Series', - 'weight': 1, - 'y_label': 'Request Rates', - 'queries': [ - { - 'query_range': 'sum(rate(nginx_responses_total{environment="production"}[2m])) by (status_code)', - 'label': 'Requests', - 'unit': 'Req/sec', - 'result': [ - { - 'metric': { - 'status_code': '1xx' - }, - 'values': [ - { - 'time': '2017-08-27T11:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T11:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T12:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T13:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T14:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T15:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T16:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T17:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:01:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:02:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:03:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:04:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:05:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:06:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:07:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:08:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:09:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:10:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:11:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:12:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:13:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:14:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:15:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:16:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:17:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:18:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:19:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:20:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:21:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:22:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:23:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:24:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:25:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:26:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:27:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:28:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:29:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:30:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:31:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:32:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:33:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:34:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:35:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:36:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:37:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:38:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:39:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:40:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:41:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:42:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:43:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:44:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:45:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:46:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:47:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:48:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:49:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:50:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:51:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:52:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:53:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:54:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:55:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:56:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:57:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:58:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T18:59:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T19:00:51.462Z', - 'value': '0' - }, - { - 'time': '2017-08-27T19:01:51.462Z', - 'value': '0' - } - ] - }, - { - 'metric': { - 'status_code': '2xx' - }, - 'values': [ - { - 'time': '2017-08-27T11:01:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:02:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T11:03:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:04:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:05:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:06:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:07:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:08:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:09:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:12:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:14:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:16:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:18:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:19:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:20:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:21:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:22:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:23:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:24:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:25:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:26:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:27:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:28:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:29:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:30:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:31:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:32:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:33:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:34:51.462Z', - 'value': '1.333320635041571' - }, - { - 'time': '2017-08-27T11:35:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:36:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:37:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:38:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:39:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:40:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:41:51.462Z', - 'value': '1.3333587306424883' - }, - { - 'time': '2017-08-27T11:42:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:43:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:44:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:45:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:46:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:47:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:48:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:49:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T11:50:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:51:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:53:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:55:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:56:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:57:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T11:58:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T11:59:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:00:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:01:51.462Z', - 'value': '1.3333460318669703' - }, - { - 'time': '2017-08-27T12:02:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:03:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:04:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:05:51.462Z', - 'value': '1.31427319739812' - }, - { - 'time': '2017-08-27T12:06:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:07:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:08:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:09:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:10:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:12:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:13:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:16:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:18:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:19:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:20:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:21:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:22:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:23:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:24:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:25:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:26:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:27:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:28:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:29:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:30:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:31:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:32:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:33:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:34:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:35:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:36:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:37:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:38:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:39:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:40:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:41:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:42:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:43:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:44:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:45:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:46:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:47:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:48:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:49:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:50:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:51:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:53:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T12:55:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:56:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:57:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T12:58:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T12:59:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:00:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:01:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T13:02:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:03:51.462Z', - 'value': '1.2952627669098458' - }, - { - 'time': '2017-08-27T13:04:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:05:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:06:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:07:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:08:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:09:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:12:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:14:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:15:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T13:16:51.462Z', - 'value': '1.3333587306424883' - }, - { - 'time': '2017-08-27T13:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:18:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:19:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:20:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:21:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:22:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:23:51.462Z', - 'value': '1.276190476190476' - }, - { - 'time': '2017-08-27T13:24:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T13:25:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:26:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:27:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:28:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:29:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:30:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:31:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:32:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:33:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:34:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:35:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:36:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:37:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:38:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:39:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:40:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:41:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:42:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:43:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:44:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:45:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:46:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T13:47:51.462Z', - 'value': '1.276190476190476' - }, - { - 'time': '2017-08-27T13:48:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:49:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T13:50:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:51:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:52:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:53:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:54:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:55:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:56:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T13:57:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T13:58:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T13:59:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T14:00:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:01:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:02:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:03:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:04:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:05:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:06:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:07:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:08:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:09:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:12:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:16:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:17:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:18:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:19:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:20:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:21:51.462Z', - 'value': '1.3333079369916765' - }, - { - 'time': '2017-08-27T14:22:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:23:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:24:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:25:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:26:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:27:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:28:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:29:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:30:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:31:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:32:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:33:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T14:34:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:35:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:36:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:37:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:38:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:39:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:40:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:41:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:42:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:43:51.462Z', - 'value': '1.276190476190476' - }, - { - 'time': '2017-08-27T14:44:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T14:45:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:46:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:47:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:48:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:49:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:50:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:51:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:53:51.462Z', - 'value': '1.333320635041571' - }, - { - 'time': '2017-08-27T14:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:55:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T14:56:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:57:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T14:58:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T14:59:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:00:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:01:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:02:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:03:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:04:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T15:05:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:06:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:07:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:08:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:09:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:10:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:11:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:12:51.462Z', - 'value': '1.31427319739812' - }, - { - 'time': '2017-08-27T15:13:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:16:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:18:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:19:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:20:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:21:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:22:51.462Z', - 'value': '1.3333460318669703' - }, - { - 'time': '2017-08-27T15:23:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:24:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:25:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:26:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:27:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:28:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:29:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:30:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:31:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:32:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:33:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:34:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:35:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:36:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:37:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:38:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:39:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:40:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:41:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:42:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:43:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:44:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:45:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:46:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:47:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:48:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:49:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T15:50:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:51:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:53:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:55:51.462Z', - 'value': '1.3333587306424883' - }, - { - 'time': '2017-08-27T15:56:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T15:57:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:58:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T15:59:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:00:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:01:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:02:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:03:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:04:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:05:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:06:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:07:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:08:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:09:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:12:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:15:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:16:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:17:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:18:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:19:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:20:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:21:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:22:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:23:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:24:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T16:25:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:26:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:27:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:28:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:29:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:30:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:31:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:32:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:33:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:34:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:35:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:36:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:37:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:38:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:39:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:40:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:41:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:42:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:43:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:44:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:45:51.462Z', - 'value': '1.3142982314117277' - }, - { - 'time': '2017-08-27T16:46:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:47:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:48:51.462Z', - 'value': '1.333320635041571' - }, - { - 'time': '2017-08-27T16:49:51.462Z', - 'value': '1.31427319739812' - }, - { - 'time': '2017-08-27T16:50:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:51:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:53:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:55:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T16:56:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:57:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T16:58:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T16:59:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:00:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:01:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:02:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:03:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:04:51.462Z', - 'value': '1.2952504309564854' - }, - { - 'time': '2017-08-27T17:05:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:06:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:07:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:08:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:09:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:12:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:16:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:18:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:19:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:20:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:21:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:22:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:23:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:24:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:25:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:26:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:27:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:28:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:29:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T17:30:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:31:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:32:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:33:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:34:51.462Z', - 'value': '1.295225759754669' - }, - { - 'time': '2017-08-27T17:35:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:36:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:37:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:38:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:39:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:40:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:41:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:42:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:43:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:44:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:45:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:46:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:47:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:48:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:49:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:50:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:51:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:52:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:53:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:54:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:55:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T17:56:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:57:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T17:58:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T17:59:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T18:00:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:01:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:02:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:03:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:04:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:05:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:06:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:07:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:08:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:09:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:10:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:11:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:12:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T18:13:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:14:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:15:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:16:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:17:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:18:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:19:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:20:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:21:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:22:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:23:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:24:51.462Z', - 'value': '1.2571428571428571' - }, - { - 'time': '2017-08-27T18:25:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:26:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:27:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:28:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:29:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:30:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:31:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:32:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:33:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:34:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:35:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:36:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:37:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T18:38:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:39:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:40:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:41:51.462Z', - 'value': '1.580952380952381' - }, - { - 'time': '2017-08-27T18:42:51.462Z', - 'value': '1.7333333333333334' - }, - { - 'time': '2017-08-27T18:43:51.462Z', - 'value': '2.057142857142857' - }, - { - 'time': '2017-08-27T18:44:51.462Z', - 'value': '2.1904761904761902' - }, - { - 'time': '2017-08-27T18:45:51.462Z', - 'value': '1.8285714285714287' - }, - { - 'time': '2017-08-27T18:46:51.462Z', - 'value': '2.1142857142857143' - }, - { - 'time': '2017-08-27T18:47:51.462Z', - 'value': '1.619047619047619' - }, - { - 'time': '2017-08-27T18:48:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:49:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:50:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T18:51:51.462Z', - 'value': '1.2952504309564854' - }, - { - 'time': '2017-08-27T18:52:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:53:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:54:51.462Z', - 'value': '1.3333333333333333' - }, - { - 'time': '2017-08-27T18:55:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:56:51.462Z', - 'value': '1.314285714285714' - }, - { - 'time': '2017-08-27T18:57:51.462Z', - 'value': '1.295238095238095' - }, - { - 'time': '2017-08-27T18:58:51.462Z', - 'value': '1.7142857142857142' - }, - { - 'time': '2017-08-27T18:59:51.462Z', - 'value': '1.7333333333333334' - }, - { - 'time': '2017-08-27T19:00:51.462Z', - 'value': '1.3904761904761904' - }, - { - 'time': '2017-08-27T19:01:51.462Z', - 'value': '1.5047619047619047' - } - ] - }, - ], - 'when': [ - { - 'value': 'hundred(s)', - 'color': 'green', - }, - ], - } - ] - }, - { - 'title': 'Throughput', - 'weight': 1, - 'y_label': 'Requests / Sec', - 'queries': [ - { - 'query_range': 'sum(rate(nginx_requests_total{server_zone!=\'*\', server_zone!=\'_\', container_name!=\'POD\',environment=\'production\'}[2m]))', - 'label': 'Total', - 'unit': 'req / sec', - 'result': [ - { - 'metric': { - - }, - 'values': [ - { - 'time': '2017-08-27T11:01:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:02:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T11:03:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:04:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:05:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:06:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:07:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:08:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:09:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:12:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:14:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:16:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:18:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:19:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:20:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:21:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:22:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:23:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:24:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:25:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:26:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:27:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:28:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:29:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:30:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:31:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:32:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:33:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:34:51.462Z', - 'value': '0.4952333787297264' - }, - { - 'time': '2017-08-27T11:35:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:36:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:37:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:38:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:39:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:40:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:41:51.462Z', - 'value': '0.49524752852435283' - }, - { - 'time': '2017-08-27T11:42:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:43:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:44:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:45:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:46:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:47:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:48:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:49:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T11:50:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:51:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:53:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:55:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:56:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:57:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T11:58:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T11:59:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:00:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:01:51.462Z', - 'value': '0.49524281183630325' - }, - { - 'time': '2017-08-27T12:02:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:03:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:04:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:05:51.462Z', - 'value': '0.4857096599080009' - }, - { - 'time': '2017-08-27T12:06:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:07:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:08:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:09:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:10:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:12:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:13:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:16:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:18:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:19:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:20:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:21:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:22:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:23:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:24:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:25:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:26:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:27:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:28:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:29:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:30:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:31:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:32:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:33:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:34:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:35:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:36:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:37:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:38:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:39:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:40:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:41:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:42:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:43:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:44:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:45:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:46:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:47:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:48:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:49:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:50:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:51:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:53:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T12:55:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:56:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:57:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T12:58:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T12:59:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:00:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:01:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T13:02:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:03:51.462Z', - 'value': '0.4761995466580315' - }, - { - 'time': '2017-08-27T13:04:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:05:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:06:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:07:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:08:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:09:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:12:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:14:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:15:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T13:16:51.462Z', - 'value': '0.49524752852435283' - }, - { - 'time': '2017-08-27T13:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:18:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:19:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:20:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:21:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:22:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:23:51.462Z', - 'value': '0.4666666666666667' - }, - { - 'time': '2017-08-27T13:24:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T13:25:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:26:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:27:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:28:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:29:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:30:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:31:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:32:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:33:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:34:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:35:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:36:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:37:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:38:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:39:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:40:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:41:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:42:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:43:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:44:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:45:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:46:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T13:47:51.462Z', - 'value': '0.4666666666666667' - }, - { - 'time': '2017-08-27T13:48:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:49:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T13:50:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:51:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:52:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:53:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:54:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:55:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:56:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T13:57:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T13:58:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T13:59:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T14:00:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:01:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:02:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:03:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:04:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:05:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:06:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:07:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:08:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:09:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:12:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:16:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:17:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:18:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:19:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:20:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:21:51.462Z', - 'value': '0.4952286623111941' - }, - { - 'time': '2017-08-27T14:22:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:23:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:24:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:25:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:26:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:27:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:28:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:29:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:30:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:31:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:32:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:33:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T14:34:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:35:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:36:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:37:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:38:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:39:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:40:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:41:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:42:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:43:51.462Z', - 'value': '0.4666666666666667' - }, - { - 'time': '2017-08-27T14:44:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T14:45:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:46:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:47:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:48:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:49:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:50:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:51:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:53:51.462Z', - 'value': '0.4952333787297264' - }, - { - 'time': '2017-08-27T14:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:55:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T14:56:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:57:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T14:58:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T14:59:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:00:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:01:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:02:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:03:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:04:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T15:05:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:06:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:07:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:08:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:09:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:10:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:11:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:12:51.462Z', - 'value': '0.4857096599080009' - }, - { - 'time': '2017-08-27T15:13:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:16:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:18:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:19:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:20:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:21:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:22:51.462Z', - 'value': '0.49524281183630325' - }, - { - 'time': '2017-08-27T15:23:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:24:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:25:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:26:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:27:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:28:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:29:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:30:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:31:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:32:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:33:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:34:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:35:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:36:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:37:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:38:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:39:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:40:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:41:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:42:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:43:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:44:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:45:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:46:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:47:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:48:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:49:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T15:50:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:51:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:53:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:55:51.462Z', - 'value': '0.49524752852435283' - }, - { - 'time': '2017-08-27T15:56:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T15:57:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:58:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T15:59:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:00:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:01:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:02:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:03:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:04:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:05:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:06:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:07:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:08:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:09:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:12:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:15:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:16:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:17:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:18:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:19:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:20:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:21:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:22:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:23:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:24:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T16:25:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:26:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:27:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:28:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:29:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:30:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:31:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:32:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:33:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:34:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:35:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:36:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:37:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:38:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:39:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:40:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:41:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:42:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:43:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:44:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:45:51.462Z', - 'value': '0.485718911608682' - }, - { - 'time': '2017-08-27T16:46:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:47:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:48:51.462Z', - 'value': '0.4952333787297264' - }, - { - 'time': '2017-08-27T16:49:51.462Z', - 'value': '0.4857096599080009' - }, - { - 'time': '2017-08-27T16:50:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:51:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:53:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:55:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T16:56:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:57:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T16:58:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T16:59:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:00:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:01:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:02:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:03:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:04:51.462Z', - 'value': '0.47619501138106085' - }, - { - 'time': '2017-08-27T17:05:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:06:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:07:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:08:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:09:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:12:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:16:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:18:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:19:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:20:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:21:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:22:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:23:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:24:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:25:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:26:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:27:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:28:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:29:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T17:30:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:31:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:32:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:33:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:34:51.462Z', - 'value': '0.4761859410862754' - }, - { - 'time': '2017-08-27T17:35:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:36:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:37:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:38:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:39:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:40:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:41:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:42:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:43:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:44:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:45:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:46:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:47:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:48:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:49:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:50:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:51:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:52:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:53:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:54:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:55:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T17:56:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:57:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T17:58:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T17:59:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T18:00:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:01:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:02:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:03:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:04:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:05:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:06:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:07:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:08:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:09:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:10:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:11:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:12:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T18:13:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:14:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:15:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:16:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:17:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:18:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:19:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:20:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:21:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:22:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:23:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:24:51.462Z', - 'value': '0.45714285714285713' - }, - { - 'time': '2017-08-27T18:25:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:26:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:27:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:28:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:29:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:30:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:31:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:32:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:33:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:34:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:35:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:36:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:37:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T18:38:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:39:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:40:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:41:51.462Z', - 'value': '0.6190476190476191' - }, - { - 'time': '2017-08-27T18:42:51.462Z', - 'value': '0.6952380952380952' - }, - { - 'time': '2017-08-27T18:43:51.462Z', - 'value': '0.857142857142857' - }, - { - 'time': '2017-08-27T18:44:51.462Z', - 'value': '0.9238095238095239' - }, - { - 'time': '2017-08-27T18:45:51.462Z', - 'value': '0.7428571428571429' - }, - { - 'time': '2017-08-27T18:46:51.462Z', - 'value': '0.8857142857142857' - }, - { - 'time': '2017-08-27T18:47:51.462Z', - 'value': '0.638095238095238' - }, - { - 'time': '2017-08-27T18:48:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:49:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:50:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T18:51:51.462Z', - 'value': '0.47619501138106085' - }, - { - 'time': '2017-08-27T18:52:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:53:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:54:51.462Z', - 'value': '0.4952380952380952' - }, - { - 'time': '2017-08-27T18:55:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:56:51.462Z', - 'value': '0.4857142857142857' - }, - { - 'time': '2017-08-27T18:57:51.462Z', - 'value': '0.47619047619047616' - }, - { - 'time': '2017-08-27T18:58:51.462Z', - 'value': '0.6857142857142856' - }, - { - 'time': '2017-08-27T18:59:51.462Z', - 'value': '0.6952380952380952' - }, - { - 'time': '2017-08-27T19:00:51.462Z', - 'value': '0.5238095238095237' - }, - { - 'time': '2017-08-27T19:01:51.462Z', - 'value': '0.5904761904761905' - } - ] - } - ] - } - ] - } + { + title: 'Multiple Time Series', + weight: 1, + y_label: 'Request Rates', + queries: [ + { + query_range: + 'sum(rate(nginx_responses_total{environment="production"}[2m])) by (status_code)', + label: 'Requests', + unit: 'Req/sec', + result: [ + { + metric: { + status_code: '1xx', + }, + values: [ + { + time: '2017-08-27T11:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T11:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T12:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T13:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T14:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T15:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T16:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T17:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:01:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:02:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:03:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:04:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:05:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:06:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:07:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:08:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:09:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:10:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:11:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:12:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:13:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:14:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:15:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:16:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:17:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:18:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:19:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:20:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:21:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:22:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:23:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:24:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:25:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:26:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:27:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:28:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:29:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:30:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:31:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:32:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:33:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:34:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:35:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:36:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:37:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:38:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:39:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:40:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:41:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:42:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:43:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:44:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:45:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:46:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:47:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:48:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:49:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:50:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:51:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:52:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:53:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:54:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:55:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:56:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:57:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:58:51.462Z', + value: '0', + }, + { + time: '2017-08-27T18:59:51.462Z', + value: '0', + }, + { + time: '2017-08-27T19:00:51.462Z', + value: '0', + }, + { + time: '2017-08-27T19:01:51.462Z', + value: '0', + }, + ], + }, + { + metric: { + status_code: '2xx', + }, + values: [ + { + time: '2017-08-27T11:01:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:02:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T11:03:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:04:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:05:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:06:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:07:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:08:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:09:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:12:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:14:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:16:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:18:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:19:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:20:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:21:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:22:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:23:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:24:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:25:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:26:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:27:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:28:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:29:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:30:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:31:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:32:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:33:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:34:51.462Z', + value: '1.333320635041571', + }, + { + time: '2017-08-27T11:35:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:36:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:37:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:38:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:39:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:40:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:41:51.462Z', + value: '1.3333587306424883', + }, + { + time: '2017-08-27T11:42:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:43:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:44:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:45:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:46:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:47:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:48:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:49:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T11:50:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:51:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:53:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:55:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:56:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:57:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T11:58:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T11:59:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:00:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:01:51.462Z', + value: '1.3333460318669703', + }, + { + time: '2017-08-27T12:02:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:03:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:04:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:05:51.462Z', + value: '1.31427319739812', + }, + { + time: '2017-08-27T12:06:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:07:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:08:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:09:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:10:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:12:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:13:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:16:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:18:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:19:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:20:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:21:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:22:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:23:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:24:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:25:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:26:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:27:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:28:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:29:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:30:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:31:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:32:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:33:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:34:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:35:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:36:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:37:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:38:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:39:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:40:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:41:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:42:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:43:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:44:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:45:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:46:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:47:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:48:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:49:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:50:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:51:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:53:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T12:55:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:56:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:57:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T12:58:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T12:59:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:00:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:01:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T13:02:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:03:51.462Z', + value: '1.2952627669098458', + }, + { + time: '2017-08-27T13:04:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:05:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:06:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:07:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:08:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:09:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:12:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:14:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:15:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T13:16:51.462Z', + value: '1.3333587306424883', + }, + { + time: '2017-08-27T13:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:18:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:19:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:20:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:21:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:22:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:23:51.462Z', + value: '1.276190476190476', + }, + { + time: '2017-08-27T13:24:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T13:25:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:26:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:27:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:28:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:29:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:30:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:31:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:32:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:33:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:34:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:35:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:36:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:37:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:38:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:39:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:40:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:41:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:42:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:43:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:44:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:45:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:46:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T13:47:51.462Z', + value: '1.276190476190476', + }, + { + time: '2017-08-27T13:48:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:49:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T13:50:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:51:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:52:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:53:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:54:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:55:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:56:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T13:57:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T13:58:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T13:59:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T14:00:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:01:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:02:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:03:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:04:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:05:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:06:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:07:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:08:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:09:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:12:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:16:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:17:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:18:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:19:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:20:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:21:51.462Z', + value: '1.3333079369916765', + }, + { + time: '2017-08-27T14:22:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:23:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:24:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:25:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:26:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:27:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:28:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:29:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:30:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:31:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:32:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:33:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T14:34:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:35:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:36:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:37:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:38:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:39:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:40:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:41:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:42:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:43:51.462Z', + value: '1.276190476190476', + }, + { + time: '2017-08-27T14:44:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T14:45:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:46:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:47:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:48:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:49:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:50:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:51:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:53:51.462Z', + value: '1.333320635041571', + }, + { + time: '2017-08-27T14:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:55:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T14:56:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:57:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T14:58:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T14:59:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:00:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:01:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:02:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:03:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:04:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T15:05:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:06:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:07:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:08:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:09:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:10:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:11:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:12:51.462Z', + value: '1.31427319739812', + }, + { + time: '2017-08-27T15:13:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:16:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:18:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:19:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:20:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:21:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:22:51.462Z', + value: '1.3333460318669703', + }, + { + time: '2017-08-27T15:23:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:24:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:25:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:26:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:27:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:28:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:29:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:30:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:31:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:32:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:33:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:34:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:35:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:36:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:37:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:38:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:39:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:40:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:41:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:42:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:43:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:44:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:45:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:46:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:47:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:48:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:49:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T15:50:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:51:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:53:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:55:51.462Z', + value: '1.3333587306424883', + }, + { + time: '2017-08-27T15:56:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T15:57:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:58:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T15:59:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:00:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:01:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:02:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:03:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:04:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:05:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:06:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:07:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:08:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:09:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:12:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:15:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:16:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:17:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:18:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:19:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:20:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:21:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:22:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:23:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:24:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T16:25:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:26:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:27:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:28:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:29:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:30:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:31:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:32:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:33:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:34:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:35:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:36:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:37:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:38:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:39:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:40:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:41:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:42:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:43:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:44:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:45:51.462Z', + value: '1.3142982314117277', + }, + { + time: '2017-08-27T16:46:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:47:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:48:51.462Z', + value: '1.333320635041571', + }, + { + time: '2017-08-27T16:49:51.462Z', + value: '1.31427319739812', + }, + { + time: '2017-08-27T16:50:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:51:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:53:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:55:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T16:56:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:57:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T16:58:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T16:59:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:00:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:01:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:02:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:03:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:04:51.462Z', + value: '1.2952504309564854', + }, + { + time: '2017-08-27T17:05:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:06:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:07:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:08:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:09:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:12:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:16:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:18:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:19:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:20:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:21:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:22:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:23:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:24:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:25:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:26:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:27:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:28:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:29:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T17:30:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:31:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:32:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:33:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:34:51.462Z', + value: '1.295225759754669', + }, + { + time: '2017-08-27T17:35:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:36:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:37:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:38:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:39:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:40:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:41:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:42:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:43:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:44:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:45:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:46:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:47:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:48:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:49:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:50:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:51:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:52:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:53:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:54:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:55:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T17:56:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:57:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T17:58:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T17:59:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T18:00:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:01:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:02:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:03:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:04:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:05:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:06:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:07:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:08:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:09:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:10:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:11:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:12:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T18:13:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:14:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:15:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:16:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:17:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:18:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:19:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:20:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:21:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:22:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:23:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:24:51.462Z', + value: '1.2571428571428571', + }, + { + time: '2017-08-27T18:25:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:26:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:27:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:28:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:29:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:30:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:31:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:32:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:33:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:34:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:35:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:36:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:37:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T18:38:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:39:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:40:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:41:51.462Z', + value: '1.580952380952381', + }, + { + time: '2017-08-27T18:42:51.462Z', + value: '1.7333333333333334', + }, + { + time: '2017-08-27T18:43:51.462Z', + value: '2.057142857142857', + }, + { + time: '2017-08-27T18:44:51.462Z', + value: '2.1904761904761902', + }, + { + time: '2017-08-27T18:45:51.462Z', + value: '1.8285714285714287', + }, + { + time: '2017-08-27T18:46:51.462Z', + value: '2.1142857142857143', + }, + { + time: '2017-08-27T18:47:51.462Z', + value: '1.619047619047619', + }, + { + time: '2017-08-27T18:48:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:49:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:50:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T18:51:51.462Z', + value: '1.2952504309564854', + }, + { + time: '2017-08-27T18:52:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:53:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:54:51.462Z', + value: '1.3333333333333333', + }, + { + time: '2017-08-27T18:55:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:56:51.462Z', + value: '1.314285714285714', + }, + { + time: '2017-08-27T18:57:51.462Z', + value: '1.295238095238095', + }, + { + time: '2017-08-27T18:58:51.462Z', + value: '1.7142857142857142', + }, + { + time: '2017-08-27T18:59:51.462Z', + value: '1.7333333333333334', + }, + { + time: '2017-08-27T19:00:51.462Z', + value: '1.3904761904761904', + }, + { + time: '2017-08-27T19:01:51.462Z', + value: '1.5047619047619047', + }, + ], + }, + ], + when: [ + { + value: 'hundred(s)', + color: 'green', + }, + ], + }, + ], + }, + { + title: 'Throughput', + weight: 1, + y_label: 'Requests / Sec', + queries: [ + { + query_range: + "sum(rate(nginx_requests_total{server_zone!='*', server_zone!='_', container_name!='POD',environment='production'}[2m]))", + label: 'Total', + unit: 'req / sec', + result: [ + { + metric: {}, + values: [ + { + time: '2017-08-27T11:01:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:02:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T11:03:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:04:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:05:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:06:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:07:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:08:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:09:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:12:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:14:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:16:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:18:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:19:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:20:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:21:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:22:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:23:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:24:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:25:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:26:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:27:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:28:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:29:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:30:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:31:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:32:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:33:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:34:51.462Z', + value: '0.4952333787297264', + }, + { + time: '2017-08-27T11:35:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:36:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:37:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:38:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:39:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:40:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:41:51.462Z', + value: '0.49524752852435283', + }, + { + time: '2017-08-27T11:42:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:43:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:44:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:45:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:46:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:47:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:48:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:49:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T11:50:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:51:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:53:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:55:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:56:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:57:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T11:58:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T11:59:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:00:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:01:51.462Z', + value: '0.49524281183630325', + }, + { + time: '2017-08-27T12:02:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:03:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:04:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:05:51.462Z', + value: '0.4857096599080009', + }, + { + time: '2017-08-27T12:06:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:07:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:08:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:09:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:10:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:12:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:13:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:16:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:18:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:19:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:20:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:21:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:22:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:23:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:24:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:25:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:26:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:27:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:28:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:29:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:30:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:31:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:32:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:33:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:34:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:35:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:36:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:37:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:38:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:39:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:40:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:41:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:42:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:43:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:44:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:45:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:46:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:47:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:48:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:49:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:50:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:51:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:53:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T12:55:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:56:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:57:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T12:58:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T12:59:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:00:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:01:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T13:02:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:03:51.462Z', + value: '0.4761995466580315', + }, + { + time: '2017-08-27T13:04:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:05:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:06:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:07:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:08:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:09:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:12:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:14:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:15:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T13:16:51.462Z', + value: '0.49524752852435283', + }, + { + time: '2017-08-27T13:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:18:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:19:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:20:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:21:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:22:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:23:51.462Z', + value: '0.4666666666666667', + }, + { + time: '2017-08-27T13:24:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T13:25:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:26:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:27:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:28:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:29:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:30:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:31:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:32:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:33:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:34:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:35:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:36:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:37:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:38:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:39:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:40:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:41:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:42:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:43:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:44:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:45:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:46:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T13:47:51.462Z', + value: '0.4666666666666667', + }, + { + time: '2017-08-27T13:48:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:49:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T13:50:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:51:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:52:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:53:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:54:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:55:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:56:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T13:57:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T13:58:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T13:59:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T14:00:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:01:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:02:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:03:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:04:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:05:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:06:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:07:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:08:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:09:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:12:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:16:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:17:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:18:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:19:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:20:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:21:51.462Z', + value: '0.4952286623111941', + }, + { + time: '2017-08-27T14:22:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:23:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:24:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:25:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:26:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:27:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:28:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:29:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:30:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:31:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:32:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:33:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T14:34:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:35:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:36:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:37:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:38:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:39:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:40:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:41:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:42:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:43:51.462Z', + value: '0.4666666666666667', + }, + { + time: '2017-08-27T14:44:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T14:45:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:46:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:47:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:48:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:49:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:50:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:51:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:53:51.462Z', + value: '0.4952333787297264', + }, + { + time: '2017-08-27T14:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:55:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T14:56:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:57:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T14:58:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T14:59:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:00:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:01:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:02:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:03:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:04:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T15:05:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:06:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:07:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:08:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:09:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:10:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:11:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:12:51.462Z', + value: '0.4857096599080009', + }, + { + time: '2017-08-27T15:13:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:16:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:18:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:19:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:20:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:21:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:22:51.462Z', + value: '0.49524281183630325', + }, + { + time: '2017-08-27T15:23:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:24:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:25:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:26:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:27:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:28:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:29:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:30:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:31:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:32:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:33:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:34:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:35:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:36:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:37:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:38:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:39:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:40:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:41:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:42:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:43:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:44:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:45:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:46:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:47:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:48:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:49:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T15:50:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:51:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:53:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:55:51.462Z', + value: '0.49524752852435283', + }, + { + time: '2017-08-27T15:56:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T15:57:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:58:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T15:59:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:00:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:01:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:02:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:03:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:04:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:05:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:06:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:07:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:08:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:09:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:12:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:15:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:16:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:17:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:18:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:19:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:20:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:21:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:22:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:23:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:24:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T16:25:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:26:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:27:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:28:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:29:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:30:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:31:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:32:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:33:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:34:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:35:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:36:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:37:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:38:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:39:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:40:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:41:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:42:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:43:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:44:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:45:51.462Z', + value: '0.485718911608682', + }, + { + time: '2017-08-27T16:46:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:47:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:48:51.462Z', + value: '0.4952333787297264', + }, + { + time: '2017-08-27T16:49:51.462Z', + value: '0.4857096599080009', + }, + { + time: '2017-08-27T16:50:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:51:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:53:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:55:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T16:56:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:57:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T16:58:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T16:59:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:00:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:01:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:02:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:03:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:04:51.462Z', + value: '0.47619501138106085', + }, + { + time: '2017-08-27T17:05:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:06:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:07:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:08:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:09:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:12:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:16:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:18:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:19:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:20:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:21:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:22:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:23:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:24:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:25:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:26:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:27:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:28:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:29:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T17:30:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:31:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:32:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:33:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:34:51.462Z', + value: '0.4761859410862754', + }, + { + time: '2017-08-27T17:35:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:36:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:37:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:38:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:39:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:40:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:41:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:42:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:43:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:44:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:45:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:46:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:47:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:48:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:49:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:50:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:51:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:52:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:53:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:54:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:55:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T17:56:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:57:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T17:58:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T17:59:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T18:00:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:01:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:02:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:03:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:04:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:05:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:06:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:07:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:08:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:09:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:10:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:11:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:12:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T18:13:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:14:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:15:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:16:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:17:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:18:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:19:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:20:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:21:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:22:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:23:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:24:51.462Z', + value: '0.45714285714285713', + }, + { + time: '2017-08-27T18:25:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:26:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:27:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:28:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:29:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:30:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:31:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:32:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:33:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:34:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:35:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:36:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:37:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T18:38:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:39:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:40:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:41:51.462Z', + value: '0.6190476190476191', + }, + { + time: '2017-08-27T18:42:51.462Z', + value: '0.6952380952380952', + }, + { + time: '2017-08-27T18:43:51.462Z', + value: '0.857142857142857', + }, + { + time: '2017-08-27T18:44:51.462Z', + value: '0.9238095238095239', + }, + { + time: '2017-08-27T18:45:51.462Z', + value: '0.7428571428571429', + }, + { + time: '2017-08-27T18:46:51.462Z', + value: '0.8857142857142857', + }, + { + time: '2017-08-27T18:47:51.462Z', + value: '0.638095238095238', + }, + { + time: '2017-08-27T18:48:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:49:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:50:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T18:51:51.462Z', + value: '0.47619501138106085', + }, + { + time: '2017-08-27T18:52:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:53:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:54:51.462Z', + value: '0.4952380952380952', + }, + { + time: '2017-08-27T18:55:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:56:51.462Z', + value: '0.4857142857142857', + }, + { + time: '2017-08-27T18:57:51.462Z', + value: '0.47619047619047616', + }, + { + time: '2017-08-27T18:58:51.462Z', + value: '0.6857142857142856', + }, + { + time: '2017-08-27T18:59:51.462Z', + value: '0.6952380952380952', + }, + { + time: '2017-08-27T19:00:51.462Z', + value: '0.5238095238095237', + }, + { + time: '2017-08-27T19:01:51.462Z', + value: '0.5904761904761905', + }, + ], + }, + ], + }, + ], + }, ]; export function convertDatesMultipleSeries(multipleSeries) { const convertedMultiple = multipleSeries; multipleSeries.forEach((column, index) => { let convertedResult = []; - convertedResult = column.queries[0].result.map((resultObj) => { + convertedResult = column.queries[0].result.map(resultObj => { const convertedMetrics = {}; convertedMetrics.values = resultObj.values.map(val => ({ - time: new Date(val.time), - value: val.value, + time: new Date(val.time), + value: val.value, })); convertedMetrics.metric = resultObj.metric; return convertedMetrics; diff --git a/spec/javascripts/monitoring/monitoring_store_spec.js b/spec/javascripts/monitoring/monitoring_store_spec.js index 88aa7659275..08d54946787 100644 --- a/spec/javascripts/monitoring/monitoring_store_spec.js +++ b/spec/javascripts/monitoring/monitoring_store_spec.js @@ -1,7 +1,7 @@ import MonitoringStore from '~/monitoring/stores/monitoring_store'; import MonitoringMock, { deploymentData } from './mock_data'; -describe('MonitoringStore', () => { +describe('MonitoringStore', function () { this.store = new MonitoringStore(); this.store.storeMetrics(MonitoringMock.data); diff --git a/spec/javascripts/notes/components/note_actions_spec.js b/spec/javascripts/notes/components/note_actions_spec.js index ab81aabb992..1dfe890e05e 100644 --- a/spec/javascripts/notes/components/note_actions_spec.js +++ b/spec/javascripts/notes/components/note_actions_spec.js @@ -3,7 +3,7 @@ import store from '~/notes/stores'; import noteActions from '~/notes/components/note_actions.vue'; import { userDataMock } from '../mock_data'; -describe('issse_note_actions component', () => { +describe('issue_note_actions component', () => { let vm; let Component; @@ -24,6 +24,7 @@ describe('issse_note_actions component', () => { authorId: 26, canDelete: true, canEdit: true, + canAwardEmoji: true, canReportAsAbuse: true, noteId: 539, reportAbusePath: '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26', @@ -70,6 +71,7 @@ describe('issse_note_actions component', () => { authorId: 26, canDelete: false, canEdit: false, + canAwardEmoji: false, canReportAsAbuse: false, noteId: 539, reportAbusePath: '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26', diff --git a/spec/javascripts/notes/components/note_awards_list_spec.js b/spec/javascripts/notes/components/note_awards_list_spec.js index 15995ec5a05..1c30d8691b1 100644 --- a/spec/javascripts/notes/components/note_awards_list_spec.js +++ b/spec/javascripts/notes/components/note_awards_list_spec.js @@ -29,6 +29,7 @@ describe('note_awards_list component', () => { awards: awardsMock, noteAuthorId: 2, noteId: 545, + canAwardEmoji: true, toggleAwardPath: '/gitlab-org/gitlab-ce/notes/545/toggle_award_emoji', }, }).$mount(); @@ -43,14 +44,45 @@ describe('note_awards_list component', () => { expect(vm.$el.querySelector('.js-awards-block button [data-name="cartwheel_tone3"]')).toBeDefined(); }); - it('should be possible to remove awareded emoji', () => { + it('should be possible to remove awarded emoji', () => { spyOn(vm, 'handleAward').and.callThrough(); + spyOn(vm, 'toggleAwardRequest').and.callThrough(); vm.$el.querySelector('.js-awards-block button').click(); expect(vm.handleAward).toHaveBeenCalledWith('flag_tz'); + expect(vm.toggleAwardRequest).toHaveBeenCalled(); }); it('should be possible to add new emoji', () => { expect(vm.$el.querySelector('.js-add-award')).toBeDefined(); }); + + describe('when the user cannot award emoji', () => { + beforeEach(() => { + const Component = Vue.extend(awardsNote); + + vm = new Component({ + store, + propsData: { + awards: awardsMock, + noteAuthorId: 2, + noteId: 545, + canAwardEmoji: false, + toggleAwardPath: '/gitlab-org/gitlab-ce/notes/545/toggle_award_emoji', + }, + }).$mount(); + }); + + it('should not be possible to remove awarded emoji', () => { + spyOn(vm, 'toggleAwardRequest').and.callThrough(); + + vm.$el.querySelector('.js-awards-block button').click(); + + expect(vm.toggleAwardRequest).not.toHaveBeenCalled(); + }); + + it('should not be possible to add new emoji', () => { + expect(vm.$el.querySelector('.js-add-award')).toBeNull(); + }); + }); }); diff --git a/spec/javascripts/notes/components/note_body_spec.js b/spec/javascripts/notes/components/note_body_spec.js index 0ff804f0e55..4e551496ff0 100644 --- a/spec/javascripts/notes/components/note_body_spec.js +++ b/spec/javascripts/notes/components/note_body_spec.js @@ -18,6 +18,7 @@ describe('issue_note_body component', () => { propsData: { note, canEdit: true, + canAwardEmoji: true, }, }).$mount(); }); diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js index 2d88cee61f1..bfe3a65feee 100644 --- a/spec/javascripts/notes/mock_data.js +++ b/spec/javascripts/notes/mock_data.js @@ -9,6 +9,7 @@ export const notesDataMock = { totalNotes: 1, closePath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=close', reopenPath: '/twitter/flight/issues/9.json?issue%5Bstate_event%5D=reopen', + canAwardEmoji: true, }; export const userDataMock = { @@ -30,6 +31,7 @@ export const noteableDataMock = { current_user: { can_create_note: true, can_update: true, + can_award_emoji: true, }, description: '', due_date: null, @@ -52,6 +54,7 @@ export const noteableDataMock = { updated_at: '2017-08-04T09:53:01.226Z', updated_by_id: 1, web_url: '/gitlab-org/gitlab-ce/issues/26', + noteableType: 'issue', }; export const lastFetchedAt = '1501862675'; @@ -85,7 +88,10 @@ export const individualNote = { human_access: 'Owner', note: 'sdfdsaf', note_html: "<p dir='auto'>sdfdsaf</p>", - current_user: { can_edit: true }, + current_user: { + can_edit: true, + can_award_emoji: true, + }, discussion_id: '0fb4e0e3f9276e55ff32eb4195add694aece4edd', emoji_awardable: true, award_emoji: [ @@ -128,6 +134,7 @@ export const note = { note_html: '<p dir="auto">Vel id placeat reprehenderit sit numquam.</p>', current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: 'd3842a451b7f3d9a5dfce329515127b2d29a4cd0', emoji_awardable: true, @@ -186,6 +193,7 @@ export const discussionMock = { note_html: "<p dir='auto'>THIS IS A DICUSSSION!</p>", current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: '9e3bd2f71a01de45fd166e6719eb380ad9f270b1', emoji_awardable: true, @@ -230,6 +238,7 @@ export const discussionMock = { }, current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: '9e3bd2f71a01de45fd166e6719eb380ad9f270b1', emoji_awardable: true, @@ -274,6 +283,7 @@ export const discussionMock = { }, current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: '9e3bd2f71a01de45fd166e6719eb380ad9f270b1', emoji_awardable: true, @@ -364,6 +374,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = { note_html: '\u003cp dir="auto"\u003esdfdsaf\u003c/p\u003e', current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: '0fb4e0e3f9276e55ff32eb4195add694aece4edd', emoji_awardable: true, @@ -424,6 +435,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = { note_html: '\u003cp dir="auto"\u003eNew note!\u003c/p\u003e', current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: '70d5c92a4039a36c70100c6691c18c27e4b0a790', emoji_awardable: true, @@ -477,6 +489,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = { }, current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: 'a3ed36e29b1957efb3b68c53e2d7a2b24b1df052', emoji_awardable: true, @@ -526,6 +539,7 @@ export const DISCUSSION_NOTE_RESPONSE_MAP = { note_html: '\u003cp dir="auto"\u003eAdding a comment\u003c/p\u003e', current_user: { can_edit: true, + can_award_emoji: true, }, discussion_id: 'a3ed36e29b1957efb3b68c53e2d7a2b24b1df052', emoji_awardable: true, diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index ec56ab0e2f0..0952356c2f4 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -3,7 +3,6 @@ import $ from 'jquery'; import _ from 'underscore'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; import 'autosize'; import '~/gl_form'; import '~/lib/utils/text_utility'; @@ -222,7 +221,7 @@ import timeoutPromise from './helpers/set_timeout_promise_helper'; }); it('sets target when hash matches', () => { - spyOn(urlUtils, 'getLocationHash').and.returnValue(hash); + spyOnDependency(Notes, 'getLocationHash').and.returnValue(hash); Notes.updateNoteTargetSelector($note); @@ -231,7 +230,7 @@ import timeoutPromise from './helpers/set_timeout_promise_helper'; }); it('unsets target when hash does not match', () => { - spyOn(urlUtils, 'getLocationHash').and.returnValue('note_doesnotexist'); + spyOnDependency(Notes, 'getLocationHash').and.returnValue('note_doesnotexist'); Notes.updateNoteTargetSelector($note); @@ -239,7 +238,7 @@ import timeoutPromise from './helpers/set_timeout_promise_helper'; }); it('unsets target when there is not a hash fragment anymore', () => { - spyOn(urlUtils, 'getLocationHash').and.returnValue(null); + spyOnDependency(Notes, 'getLocationHash').and.returnValue(null); Notes.updateNoteTargetSelector($note); diff --git a/spec/javascripts/pager_spec.js b/spec/javascripts/pager_spec.js index b09494f0b77..04f2e7ef4f9 100644 --- a/spec/javascripts/pager_spec.js +++ b/spec/javascripts/pager_spec.js @@ -1,15 +1,25 @@ -/* global fixture */ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import * as utils from '~/lib/utils/url_utility'; import Pager from '~/pager'; describe('pager', () => { + let axiosMock; + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + }); + + afterEach(() => { + axiosMock.restore(); + }); + describe('init', () => { const originalHref = window.location.href; beforeEach(() => { setFixtures('<div class="content_list"></div><div class="loading"></div>'); + spyOn($.fn, 'endlessScroll').and.stub(); }); afterEach(() => { @@ -25,7 +35,7 @@ describe('pager', () => { it('should use current url if data-href attribute not provided', () => { const href = `${gl.TEST_HOST}/some_list`; - spyOn(utils, 'removeParams').and.returnValue(href); + spyOnDependency(Pager, 'removeParams').and.returnValue(href); Pager.init(); expect(Pager.url).toBe(href); }); @@ -39,42 +49,37 @@ describe('pager', () => { it('keeps extra query parameters from url', () => { window.history.replaceState({}, null, '?filter=test&offset=100'); const href = `${gl.TEST_HOST}/some_list?filter=test`; - spyOn(utils, 'removeParams').and.returnValue(href); + const removeParams = spyOnDependency(Pager, 'removeParams').and.returnValue(href); Pager.init(); - expect(utils.removeParams).toHaveBeenCalledWith(['limit', 'offset']); + expect(removeParams).toHaveBeenCalledWith(['limit', 'offset']); expect(Pager.url).toEqual(href); }); }); describe('getOld', () => { const urlRegex = /(.*)some_list(.*)$/; - let mock; function mockSuccess() { - mock.onGet(urlRegex).reply(200, { + axiosMock.onGet(urlRegex).reply(200, { count: 0, html: '', }); } function mockError() { - mock.onGet(urlRegex).networkError(); + axiosMock.onGet(urlRegex).networkError(); } beforeEach(() => { - setFixtures('<div class="content_list" data-href="/some_list"></div><div class="loading"></div>'); + setFixtures( + '<div class="content_list" data-href="/some_list"></div><div class="loading"></div>', + ); spyOn(axios, 'get').and.callThrough(); - mock = new MockAdapter(axios); - Pager.init(); }); - afterEach(() => { - mock.restore(); - }); - - it('shows loader while loading next page', (done) => { + it('shows loader while loading next page', done => { mockSuccess(); spyOn(Pager.loading, 'show'); @@ -87,7 +92,7 @@ describe('pager', () => { }); }); - it('hides loader on success', (done) => { + it('hides loader on success', done => { mockSuccess(); spyOn(Pager.loading, 'hide'); @@ -100,7 +105,7 @@ describe('pager', () => { }); }); - it('hides loader on error', (done) => { + it('hides loader on error', done => { mockError(); spyOn(Pager.loading, 'hide'); @@ -113,7 +118,7 @@ describe('pager', () => { }); }); - it('sends request to url with offset and limit params', (done) => { + it('sends request to url with offset and limit params', done => { Pager.offset = 100; Pager.limit = 20; Pager.getOld(); diff --git a/spec/javascripts/pages/admin/jobs/index/components/stop_jobs_modal_spec.js b/spec/javascripts/pages/admin/jobs/index/components/stop_jobs_modal_spec.js index a6fe9fb65e9..b69e5f9a3a0 100644 --- a/spec/javascripts/pages/admin/jobs/index/components/stop_jobs_modal_spec.js +++ b/spec/javascripts/pages/admin/jobs/index/components/stop_jobs_modal_spec.js @@ -2,7 +2,6 @@ import Vue from 'vue'; import axios from '~/lib/utils/axios_utils'; import stopJobsModal from '~/pages/admin/jobs/index/components/stop_jobs_modal.vue'; -import * as urlUtility from '~/lib/utils/url_utility'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; @@ -24,7 +23,7 @@ describe('stop_jobs_modal.vue', () => { describe('onSubmit', () => { it('stops jobs and redirects to overview page', (done) => { const responseURL = `${gl.TEST_HOST}/stop_jobs_modal.vue/jobs`; - const redirectSpy = spyOn(urlUtility, 'redirectTo'); + const redirectSpy = spyOnDependency(stopJobsModal, 'redirectTo'); spyOn(axios, 'post').and.callFake((url) => { expect(url).toBe(props.url); return Promise.resolve({ @@ -44,7 +43,7 @@ describe('stop_jobs_modal.vue', () => { it('displays error if stopping jobs failed', (done) => { const dummyError = new Error('stopping jobs failed'); - const redirectSpy = spyOn(urlUtility, 'redirectTo'); + const redirectSpy = spyOnDependency(stopJobsModal, 'redirectTo'); spyOn(axios, 'post').and.callFake((url) => { expect(url).toBe(props.url); return Promise.reject(dummyError); diff --git a/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js b/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js index 6074e06fcec..94401beb5c9 100644 --- a/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js +++ b/spec/javascripts/pages/milestones/shared/components/delete_milestone_modal_spec.js @@ -3,7 +3,6 @@ import Vue from 'vue'; import axios from '~/lib/utils/axios_utils'; import deleteMilestoneModal from '~/pages/milestones/shared/components/delete_milestone_modal.vue'; import eventHub from '~/pages/milestones/shared/event_hub'; -import * as urlUtility from '~/lib/utils/url_utility'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; @@ -40,7 +39,7 @@ describe('delete_milestone_modal.vue', () => { }, }); }); - const redirectSpy = spyOn(urlUtility, 'redirectTo'); + const redirectSpy = spyOnDependency(deleteMilestoneModal, 'redirectTo'); vm.onSubmit() .then(() => { @@ -60,7 +59,7 @@ describe('delete_milestone_modal.vue', () => { eventHub.$emit.calls.reset(); return Promise.reject(dummyError); }); - const redirectSpy = spyOn(urlUtility, 'redirectTo'); + const redirectSpy = spyOnDependency(deleteMilestoneModal, 'redirectTo'); vm.onSubmit() .catch((error) => { diff --git a/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js index f95a7cef18a..fb7d2763b49 100644 --- a/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js +++ b/spec/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js @@ -6,7 +6,7 @@ const PipelineSchedulesCalloutComponent = Vue.extend(PipelineSchedulesCallout); const cookieKey = 'pipeline_schedules_callout_dismissed'; const docsUrl = 'help/ci/scheduled_pipelines'; -describe('Pipeline Schedule Callout', () => { +describe('Pipeline Schedule Callout', function () { beforeEach(() => { setFixtures(` <div id='pipeline-schedules-callout' data-docs-url=${docsUrl}></div> diff --git a/spec/javascripts/pipelines/graph/action_component_spec.js b/spec/javascripts/pipelines/graph/action_component_spec.js index e8fcd4b1a36..3de10392472 100644 --- a/spec/javascripts/pipelines/graph/action_component_spec.js +++ b/spec/javascripts/pipelines/graph/action_component_spec.js @@ -1,32 +1,37 @@ import Vue from 'vue'; import actionComponent from '~/pipelines/components/graph/action_component.vue'; +import eventHub from '~/pipelines/event_hub'; +import mountComponent from '../../helpers/vue_mount_component_helper'; describe('pipeline graph action component', () => { let component; - beforeEach((done) => { + beforeEach(done => { const ActionComponent = Vue.extend(actionComponent); - component = new ActionComponent({ - propsData: { - tooltipText: 'bar', - link: 'foo', - actionMethod: 'post', - actionIcon: 'cancel', - }, - }).$mount(); + component = mountComponent(ActionComponent, { + tooltipText: 'bar', + link: 'foo', + actionIcon: 'cancel', + }); Vue.nextTick(done); }); - it('should render a link', () => { - expect(component.$el.getAttribute('href')).toEqual('foo'); + afterEach(() => { + component.$destroy(); + }); + + it('should emit an event with the provided link', () => { + eventHub.$on('graphAction', link => { + expect(link).toEqual('foo'); + }); }); it('should render the provided title as a bootstrap tooltip', () => { expect(component.$el.getAttribute('data-original-title')).toEqual('bar'); }); - it('should update bootstrap tooltip when title changes', (done) => { + it('should update bootstrap tooltip when title changes', done => { component.tooltipText = 'changed'; setTimeout(() => { @@ -39,4 +44,45 @@ describe('pipeline graph action component', () => { expect(component.$el.querySelector('.ci-action-icon-wrapper')).toBeDefined(); expect(component.$el.querySelector('svg')).toBeDefined(); }); + + it('disables the button when clicked', done => { + component.$el.click(); + + component.$nextTick(() => { + expect(component.$el.getAttribute('disabled')).toEqual('disabled'); + done(); + }); + }); + + it('re-enabled the button when `requestFinishedFor` matches `linkRequested`', done => { + component.$el.click(); + + component + .$nextTick() + .then(() => { + expect(component.$el.getAttribute('disabled')).toEqual('disabled'); + component.requestFinishedFor = 'foo'; + }) + .then(() => { + expect(component.$el.getAttribute('disabled')).toBeNull(); + }) + .then(done) + .catch(done.fail); + }); + + it('does not re-enable the button when `requestFinishedFor` does not matches `linkRequested`', done => { + component.$el.click(); + + component + .$nextTick() + .then(() => { + expect(component.$el.getAttribute('disabled')).toEqual('disabled'); + component.requestFinishedFor = 'bar'; + }) + .then(() => { + expect(component.$el.getAttribute('disabled')).toEqual('disabled'); + }) + .then(done) + .catch(done.fail); + }); }); diff --git a/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js b/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js deleted file mode 100644 index ba721bc53c6..00000000000 --- a/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js +++ /dev/null @@ -1,32 +0,0 @@ -import Vue from 'vue'; -import dropdownActionComponent from '~/pipelines/components/graph/dropdown_action_component.vue'; - -describe('action component', () => { - let component; - - beforeEach((done) => { - const DropdownActionComponent = Vue.extend(dropdownActionComponent); - component = new DropdownActionComponent({ - propsData: { - tooltipText: 'bar', - link: 'foo', - actionMethod: 'post', - actionIcon: 'cancel', - }, - }).$mount(); - - Vue.nextTick(done); - }); - - it('should render a link', () => { - expect(component.$el.getAttribute('href')).toEqual('foo'); - }); - - it('should render the provided title as a bootstrap tooltip', () => { - expect(component.$el.getAttribute('data-original-title')).toEqual('bar'); - }); - - it('should render an svg', () => { - expect(component.$el.querySelector('svg')).toBeDefined(); - }); -}); diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js index ce181a1e515..073dae56c25 100644 --- a/spec/javascripts/pipelines/graph/job_component_spec.js +++ b/spec/javascripts/pipelines/graph/job_component_spec.js @@ -13,6 +13,7 @@ describe('pipeline graph job component', () => { icon: 'icon_status_success', text: 'passed', label: 'passed', + tooltip: 'passed', group: 'success', details_path: '/root/ci-mock/builds/4256', has_details: true, @@ -92,17 +93,6 @@ describe('pipeline graph job component', () => { }); }); - describe('dropdown', () => { - it('should render the dropdown action icon', () => { - component = mountComponent(JobComponent, { - job: mockJob, - isDropdown: true, - }); - - expect(component.$el.querySelector('a.ci-action-icon-wrapper')).toBeDefined(); - }); - }); - it('should render provided class name', () => { component = mountComponent(JobComponent, { job: mockJob, @@ -137,6 +127,7 @@ describe('pipeline graph job component', () => { status: { icon: 'icon_status_success', label: 'success', + tooltip: 'success', }, }, }); diff --git a/spec/javascripts/pipelines/mock_data.js b/spec/javascripts/pipelines/mock_data.js new file mode 100644 index 00000000000..59092e0f041 --- /dev/null +++ b/spec/javascripts/pipelines/mock_data.js @@ -0,0 +1,326 @@ +export const pipelineWithStages = { + id: 20333396, + user: { + id: 128633, + name: 'Rémy Coutable', + username: 'rymai', + state: 'active', + avatar_url: + 'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/rymai', + path: '/rymai', + }, + active: true, + coverage: '58.24', + source: 'push', + created_at: '2018-04-11T14:04:53.881Z', + updated_at: '2018-04-11T14:05:00.792Z', + path: '/gitlab-org/gitlab-ee/pipelines/20333396', + flags: { + latest: true, + stuck: false, + auto_devops: false, + yaml_errors: false, + retryable: false, + cancelable: true, + failure_reason: false, + }, + details: { + status: { + icon: 'status_running', + text: 'running', + label: 'running', + group: 'running', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_running-2eb56be2871937954b2ba6d6f4ee9fdf7e5e1c146ac45f7be98119ccaca1aca9.ico', + }, + duration: null, + finished_at: null, + stages: [ + { + name: 'build', + title: 'build: skipped', + status: { + icon: 'status_skipped', + text: 'skipped', + label: 'skipped', + group: 'skipped', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#build', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_skipped-a2eee568a5bffdb494050c7b62dde241de9189280836288ac8923d369f16222d.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#build', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=build', + }, + { + name: 'prepare', + title: 'prepare: passed', + status: { + icon: 'status_success', + text: 'passed', + label: 'passed', + group: 'success', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#prepare', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_success-26f59841becbef8c6fe414e9e74471d8bfd6a91b5855c19fe7f5923a40a7da47.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#prepare', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=prepare', + }, + { + name: 'test', + title: 'test: running', + status: { + icon: 'status_running', + text: 'running', + label: 'running', + group: 'running', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#test', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_running-2eb56be2871937954b2ba6d6f4ee9fdf7e5e1c146ac45f7be98119ccaca1aca9.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#test', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=test', + }, + { + name: 'post-test', + title: 'post-test: created', + status: { + icon: 'status_created', + text: 'created', + label: 'created', + group: 'created', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#post-test', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#post-test', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=post-test', + }, + { + name: 'pages', + title: 'pages: created', + status: { + icon: 'status_created', + text: 'created', + label: 'created', + group: 'created', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#pages', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#pages', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=pages', + }, + { + name: 'post-cleanup', + title: 'post-cleanup: created', + status: { + icon: 'status_created', + text: 'created', + label: 'created', + group: 'created', + has_details: true, + details_path: '/gitlab-org/gitlab-ee/pipelines/20333396#post-cleanup', + favicon: + 'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico', + }, + path: '/gitlab-org/gitlab-ee/pipelines/20333396#post-cleanup', + dropdown_path: '/gitlab-org/gitlab-ee/pipelines/20333396/stage.json?stage=post-cleanup', + }, + ], + artifacts: [ + { + name: 'gitlab:assets:compile', + expired: false, + expire_at: '2018-05-12T14:22:54.730Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411438/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411438/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411438/artifacts/browse', + }, + { + name: 'rspec-mysql 12 28', + expired: false, + expire_at: '2018-05-12T14:22:45.136Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411397/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411397/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411397/artifacts/browse', + }, + { + name: 'rspec-mysql 6 28', + expired: false, + expire_at: '2018-05-12T14:22:41.523Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411391/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411391/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411391/artifacts/browse', + }, + { + name: 'rspec-pg geo 0 1', + expired: false, + expire_at: '2018-05-12T14:22:13.287Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411353/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411353/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411353/artifacts/browse', + }, + { + name: 'rspec-mysql 0 28', + expired: false, + expire_at: '2018-05-12T14:22:06.834Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411385/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411385/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411385/artifacts/browse', + }, + { + name: 'spinach-mysql 0 2', + expired: false, + expire_at: '2018-05-12T14:21:51.409Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411423/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411423/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411423/artifacts/browse', + }, + { + name: 'karma', + expired: false, + expire_at: '2018-05-12T14:21:20.934Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411440/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411440/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411440/artifacts/browse', + }, + { + name: 'spinach-pg 0 2', + expired: false, + expire_at: '2018-05-12T14:20:01.028Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411419/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411419/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411419/artifacts/browse', + }, + { + name: 'spinach-pg 1 2', + expired: false, + expire_at: '2018-05-12T14:19:04.336Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411421/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411421/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411421/artifacts/browse', + }, + { + name: 'sast', + expired: null, + expire_at: null, + path: '/gitlab-org/gitlab-ee/-/jobs/62411442/artifacts/download', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411442/artifacts/browse', + }, + { + name: 'codequality', + expired: false, + expire_at: '2018-04-18T14:16:24.484Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411441/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411441/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411441/artifacts/browse', + }, + { + name: 'cache gems', + expired: null, + expire_at: null, + path: '/gitlab-org/gitlab-ee/-/jobs/62411447/artifacts/download', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411447/artifacts/browse', + }, + { + name: 'dependency_scanning', + expired: null, + expire_at: null, + path: '/gitlab-org/gitlab-ee/-/jobs/62411443/artifacts/download', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411443/artifacts/browse', + }, + { + name: 'compile-assets', + expired: false, + expire_at: '2018-04-18T14:12:07.638Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411334/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411334/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411334/artifacts/browse', + }, + { + name: 'setup-test-env', + expired: false, + expire_at: '2018-04-18T14:10:27.024Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411336/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411336/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411336/artifacts/browse', + }, + { + name: 'retrieve-tests-metadata', + expired: false, + expire_at: '2018-05-12T14:06:35.926Z', + path: '/gitlab-org/gitlab-ee/-/jobs/62411333/artifacts/download', + keep_path: '/gitlab-org/gitlab-ee/-/jobs/62411333/artifacts/keep', + browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411333/artifacts/browse', + }, + ], + manual_actions: [ + { + name: 'package-and-qa', + path: '/gitlab-org/gitlab-ee/-/jobs/62411330/play', + playable: true, + }, + { + name: 'review-docs-deploy', + path: '/gitlab-org/gitlab-ee/-/jobs/62411332/play', + playable: true, + }, + ], + }, + ref: { + name: 'master', + path: '/gitlab-org/gitlab-ee/commits/master', + tag: false, + branch: true, + }, + commit: { + id: 'e6a2885c503825792cb8a84a8731295e361bd059', + short_id: 'e6a2885c', + title: "Merge branch 'ce-to-ee-2018-04-11' into 'master'", + created_at: '2018-04-11T14:04:39.000Z', + parent_ids: [ + '5d9b5118f6055f72cff1a82b88133609912f2c1d', + '6fdc6ee76a8062fe41b1a33f7c503334a6ebdc02', + ], + message: + "Merge branch 'ce-to-ee-2018-04-11' into 'master'\n\nCE upstream - 2018-04-11 12:26 UTC\n\nSee merge request gitlab-org/gitlab-ee!5326", + author_name: 'Rémy Coutable', + author_email: 'remy@rymai.me', + authored_date: '2018-04-11T14:04:39.000Z', + committer_name: 'Rémy Coutable', + committer_email: 'remy@rymai.me', + committed_date: '2018-04-11T14:04:39.000Z', + author: { + id: 128633, + name: 'Rémy Coutable', + username: 'rymai', + state: 'active', + avatar_url: + 'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/rymai', + path: '/rymai', + }, + author_gravatar_url: + 'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon', + commit_url: + 'https://gitlab.com/gitlab-org/gitlab-ee/commit/e6a2885c503825792cb8a84a8731295e361bd059', + commit_path: '/gitlab-org/gitlab-ee/commit/e6a2885c503825792cb8a84a8731295e361bd059', + }, + cancel_path: '/gitlab-org/gitlab-ee/pipelines/20333396/cancel', + triggered_by: null, + triggered: [], +}; + +export const stageReply = { + html: + '\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="karma - failed \u0026lt;br\u0026gt; (script failure)" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62402048"\u003e\u003cspan class="ci-status-icon ci-status-icon-failed"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_failed"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003ekarma\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62402048/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="codequality - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398081"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003ecodequality\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398081/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="db:check-schema-pg - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398066"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edb:check-schema-pg\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398066/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="db:migrate:reset-mysql - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398065"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edb:migrate:reset-mysql\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398065/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="db:migrate:reset-pg - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398064"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edb:migrate:reset-pg\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398064/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="db:rollback-mysql - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398070"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edb:rollback-mysql\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398070/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="db:rollback-pg - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398069"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edb:rollback-pg\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398069/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="dependency_scanning - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398083"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edependency_scanning\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398083/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="docs lint - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398061"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edocs lint\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398061/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="downtime_check - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398062"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003edowntime_check\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398062/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="ee_compat_check - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398063"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003eee_compat_check\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398063/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="gitlab:assets:compile - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398075"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003egitlab:assets:compile\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398075/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="gitlab:setup-mysql - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398073"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003egitlab:setup-mysql\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398073/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="gitlab:setup-pg - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398071"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003egitlab:setup-pg\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398071/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="gitlab_git_test - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398086"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003egitlab_git_test\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398086/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="migration:path-mysql - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398068"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003emigration:path-mysql\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398068/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="migration:path-pg - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398067"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003emigration:path-pg\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398067/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="qa:internal - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398084"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003eqa:internal\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398084/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="qa:selectors - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398085"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003eqa:selectors\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398085/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 0 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398020"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 0 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398020/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 1 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398022"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 1 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398022/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 10 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398033"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 10 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398033/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 11 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398034"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 11 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398034/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 12 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398035"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 12 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398035/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 13 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398036"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 13 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398036/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 14 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398037"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 14 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398037/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 15 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398038"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 15 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398038/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 16 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398039"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 16 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398039/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 17 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398040"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 17 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398040/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 18 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398041"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 18 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398041/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 19 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398042"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 19 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398042/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 2 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398024"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 2 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398024/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 20 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398043"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 20 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398043/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 21 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398044"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 21 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398044/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 22 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398046"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 22 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398046/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 23 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398047"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 23 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398047/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 24 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398048"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 24 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398048/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 25 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398049"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 25 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398049/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 26 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398050"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 26 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398050/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 27 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398051"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 27 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398051/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 3 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398025"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 3 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398025/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 4 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398027"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 4 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398027/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 5 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398028"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 5 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398028/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 6 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398029"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 6 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398029/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 7 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398030"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 7 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398030/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 8 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398031"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 8 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398031/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-mysql 9 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398032"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-mysql 9 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398032/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 0 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397981"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 0 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397981/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 1 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397985"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 1 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397985/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 10 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398000"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 10 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398000/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 11 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398001"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 11 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398001/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 12 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398002"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 12 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398002/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 13 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398003"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 13 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398003/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 14 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398004"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 14 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398004/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 15 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398006"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 15 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398006/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 16 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398007"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 16 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398007/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 17 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398008"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 17 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398008/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 18 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398009"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 18 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398009/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 19 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398010"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 19 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398010/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 2 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397986"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 2 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397986/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 20 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398012"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 20 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398012/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 21 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398013"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 21 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398013/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 22 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398014"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 22 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398014/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 23 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398015"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 23 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398015/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 24 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398016"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 24 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398016/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 25 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398017"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 25 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398017/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 26 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398018"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 26 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398018/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 27 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398019"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 27 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398019/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 3 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397988"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 3 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397988/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 4 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397989"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 4 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397989/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 5 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397991"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 5 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397991/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 6 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397993"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 6 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397993/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 7 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397994"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 7 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397994/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 8 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397995"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 8 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397995/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="rspec-pg 9 28 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62397996"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003erspec-pg 9 28\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62397996/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="sast - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398082"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003esast\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398082/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="spinach-mysql 0 2 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398058"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003espinach-mysql 0 2\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398058/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="spinach-mysql 1 2 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398059"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003espinach-mysql 1 2\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398059/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="spinach-pg 0 2 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398053"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003espinach-pg 0 2\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398053/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="spinach-pg 1 2 - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398056"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003espinach-pg 1 2\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398056/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca class="mini-pipeline-graph-dropdown-item" data-toggle="tooltip" data-title="static-analysis - passed" data-html="true" data-container="body" href="/gitlab-org/gitlab-ce/-/jobs/62398060"\u003e\u003cspan class="ci-status-icon ci-status-icon-success"\u003e\u003csvg\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#status_success"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/span\u003e\n\u003cspan class="ci-build-text"\u003estatic-analysis\u003c/span\u003e\n\u003c/a\u003e\u003ca class="ci-action-icon-wrapper js-ci-action-icon" data-toggle="tooltip" data-title="Retry" data-container="body" rel="nofollow" data-method="post" href="/gitlab-org/gitlab-ce/-/jobs/62398060/retry"\u003e\u003csvg class=" icon-action-retry"\u003e\u003cuse xlink:href="https://gitlab.com/assets/icons-fe86f87a3d244c952cc0ec8d7f88c5effefcbe454d751d8449d4a1a32aaaf9a0.svg#retry"\u003e\u003c/use\u003e\u003c/svg\u003e\n\u003c/a\u003e\n\u003c/li\u003e\n', +}; diff --git a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js b/spec/javascripts/pipelines/pipeline_details_mediator_spec.js index e58a8018ed5..61ee2dc13ca 100644 --- a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js +++ b/spec/javascripts/pipelines/pipeline_details_mediator_spec.js @@ -1,42 +1,36 @@ -import _ from 'underscore'; -import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import PipelineMediator from '~/pipelines/pipeline_details_mediator'; describe('PipelineMdediator', () => { let mediator; + let mock; + beforeEach(() => { - mediator = new PipelineMediator({ endpoint: 'foo' }); + mock = new MockAdapter(axios); + mediator = new PipelineMediator({ endpoint: 'foo.json' }); + }); + + afterEach(() => { + mock.restore(); }); it('should set defaults', () => { - expect(mediator.options).toEqual({ endpoint: 'foo' }); + expect(mediator.options).toEqual({ endpoint: 'foo.json' }); expect(mediator.state.isLoading).toEqual(false); expect(mediator.store).toBeDefined(); expect(mediator.service).toBeDefined(); }); describe('request and store data', () => { - const interceptor = (request, next) => { - next(request.respondWith(JSON.stringify({ foo: 'bar' }), { - status: 200, - })); - }; - - beforeEach(() => { - Vue.http.interceptors.push(interceptor); - }); - - afterEach(() => { - Vue.http.interceptors = _.without(Vue.http.interceptor, interceptor); - }); - - it('should store received data', (done) => { + it('should store received data', done => { + mock.onGet('foo.json').reply(200, { id: '121123' }); mediator.fetchPipeline(); setTimeout(() => { - expect(mediator.store.state.pipeline).toEqual({ foo: 'bar' }); + expect(mediator.store.state.pipeline).toEqual({ id: '121123' }); done(); - }); + }, 0); }); }); }); diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js index 7e242eb45e1..ff17602da2b 100644 --- a/spec/javascripts/pipelines/pipelines_spec.js +++ b/spec/javascripts/pipelines/pipelines_spec.js @@ -1,8 +1,10 @@ -import _ from 'underscore'; import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import pipelinesComp from '~/pipelines/components/pipelines.vue'; import Store from '~/pipelines/stores/pipelines_store'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { pipelineWithStages, stageReply } from './mock_data'; describe('Pipelines', () => { const jsonFixtureName = 'pipelines/pipelines.json'; @@ -12,6 +14,8 @@ describe('Pipelines', () => { let PipelinesComponent; let pipelines; let vm; + let mock; + const paths = { endpoint: 'twitter/flight/pipelines.json', autoDevopsPath: '/help/topics/autodevops/index.md', @@ -34,6 +38,8 @@ describe('Pipelines', () => { }; beforeEach(() => { + mock = new MockAdapter(axios); + pipelines = getJSONFixture(jsonFixtureName); PipelinesComponent = Vue.extend(pipelinesComp); @@ -41,38 +47,14 @@ describe('Pipelines', () => { afterEach(() => { vm.$destroy(); + mock.restore(); }); - const pipelinesInterceptor = (request, next) => { - next(request.respondWith(JSON.stringify(pipelines), { - status: 200, - })); - }; - - const emptyStateInterceptor = (request, next) => { - next(request.respondWith(JSON.stringify({ - pipelines: [], - count: { - all: 0, - pending: 0, - running: 0, - finished: 0, - }, - }), { - status: 200, - })); - }; - - const errorInterceptor = (request, next) => { - next(request.respondWith(JSON.stringify({}), { - status: 500, - })); - }; - describe('With permission', () => { describe('With pipelines in main tab', () => { beforeEach((done) => { - Vue.http.interceptors.push(pipelinesInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: true, @@ -85,12 +67,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesInterceptor, - ); - }); - it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -116,7 +92,15 @@ describe('Pipelines', () => { describe('Without pipelines on main tab with CI', () => { beforeEach((done) => { - Vue.http.interceptors.push(emptyStateInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, { + pipelines: [], + count: { + all: 0, + pending: 0, + running: 0, + finished: 0, + }, + }); vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: true, @@ -129,12 +113,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, emptyStateInterceptor, - ); - }); - it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -158,7 +136,15 @@ describe('Pipelines', () => { describe('Without pipelines nor CI', () => { beforeEach((done) => { - Vue.http.interceptors.push(emptyStateInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, { + pipelines: [], + count: { + all: 0, + pending: 0, + running: 0, + finished: 0, + }, + }); vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: false, @@ -171,12 +157,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, emptyStateInterceptor, - ); - }); - it('renders empty state', () => { expect(vm.$el.querySelector('.js-empty-state h4').textContent.trim()).toEqual('Build with confidence'); expect(vm.$el.querySelector('.js-get-started-pipelines').getAttribute('href')).toEqual(paths.helpPagePath); @@ -192,7 +172,7 @@ describe('Pipelines', () => { describe('When API returns error', () => { beforeEach((done) => { - Vue.http.interceptors.push(errorInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(500, {}); vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: false, @@ -205,12 +185,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, errorInterceptor, - ); - }); - it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -230,7 +204,8 @@ describe('Pipelines', () => { describe('Without permission', () => { describe('With pipelines in main tab', () => { beforeEach((done) => { - Vue.http.interceptors.push(pipelinesInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: false, @@ -243,12 +218,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesInterceptor, - ); - }); - it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -268,7 +237,16 @@ describe('Pipelines', () => { describe('Without pipelines on main tab with CI', () => { beforeEach((done) => { - Vue.http.interceptors.push(emptyStateInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, { + pipelines: [], + count: { + all: 0, + pending: 0, + running: 0, + finished: 0, + }, + }); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: true, @@ -281,11 +259,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, emptyStateInterceptor, - ); - }); it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -303,7 +276,16 @@ describe('Pipelines', () => { describe('Without pipelines nor CI', () => { beforeEach((done) => { - Vue.http.interceptors.push(emptyStateInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, { + pipelines: [], + count: { + all: 0, + pending: 0, + running: 0, + finished: 0, + }, + }); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: false, @@ -316,12 +298,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, emptyStateInterceptor, - ); - }); - it('renders empty state without button to set CI', () => { expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toEqual('This project is not currently set up to run pipelines.'); expect(vm.$el.querySelector('.js-get-started-pipelines')).toBeNull(); @@ -337,7 +313,8 @@ describe('Pipelines', () => { describe('When API returns error', () => { beforeEach((done) => { - Vue.http.interceptors.push(errorInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(500, {}); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: false, @@ -350,12 +327,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, errorInterceptor, - ); - }); - it('renders tabs', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); @@ -375,7 +346,8 @@ describe('Pipelines', () => { describe('successfull request', () => { describe('with pipelines', () => { beforeEach(() => { - Vue.http.interceptors.push(pipelinesInterceptor); + mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines); + vm = mountComponent(PipelinesComponent, { store: new Store(), hasGitlabCi: true, @@ -384,12 +356,6 @@ describe('Pipelines', () => { }); }); - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, pipelinesInterceptor, - ); - }); - it('should render table', (done) => { setTimeout(() => { expect(vm.$el.querySelector('.table-holder')).toBeDefined(); @@ -703,4 +669,79 @@ describe('Pipelines', () => { }); }); }); + + describe('updates results when a staged is clicked', () => { + beforeEach(() => { + const copyPipeline = Object.assign({}, pipelineWithStages); + copyPipeline.id += 1; + mock + .onGet('twitter/flight/pipelines.json').reply(200, { + pipelines: [pipelineWithStages], + count: { + all: 1, + finished: 1, + pending: 0, + running: 0, + }, + }, { + 'POLL-INTERVAL': 100, + }) + .onGet(pipelineWithStages.details.stages[0].dropdown_path) + .reply(200, stageReply); + + vm = mountComponent(PipelinesComponent, { + store: new Store(), + hasGitlabCi: true, + canCreatePipeline: true, + ...paths, + }); + }); + + describe('when a request is being made', () => { + it('stops polling, cancels the request, fetches pipelines & restarts polling', (done) => { + spyOn(vm.poll, 'stop'); + spyOn(vm.poll, 'restart'); + spyOn(vm, 'getPipelines').and.returnValue(Promise.resolve()); + spyOn(vm.service.cancelationSource, 'cancel').and.callThrough(); + + setTimeout(() => { + vm.isMakingRequest = true; + return vm.$nextTick() + .then(() => { + vm.$el.querySelector('.js-builds-dropdown-button').click(); + }) + .then(() => { + expect(vm.service.cancelationSource.cancel).toHaveBeenCalled(); + expect(vm.poll.stop).toHaveBeenCalled(); + + setTimeout(() => { + expect(vm.getPipelines).toHaveBeenCalled(); + expect(vm.poll.restart).toHaveBeenCalled(); + done(); + }, 0); + }); + }, 0); + }); + }); + + describe('when no request is being made', () => { + it('stops polling, fetches pipelines & restarts polling', (done) => { + spyOn(vm.poll, 'stop'); + spyOn(vm.poll, 'restart'); + spyOn(vm, 'getPipelines').and.returnValue(Promise.resolve()); + + setTimeout(() => { + vm.$el.querySelector('.js-builds-dropdown-button').click(); + + expect(vm.poll.stop).toHaveBeenCalled(); + + setTimeout(() => { + expect(vm.getPipelines).toHaveBeenCalled(); + expect(vm.poll.restart).toHaveBeenCalled(); + done(); + }, 0); + }, 0); + }); + }); + }); }); diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js index 61c2f783acc..be1632e7206 100644 --- a/spec/javascripts/pipelines/stage_spec.js +++ b/spec/javascripts/pipelines/stage_spec.js @@ -1,27 +1,36 @@ -import _ from 'underscore'; import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import stage from '~/pipelines/components/stage.vue'; +import eventHub from '~/pipelines/event_hub'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('Pipelines stage component', () => { let StageComponent; let component; + let mock; beforeEach(() => { + mock = new MockAdapter(axios); + StageComponent = Vue.extend(stage); - component = new StageComponent({ - propsData: { - stage: { - status: { - group: 'success', - icon: 'icon_status_success', - title: 'success', - }, - dropdown_path: 'foo', + component = mountComponent(StageComponent, { + stage: { + status: { + group: 'success', + icon: 'icon_status_success', + title: 'success', }, - updateDropdown: false, + dropdown_path: 'path.json', }, - }).$mount(); + updateDropdown: false, + }); + }); + + afterEach(() => { + component.$destroy(); + mock.restore(); }); it('should render a dropdown with the status icon', () => { @@ -31,49 +40,27 @@ describe('Pipelines stage component', () => { }); describe('with successfull request', () => { - const interceptor = (request, next) => { - next(request.respondWith(JSON.stringify({ html: 'foo' }), { - status: 200, - })); - }; - beforeEach(() => { - Vue.http.interceptors.push(interceptor); - }); - - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, interceptor, - ); + mock.onGet('path.json').reply(200, { html: 'foo' }); }); - it('should render the received data', (done) => { + it('should render the received data and emit `clickedDropdown` event', done => { + spyOn(eventHub, '$emit'); component.$el.querySelector('button').click(); setTimeout(() => { expect( component.$el.querySelector('.js-builds-dropdown-container ul').textContent.trim(), ).toEqual('foo'); + expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown'); done(); }, 0); }); }); describe('when request fails', () => { - const interceptor = (request, next) => { - next(request.respondWith(JSON.stringify({}), { - status: 500, - })); - }; - beforeEach(() => { - Vue.http.interceptors.push(interceptor); - }); - - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, interceptor, - ); + mock.onGet('path.json').reply(500); }); it('should close the dropdown', () => { @@ -86,33 +73,18 @@ describe('Pipelines stage component', () => { }); describe('update endpoint correctly', () => { - const updatedInterceptor = (request, next) => { - if (request.url === 'bar') { - next(request.respondWith(JSON.stringify({ html: 'this is the updated content' }), { - status: 200, - })); - } - next(); - }; - beforeEach(() => { - Vue.http.interceptors.push(updatedInterceptor); - }); - - afterEach(() => { - Vue.http.interceptors = _.without( - Vue.http.interceptors, updatedInterceptor, - ); + mock.onGet('bar.json').reply(200, { html: 'this is the updated content' }); }); - it('should update the stage to request the new endpoint provided', (done) => { + it('should update the stage to request the new endpoint provided', done => { component.stage = { status: { group: 'running', icon: 'running', title: 'running', }, - dropdown_path: 'bar', + dropdown_path: 'bar.json', }; Vue.nextTick(() => { @@ -121,7 +93,7 @@ describe('Pipelines stage component', () => { setTimeout(() => { expect( component.$el.querySelector('.js-builds-dropdown-container ul').textContent.trim(), - ).toEqual('this is the updated content'); + ).toEqual('this is the updated content'); done(); }); }); diff --git a/spec/javascripts/profile/account/components/update_username_spec.js b/spec/javascripts/profile/account/components/update_username_spec.js new file mode 100644 index 00000000000..bac306edf5a --- /dev/null +++ b/spec/javascripts/profile/account/components/update_username_spec.js @@ -0,0 +1,172 @@ +import Vue from 'vue'; +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; + +import updateUsername from '~/profile/account/components/update_username.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('UpdateUsername component', () => { + const rootUrl = gl.TEST_HOST; + const actionUrl = `${gl.TEST_HOST}/update/username`; + const username = 'hasnoname'; + const newUsername = 'new_username'; + let Component; + let vm; + let axiosMock; + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + Component = Vue.extend(updateUsername); + vm = mountComponent(Component, { + actionUrl, + rootUrl, + initialUsername: username, + }); + }); + + afterEach(() => { + vm.$destroy(); + axiosMock.restore(); + }); + + const findElements = () => { + const modalSelector = `#${vm.$options.modalId}`; + + return { + input: vm.$el.querySelector(`#${vm.$options.inputId}`), + openModalBtn: vm.$el.querySelector(`[data-target="${modalSelector}"]`), + modal: vm.$el.querySelector(modalSelector), + modalBody: vm.$el.querySelector(`${modalSelector} .modal-body`), + modalHeader: vm.$el.querySelector(`${modalSelector} .modal-title`), + confirmModalBtn: vm.$el.querySelector(`${modalSelector} .btn-warning`), + }; + }; + + it('has a disabled button if the username was not changed', done => { + const { input, openModalBtn } = findElements(); + input.dispatchEvent(new Event('input')); + + Vue.nextTick() + .then(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(username); + expect(openModalBtn).toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('has an enabled button which if the username was changed', done => { + const { input, openModalBtn } = findElements(); + input.value = newUsername; + input.dispatchEvent(new Event('input')); + + Vue.nextTick() + .then(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(newUsername); + expect(openModalBtn).not.toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('confirmation modal contains proper header and body', done => { + const { modalBody, modalHeader } = findElements(); + + vm.newUsername = newUsername; + + Vue.nextTick() + .then(() => { + expect(modalHeader.textContent).toContain('Change username?'); + expect(modalBody.textContent).toContain( + `You are going to change the username ${username} to ${newUsername}`, + ); + }) + .then(done) + .catch(done.fail); + }); + + it('confirmation modal should escape usernames properly', done => { + const { modalBody } = findElements(); + + vm.username = vm.newUsername = '<i>Italic</i>'; + + Vue.nextTick() + .then(() => { + expect(modalBody.innerHTML).toContain('<i>Italic</i>'); + expect(modalBody.innerHTML).not.toContain(vm.username); + }) + .then(done) + .catch(done.fail); + }); + + it('executes API call on confirmation button click', done => { + const { confirmModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => [200, { message: 'Username changed' }]); + spyOn(axios, 'put').and.callThrough(); + + vm.newUsername = newUsername; + + Vue.nextTick() + .then(() => { + confirmModalBtn.click(); + expect(axios.put).toHaveBeenCalledWith(actionUrl, { user: { username: newUsername } }); + }) + .then(done) + .catch(done.fail); + }); + + it('sets the username after a successful update', done => { + const { input, openModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => { + expect(input).toBeDisabled(); + expect(openModalBtn).toBeDisabled(); + + return [200, { message: 'Username changed' }]; + }); + + vm.newUsername = newUsername; + + vm + .onConfirm() + .then(() => { + expect(vm.username).toBe(newUsername); + expect(vm.newUsername).toBe(newUsername); + expect(input).not.toBeDisabled(); + expect(input.value).toBe(newUsername); + expect(openModalBtn).toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); + + it('does not set the username after a erroneous update', done => { + const { input, openModalBtn } = findElements(); + + axiosMock.onPut(actionUrl).replyOnce(() => { + expect(input).toBeDisabled(); + expect(openModalBtn).toBeDisabled(); + + return [400, { message: 'Invalid username' }]; + }); + + const invalidUsername = 'anything.git'; + vm.newUsername = invalidUsername; + + vm + .onConfirm() + .then(() => done.fail('Expected onConfirm to throw!')) + .catch(() => { + expect(vm.username).toBe(username); + expect(vm.newUsername).toBe(invalidUsername); + expect(input).not.toBeDisabled(); + expect(input.value).toBe(invalidUsername); + expect(openModalBtn).not.toBeDisabled(); + }) + .then(done) + .catch(done.fail); + }); +}); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 80770a61011..e264b16335f 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -9,8 +9,6 @@ import Sidebar from '~/right_sidebar'; (function() { var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState; - this.sidebar = null; - $aside = null; $toggle = null; @@ -43,7 +41,7 @@ import Sidebar from '~/right_sidebar'; beforeEach(function() { loadFixtures(fixtureName); mock = new MockAdapter(axios); - this.sidebar = new Sidebar(); + new Sidebar(); // eslint-disable-line no-new $aside = $('.right-sidebar'); $page = $('.layout-page'); $icon = $aside.find('i'); diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 40115792652..4f515f98a7e 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -4,10 +4,22 @@ import $ from 'jquery'; import '~/gl_dropdown'; import SearchAutocomplete from '~/search_autocomplete'; import '~/lib/utils/common_utils'; -import * as urlUtils from '~/lib/utils/url_utility'; -(function() { - var assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; +describe('Search autocomplete dropdown', () => { + var assertLinks, + dashboardIssuesPath, + dashboardMRsPath, + groupIssuesPath, + groupMRsPath, + groupName, + mockDashboardOptions, + mockGroupOptions, + mockProjectOptions, + projectIssuesPath, + projectMRsPath, + projectName, + userId, + widget; var userName = 'root'; widget = null; @@ -66,133 +78,123 @@ import * as urlUtils from '~/lib/utils/url_utility'; // Mock `gl` object in window for dashboard specific page. App code will need it. mockDashboardOptions = function() { window.gl || (window.gl = {}); - return window.gl.dashboardOptions = { + return (window.gl.dashboardOptions = { issuesPath: dashboardIssuesPath, - mrPath: dashboardMRsPath - }; + mrPath: dashboardMRsPath, + }); }; // Mock `gl` object in window for project specific page. App code will need it. mockProjectOptions = function() { window.gl || (window.gl = {}); - return window.gl.projectOptions = { + return (window.gl.projectOptions = { 'gitlab-ce': { issuesPath: projectIssuesPath, mrPath: projectMRsPath, - projectName: projectName - } - }; + projectName: projectName, + }, + }); }; mockGroupOptions = function() { window.gl || (window.gl = {}); - return window.gl.groupOptions = { + return (window.gl.groupOptions = { 'gitlab-org': { issuesPath: groupIssuesPath, mrPath: groupMRsPath, - projectName: groupName - } - }; + projectName: groupName, + }, + }); }; assertLinks = function(list, issuesPath, mrsPath) { - var a1, a2, a3, a4, issuesAssignedToMeLink, issuesIHaveCreatedLink, mrsAssignedToMeLink, mrsIHaveCreatedLink; if (issuesPath) { - issuesAssignedToMeLink = issuesPath + "/?assignee_username=" + userName; - issuesIHaveCreatedLink = issuesPath + "/?author_username=" + userName; - a1 = "a[href='" + issuesAssignedToMeLink + "']"; - a2 = "a[href='" + issuesIHaveCreatedLink + "']"; - expect(list.find(a1).length).toBe(1); - expect(list.find(a1).text()).toBe('Issues assigned to me'); - expect(list.find(a2).length).toBe(1); - expect(list.find(a2).text()).toBe("Issues I've created"); + const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_id=${userId}"]`; + const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_id=${userId}"]`; + expect(list.find(issuesAssignedToMeLink).length).toBe(1); + expect(list.find(issuesAssignedToMeLink).text()).toBe('Issues assigned to me'); + expect(list.find(issuesIHaveCreatedLink).length).toBe(1); + expect(list.find(issuesIHaveCreatedLink).text()).toBe("Issues I've created"); } - mrsAssignedToMeLink = mrsPath + "/?assignee_username=" + userName; - mrsIHaveCreatedLink = mrsPath + "/?author_username=" + userName; - a3 = "a[href='" + mrsAssignedToMeLink + "']"; - a4 = "a[href='" + mrsIHaveCreatedLink + "']"; - expect(list.find(a3).length).toBe(1); - expect(list.find(a3).text()).toBe('Merge requests assigned to me'); - expect(list.find(a4).length).toBe(1); - return expect(list.find(a4).text()).toBe("Merge requests I've created"); + const mrsAssignedToMeLink = `a[href="${mrsPath}/?assignee_id=${userId}"]`; + const mrsIHaveCreatedLink = `a[href="${mrsPath}/?author_id=${userId}"]`; + expect(list.find(mrsAssignedToMeLink).length).toBe(1); + expect(list.find(mrsAssignedToMeLink).text()).toBe('Merge requests assigned to me'); + expect(list.find(mrsIHaveCreatedLink).length).toBe(1); + expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created"); }; - describe('Search autocomplete dropdown', function() { - preloadFixtures('static/search_autocomplete.html.raw'); - beforeEach(function() { - loadFixtures('static/search_autocomplete.html.raw'); + preloadFixtures('static/search_autocomplete.html.raw'); + beforeEach(function() { + loadFixtures('static/search_autocomplete.html.raw'); - // Prevent turbolinks from triggering within gl_dropdown - spyOn(urlUtils, 'visitUrl').and.returnValue(true); + window.gon = {}; + window.gon.current_user_id = userId; + window.gon.current_username = userName; - window.gon = {}; - window.gon.current_user_id = userId; - window.gon.current_username = userName; - - return widget = new SearchAutocomplete(); - }); + return (widget = new SearchAutocomplete()); + }); - afterEach(function() { - // Undo what we did to the shared <body> - removeBodyAttributes(); - window.gon = {}; - }); - it('should show Dashboard specific dropdown menu', function() { - var list; - addBodyAttributes(); - mockDashboardOptions(); - widget.searchInput.triggerHandler('focus'); - list = widget.wrap.find('.dropdown-menu').find('ul'); - return assertLinks(list, dashboardIssuesPath, dashboardMRsPath); - }); - it('should show Group specific dropdown menu', function() { - var list; - addBodyAttributes('group'); - mockGroupOptions(); - widget.searchInput.triggerHandler('focus'); - list = widget.wrap.find('.dropdown-menu').find('ul'); - return assertLinks(list, groupIssuesPath, groupMRsPath); - }); - it('should show Project specific dropdown menu', function() { - var list; - addBodyAttributes('project'); - mockProjectOptions(); - widget.searchInput.triggerHandler('focus'); - list = widget.wrap.find('.dropdown-menu').find('ul'); - return assertLinks(list, projectIssuesPath, projectMRsPath); - }); - it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() { - addBodyAttributes('project'); - disableProjectIssues(); - mockProjectOptions(); - widget.searchInput.triggerHandler('focus'); - const list = widget.wrap.find('.dropdown-menu').find('ul'); - assertLinks(list, null, projectMRsPath); - }); - it('should not show category related menu if there is text in the input', function() { - var link, list; - addBodyAttributes('project'); - mockProjectOptions(); - widget.searchInput.val('help'); - widget.searchInput.triggerHandler('focus'); - list = widget.wrap.find('.dropdown-menu').find('ul'); - link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']"; - return expect(list.find(link).length).toBe(0); - }); - return it('should not submit the search form when selecting an autocomplete row with the keyboard', function() { - var ENTER = 13; - var DOWN = 40; - addBodyAttributes(); - mockDashboardOptions(true); - var submitSpy = spyOnEvent('form', 'submit'); - widget.searchInput.triggerHandler('focus'); - widget.wrap.trigger($.Event('keydown', { which: DOWN })); - var enterKeyEvent = $.Event('keydown', { which: ENTER }); - widget.searchInput.trigger(enterKeyEvent); - // This does not currently catch failing behavior. For security reasons, - // browsers will not trigger default behavior (form submit, in this - // example) on JavaScript-created keypresses. - expect(submitSpy).not.toHaveBeenTriggered(); - }); + afterEach(function() { + // Undo what we did to the shared <body> + removeBodyAttributes(); + window.gon = {}; + }); + it('should show Dashboard specific dropdown menu', function() { + var list; + addBodyAttributes(); + mockDashboardOptions(); + widget.searchInput.triggerHandler('focus'); + list = widget.wrap.find('.dropdown-menu').find('ul'); + return assertLinks(list, dashboardIssuesPath, dashboardMRsPath); + }); + it('should show Group specific dropdown menu', function() { + var list; + addBodyAttributes('group'); + mockGroupOptions(); + widget.searchInput.triggerHandler('focus'); + list = widget.wrap.find('.dropdown-menu').find('ul'); + return assertLinks(list, groupIssuesPath, groupMRsPath); + }); + it('should show Project specific dropdown menu', function() { + var list; + addBodyAttributes('project'); + mockProjectOptions(); + widget.searchInput.triggerHandler('focus'); + list = widget.wrap.find('.dropdown-menu').find('ul'); + return assertLinks(list, projectIssuesPath, projectMRsPath); + }); + it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() { + addBodyAttributes('project'); + disableProjectIssues(); + mockProjectOptions(); + widget.searchInput.triggerHandler('focus'); + const list = widget.wrap.find('.dropdown-menu').find('ul'); + assertLinks(list, null, projectMRsPath); + }); + it('should not show category related menu if there is text in the input', function() { + var link, list; + addBodyAttributes('project'); + mockProjectOptions(); + widget.searchInput.val('help'); + widget.searchInput.triggerHandler('focus'); + list = widget.wrap.find('.dropdown-menu').find('ul'); + link = "a[href='" + projectIssuesPath + '/?assignee_id=' + userId + "']"; + return expect(list.find(link).length).toBe(0); + }); + it('should not submit the search form when selecting an autocomplete row with the keyboard', function() { + var ENTER = 13; + var DOWN = 40; + addBodyAttributes(); + mockDashboardOptions(true); + var submitSpy = spyOnEvent('form', 'submit'); + widget.searchInput.triggerHandler('focus'); + widget.wrap.trigger($.Event('keydown', { which: DOWN })); + var enterKeyEvent = $.Event('keydown', { which: ENTER }); + widget.searchInput.trigger(enterKeyEvent); + // This does not currently catch failing behavior. For security reasons, + // browsers will not trigger default behavior (form submit, in this + // example) on JavaScript-created keypresses. + expect(submitSpy).not.toHaveBeenTriggered(); }); -}).call(window); +}); diff --git a/spec/javascripts/settings_panels_spec.js b/spec/javascripts/settings_panels_spec.js index d433f8c3e07..4fba36bd4de 100644 --- a/spec/javascripts/settings_panels_spec.js +++ b/spec/javascripts/settings_panels_spec.js @@ -13,9 +13,9 @@ describe('Settings Panels', () => { }); it('should expand linked hash fragment panel', () => { - location.hash = '#js-general-pipeline-settings'; + location.hash = '#autodevops-settings'; - const pipelineSettingsPanel = document.querySelector('#js-general-pipeline-settings'); + const pipelineSettingsPanel = document.querySelector('#autodevops-settings'); // Our test environment automatically expands everything so we need to clear that out first pipelineSettingsPanel.classList.remove('expanded'); diff --git a/spec/javascripts/shared/popover_spec.js b/spec/javascripts/shared/popover_spec.js new file mode 100644 index 00000000000..1d574c9424b --- /dev/null +++ b/spec/javascripts/shared/popover_spec.js @@ -0,0 +1,162 @@ +import $ from 'jquery'; +import { + togglePopover, + mouseleave, + mouseenter, +} from '~/shared/popover'; + +describe('popover', () => { + describe('togglePopover', () => { + describe('togglePopover(true)', () => { + it('returns true when popover is shown', () => { + const context = { + hasClass: () => false, + popover: () => {}, + toggleClass: () => {}, + }; + + expect(togglePopover.call(context, true)).toEqual(true); + }); + + it('returns false when popover is already shown', () => { + const context = { + hasClass: () => true, + }; + + expect(togglePopover.call(context, true)).toEqual(false); + }); + + it('shows popover', (done) => { + const context = { + hasClass: () => false, + popover: () => {}, + toggleClass: () => {}, + }; + + spyOn(context, 'popover').and.callFake((method) => { + expect(method).toEqual('show'); + done(); + }); + + togglePopover.call(context, true); + }); + + it('adds disable-animation and js-popover-show class', (done) => { + const context = { + hasClass: () => false, + popover: () => {}, + toggleClass: () => {}, + }; + + spyOn(context, 'toggleClass').and.callFake((classNames, show) => { + expect(classNames).toEqual('disable-animation js-popover-show'); + expect(show).toEqual(true); + done(); + }); + + togglePopover.call(context, true); + }); + }); + + describe('togglePopover(false)', () => { + it('returns true when popover is hidden', () => { + const context = { + hasClass: () => true, + popover: () => {}, + toggleClass: () => {}, + }; + + expect(togglePopover.call(context, false)).toEqual(true); + }); + + it('returns false when popover is already hidden', () => { + const context = { + hasClass: () => false, + }; + + expect(togglePopover.call(context, false)).toEqual(false); + }); + + it('hides popover', (done) => { + const context = { + hasClass: () => true, + popover: () => {}, + toggleClass: () => {}, + }; + + spyOn(context, 'popover').and.callFake((method) => { + expect(method).toEqual('hide'); + done(); + }); + + togglePopover.call(context, false); + }); + + it('removes disable-animation and js-popover-show class', (done) => { + const context = { + hasClass: () => true, + popover: () => {}, + toggleClass: () => {}, + }; + + spyOn(context, 'toggleClass').and.callFake((classNames, show) => { + expect(classNames).toEqual('disable-animation js-popover-show'); + expect(show).toEqual(false); + done(); + }); + + togglePopover.call(context, false); + }); + }); + }); + + describe('mouseleave', () => { + it('calls hide popover if .popover:hover is false', () => { + const fakeJquery = { + length: 0, + }; + + spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); + spyOn(togglePopover, 'call'); + mouseleave(); + expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), false); + }); + + it('does not call hide popover if .popover:hover is true', () => { + const fakeJquery = { + length: 1, + }; + + spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn)); + spyOn(togglePopover, 'call'); + mouseleave(); + expect(togglePopover.call).not.toHaveBeenCalledWith(false); + }); + }); + + describe('mouseenter', () => { + const context = {}; + + it('shows popover', () => { + spyOn(togglePopover, 'call').and.returnValue(false); + mouseenter.call(context); + expect(togglePopover.call).toHaveBeenCalledWith(jasmine.any(Object), true); + }); + + it('registers mouseleave event if popover is showed', (done) => { + spyOn(togglePopover, 'call').and.returnValue(true); + spyOn($.fn, 'on').and.callFake((eventName) => { + expect(eventName).toEqual('mouseleave'); + done(); + }); + mouseenter.call(context); + }); + + it('does not register mouseleave event if popover is not showed', () => { + spyOn(togglePopover, 'call').and.returnValue(false); + const spy = spyOn($.fn, 'on').and.callFake(() => {}); + mouseenter.call(context); + expect(spy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/shortcuts_dashboard_navigation_spec.js b/spec/javascripts/shortcuts_dashboard_navigation_spec.js new file mode 100644 index 00000000000..7cb201e01d8 --- /dev/null +++ b/spec/javascripts/shortcuts_dashboard_navigation_spec.js @@ -0,0 +1,23 @@ +import findAndFollowLink from '~/shortcuts_dashboard_navigation'; + +describe('findAndFollowLink', () => { + it('visits a link when the selector exists', () => { + const href = '/some/path'; + const visitUrl = spyOnDependency(findAndFollowLink, 'visitUrl'); + + setFixtures(`<a class="my-shortcut" href="${href}">link</a>`); + + findAndFollowLink('.my-shortcut'); + + expect(visitUrl).toHaveBeenCalledWith(href); + }); + + it('does not throw an exception when the selector does not exist', () => { + const visitUrl = spyOnDependency(findAndFollowLink, 'visitUrl'); + + // this should not throw an exception + findAndFollowLink('.this-selector-does-not-exist'); + + expect(visitUrl).not.toHaveBeenCalled(); + }); +}); diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index b0d714cbefb..d73608ed0ed 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -4,7 +4,7 @@ import ShortcutsIssuable from '~/shortcuts_issuable'; initCopyAsGFM(); -describe('ShortcutsIssuable', () => { +describe('ShortcutsIssuable', function () { const fixtureName = 'merge_requests/diff_comment.html.raw'; preloadFixtures(fixtureName); beforeEach(() => { diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js index 8b6e8b24f00..fcd7bea3f6d 100644 --- a/spec/javascripts/sidebar/mock_data.js +++ b/spec/javascripts/sidebar/mock_data.js @@ -138,7 +138,7 @@ const RESPONSE_MAP = { }, { id: 20, - name_with_namespace: 'foo / bar', + name_with_namespace: '<img src=x onerror=alert(document.domain)> foo / bar', }, ], }, diff --git a/spec/javascripts/sidebar/participants_spec.js b/spec/javascripts/sidebar/participants_spec.js index 2a3b60c399c..e796ddee62f 100644 --- a/spec/javascripts/sidebar/participants_spec.js +++ b/spec/javascripts/sidebar/participants_spec.js @@ -170,5 +170,19 @@ describe('Participants', function () { expect(vm.isShowingMoreParticipants).toBe(true); }); + + it('clicking on participants icon emits `toggleSidebar` event', () => { + vm = mountComponent(Participants, { + loading: false, + participants: PARTICIPANT_LIST, + numberOfLessParticipants: 2, + }); + spyOn(vm, '$emit'); + + const participantsIconEl = vm.$el.querySelector('.sidebar-collapsed-icon'); + + participantsIconEl.click(); + expect(vm.$emit).toHaveBeenCalledWith('toggleSidebar'); + }); }); }); diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js index afa18cc127e..da950258a94 100644 --- a/spec/javascripts/sidebar/sidebar_mediator_spec.js +++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js @@ -1,12 +1,11 @@ import _ from 'underscore'; import Vue from 'vue'; -import * as urlUtils from '~/lib/utils/url_utility'; import SidebarMediator from '~/sidebar/sidebar_mediator'; import SidebarStore from '~/sidebar/stores/sidebar_store'; import SidebarService from '~/sidebar/services/sidebar_service'; import Mock from './mock_data'; -describe('Sidebar mediator', () => { +describe('Sidebar mediator', function() { beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); this.mediator = new SidebarMediator(Mock.mediator); @@ -87,12 +86,12 @@ describe('Sidebar mediator', () => { const moveToProjectId = 7; this.mediator.store.setMoveToProjectId(moveToProjectId); spyOn(this.mediator.service, 'moveIssue').and.callThrough(); - spyOn(urlUtils, 'visitUrl'); + const visitUrl = spyOnDependency(SidebarMediator, 'visitUrl'); this.mediator.moveIssue() .then(() => { expect(this.mediator.service.moveIssue).toHaveBeenCalledWith(moveToProjectId); - expect(urlUtils.visitUrl).toHaveBeenCalledWith('/root/some-project/issues/5'); + expect(visitUrl).toHaveBeenCalledWith('/root/some-project/issues/5'); }) .then(done) .catch(done.fail); diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js index d8e636cbdf0..00847df4b60 100644 --- a/spec/javascripts/sidebar/sidebar_move_issue_spec.js +++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js @@ -7,7 +7,7 @@ import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue'; import Mock from './mock_data'; -describe('SidebarMoveIssue', () => { +describe('SidebarMoveIssue', function () { beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); this.mediator = new SidebarMediator(Mock.mediator); @@ -69,6 +69,15 @@ describe('SidebarMoveIssue', () => { expect($.fn.glDropdown).toHaveBeenCalled(); }); + + it('escapes html from project name', (done) => { + this.$toggleButton.dropdown('toggle'); + + setTimeout(() => { + expect(this.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual('<img src=x onerror=alert(document.domain)> foo / bar'); + done(); + }); + }); }); describe('onConfirmClicked', () => { diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js index 3591f96ff87..08b112a54ba 100644 --- a/spec/javascripts/sidebar/sidebar_store_spec.js +++ b/spec/javascripts/sidebar/sidebar_store_spec.js @@ -31,7 +31,7 @@ const PARTICIPANT_LIST = [ { ...PARTICIPANT, id: 3 }, ]; -describe('Sidebar store', () => { +describe('Sidebar store', function () { beforeEach(() => { this.store = new SidebarStore({ currentUser: { diff --git a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js index 56a2543660b..9e437084224 100644 --- a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js +++ b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js @@ -3,7 +3,6 @@ import sidebarSubscriptions from '~/sidebar/components/subscriptions/sidebar_sub import SidebarMediator from '~/sidebar/sidebar_mediator'; import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarStore from '~/sidebar/stores/sidebar_store'; -import eventHub from '~/sidebar/event_hub'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; import Mock from './mock_data'; @@ -32,7 +31,7 @@ describe('Sidebar Subscriptions', function () { mediator, }); - eventHub.$emit('toggleSubscription'); + vm.onToggleSubscription(); expect(mediator.toggleSubscription).toHaveBeenCalled(); }); diff --git a/spec/javascripts/sidebar/subscriptions_spec.js b/spec/javascripts/sidebar/subscriptions_spec.js index aee8f0acbb9..f0a53e573c3 100644 --- a/spec/javascripts/sidebar/subscriptions_spec.js +++ b/spec/javascripts/sidebar/subscriptions_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue'; +import eventHub from '~/sidebar/event_hub'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('Subscriptions', function () { @@ -39,4 +40,22 @@ describe('Subscriptions', function () { expect(vm.$refs.toggleButton.$el.querySelector('.project-feature-toggle')).toHaveClass('is-checked'); }); + + it('toggleSubscription method emits `toggleSubscription` event on eventHub and Component', () => { + vm = mountComponent(Subscriptions, { subscribed: true }); + spyOn(eventHub, '$emit'); + spyOn(vm, '$emit'); + + vm.toggleSubscription(); + expect(eventHub.$emit).toHaveBeenCalledWith('toggleSubscription', jasmine.any(Object)); + expect(vm.$emit).toHaveBeenCalledWith('toggleSubscription', jasmine.any(Object)); + }); + + it('onClickCollapsedIcon method emits `toggleSidebar` event on component', () => { + vm = mountComponent(Subscriptions, { subscribed: true }); + spyOn(vm, '$emit'); + + vm.onClickCollapsedIcon(); + expect(vm.$emit).toHaveBeenCalledWith('toggleSidebar'); + }); }); diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js index b1b03ef1e09..423432c9e5d 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js +++ b/spec/javascripts/signin_tabs_memoizer_spec.js @@ -4,7 +4,7 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; (() => { describe('SigninTabsMemoizer', () => { const fixtureTemplate = 'static/signin_tabs.html.raw'; - const tabSelector = 'ul.nav-tabs'; + const tabSelector = 'ul.new-session-tabs'; const currentTabKey = 'current_signin_tab'; let memo; @@ -27,7 +27,7 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; it('does nothing if no tab was previously selected', () => { createMemoizer(); - expect(document.querySelector('li a.active').getAttribute('id')).toEqual('standard'); + expect(document.querySelector(`${tabSelector} > li.active a`).getAttribute('href')).toEqual('#ldap'); }); it('shows last selected tab on boot', () => { @@ -48,9 +48,9 @@ import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; it('saves last selected tab on change', () => { createMemoizer(); - document.getElementById('standard').click(); + document.querySelector('a[href="#login-pane"]').click(); - expect(memo.readData()).toEqual('#standard'); + expect(memo.readData()).toEqual('#login-pane'); }); it('overrides last selected tab with hash tag when given', () => { diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index 1bcfdfe72b6..2411d33a496 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -1,12 +1,17 @@ -/* eslint-disable jasmine/no-global-setup */ +/* eslint-disable jasmine/no-global-setup, jasmine/no-unsafe-spy, no-underscore-dangle */ + import $ from 'jquery'; import 'vendor/jasmine-jquery'; import '~/commons'; import Vue from 'vue'; import VueResource from 'vue-resource'; +import Translate from '~/vue_shared/translate'; import { getDefaultAdapter } from '~/lib/utils/axios_utils'; +import { FIXTURES_PATH, TEST_HOST } from './test_constants'; + +import customMatchers from './matchers'; const isHeadlessChrome = /\bHeadlessChrome\//.test(navigator.userAgent); Vue.config.devtools = !isHeadlessChrome; @@ -19,34 +24,49 @@ Vue.config.warnHandler = (msg, vm, trace) => { }; let hasVueErrors = false; -Vue.config.errorHandler = function (err) { +Vue.config.errorHandler = function(err) { hasVueErrors = true; fail(err); }; Vue.use(VueResource); +Vue.use(Translate); // enable test fixtures -jasmine.getFixtures().fixturesPath = '/base/spec/javascripts/fixtures'; -jasmine.getJSONFixtures().fixturesPath = '/base/spec/javascripts/fixtures'; +jasmine.getFixtures().fixturesPath = FIXTURES_PATH; +jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH; + +beforeAll(() => jasmine.addMatchers(customMatchers)); // globalize common libraries window.$ = window.jQuery = $; // stub expected globals window.gl = window.gl || {}; -window.gl.TEST_HOST = 'http://test.host'; +window.gl.TEST_HOST = TEST_HOST; window.gon = window.gon || {}; window.gon.test_env = true; +gon.relative_url_root = ''; let hasUnhandledPromiseRejections = false; -window.addEventListener('unhandledrejection', (event) => { +window.addEventListener('unhandledrejection', event => { hasUnhandledPromiseRejections = true; console.error('Unhandled promise rejection:'); console.error(event.reason.stack || event.reason); }); +// Add global function to spy on a module's dependencies via rewire +window.spyOnDependency = (module, name) => { + const dependency = module.__GetDependency__(name); + const spy = jasmine.createSpy(name, dependency); + module.__Rewire__(name, spy); + return spy; +}; + +// Reset any rewired modules after each test (see babel-plugin-rewire) +afterEach(__rewire_reset_all__); // eslint-disable-line + // HACK: Chrome 59 disconnects if there are too many synchronous tests in a row // because it appears to lock up the thread that communicates to Karma's socket // This async beforeEach gets called on every spec and releases the JS thread long @@ -66,13 +86,13 @@ const axiosDefaultAdapter = getDefaultAdapter(); // render all of our tests const testsContext = require.context('.', true, /_spec$/); -testsContext.keys().forEach(function (path) { +testsContext.keys().forEach(function(path) { try { testsContext(path); } catch (err) { console.error('[ERROR] Unable to load spec: ', path); - describe('Test bundle', function () { - it(`includes '${path}'`, function () { + describe('Test bundle', function() { + it(`includes '${path}'`, function() { expect(err).toBeNull(); }); }); @@ -80,7 +100,7 @@ testsContext.keys().forEach(function (path) { }); describe('test errors', () => { - beforeAll((done) => { + beforeAll(done => { if (hasUnhandledPromiseRejections || hasVueWarnings || hasVueErrors) { setTimeout(done, 1000); } else { @@ -144,18 +164,18 @@ if (process.env.BABEL_ENV === 'coverage') { './issue_show/index.js', ]; - describe('Uncovered files', function () { + describe('Uncovered files', function() { const sourceFiles = require.context('~', true, /\.js$/); $.holdReady(true); - sourceFiles.keys().forEach(function (path) { + sourceFiles.keys().forEach(function(path) { // ignore if there is a matching spec file if (testsContext.keys().indexOf(`${path.replace(/\.js$/, '')}_spec`) > -1) { return; } - it(`includes '${path}'`, function () { + it(`includes '${path}'`, function() { try { sourceFiles(path); } catch (err) { diff --git a/spec/javascripts/test_constants.js b/spec/javascripts/test_constants.js new file mode 100644 index 00000000000..df59195e9f6 --- /dev/null +++ b/spec/javascripts/test_constants.js @@ -0,0 +1,4 @@ +export const FIXTURES_PATH = '/base/spec/javascripts/fixtures'; +export const TEST_HOST = 'http://test.host'; + +export const DUMMY_IMAGE_URL = `${FIXTURES_PATH}/one_white_pixel.png`; diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index 898bbb3819b..e74f4bdef7e 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -1,5 +1,4 @@ import $ from 'jquery'; -import * as urlUtils from '~/lib/utils/url_utility'; import Todos from '~/pages/dashboard/todos/index/todos'; import '~/lib/utils/common_utils'; @@ -18,7 +17,7 @@ describe('Todos', () => { it('opens the todo url', (done) => { const todoLink = todoItem.dataset.url; - spyOn(urlUtils, 'visitUrl').and.callFake((url) => { + spyOnDependency(Todos, 'visitUrl').and.callFake((url) => { expect(url).toEqual(todoLink); done(); }); @@ -33,7 +32,7 @@ describe('Todos', () => { beforeEach(() => { metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true }); - visitUrlSpy = spyOn(urlUtils, 'visitUrl').and.callFake(() => {}); + visitUrlSpy = spyOnDependency(Todos, 'visitUrl').and.callFake(() => {}); windowOpenSpy = spyOn(window, 'open').and.callFake(() => {}); }); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 39c47a5c06d..d84b13b07c4 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -3,7 +3,7 @@ import U2FAuthenticate from '~/u2f/authenticate'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; -describe('U2FAuthenticate', () => { +describe('U2FAuthenticate', function () { preloadFixtures('u2f/authenticate.html.raw'); beforeEach((done) => { diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 136b4cad737..d9383314891 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -3,7 +3,7 @@ import U2FRegister from '~/u2f/register'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; -describe('U2FRegister', () => { +describe('U2FRegister', function () { preloadFixtures('u2f/register.html.raw'); beforeEach((done) => { diff --git a/spec/javascripts/visibility_select_spec.js b/spec/javascripts/visibility_select_spec.js deleted file mode 100644 index 82714cb69bd..00000000000 --- a/spec/javascripts/visibility_select_spec.js +++ /dev/null @@ -1,98 +0,0 @@ -import VisibilitySelect from '~/visibility_select'; - -(() => { - describe('VisibilitySelect', function () { - const lockedElement = document.createElement('div'); - lockedElement.dataset.helpBlock = 'lockedHelpBlock'; - - const checkedElement = document.createElement('div'); - checkedElement.dataset.description = 'checkedDescription'; - - const mockElements = { - container: document.createElement('div'), - select: document.createElement('div'), - '.help-block': document.createElement('div'), - '.js-locked': lockedElement, - 'option:checked': checkedElement, - }; - - beforeEach(function () { - spyOn(Element.prototype, 'querySelector').and.callFake(selector => mockElements[selector]); - }); - - describe('constructor', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - }); - - it('sets the container member', function () { - expect(this.visibilitySelect.container).toEqual(mockElements.container); - }); - - it('queries and sets the helpBlock member', function () { - expect(Element.prototype.querySelector).toHaveBeenCalledWith('.help-block'); - expect(this.visibilitySelect.helpBlock).toEqual(mockElements['.help-block']); - }); - - it('queries and sets the select member', function () { - expect(Element.prototype.querySelector).toHaveBeenCalledWith('select'); - expect(this.visibilitySelect.select).toEqual(mockElements.select); - }); - - describe('if there is no container element provided', function () { - it('throws an error', function () { - expect(() => new VisibilitySelect()).toThrowError('VisibilitySelect requires a container element as argument 1'); - }); - }); - }); - - describe('init', function () { - describe('if there is a select', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - }); - - it('calls updateHelpText', function () { - spyOn(VisibilitySelect.prototype, 'updateHelpText'); - this.visibilitySelect.init(); - expect(this.visibilitySelect.updateHelpText).toHaveBeenCalled(); - }); - - it('adds a change event listener', function () { - spyOn(this.visibilitySelect.select, 'addEventListener'); - this.visibilitySelect.init(); - expect(this.visibilitySelect.select.addEventListener.calls.argsFor(0)).toContain('change'); - }); - }); - - describe('if there is no select', function () { - beforeEach(function () { - mockElements.select = undefined; - this.visibilitySelect = new VisibilitySelect(mockElements.container); - this.visibilitySelect.init(); - }); - - it('updates the helpBlock text to the locked `data-help-block` messaged', function () { - expect(this.visibilitySelect.helpBlock.textContent) - .toEqual(lockedElement.dataset.helpBlock); - }); - - afterEach(function () { - mockElements.select = document.createElement('div'); - }); - }); - }); - - describe('updateHelpText', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - this.visibilitySelect.init(); - }); - - it('updates the helpBlock text to the selected options `data-description`', function () { - expect(this.visibilitySelect.helpBlock.textContent) - .toEqual(checkedElement.dataset.description); - }); - }); - }); -})(); diff --git a/spec/javascripts/vue_mr_widget/components/deployment_spec.js b/spec/javascripts/vue_mr_widget/components/deployment_spec.js index ff8d54c029f..c82ba61a5b1 100644 --- a/spec/javascripts/vue_mr_widget/components/deployment_spec.js +++ b/spec/javascripts/vue_mr_widget/components/deployment_spec.js @@ -1,5 +1,4 @@ import Vue from 'vue'; -import * as urlUtils from '~/lib/utils/url_utility'; import deploymentComponent from '~/vue_merge_request_widget/components/deployment.vue'; import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; import { getTimeago } from '~/lib/utils/datetime_utility'; @@ -117,13 +116,13 @@ describe('Deployment component', () => { it('should show a confirm dialog and call service.stopEnvironment when confirmed', (done) => { spyOn(window, 'confirm').and.returnValue(true); spyOn(MRWidgetService, 'stopEnvironment').and.returnValue(returnPromise(true)); - spyOn(urlUtils, 'visitUrl').and.returnValue(true); + const visitUrl = spyOnDependency(deploymentComponent, 'visitUrl').and.returnValue(true); vm = mockStopEnvironment(); expect(window.confirm).toHaveBeenCalled(); expect(MRWidgetService.stopEnvironment).toHaveBeenCalledWith(deploymentMockData.stop_url); setTimeout(() => { - expect(urlUtils.visitUrl).toHaveBeenCalledWith(url); + expect(visitUrl).toHaveBeenCalledWith(url); done(); }, 333); }); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js index d9c03296857..91e81a0675a 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js @@ -51,8 +51,7 @@ const createComponent = () => { const messages = { loadingMetrics: 'Loading deployment statistics', - hasMetrics: - '<a href="/root/acets-review-apps/environments/15/metrics"> Memory </a> usage is <b> unchanged </b> at 0MB', + hasMetrics: 'Memory usage is unchanged at 0MB', loadFailed: 'Failed to load deployment statistics', metricsUnavailable: 'Deployment statistics are not available currently', }; diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js index 431cb7f3913..ea8007d2029 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js @@ -113,6 +113,46 @@ describe('MRWidgetPipeline', () => { }); }); + describe('without commit path', () => { + beforeEach(() => { + const mockCopy = Object.assign({}, mockData); + delete mockCopy.pipeline.commit; + + vm = mountComponent(Component, { + pipeline: mockCopy.pipeline, + hasCi: true, + ciStatus: 'success', + }); + }); + + it('should render pipeline ID', () => { + expect( + vm.$el.querySelector('.pipeline-id').textContent.trim(), + ).toEqual(`#${mockData.pipeline.id}`); + }); + + it('should render pipeline status', () => { + expect( + vm.$el.querySelector('.media-body').textContent.trim(), + ).toContain(mockData.pipeline.details.status.label); + + expect( + vm.$el.querySelector('.js-commit-link'), + ).toBeNull(); + }); + + it('should render pipeline graph', () => { + expect(vm.$el.querySelector('.mr-widget-pipeline-graph')).toBeDefined(); + expect(vm.$el.querySelectorAll('.stage-container').length).toEqual(mockData.pipeline.details.stages.length); + }); + + it('should render coverage information', () => { + expect( + vm.$el.querySelector('.media-body').textContent, + ).toContain(`Coverage ${mockData.pipeline.coverage}`); + }); + }); + describe('without coverage', () => { it('should not render a coverage', () => { const mockCopy = Object.assign({}, mockData); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js index fcbd8169bc7..3d05dbfa305 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import removeBreakLine from 'spec/helpers/vue_component_helper'; +import { removeBreakLine } from 'spec/helpers/vue_component_helper'; describe('MRWidgetConflicts', () => { let Component; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js index dd1d62cd4ed..a0a74648328 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js @@ -4,21 +4,37 @@ import eventHub from '~/vue_merge_request_widget/event_hub'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('MRWidgetFailedToMerge', () => { + const dummyIntervalId = 1337; let Component; let vm; beforeEach(() => { Component = Vue.extend(failedToMergeComponent); spyOn(eventHub, '$emit'); - vm = mountComponent(Component, { mr: { - mergeError: 'Merge error happened.', - } }); + spyOn(window, 'setInterval').and.returnValue(dummyIntervalId); + spyOn(window, 'clearInterval').and.stub(); + vm = mountComponent(Component, { + mr: { + mergeError: 'Merge error happened.', + }, + }); }); afterEach(() => { vm.$destroy(); }); + it('sets interval to refresh', () => { + expect(window.setInterval).toHaveBeenCalledWith(vm.updateTimer, 1000); + expect(vm.intervalId).toBe(dummyIntervalId); + }); + + it('clears interval when destroying ', () => { + vm.$destroy(); + + expect(window.clearInterval).toHaveBeenCalledWith(dummyIntervalId); + }); + describe('computed', () => { describe('timerText', () => { it('should return correct timer text', () => { @@ -65,11 +81,13 @@ describe('MRWidgetFailedToMerge', () => { }); describe('while it is refreshing', () => { - it('renders Refresing now', (done) => { + it('renders Refresing now', done => { vm.isRefreshing = true; Vue.nextTick(() => { - expect(vm.$el.querySelector('.js-refresh-label').textContent.trim()).toEqual('Refreshing now'); + expect(vm.$el.querySelector('.js-refresh-label').textContent.trim()).toEqual( + 'Refreshing now', + ); done(); }); }); @@ -78,11 +96,15 @@ describe('MRWidgetFailedToMerge', () => { describe('while it is not regresing', () => { it('renders warning icon and disabled merge button', () => { expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull(); - expect(vm.$el.querySelector('.js-disabled-merge-button').getAttribute('disabled')).toEqual('disabled'); + expect(vm.$el.querySelector('.js-disabled-merge-button').getAttribute('disabled')).toEqual( + 'disabled', + ); }); it('renders given error', () => { - expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual('Merge error happened..'); + expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual( + 'Merge error happened..', + ); }); it('renders refresh button', () => { @@ -90,13 +112,13 @@ describe('MRWidgetFailedToMerge', () => { }); it('renders remaining time', () => { - expect( - vm.$el.querySelector('.has-custom-error').textContent.trim(), - ).toEqual('Refreshing in 10 seconds to show the updated status...'); + expect(vm.$el.querySelector('.has-custom-error').textContent.trim()).toEqual( + 'Refreshing in 10 seconds to show the updated status...', + ); }); }); - it('should just generic merge failed message if merge_error is not available', (done) => { + it('should just generic merge failed message if merge_error is not available', done => { vm.mr.mergeError = null; Vue.nextTick(() => { @@ -106,7 +128,7 @@ describe('MRWidgetFailedToMerge', () => { }); }); - it('should show refresh label when refresh requested', (done) => { + it('should show refresh label when refresh requested', done => { vm.refresh(); Vue.nextTick(() => { expect(vm.$el.innerText).not.toContain('Merge failed. Refreshing'); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js index 894dbe3382f..ab096a56918 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import removeBreakLine from 'spec/helpers/vue_component_helper'; +import { removeBreakLine } from 'spec/helpers/vue_component_helper'; describe('MRWidgetPipelineBlocked', () => { let vm; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js index 78bac1c61a5..5573d7c5c93 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js @@ -1,16 +1,19 @@ import Vue from 'vue'; -import pipelineFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_failed'; +import PipelineFailed from '~/vue_merge_request_widget/components/states/pipeline_failed.vue'; +import { removeBreakLine } from 'spec/helpers/vue_component_helper'; -describe('MRWidgetPipelineFailed', () => { +describe('PipelineFailed', () => { describe('template', () => { - const Component = Vue.extend(pipelineFailedComponent); + const Component = Vue.extend(PipelineFailed); const vm = new Component({ el: document.createElement('div'), }); it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(vm.$el.innerText).toContain('The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure'); + expect( + removeBreakLine(vm.$el.innerText).trim(), + ).toContain('The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js index 58f683fb3e6..81c16593eb4 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js @@ -1,12 +1,11 @@ import Vue from 'vue'; -import readyToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_ready_to_merge'; +import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue'; import eventHub from '~/vue_merge_request_widget/event_hub'; -import * as simplePoll from '~/lib/utils/simple_poll'; const commitMessage = 'This is the commit message'; const commitMessageWithDescription = 'This is the commit message description'; const createComponent = (customConfig = {}) => { - const Component = Vue.extend(readyToMergeComponent); + const Component = Vue.extend(ReadyToMerge); const mr = { isPipelineActive: false, pipeline: null, @@ -36,7 +35,7 @@ const createComponent = (customConfig = {}) => { }); }; -describe('MRWidgetReadyToMerge', () => { +describe('ReadyToMerge', () => { let vm; beforeEach(() => { @@ -49,7 +48,7 @@ describe('MRWidgetReadyToMerge', () => { describe('props', () => { it('should have props', () => { - const { mr, service } = readyToMergeComponent.props; + const { mr, service } = ReadyToMerge.props; expect(mr.type instanceof Object).toBeTruthy(); expect(mr.required).toBeTruthy(); @@ -355,9 +354,9 @@ describe('MRWidgetReadyToMerge', () => { describe('initiateMergePolling', () => { it('should call simplePoll', () => { - spyOn(simplePoll, 'default'); + const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll'); vm.initiateMergePolling(); - expect(simplePoll.default).toHaveBeenCalled(); + expect(simplePoll).toHaveBeenCalled(); }); }); @@ -457,11 +456,11 @@ describe('MRWidgetReadyToMerge', () => { describe('initiateRemoveSourceBranchPolling', () => { it('should emit event and call simplePoll', () => { spyOn(eventHub, '$emit'); - spyOn(simplePoll, 'default'); + const simplePoll = spyOnDependency(ReadyToMerge, 'simplePoll'); vm.initiateRemoveSourceBranchPolling(); expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [true]); - expect(simplePoll.default).toHaveBeenCalled(); + expect(simplePoll).toHaveBeenCalled(); }); }); @@ -524,18 +523,20 @@ describe('MRWidgetReadyToMerge', () => { }); describe('when user can merge and can delete branch', () => { + let customVm; + beforeEach(() => { - this.customVm = createComponent({ + customVm = createComponent({ mr: { canRemoveSourceBranch: true }, }); }); it('isRemoveSourceBranchButtonDisabled should be false', () => { - expect(this.customVm.isRemoveSourceBranchButtonDisabled).toBe(false); + expect(customVm.isRemoveSourceBranchButtonDisabled).toBe(false); }); it('should be enabled in rendered output', () => { - const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input'); + const checkboxElement = customVm.$el.querySelector('#remove-source-branch-input'); expect(checkboxElement).not.toBeNull(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js index b02af94d03a..abf642c166a 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import removeBreakLine from 'spec/helpers/vue_component_helper'; +import { removeBreakLine } from 'spec/helpers/vue_component_helper'; describe('ShaMismatch', () => { let vm; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js index 046968fbc1f..d797f1266df 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js @@ -1,47 +1,37 @@ import Vue from 'vue'; import UnresolvedDiscussions from '~/vue_merge_request_widget/components/states/unresolved_discussions.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('UnresolvedDiscussions', () => { - describe('props', () => { - it('should have props', () => { - const { mr } = UnresolvedDiscussions.props; + const Component = Vue.extend(UnresolvedDiscussions); + let vm; - expect(mr.type instanceof Object).toBeTruthy(); - expect(mr.required).toBeTruthy(); - }); + afterEach(() => { + vm.$destroy(); }); - describe('template', () => { - let el; - let vm; - const path = 'foo/bar'; - + describe('with discussions path', () => { beforeEach(() => { - const Component = Vue.extend(UnresolvedDiscussions); - const mr = { - createIssueToResolveDiscussionsPath: path, - }; - vm = new Component({ - el: document.createElement('div'), - propsData: { mr }, - }); - el = vm.$el; + vm = mountComponent(Component, { mr: { + createIssueToResolveDiscussionsPath: gl.TEST_HOST, + } }); }); it('should have correct elements', () => { - expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.innerText).toContain('There are unresolved discussions. Please resolve these discussions'); - expect(el.innerText).toContain('Create an issue to resolve them later'); - expect(el.querySelector('.js-create-issue').getAttribute('href')).toEqual(path); + expect(vm.$el.innerText).toContain('There are unresolved discussions. Please resolve these discussions'); + expect(vm.$el.innerText).toContain('Create an issue to resolve them later'); + expect(vm.$el.querySelector('.js-create-issue').getAttribute('href')).toEqual(gl.TEST_HOST); }); + }); - it('should not show create issue button if user cannot create issue', (done) => { - vm.mr.createIssueToResolveDiscussionsPath = ''; + describe('without discussions path', () => { + beforeEach(() => { + vm = mountComponent(Component, { mr: {} }); + }); - Vue.nextTick(() => { - expect(el.querySelector('.js-create-issue')).toEqual(null); - done(); - }); + it('should not show create issue link if user cannot create issue', () => { + expect(vm.$el.innerText).toContain('There are unresolved discussions. Please resolve these discussions'); + expect(vm.$el.querySelector('.js-create-issue')).toEqual(null); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js index 98ab61a0367..cea603368bf 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import wipComponent from '~/vue_merge_request_widget/components/states/mr_widget_wip'; +import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue'; import eventHub from '~/vue_merge_request_widget/event_hub'; const createComponent = () => { - const Component = Vue.extend(wipComponent); + const Component = Vue.extend(WorkInProgress); const mr = { title: 'The best MR ever', removeWIPPath: '/path/to/remove/wip', @@ -17,10 +17,10 @@ const createComponent = () => { }); }; -describe('MRWidgetWIP', () => { +describe('Wip', () => { describe('props', () => { it('should have props', () => { - const { mr, service } = wipComponent.props; + const { mr, service } = WorkInProgress.props; expect(mr.type instanceof Object).toBeTruthy(); expect(mr.required).toBeTruthy(); diff --git a/spec/javascripts/vue_shared/components/callout_spec.js b/spec/javascripts/vue_shared/components/callout_spec.js new file mode 100644 index 00000000000..e62bd86f4ca --- /dev/null +++ b/spec/javascripts/vue_shared/components/callout_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import callout from '~/vue_shared/components/callout.vue'; +import createComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Callout Component', () => { + let CalloutComponent; + let vm; + const exampleMessage = 'This is a callout message!'; + + beforeEach(() => { + CalloutComponent = Vue.extend(callout); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render the appropriate variant of callout', () => { + vm = createComponent(CalloutComponent, { + category: 'info', + message: exampleMessage, + }); + + expect(vm.$el.getAttribute('class')).toEqual('bs-callout bs-callout-info'); + + expect(vm.$el.tagName).toEqual('DIV'); + }); + + it('should render accessibility attributes', () => { + vm = createComponent(CalloutComponent, { + message: exampleMessage, + }); + + expect(vm.$el.getAttribute('role')).toEqual('alert'); + expect(vm.$el.getAttribute('aria-live')).toEqual('assertive'); + }); + + it('should render the provided message', () => { + vm = createComponent(CalloutComponent, { + message: exampleMessage, + }); + + expect(vm.$el.innerHTML.trim()).toEqual(exampleMessage); + }); +}); diff --git a/spec/javascripts/vue_shared/components/ci_icon_spec.js b/spec/javascripts/vue_shared/components/ci_icon_spec.js index d8664408595..423bc746a22 100644 --- a/spec/javascripts/vue_shared/components/ci_icon_spec.js +++ b/spec/javascripts/vue_shared/components/ci_icon_spec.js @@ -1,139 +1,122 @@ import Vue from 'vue'; import ciIcon from '~/vue_shared/components/ci_icon.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('CI Icon component', () => { - let CiIcon; - beforeEach(() => { - CiIcon = Vue.extend(ciIcon); + const Component = Vue.extend(ciIcon); + let vm; + + afterEach(() => { + vm.$destroy(); }); it('should render a span element with an svg', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_success', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_success', }, - }).$mount(); + }); - expect(component.$el.tagName).toEqual('SPAN'); - expect(component.$el.querySelector('span > svg')).toBeDefined(); + expect(vm.$el.tagName).toEqual('SPAN'); + expect(vm.$el.querySelector('span > svg')).toBeDefined(); }); it('should render a success status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_success', - group: 'success', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_success', + group: 'success', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-success')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-success')).toEqual(true); }); it('should render a failed status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_failed', - group: 'failed', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_failed', + group: 'failed', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-failed')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-failed')).toEqual(true); }); it('should render success with warnings status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_warning', - group: 'warning', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_warning', + group: 'warning', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-warning')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-warning')).toEqual(true); }); it('should render pending status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_pending', - group: 'pending', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_pending', + group: 'pending', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-pending')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-pending')).toEqual(true); }); it('should render running status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_running', - group: 'running', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_running', + group: 'running', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-running')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-running')).toEqual(true); }); it('should render created status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_created', - group: 'created', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_created', + group: 'created', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-created')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-created')).toEqual(true); }); it('should render skipped status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_skipped', - group: 'skipped', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_skipped', + group: 'skipped', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-skipped')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-skipped')).toEqual(true); }); it('should render canceled status', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_canceled', - group: 'canceled', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_canceled', + group: 'canceled', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-canceled')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-canceled')).toEqual(true); }); it('should render status for manual action', () => { - const component = new CiIcon({ - propsData: { - status: { - icon: 'icon_status_manual', - group: 'manual', - }, + vm = mountComponent(Component, { + status: { + icon: 'icon_status_manual', + group: 'manual', }, - }).$mount(); + }); - expect(component.$el.classList.contains('ci-status-icon-manual')).toEqual(true); + expect(vm.$el.classList.contains('ci-status-icon-manual')).toEqual(true); }); }); diff --git a/spec/javascripts/vue_shared/components/clipboard_button_spec.js b/spec/javascripts/vue_shared/components/clipboard_button_spec.js index f598b1afa74..97f0fbb04db 100644 --- a/spec/javascripts/vue_shared/components/clipboard_button_spec.js +++ b/spec/javascripts/vue_shared/components/clipboard_button_spec.js @@ -3,10 +3,10 @@ import clipboardButton from '~/vue_shared/components/clipboard_button.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('clipboard button', () => { + const Component = Vue.extend(clipboardButton); let vm; beforeEach(() => { - const Component = Vue.extend(clipboardButton); vm = mountComponent(Component, { text: 'copy me', title: 'Copy this value into Clipboard!', diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js index fdead874209..7189e8cfcfa 100644 --- a/spec/javascripts/vue_shared/components/commit_spec.js +++ b/spec/javascripts/vue_shared/components/commit_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import commitComp from '~/vue_shared/components/commit.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; describe('Commit component', () => { let props; @@ -10,25 +11,28 @@ describe('Commit component', () => { CommitComponent = Vue.extend(commitComp); }); + afterEach(() => { + component.$destroy(); + }); + it('should render a fork icon if it does not represent a tag', () => { - component = new CommitComponent({ - propsData: { - tag: false, - commitRef: { - name: 'master', - ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', - }, - commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', - shortSha: 'b7836edd', - title: 'Commit message', - author: { - avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png', - web_url: 'https://gitlab.com/jschatz1', - path: '/jschatz1', - username: 'jschatz1', - }, + component = mountComponent(CommitComponent, { + tag: false, + commitRef: { + name: 'master', + ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', + }, + commitUrl: + 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', + shortSha: 'b7836edd', + title: 'Commit message', + author: { + avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png', + web_url: 'https://gitlab.com/jschatz1', + path: '/jschatz1', + username: 'jschatz1', }, - }).$mount(); + }); expect(component.$el.querySelector('.icon-container').children).toContain('svg'); }); @@ -41,7 +45,8 @@ describe('Commit component', () => { name: 'master', ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', }, - commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', + commitUrl: + 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', shortSha: 'b7836edd', title: 'Commit message', author: { @@ -50,12 +55,9 @@ describe('Commit component', () => { path: '/jschatz1', username: 'jschatz1', }, - commitIconSvg: '<svg></svg>', }; - component = new CommitComponent({ - propsData: props, - }).$mount(); + component = mountComponent(CommitComponent, props); }); it('should render a tag icon if it represents a tag', () => { @@ -63,7 +65,9 @@ describe('Commit component', () => { }); it('should render a link to the ref url', () => { - expect(component.$el.querySelector('.ref-name').getAttribute('href')).toEqual(props.commitRef.ref_url); + expect(component.$el.querySelector('.ref-name').getAttribute('href')).toEqual( + props.commitRef.ref_url, + ); }); it('should render the ref name', () => { @@ -71,12 +75,16 @@ describe('Commit component', () => { }); it('should render the commit short sha with a link to the commit url', () => { - expect(component.$el.querySelector('.commit-sha').getAttribute('href')).toEqual(props.commitUrl); + expect(component.$el.querySelector('.commit-sha').getAttribute('href')).toEqual( + props.commitUrl, + ); expect(component.$el.querySelector('.commit-sha').textContent).toContain(props.shortSha); }); - it('should render the given commitIconSvg', () => { - expect(component.$el.querySelector('.js-commit-icon').children).toContain('svg'); + it('should render icon for commit', () => { + expect( + component.$el.querySelector('.js-commit-icon use').getAttribute('xlink:href'), + ).toContain('commit'); }); describe('Given commit title and author props', () => { @@ -88,21 +96,25 @@ describe('Commit component', () => { it('Should render the author avatar with title and alt attributes', () => { expect( - component.$el.querySelector('.commit-title .avatar-image-container img').getAttribute('data-original-title'), + component.$el + .querySelector('.commit-title .avatar-image-container img') + .getAttribute('data-original-title'), ).toContain(props.author.username); expect( - component.$el.querySelector('.commit-title .avatar-image-container img').getAttribute('alt'), + component.$el + .querySelector('.commit-title .avatar-image-container img') + .getAttribute('alt'), ).toContain(`${props.author.username}'s avatar`); }); }); it('should render the commit title', () => { - expect( - component.$el.querySelector('a.commit-row-message').getAttribute('href'), - ).toEqual(props.commitUrl); - expect( - component.$el.querySelector('a.commit-row-message').textContent, - ).toContain(props.title); + expect(component.$el.querySelector('a.commit-row-message').getAttribute('href')).toEqual( + props.commitUrl, + ); + expect(component.$el.querySelector('a.commit-row-message').textContent).toContain( + props.title, + ); }); }); @@ -114,19 +126,18 @@ describe('Commit component', () => { name: 'master', ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', }, - commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', + commitUrl: + 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', shortSha: 'b7836edd', title: null, author: {}, }; - component = new CommitComponent({ - propsData: props, - }).$mount(); + component = mountComponent(CommitComponent, props); - expect( - component.$el.querySelector('.commit-title span').textContent, - ).toContain('Cant find HEAD commit for this branch'); + expect(component.$el.querySelector('.commit-title span').textContent).toContain( + "Can't find HEAD commit for this branch", + ); }); }); }); diff --git a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js new file mode 100644 index 00000000000..383f0cd29ea --- /dev/null +++ b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js @@ -0,0 +1,70 @@ +import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import contentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('ContentViewer', () => { + let vm; + let mock; + + function createComponent(props) { + const ContentViewer = Vue.extend(contentViewer); + vm = mountComponent(ContentViewer, props); + } + + afterEach(() => { + vm.$destroy(); + if (mock) mock.restore(); + }); + + it('markdown preview renders + loads rendered markdown from server', done => { + mock = new MockAdapter(axios); + mock.onPost(`${gon.relative_url_root}/testproject/preview_markdown`).reply(200, { + body: '<b>testing</b>', + }); + + createComponent({ + path: 'test.md', + content: '* Test', + projectPath: 'testproject', + }); + + const previewContainer = vm.$el.querySelector('.md-previewer'); + + setTimeout(() => { + expect(previewContainer.textContent).toContain('testing'); + + done(); + }); + }); + + it('renders image preview', done => { + createComponent({ + path: 'test.jpg', + fileSize: 1024, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.image_file img').getAttribute('src')).toBe('test.jpg'); + + done(); + }); + }); + + it('renders fallback download control', done => { + createComponent({ + path: 'test.abc', + fileSize: 1024, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain( + 'test.abc (1.00 KiB)', + ); + expect(vm.$el.querySelector('.btn.btn-default').textContent.trim()).toContain('Download'); + + done(); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/expand_button_spec.js b/spec/javascripts/vue_shared/components/expand_button_spec.js index f19589d3b75..af9693c48fd 100644 --- a/spec/javascripts/vue_shared/components/expand_button_spec.js +++ b/spec/javascripts/vue_shared/components/expand_button_spec.js @@ -3,10 +3,10 @@ import expandButton from '~/vue_shared/components/expand_button.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('expand button', () => { + const Component = Vue.extend(expandButton); let vm; beforeEach(() => { - const Component = Vue.extend(expandButton); vm = mountComponent(Component, { slots: { expanded: '<p>Expanded!</p>', @@ -22,7 +22,7 @@ describe('expand button', () => { expect(vm.$el.textContent.trim()).toEqual('...'); }); - it('hides expander on click', (done) => { + it('hides expander on click', done => { vm.$el.querySelector('button').click(); vm.$nextTick(() => { expect(vm.$el.querySelector('button').getAttribute('style')).toEqual('display: none;'); diff --git a/spec/javascripts/vue_shared/components/markdown/header_spec.js b/spec/javascripts/vue_shared/components/markdown/header_spec.js index edebd822295..02117638b63 100644 --- a/spec/javascripts/vue_shared/components/markdown/header_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/header_spec.js @@ -1,10 +1,11 @@ import Vue from 'vue'; +import $ from 'jquery'; import headerComponent from '~/vue_shared/components/markdown/header.vue'; describe('Markdown field header component', () => { let vm; - beforeEach((done) => { + beforeEach(done => { const Component = Vue.extend(headerComponent); vm = new Component({ @@ -17,24 +18,18 @@ describe('Markdown field header component', () => { }); it('renders markdown buttons', () => { - expect( - vm.$el.querySelectorAll('.js-md').length, - ).toBe(7); + expect(vm.$el.querySelectorAll('.js-md').length).toBe(7); }); it('renders `write` link as active when previewMarkdown is false', () => { - expect( - vm.$el.querySelector('li:nth-child(1)').classList.contains('active'), - ).toBeTruthy(); + expect(vm.$el.querySelector('li:nth-child(1)').classList.contains('active')).toBeTruthy(); }); - it('renders `preview` link as active when previewMarkdown is true', (done) => { + it('renders `preview` link as active when previewMarkdown is true', done => { vm.previewMarkdown = true; Vue.nextTick(() => { - expect( - vm.$el.querySelector('li:nth-child(2)').classList.contains('active'), - ).toBeTruthy(); + expect(vm.$el.querySelector('li:nth-child(2)').classList.contains('active')).toBeTruthy(); done(); }); @@ -52,16 +47,24 @@ describe('Markdown field header component', () => { expect(vm.$emit).toHaveBeenCalledWith('write-markdown'); }); - it('blurs preview link after click', (done) => { + it('does not emit toggle markdown event when triggered from another form', () => { + spyOn(vm, '$emit'); + + $(document).triggerHandler('markdown-preview:show', [ + $('<form><textarea class="markdown-area"></textarea></textarea></form>'), + ]); + + expect(vm.$emit).not.toHaveBeenCalled(); + }); + + it('blurs preview link after click', done => { const link = vm.$el.querySelector('li:nth-child(2) a'); spyOn(HTMLElement.prototype, 'blur'); link.click(); setTimeout(() => { - expect( - link.blur, - ).toHaveBeenCalled(); + expect(link.blur).toHaveBeenCalled(); done(); }); diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js index 6fe95153204..e8685ab48be 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js @@ -73,6 +73,22 @@ describe('BaseComponent', () => { expect(vm.$emit).toHaveBeenCalledWith('onLabelClick', mockLabels[0]); }); }); + + describe('handleCollapsedValueClick', () => { + it('emits toggleCollapse event on component', () => { + spyOn(vm, '$emit'); + vm.handleCollapsedValueClick(); + expect(vm.$emit).toHaveBeenCalledWith('toggleCollapse'); + }); + }); + + describe('handleDropdownHidden', () => { + it('emits onDropdownClose event on component', () => { + spyOn(vm, '$emit'); + vm.handleDropdownHidden(); + expect(vm.$emit).toHaveBeenCalledWith('onDropdownClose'); + }); + }); }); describe('mounted', () => { diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js index 39040670a87..da74595bcdc 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js @@ -56,6 +56,16 @@ describe('DropdownValueCollapsedComponent', () => { }); }); + describe('methods', () => { + describe('handleClick', () => { + it('emits onValueClick event on component', () => { + spyOn(vm, '$emit'); + vm.handleClick(); + expect(vm.$emit).toHaveBeenCalledWith('onValueClick'); + }); + }); + }); + describe('template', () => { it('renders component container element with tooltip`', () => { expect(vm.$el.dataset.placement).toBe('left'); diff --git a/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js b/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js index bbd50863069..34487885cf0 100644 --- a/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js +++ b/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js @@ -14,8 +14,8 @@ describe('Skeleton loading container', () => { vm.$destroy(); }); - it('renders 6 skeleton lines by default', () => { - expect(vm.$el.querySelector('.skeleton-line-6')).not.toBeNull(); + it('renders 3 skeleton lines by default', () => { + expect(vm.$el.querySelector('.skeleton-line-3')).not.toBeNull(); }); it('renders in full mode by default', () => { |