text: import { GlLink } from '@gitlab/ui';
  import { getAllByRole, getByTestId } from '@testing-library/dom';
  import { mount, shallowMount } from '@vue/test-utils';
  import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
  import VulnerabilityDetails from 'ee/vulnerabilities/components/vulnerability_details.vue';
  import {
    SUPPORTING_MESSAGE_TYPES,
    VULNERABILITY_TRAINING_HEADING,
  } from 'ee/vulnerabilities/constants';
  import VulnerabilityTraining from 'ee/vulnerabilities/components/vulnerability_training.vue';
  
  describe('Vulnerability Details', () => {
    let wrapper;
  
    const vulnerability = {
      severity: 'bad severity',
      confidence: 'high confidence',
      reportType: 'Some report type',
      description: 'vulnerability description',
      descriptionHtml: 'vulnerability description <code>sample</code>',
      identifiers: [],
    };
  
    const createWrapper = (vulnerabilityOverrides, { mountFn = mount, options = {} } = {}) => {
      const propsData = {
        vulnerability: { ...vulnerability, ...vulnerabilityOverrides },
      };
      wrapper = mountFn(VulnerabilityDetails, {
        propsData,
        provide: {
          projectFullPath: 'namespace/project',
        },
        ...options,
      });
    };
    const createShallowWrapper = (vulnerabilityOverrides, options = {}) =>
      createWrapper(vulnerabilityOverrides, { mountFn: shallowMount, options });
  
    const getById = (id) => wrapper.find(`[data-testid="${id}"]`);
    const getAllById = (id) => wrapper.findAll(`[data-testid="${id}"]`);
    const getText = (id) => getById(id).text();
    const findVulnerabilityTraining = () => wrapper.findComponent(VulnerabilityTraining);
  
    afterEach(() => {
      wrapper.destroy();
    });
  
    it('shows the properties that should always be shown', () => {
      createWrapper();
      expect(getById('description').html()).toContain(vulnerability.descriptionHtml);
      expect(wrapper.findComponent(SeverityBadge).props('severity')).toBe(vulnerability.severity);
      expect(getText('reportType')).toBe(`Tool: ${vulnerability.reportType}`);
  
      expect(getById('title').exists()).toBe(false);
      expect(getById('image').exists()).toBe(false);
      expect(getById('os').exists()).toBe(false);
      expect(getById('file').exists()).toBe(false);
      expect(getById('class').exists()).toBe(false);
      expect(getById('method').exists()).toBe(false);
      expect(getById('evidence').exists()).toBe(false);
      expect(getById('scanner').exists()).toBe(false);
      expect(getAllById('link')).toHaveLength(0);
      expect(getAllById('identifier')).toHaveLength(0);
    });
  
    it('renders description when descriptionHtml is not present', () => {
      createWrapper({
        descriptionHtml: null,
      });
      expect(getById('description').html()).not.toContain(vulnerability.descriptionHtml);
      expect(getText('description')).toBe(vulnerability.description);
    });
  
    it.each`
      reportType                  | expectedOutput
      ${'SAST'}                   | ${'SAST'}
      ${'DAST'}                   | ${'DAST'}
      ${'DEPENDENCY_SCANNING'}    | ${'Dependency Scanning'}
      ${'CONTAINER_SCANNING'}     | ${'Container Scanning'}
      ${'SECRET_DETECTION'}       | ${'Secret Detection'}
      ${'COVERAGE_FUZZING'}       | ${'Coverage Fuzzing'}
      ${'API_FUZZING'}            | ${'API Fuzzing'}
      ${'CLUSTER_IMAGE_SCANNING'} | ${'Cluster Image Scanning'}
    `(
      'displays "$expectedOutput" when report type is "$reportType"',
      ({ reportType, expectedOutput }) => {
        createWrapper({ reportType });
        expect(getText('reportType')).toBe(`Tool: ${expectedOutput}`);
      },
    );
  
    it('shows the title if it exists', () => {
      createWrapper({ title: 'some title' });
      expect(getText('title')).toBe('some title');
    });
  
    it('shows the location image if it exists', () => {
      createWrapper({ location: { image: 'some image' } });
      expect(getText('image')).toBe(`Image: some image`);
    });
  
    it('shows the operating system if it exists', () => {
      createWrapper({ location: { operatingSystem: 'linux' } });
      expect(getText('namespace')).toBe(`Namespace: linux`);
    });
  
    it('shows the vulnerability class if it exists', () => {
      createWrapper({ location: { file: 'file', class: 'class name' } });
      expect(getText('class')).toBe(`Class: class name`);
    });
  
    it('shows the vulnerability method if it exists', () => {
      createWrapper({ location: { file: 'file', method: 'method name' } });
      expect(getText('method')).toBe(`Method: method name`);
    });
  
    it('shows the evidence if it exists', () => {
      createWrapper({ evidence: 'some evidence' });
      expect(getText('evidence')).toBe(`Evidence: some evidence`);
    });
  
    it('shows the links if they exist', () => {
      createWrapper({ links: [{ url: '0' }, { url: '1' }, { url: '2' }] });
      const links = getAllById('link');
      expect(links).toHaveLength(3);
  
      links.wrappers.forEach((link, index) => {
        expect(link.attributes('target')).toBe('_blank');
        expect(link.attributes('href')).toBe(index.toString());
        expect(link.text()).toBe(index.toString());
      });
    });
  
    it('shows the vulnerability identifiers if they exist', () => {
      const identifiersData = [
        { name: '00', url: 'http://example.com/00' },
        { name: '11', url: 'http://example.com/11' },
        { name: '22', url: 'http://example.com/22' },
        { name: '33' },
        { name: '44' },
        { name: '55' },
      ];
  
      createWrapper({
        identifiers: identifiersData,
      });
  
      const identifiers = getAllById('identifier');
  
      expect(identifiers).toHaveLength(identifiersData.length);
  
      const checkIdentifier = ({ name, url }, index) => {
        const identifier = identifiers.at(index);
  
        expect(identifier.text()).toBe(name);
  
        if (url) {
          expect(identifier.is(GlLink)).toBe(true);
          expect(identifier.attributes()).toMatchObject({
            target: '_blank',
            href: url,
          });
        } else {
          expect(identifier.is(GlLink)).toBe(false);
        }
      };
  
      identifiersData.forEach(checkIdentifier);
    });
  
    it('shows the vulnerability assets if they exist', () => {
      const assetsData = [
        { name: 'Postman Collection', url: 'http://example.com/postman' },
        { name: 'HTTP Messages', url: 'http://example.com/http-messages' },
        { name: 'Foo' },
        { name: 'Bar' },
      ];
  
      createWrapper({
        assets: assetsData,
      });
  
      const assets = getAllById('asset');
  
      expect(assets).toHaveLength(assetsData.length);
  
      const checkIdentifier = ({ name, url }, index) => {
        const asset = assets.at(index);
  
        expect(asset.text()).toBe(name);
  
        if (url) {
          expect(asset.is(GlLink)).toBe(true);
          expect(asset.attributes()).toMatchObject({
            target: '_blank',
            href: url,
          });
        } else {
          expect(asset.is(GlLink)).toBe(false);
        }
      };
  
      assetsData.forEach(checkIdentifier);
    });
  
    describe('VulnerabilityTraining', () => {
      const identifiers = [{ externalType: 'cwe' }, { externalType: 'cve' }];
  
      it('renders component', () => {
        createShallowWrapper({
          identifiers,
        });
  
        expect(findVulnerabilityTraining().props()).toMatchObject({
          identifiers,
        });
      });
  
      it('renders title text', () => {
        createShallowWrapper(
          {
            identifiers,
          },
          {
            stubs: {
              VulnerabilityTraining: {
                template: '<div><slot name="header"></slot></div>',
              },
            },
          },
        );
  
        expect(wrapper.text()).toContain(VULNERABILITY_TRAINING_HEADING.title);
      });
    });
  
    describe('file link', () => {
      const file = () => getById('file').findComponent(GlLink);
  
      it('shows only the file name if there is no start line', () => {
        createWrapper({ location: { file: 'test.txt', blobPath: 'blob_path.txt' } });
        expect(file().attributes('target')).toBe('_blank');
        expect(file().attributes('href')).toBe('blob_path.txt');
        expect(file().text()).toBe('test.txt');
      });
  
      it('shows the correct line number when there is a start line', () => {
        createWrapper({ location: { file: 'test.txt', startLine: 24, blobPath: 'blob.txt' } });
        expect(file().attributes('target')).toBe('_blank');
        expect(file().attributes('href')).toBe('blob.txt#L24');
        expect(file().text()).toBe('test.txt:24');
      });
  
      it('shows the correct line numbers when there is a start and end line', () => {
        createWrapper({
          location: { file: 'test.txt', startLine: 24, endLine: 27, blobPath: 'blob.txt' },
        });
        expect(file().attributes('target')).toBe('_blank');
        expect(file().attributes('href')).toBe('blob.txt#L24-27');
        expect(file().text()).toBe('test.txt:24-27');
      });
  
      it('shows only the start line when the end line is the same', () => {
        createWrapper({
          location: { file: 'test.txt', startLine: 24, endLine: 24, blobPath: 'blob.txt' },
        });
        expect(file().attributes('target')).toBe('_blank');
        expect(file().attributes('href')).toBe('blob.txt#L24');
        expect(file().text()).toBe('test.txt:24');
      });
    });
  
    describe('scanner', () => {
      const link = () => getById('scannerSafeLink');
      const scannerText = () => getById('scanner').text();
  
      it('shows the scanner name only but no link', () => {
        createWrapper({ scanner: { name: 'some scanner' } });
        expect(scannerText()).toBe('Scanner: some scanner');
        expect(link().element instanceof HTMLSpanElement).toBe(true);
      });
  
      it('shows the scanner name and version but no link', () => {
        createWrapper({ scanner: { name: 'some scanner', version: '1.2.3' } });
        expect(scannerText()).toBe('Scanner: some scanner (version 1.2.3)');
        expect(link().element instanceof HTMLSpanElement).toBe(true);
      });
  
      it('shows the scanner name only with a link', () => {
        createWrapper({ scanner: { name: 'some tool', url: '//link' } });
        expect(scannerText()).toBe('Scanner: some tool');
        expect(link().attributes('href')).toBe('//link');
      });
  
      it('shows the scanner name and version with a link', () => {
        createWrapper({ scanner: { name: 'some tool', version: '1.2.3', url: '//link' } });
        expect(scannerText()).toBe('Scanner: some tool (version 1.2.3)');
        expect(link().attributes('href')).toBe('//link');
      });
    });
  
    describe('http data', () => {
      const TEST_HEADERS = [
        { name: 'Name1', value: 'Value1' },
        { name: 'Name2', value: 'Value2' },
      ];
      const EXPECT_REQUEST = {
        label: 'Sent request:',
        content: 'GET http://www.gitlab.com\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
        isCode: true,
      };
  
      const EXPECT_REQUEST_WITHOUT_BODY = {
        label: 'Sent request:',
        content:
          'GET http://www.gitlab.com\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
        isCode: true,
      };
  
      const EXPECT_REQUEST_WITH_EMPTY_STRING = {
        label: 'Sent request:',
        content: 'GET http://www.gitlab.com\nName1: Value1\nName2: Value2',
        isCode: true,
      };
  
      const EXPECT_RESPONSE = {
        label: 'Actual response:',
        content: '500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
        isCode: true,
      };
  
      const EXPECT_RESPONSE_WITHOUT_REASON_PHRASE = {
        label: 'Actual response:',
        content: '500 \nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
        isCode: true,
      };
  
      const EXPECT_RESPONSE_WITHOUT_BODY = {
        label: 'Actual response:',
        content:
          '500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
        isCode: true,
      };
  
      const EXPECT_RESPONSE_WITH_EMPTY_STRING = {
        label: 'Actual response:',
        content: '500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2',
        isCode: true,
      };
  
      const EXPECT_RECORDED_RESPONSE = {
        label: 'Unmodified response:',
        content: '200 OK\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
        isCode: true,
      };
  
      const EXPECT_RECORDED_RESPONSE_WITHOUT_REASON_PHRASE = {
        label: 'Unmodified response:',
        content: '200 \nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
        isCode: true,
      };
  
      const EXPECT_RECORDED_RESPONSE_WITHOUT_BODY = {
        label: 'Unmodified response:',
        content: '200 OK\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
        isCode: true,
      };
  
      const EXPECT_RECORDED_RESPONSE_WITH_EMPTY_STRING = {
        label: 'Unmodified response:',
        content: '200 OK\nName1: Value1\nName2: Value2',
        isCode: true,
      };
  
      const getTextContent = (el) => el.textContent.trim();
      const getLabel = (el) => getTextContent(getByTestId(el, 'label'));
      const getContent = (el) => getTextContent(getByTestId(el, 'value'));
      const getSectionData = (testId) => {
        const section = getById(testId).element;
  
        if (!section) {
          return null;
        }
  
        return getAllByRole(section, 'listitem').map((li) => ({
          label: getLabel(li),
          content: getContent(li),
          ...(li.querySelector('code') ? { isCode: true } : {}),
        }));
      };
  
      it.each`
        request                                                                                             | expectedData
        ${null}                                                                                             | ${null}
        ${{}}                                                                                               | ${null}
        ${{ headers: TEST_HEADERS }}                                                                        | ${null}
        ${{ method: 'GET' }}                                                                                | ${null}
        ${{ method: 'GET', url: 'http://www.gitlab.com' }}                                                  | ${null}
        ${{ method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }}                        | ${null}
        ${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }} | ${[EXPECT_REQUEST]}
        ${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: null }}               | ${[EXPECT_REQUEST_WITHOUT_BODY]}
        ${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: undefined }}          | ${[EXPECT_REQUEST_WITHOUT_BODY]}
        ${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: '' }}                 | ${[EXPECT_REQUEST_WITH_EMPTY_STRING]}
      `('shows request data for $request', ({ request, expectedData }) => {
        createWrapper({ request });
        expect(getSectionData('request')).toEqual(expectedData);
      });
  
      it.each`
        response                                                                                                         | expectedData
        ${null}                                                                                                          | ${null}
        ${{}}                                                                                                            | ${null}
        ${{ headers: TEST_HEADERS }}                                                                                     | ${null}
        ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]' }}                                                           | ${null}
        ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500' }}                                        | ${[EXPECT_RESPONSE_WITHOUT_REASON_PHRASE]}
        ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }} | ${[EXPECT_RESPONSE]}
        ${{ headers: TEST_HEADERS, body: null, statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }}               | ${[EXPECT_RESPONSE_WITHOUT_BODY]}
        ${{ headers: TEST_HEADERS, body: undefined, statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }}          | ${[EXPECT_RESPONSE_WITHOUT_BODY]}
        ${{ headers: TEST_HEADERS, body: '', statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }}                 | ${[EXPECT_RESPONSE_WITH_EMPTY_STRING]}
      `('shows response data for $response', ({ response, expectedData }) => {
        createWrapper({ response });
        expect(getSectionData('response')).toEqual(expectedData);
      });
  
      it.each`
        supportingMessages                                                                                                                                         | expectedData
        ${null}                                                                                                                                                    | ${null}
        ${[]}                                                                                                                                                      | ${null}
        ${[{}]}                                                                                                                                                    | ${null}
        ${[{}, { response: {} }]}                                                                                                                                  | ${null}
        ${[{}, { response: { headers: TEST_HEADERS } }]}                                                                                                           | ${null}
        ${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]' } }]}                                                                                 | ${null}
        ${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200' } }]}                                                             | ${null}
        ${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200', reason_phrase: 'OK' } }]}                                        | ${null}
        ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '200' } }]}                     | ${[EXPECT_RECORDED_RESPONSE_WITHOUT_REASON_PHRASE]}
        ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '200', reasonPhrase: 'OK' } }]} | ${[EXPECT_RECORDED_RESPONSE]}
        ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: null, statusCode: '200', reasonPhrase: 'OK' } }]}               | ${[EXPECT_RECORDED_RESPONSE_WITHOUT_BODY]}
        ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: undefined, statusCode: '200', reasonPhrase: 'OK' } }]}          | ${[EXPECT_RECORDED_RESPONSE_WITHOUT_BODY]}
        ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '', statusCode: '200', reasonPhrase: 'OK' } }]}                 | ${[EXPECT_RECORDED_RESPONSE_WITH_EMPTY_STRING]}
      `('shows response data for $supporting_messages', ({ supportingMessages, expectedData }) => {
        createWrapper({ supportingMessages });
        expect(getSectionData('recorded-response')).toEqual(expectedData);
      });
    });
  });
  