summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_mr_widget/extensions/test_report/index_spec.js
blob: 88b8e32bd5d70578482502c67e3c614a2dc74d38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import { GlButton } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import testReportExtension from '~/vue_merge_request_widget/extensions/test_report';
import { i18n } from '~/vue_merge_request_widget/extensions/test_report/constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
import httpStatusCodes from '~/lib/utils/http_status';

import { failedReport } from 'jest/reports/mock_data/mock_data';
import mixedResultsTestReports from 'jest/reports/mock_data/new_and_fixed_failures_report.json';
import newErrorsTestReports from 'jest/reports/mock_data/new_errors_report.json';
import newFailedTestReports from 'jest/reports/mock_data/new_failures_report.json';
import successTestReports from 'jest/reports/mock_data/no_failures_report.json';
import resolvedFailures from 'jest/reports/mock_data/resolved_failures.json';

const reportWithParsingErrors = failedReport;
reportWithParsingErrors.suites[0].suite_errors = {
  head: 'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
  base: 'JUnit data parsing failed: string not matched',
};

describe('Test report extension', () => {
  let wrapper;
  let mock;

  registerExtension(testReportExtension);

  const endpoint = '/root/repo/-/merge_requests/4/test_reports.json';

  const mockApi = (statusCode, data = mixedResultsTestReports) => {
    mock.onGet(endpoint).reply(statusCode, data);
  };

  const findToggleCollapsedButton = () => wrapper.findByTestId('toggle-button');
  const findTertiaryButton = () => wrapper.find(GlButton);
  const findAllExtensionListItems = () => wrapper.findAllByTestId('extension-list-item');

  const createComponent = () => {
    wrapper = mountExtended(extensionsContainer, {
      propsData: {
        mr: {
          testResultsPath: endpoint,
          headBlobPath: 'head/blob/path',
          pipeline: { path: 'pipeline/path' },
        },
      },
    });
  };

  const createExpandedWidgetWithData = async (data = mixedResultsTestReports) => {
    mockApi(httpStatusCodes.OK, data);
    createComponent();
    await waitForPromises();
    findToggleCollapsedButton().trigger('click');
    await waitForPromises();
  };

  beforeEach(() => {
    mock = new MockAdapter(axios);
  });

  afterEach(() => {
    wrapper.destroy();
    mock.restore();
  });

  describe('summary', () => {
    it('displays loading text', () => {
      mockApi(httpStatusCodes.OK);
      createComponent();

      expect(wrapper.text()).toContain(i18n.loading);
    });

    it('displays failed loading text', async () => {
      mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
      createComponent();

      await waitForPromises();

      expect(wrapper.text()).toContain(i18n.error);
    });

    it.each`
      description                 | mockData                   | expectedResult
      ${'mixed test results'}     | ${mixedResultsTestReports} | ${'Test summary: 2 failed and 2 fixed test results, 11 total tests'}
      ${'unchanged test results'} | ${successTestReports}      | ${'Test summary: no changed test results, 11 total tests'}
      ${'tests with errors'}      | ${newErrorsTestReports}    | ${'Test summary: 2 errors, 11 total tests'}
      ${'failed test results'}    | ${newFailedTestReports}    | ${'Test summary: 2 failed, 11 total tests'}
      ${'resolved failures'}      | ${resolvedFailures}        | ${'Test summary: 4 fixed test results, 11 total tests'}
    `('displays summary text for $description', async ({ mockData, expectedResult }) => {
      mockApi(httpStatusCodes.OK, mockData);
      createComponent();

      await waitForPromises();

      expect(wrapper.text()).toContain(expectedResult);
    });

    it('displays a link to the full report', async () => {
      mockApi(httpStatusCodes.OK);
      createComponent();

      await waitForPromises();

      expect(findTertiaryButton().text()).toBe('Full report');
      expect(findTertiaryButton().attributes('href')).toBe('pipeline/path/test_report');
    });

    it('shows an error when a suite has a parsing error', async () => {
      mockApi(httpStatusCodes.OK, reportWithParsingErrors);
      createComponent();

      await waitForPromises();

      expect(wrapper.text()).toContain(i18n.error);
    });
  });

  describe('expanded data', () => {
    it('displays summary for each suite', async () => {
      await createExpandedWidgetWithData();

      expect(trimText(findAllExtensionListItems().at(0).text())).toBe(
        'rspec:pg: 1 failed and 2 fixed test results, 8 total tests',
      );
      expect(trimText(findAllExtensionListItems().at(1).text())).toBe(
        'java ant: 1 failed, 3 total tests',
      );
    });

    it('displays suite parsing errors', async () => {
      await createExpandedWidgetWithData(reportWithParsingErrors);

      const suiteText = trimText(findAllExtensionListItems().at(0).text());

      expect(suiteText).toContain(
        'Head report parsing error: JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
      );
      expect(suiteText).toContain(
        'Base report parsing error: JUnit data parsing failed: string not matched',
      );
    });
  });
});