Commit f4d3ffca authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch '220601-improve-csv-export-button-tests' into 'master'

Improve CSV export button tests

See merge request gitlab-org/gitlab!40672
parents d6c4996f 43288bf1
...@@ -2,24 +2,26 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,24 +2,26 @@ import { shallowMount } from '@vue/test-utils';
import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { useFakeDate } from 'helpers/fake_date';
import CsvExportButton, { import CsvExportButton, {
STORAGE_KEY, STORAGE_KEY,
} from 'ee/security_dashboard/components/csv_export_button.vue'; } from 'ee/security_dashboard/components/csv_export_button.vue';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import statusCodes from '~/lib/utils/http_status'; import statusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import downloader from '~/lib/utils/downloader';
import { formatDate } from '~/lib/utils/datetime_utility';
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/lib/utils/datetime_utility', () => ({ jest.mock('~/lib/utils/downloader');
formatDate: () => '2020-04-12-10T14_32_35', useFakeDate();
}));
const mockReportDate = formatDate(new Date(), 'isoDateTime');
const vulnerabilitiesExportEndpoint = `${TEST_HOST}/vulnerability_findings.csv`; const vulnerabilitiesExportEndpoint = `${TEST_HOST}/vulnerability_findings.csv`;
describe('Csv Button Export', () => { describe('Csv Button Export', () => {
let mock; let mock;
let wrapper; let wrapper;
let spy;
const issueUrl = 'https://gitlab.com/gitlab-org/gitlab/issues/197111'; const issueUrl = 'https://gitlab.com/gitlab-org/gitlab/issues/197111';
const findPopoverExternalLink = () => wrapper.find({ ref: 'popoverExternalLink' }); const findPopoverExternalLink = () => wrapper.find({ ref: 'popoverExternalLink' });
...@@ -39,21 +41,12 @@ describe('Csv Button Export', () => { ...@@ -39,21 +41,12 @@ describe('Csv Button Export', () => {
}); });
}; };
const setupMocksAndSpy = (statusLink, downloadLink, downloadAnchor, status = 'finished') => { const mockCsvExportRequest = (download, status = 'finished') => {
mock mock
.onPost(vulnerabilitiesExportEndpoint) .onPost(vulnerabilitiesExportEndpoint)
.reply(statusCodes.ACCEPTED, { _links: { self: statusLink } }); .reply(statusCodes.ACCEPTED, { _links: { self: 'status/url' } });
mock.onGet(statusLink).reply(() => {
// We need to mock it at this stage because vue internally uses
// document.createElement to mount the elements.
spy = jest.spyOn(document, 'createElement').mockImplementationOnce(() => {
// eslint-disable-next-line no-param-reassign
downloadAnchor.click = jest.fn();
return downloadAnchor;
});
return [statusCodes.OK, { _links: { download: downloadLink }, status }]; mock.onGet('status/url').reply(statusCodes.OK, { _links: { download }, status });
});
}; };
afterEach(() => { afterEach(() => {
...@@ -75,62 +68,53 @@ describe('Csv Button Export', () => { ...@@ -75,62 +68,53 @@ describe('Csv Button Export', () => {
); );
}); });
it('is a link that initiates the download and polls until the file is ready, and then opens the download in a new tab.', () => { it('will start the download when clicked', async () => {
const downloadAnchor = document.createElement('a'); const url = 'download/url';
const statusLink = '/poll/until/complete'; mockCsvExportRequest(url);
const downloadLink = '/link/to/download';
setupMocksAndSpy(statusLink, downloadLink, downloadAnchor);
findCsvExportButton().vm.$emit('click'); findCsvExportButton().vm.$emit('click');
await axios.waitForAll();
return axios.waitForAll().then(() => {
expect(spy).toHaveBeenCalledWith('a'); expect(mock.history.post).toHaveLength(1); // POST is the create report endpoint.
expect(downloadAnchor.href).toContain(downloadLink); expect(mock.history.get).toHaveLength(1); // GET is the poll endpoint.
expect(downloadAnchor.getAttribute('download')).toBe( expect(downloader).toHaveBeenCalledTimes(1);
`csv-export-2020-04-12-10T14_32_35.csv`, expect(downloader).toHaveBeenCalledWith({
); fileName: `csv-export-${mockReportDate}.csv`,
expect(downloadAnchor.click).toHaveBeenCalled(); url,
}); });
}); });
it(`shows the flash error when the export job status is 'failed'`, () => { it('shows the flash error when the export job status is failed', async () => {
setupMocksAndSpy( mockCsvExportRequest('', 'failed');
'/poll/until/complete',
'/link/to/download',
document.createElement('a'),
'failed',
);
findCsvExportButton().vm.$emit('click'); findCsvExportButton().vm.$emit('click');
await axios.waitForAll();
return axios.waitForAll().then(() => { expect(downloader).not.toHaveBeenCalled();
expect(spy).not.toHaveBeenCalled(); expect(createFlash).toHaveBeenCalledWith('There was an error while generating the report.');
expect(createFlash).toHaveBeenCalledWith('There was an error while generating the report.');
});
}); });
it('shows the flash error when backend fails to generate the export', () => { it('shows the flash error when backend fails to generate the export', async () => {
mock.onPost(vulnerabilitiesExportEndpoint).reply(statusCodes.NOT_FOUND, {}); mock.onPost(vulnerabilitiesExportEndpoint).reply(statusCodes.NOT_FOUND, {});
findCsvExportButton().vm.$emit('click'); findCsvExportButton().vm.$emit('click');
await axios.waitForAll();
return axios.waitForAll().then(() => { expect(createFlash).toHaveBeenCalledWith('There was an error while generating the report.');
expect(createFlash).toHaveBeenCalledWith('There was an error while generating the report.');
});
}); });
it('displays the export icon when not loading and the loading icon when loading', () => { it('displays the export icon when not loading and the loading icon when loading', async () => {
expect(findCsvExportButton().props('icon')).toBe('export'); expect(findCsvExportButton().props()).toMatchObject({
expect(findCsvExportButton().props('loading')).toBe(false); icon: 'export',
loading: false,
wrapper.setData({
isPreparingCsvExport: true,
}); });
return wrapper.vm.$nextTick(() => { wrapper.setData({ isPreparingCsvExport: true });
expect(findCsvExportButton().props('icon')).toBeFalsy(); await wrapper.vm.$nextTick();
expect(findCsvExportButton().props('loading')).toBe(true);
expect(findCsvExportButton().props()).toMatchObject({
icon: '',
loading: true,
}); });
}); });
...@@ -138,13 +122,13 @@ describe('Csv Button Export', () => { ...@@ -138,13 +122,13 @@ describe('Csv Button Export', () => {
expect(findPopover().attributes('show')).toBeTruthy(); expect(findPopover().attributes('show')).toBeTruthy();
}); });
it('closes the popover when the button is clicked', () => { it('closes the popover when the button is clicked', async () => {
const button = findPopoverButton(); const button = findPopoverButton();
expect(button.text().trim()).toBe('Got it!'); expect(button.text().trim()).toBe('Got it!');
button.vm.$emit('click'); button.vm.$emit('click');
return wrapper.vm.$nextTick(() => { await wrapper.vm.$nextTick();
expect(findPopover().attributes('show')).toBeFalsy();
}); expect(findPopover().attributes('show')).toBeUndefined();
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment