diff options
-rw-r--r-- | app/serializers/merge_request_noteable_entity.rb | 2 | ||||
-rw-r--r-- | changelogs/unreleased/id-autosave-for-new-mr.yml | 5 | ||||
-rw-r--r-- | doc/user/project/merge_requests/index.md | 2 | ||||
-rw-r--r-- | spec/controllers/registrations_controller_spec.rb | 12 | ||||
-rw-r--r-- | spec/features/merge_request/user_posts_notes_spec.rb | 11 | ||||
-rw-r--r-- | spec/fixtures/api/schemas/entities/merge_request_noteable.json | 4 | ||||
-rw-r--r-- | spec/frontend/environment.js | 1 | ||||
-rw-r--r-- | spec/frontend/test_setup.js | 3 | ||||
-rw-r--r-- | spec/javascripts/monitoring/components/dashboard_spec.js (renamed from spec/frontend/monitoring/components/dashboard_spec.js) | 380 | ||||
-rw-r--r-- | spec/serializers/merge_request_serializer_spec.rb | 5 |
10 files changed, 224 insertions, 201 deletions
diff --git a/app/serializers/merge_request_noteable_entity.rb b/app/serializers/merge_request_noteable_entity.rb index e22be6880bb..9504fdd8eac 100644 --- a/app/serializers/merge_request_noteable_entity.rb +++ b/app/serializers/merge_request_noteable_entity.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class MergeRequestNoteableEntity < Grape::Entity +class MergeRequestNoteableEntity < IssuableEntity include RequestAwareEntity # Currently this attr is exposed to be used in app/assets/javascripts/notes/stores/getters.js diff --git a/changelogs/unreleased/id-autosave-for-new-mr.yml b/changelogs/unreleased/id-autosave-for-new-mr.yml new file mode 100644 index 00000000000..8f269094715 --- /dev/null +++ b/changelogs/unreleased/id-autosave-for-new-mr.yml @@ -0,0 +1,5 @@ +--- +title: Fix sharing localStorage with all MRs +merge_request: 32699 +author: +type: fixed diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 4e79d66df47..aa58e971cc3 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -398,6 +398,8 @@ You can also use this push option in addition to the ### Add or remove labels using git push options +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31831) in GitLab 12.3. + You can add or remove labels from merge requests using push options. For example, to add two labels to an existing merge request, use the diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 35487682462..b79a1ac4810 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -83,6 +83,13 @@ describe RegistrationsController do stub_application_setting(recaptcha_enabled: true) end + after do + # Avoid test ordering issue and ensure `verify_recaptcha` returns true + unless Recaptcha.configuration.skip_verify_env.include?('test') + Recaptcha.configuration.skip_verify_env << 'test' + end + end + it 'displays an error when the reCAPTCHA is not solved' do fail_recaptcha @@ -93,11 +100,6 @@ describe RegistrationsController do end it 'redirects to the dashboard when the recaptcha is solved' do - # Avoid test ordering issue and ensure `verify_recaptcha` returns true - unless Recaptcha.configuration.skip_verify_env.include?('test') - Recaptcha.configuration.skip_verify_env << 'test' - end - post(:create, params: user_params) expect(flash[:notice]).to include 'Welcome! You have signed up successfully.' diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index 435b3cd2555..7d89b8e97a6 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -5,7 +5,8 @@ require 'spec_helper' describe 'Merge request > User posts notes', :js do include NoteInteractionHelpers - let(:project) { create(:project, :repository) } + set(:project) { create(:project, :repository) } + let(:user) { project.creator } let(:merge_request) do create(:merge_request, source_project: project, target_project: project) @@ -33,17 +34,21 @@ describe 'Merge request > User posts notes', :js do end describe 'with text' do + let(:text) { 'This is awesome' } + before do page.within('.js-main-target-form') do - fill_in 'note[note]', with: 'This is awesome' + fill_in 'note[note]', with: text end end - it 'has enable submit button and preview button' do + it 'has enable submit button, preview button and saves content to local storage' do page.within('.js-main-target-form') do expect(page).not_to have_css('.js-comment-button[disabled]') expect(page).to have_css('.js-md-preview-button', visible: true) end + + expect(page.evaluate_script("localStorage['autosave/Note/MergeRequest/#{merge_request.id}']")).to eq(text) end end end diff --git a/spec/fixtures/api/schemas/entities/merge_request_noteable.json b/spec/fixtures/api/schemas/entities/merge_request_noteable.json index 88b0fecc24c..d37f5b864d7 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_noteable.json +++ b/spec/fixtures/api/schemas/entities/merge_request_noteable.json @@ -1,6 +1,10 @@ { "type": "object", "properties" : { + "id": { "type": "integer" }, + "iid": { "type": "integer" }, + "title": { "type": "string" }, + "description": { "type": "string" }, "merge_params": { "type": ["object", "null"] }, "state": { "type": "string" }, "source_branch": { "type": "string" }, diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js index a8e42721bf0..290c0e797cb 100644 --- a/spec/frontend/environment.js +++ b/spec/frontend/environment.js @@ -40,7 +40,6 @@ class CustomEnvironment extends JSDOMEnvironment { this.global.fixturesBasePath = `${ROOT_PATH}/tmp/tests/frontend/fixtures${IS_EE ? '-ee' : ''}`; this.global.staticFixturesBasePath = `${ROOT_PATH}/spec/frontend/fixtures`; - this.global.IS_EE = IS_EE; // Not yet supported by JSDOM: https://github.com/jsdom/jsdom/issues/317 this.global.document.createRange = () => ({ diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index e7944441fe1..d52aeb1fe6b 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -73,9 +73,6 @@ expect.extend(customMatchers); // Tech debt issue TBD testUtilsConfig.logModifiedComponents = false; -// Stub for URL.createObjectURL -window.URL.createObjectURL = function createObjectURL() {}; - // Basic stub for MutationObserver global.MutationObserver = () => ({ disconnect: () => {}, diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js index 2a8e0240bf9..15e41e2fe93 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/javascripts/monitoring/components/dashboard_spec.js @@ -1,64 +1,19 @@ import Vue from 'vue'; import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlToast, GlDropdownItem } from '@gitlab/ui'; +import { GlToast } from '@gitlab/ui'; import MockAdapter from 'axios-mock-adapter'; import Dashboard from '~/monitoring/components/dashboard.vue'; -import GraphGroup from '~/monitoring/components/graph_group.vue'; -import EmptyState from '~/monitoring/components/empty_state.vue'; -import { timeWindows } from '~/monitoring/constants'; +import { timeWindows, timeWindowsKeyNames } from '~/monitoring/constants'; import * as types from '~/monitoring/stores/mutation_types'; import { createStore } from '~/monitoring/stores'; import axios from '~/lib/utils/axios_utils'; - -// TODO: replace with dynamic fixture -// https://gitlab.com/gitlab-org/gitlab-ce/issues/62785 import MonitoringMock, { metricsGroupsAPIResponse, mockApiEndpoint, environmentData, singleGroupResponse, dashboardGitResponse, -} from '../../../../spec/javascripts/monitoring/mock_data'; - -/* eslint-disable no-unused-vars */ -/* eslint-disable no-undef */ -// see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/32571#note_211860465 -function setupComponentStore(component) { - component.$store.commit( - `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, - metricsGroupsAPIResponse, - ); - component.$store.commit( - `monitoringDashboard/${types.SET_QUERY_RESULT}`, - mockedQueryResultPayload, - ); - component.$store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); -} - -// Mock imported files while retaining the original behaviour -// See https://github.com/facebook/jest/issues/936#issuecomment-265074320 -function mockMonitoringUtils() { - const original = require.requireActual('~/monitoring/utils'); - return { - ...original, // Pass down all the exported objects - getTimeDiff: jest.spyOn(original, 'getTimeDiff'), - }; -} -jest.mock('~/monitoring/utils', () => mockMonitoringUtils()); -const monitoringUtils = require.requireMock('~/monitoring/utils'); - -function mockUrlUtility() { - const original = require.requireActual('~/lib/utils/url_utility'); - return { - ...original, // Pass down all the exported objects - getParameterValues: jest.spyOn(original, 'getParameterValues'), - }; -} -jest.mock('~/lib/utils/url_utility', () => mockUrlUtility()); -const urlUtility = require.requireMock('~/lib/utils/url_utility'); +} from '../mock_data'; const localVue = createLocalVue(); const propsData = { @@ -128,7 +83,7 @@ describe('Dashboard', () => { }); it('shows the environment selector', () => { - expect(component.$el.querySelector('#monitor-environments-dropdown')).toBeTruthy(); + expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy(); }); }); @@ -140,7 +95,7 @@ describe('Dashboard', () => { store, }); - expect(component.$el.querySelector('#monitor-environments-dropdown')).toBeTruthy(); + expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy(); }); }); @@ -162,27 +117,47 @@ describe('Dashboard', () => { }); }); + it('hides the legend when showLegend is false', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showLegend: false, + }, + store, + }); + + setTimeout(() => { + expect(component.showEmptyState).toEqual(false); + expect(component.$el.querySelector('.legend-group')).toEqual(null); + expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy(); + done(); + }); + }); + it('hides the group panels when showPanels is false', done => { - const wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, }, store, - sync: false, - localVue, }); - setImmediate(() => { - expect(wrapper.find(EmptyState).exists()).toBe(false); - expect(wrapper.find(GraphGroup).exists()).toBe(true); - expect(wrapper.find(GraphGroup).props().showPanels).toBe(false); + + setTimeout(() => { + expect(component.showEmptyState).toEqual(false); + expect(component.$el.querySelector('.prometheus-panel')).toEqual(null); + expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy(); done(); }); }); - it('renders the environments dropdown with a number of environments', () => { - const wrapper = shallowMount(DashboardComponent, { + it('renders the environments dropdown with a number of environments', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -191,30 +166,38 @@ describe('Dashboard', () => { store, }); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, environmentData, ); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - Vue.nextTick(() => { - const dropdownMenuEnvironments = wrapper - .find('.js-environments-dropdown') - .findAll(GlDropdownItem); + Vue.nextTick() + .then(() => { + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); - expect(environmentData.length).toBeGreaterThan(0); - expect(dropdownMenuEnvironments.length).toEqual(environmentData.length); - dropdownMenuEnvironments.wrappers.forEach((value, index) => { - expect(value.attributes('href')).toEqual(environmentData[index].metrics_path); - }); - }); + expect(component.environments.length).toEqual(environmentData.length); + expect(dropdownMenuEnvironments.length).toEqual(component.environments.length); + + Array.from(dropdownMenuEnvironments).forEach((value, index) => { + if (environmentData[index].metrics_path) { + expect(value).toHaveAttr('href', environmentData[index].metrics_path); + } + }); + + done(); + }) + .catch(done.fail); }); - it('hides the environments dropdown list when there is no environments', () => { - const wrapper = shallowMount(DashboardComponent, { + it('hides the environments dropdown list when there is no environments', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -223,48 +206,54 @@ describe('Dashboard', () => { store, }); - const findEnvironmentsDropdownItems = () => wrapper.find('#monitor-environments-wrapper'); - - store.commit(`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, []); - store.commit( + component.$store.commit(`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, []); + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - return Vue.nextTick(() => { - expect(findEnvironmentsDropdownItems(wrapper).exists()).toEqual(false); - }); + Vue.nextTick() + .then(() => { + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); + + expect(dropdownMenuEnvironments.length).toEqual(0); + done(); + }) + .catch(done.fail); }); - it('renders the environments dropdown with a single active element', () => { - const wrapper = shallowMount(DashboardComponent, { + it('renders the environments dropdown with a single active element', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, }, store, - sync: false, - localVue, }); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, environmentData, ); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - Vue.nextTick(() => { - const activeDropdownMenuEnvironments = wrapper - .find('#monitor-environments-dropdown') - .findAll(GlDropdownItem) - .filter(item => item.attributes('active') === 'true'); + Vue.nextTick() + .then(() => { + const dropdownItems = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item.active', + ); - expect(activeDropdownMenuEnvironments.length).toEqual(1); - }); + expect(dropdownItems.length).toEqual(1); + done(); + }) + .catch(done.fail); }); it('hides the dropdown', done => { @@ -288,40 +277,33 @@ describe('Dashboard', () => { }); it('renders the time window dropdown with a set of options', done => { - const wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, - sync: false, }, store, }); - const numberOfTimeWindows = Object.keys(timeWindows).length; - setImmediate(() => { - const timeWindowDropdown = wrapper.find('.js-time-window-dropdown'); - const timeWindowDropdownEls = wrapper - .find('.js-time-window-dropdown') - .findAll(GlDropdownItem); + setTimeout(() => { + const timeWindowDropdown = component.$el.querySelector('.js-time-window-dropdown'); + const timeWindowDropdownEls = component.$el.querySelectorAll( + '.js-time-window-dropdown .dropdown-item', + ); - expect(timeWindowDropdown.exists()).toBe(true); + expect(timeWindowDropdown).not.toBeNull(); expect(timeWindowDropdownEls.length).toEqual(numberOfTimeWindows); done(); }); }); - it('fetches the metrics data with proper time window', () => { - jest.spyOn(store, 'dispatch').mockImplementationOnce(() => {}); - - store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); - - shallowMount(DashboardComponent, { + it('fetches the metrics data with proper time window', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -330,49 +312,75 @@ describe('Dashboard', () => { store, }); - const defaultRange = monitoringUtils.getTimeDiff(); - return Vue.nextTick().then(() => { - expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', defaultRange); - }); + spyOn(component.$store, 'dispatch').and.stub(); + const getTimeDiffSpy = spyOnDependency(Dashboard, 'getTimeDiff').and.callThrough(); + + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, + environmentData, + ); + + component.$mount(); + + Vue.nextTick() + .then(() => { + expect(component.$store.dispatch).toHaveBeenCalled(); + expect(getTimeDiffSpy).toHaveBeenCalled(); + + done(); + }) + .catch(done.fail); }); it('shows a specific time window selected from the url params', done => { const start = 1564439536; const end = 1564441336; - monitoringUtils.getTimeDiff.mockReturnValueOnce({ + spyOnDependency(Dashboard, 'getTimeDiff').and.returnValue({ start, end, }); - urlUtility.getParameterValues.mockImplementationOnce(param => { + spyOnDependency(Dashboard, 'getParameterValues').and.callFake(param => { if (param === 'start') return [start]; if (param === 'end') return [end]; return []; }); - const wrapper = shallowMount(DashboardComponent, { - propsData: { - ...propsData, - hasMetrics: true, - showPanels: false, - }, + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { ...propsData, hasMetrics: true }, store, }); - setImmediate(() => { - const activeTimeWindowItems = wrapper - .find('.js-time-window-dropdown') - .findAll(GlDropdownItem) - .filter(item => item.attributes('active') === 'true'); + setTimeout(() => { + const selectedTimeWindow = component.$el.querySelector('.js-time-window-dropdown .active'); + + expect(selectedTimeWindow.textContent.trim()).toEqual('30 minutes'); + done(); + }); + }); - expect(activeTimeWindowItems.length).toEqual(1); - expect(activeTimeWindowItems.wrappers[0].text().trim()).toEqual('30 minutes'); + it('defaults to the eight hours time window for non valid url parameters', done => { + spyOnDependency(Dashboard, 'getParameterValues').and.returnValue([ + '<script>alert("XSS")</script>', + ]); + + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { ...propsData, hasMetrics: true }, + store, + }); + + Vue.nextTick(() => { + expect(component.selectedTimeWindowKey).toEqual(timeWindowsKeyNames.eightHours); done(); }); }); }); - describe('link to chart', () => { + // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922 + // eslint-disable-next-line jasmine/no-disabled-tests + xdescribe('link to chart', () => { let wrapper; const currentDashboard = 'TEST_DASHBOARD'; localVue.use(GlToast); @@ -384,13 +392,13 @@ describe('Dashboard', () => { wrapper = shallowMount(DashboardComponent, { localVue, + sync: false, + attachToDocument: true, propsData: { ...propsData, hasMetrics: true, currentDashboard }, store, }); - setImmediate(() => { - done(); - }); + setTimeout(done); }); afterEach(() => { @@ -429,7 +437,7 @@ describe('Dashboard', () => { }); it('creates a toast when clicked', () => { - jest.spyOn(wrapper.vm.$toast, 'show').mockImplementation(() => {}); + spyOn(wrapper.vm.$toast, 'show').and.stub(); link().vm.$emit('click'); @@ -440,6 +448,11 @@ describe('Dashboard', () => { describe('when the window resizes', () => { beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); + jasmine.clock().install(); + }); + + afterEach(() => { + jasmine.clock().uninstall(); }); it('sets elWidth to page width when the sidebar is resized', done => { @@ -460,7 +473,7 @@ describe('Dashboard', () => { Vue.nextTick() .then(() => { - jest.advanceTimersByTime(1000); + jasmine.clock().tick(1000); return Vue.nextTick(); }) .then(() => { @@ -472,12 +485,11 @@ describe('Dashboard', () => { }); describe('external dashboard link', () => { - let wrapper; - - beforeEach(done => { + beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); - wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -486,53 +498,61 @@ describe('Dashboard', () => { externalDashboardUrl: '/mockUrl', }, store, - sync: false, - localVue, }); - - setImmediate(done); }); - it('shows the link', () => { - expect(wrapper.find('.js-external-dashboard-link').text()).toContain('View full dashboard'); + it('shows the link', done => { + setTimeout(() => { + expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain( + 'View full dashboard', + ); + done(); + }); }); }); describe('Dashboard dropdown', () => { - let wrapper; - - beforeEach(done => { + beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); - wrapper = shallowMount(DashboardComponent, { - propsData: { ...propsData, hasMetrics: true, showPanels: false }, + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showPanels: false, + }, store, - sync: false, - localVue, }); - setImmediate(() => { - store.dispatch('monitoringDashboard/setFeatureFlags', { - prometheusEndpoint: false, - multipleDashboardsEnabled: true, - }); + component.$store.dispatch('monitoringDashboard/setFeatureFlags', { + prometheusEndpoint: false, + multipleDashboardsEnabled: true, + }); - store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); - store.commit( - `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, - singleGroupResponse, - ); + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, + environmentData, + ); - store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, dashboardGitResponse); - done(); - }); + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, + singleGroupResponse, + ); + + component.$store.commit( + `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, + dashboardGitResponse, + ); }); - it('shows the dashboard dropdown', () => { - expect(wrapper.find('.js-dashboards-dropdown').exists()).toEqual(true); + it('shows the dashboard dropdown', done => { + setTimeout(() => { + const dashboardDropdown = component.$el.querySelector('.js-dashboards-dropdown'); + + expect(dashboardDropdown).not.toEqual(null); + done(); + }); }); }); @@ -557,25 +577,13 @@ describe('Dashboard', () => { const data = mockGraphData.queries[0].result[0].values; const firstRow = `${data[0][0]},${data[0][1]}`; - expect(component.csvText(mockGraphData)).toContain(`${header}\r\n${firstRow}`); + expect(component.csvText(mockGraphData)).toMatch(`^${header}\r\n${firstRow}`); }); }); describe('downloadCsv', () => { - let spy; - - beforeEach(() => { - spy = jest.spyOn(window.URL, 'createObjectURL'); - }); - - afterEach(() => { - spy.mockRestore(); - }); - - it('creates a string containing a URL that represents the object', () => { - component.downloadCsv(mockGraphData); - - expect(spy).toHaveBeenCalled(); + it('produces a link with a Blob', () => { + expect(component.downloadCsv(mockGraphData)).toContain(`blob:`); }); }); }); diff --git a/spec/serializers/merge_request_serializer_spec.rb b/spec/serializers/merge_request_serializer_spec.rb index d1483c3c41e..cf0b8ea9b40 100644 --- a/spec/serializers/merge_request_serializer_spec.rb +++ b/spec/serializers/merge_request_serializer_spec.rb @@ -1,8 +1,9 @@ require 'spec_helper' describe MergeRequestSerializer do - let(:user) { create(:user) } - let(:resource) { create(:merge_request) } + set(:user) { create(:user) } + set(:resource) { create(:merge_request, description: "Description") } + let(:json_entity) do described_class.new(current_user: user) .represent(resource, serializer: serializer) |