import { mount, shallowMount } from '@vue/test-utils';
import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { cloneDeep } from 'lodash';
import { mockFindings } from '../mock_data';

function makeVulnerability(changes = {}) {
  return Object.assign(cloneDeep(mockFindings[0]), changes);
}

describe('VulnerabilityDetails component', () => {
  let wrapper;

  const componentFactory = vulnerability => {
    wrapper = mount(VulnerabilityDetails, {
      propsData: { vulnerability },
    });
  };

  const expectSafeLink = (link, { href, text }) => {
    expect(link.is(SafeLink)).toBe(true);
    expect(link.props('href')).toBe(href);
    expect(link.text()).toBe(text);
  };

  const findLink = name => wrapper.find({ ref: `${name}Link` });

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

  it('renders severity with a badge', () => {
    const vulnerability = makeVulnerability({ severity: 'critical' });
    componentFactory(vulnerability);
    const badge = wrapper.find(SeverityBadge);

    expect(badge.props('severity')).toBe(vulnerability.severity);
  });

  it('renders link fields with link', () => {
    const vulnerability = makeVulnerability();
    componentFactory(vulnerability);

    expectSafeLink(findLink('project'), {
      href: vulnerability.project.full_path,
      text: vulnerability.project.full_name,
    });
  });

  it('renders wrapped file paths', () => {
    const vulnerability = makeVulnerability({
      blob_path: `${TEST_HOST}/bar`,
      location: {
        file: '/some/file/path',
      },
    });

    componentFactory(vulnerability);

    expect(findLink('file').html()).toMatch('/<wbr>some/<wbr>file/<wbr>path');
  });

  it('escapes wrapped file paths', () => {
    const vulnerability = makeVulnerability({
      blob_path: `${TEST_HOST}/bar`,
      location: {
        file: '/unsafe/path<script></script>',
      },
    });

    componentFactory(vulnerability);

    expect(findLink('file').html()).toMatch(
      '/<wbr>unsafe/<wbr>path&lt;script&gt;&lt;/<wbr>script&gt;',
    );
  });

  describe('does not render XSS links', () => {
    // eslint-disable-next-line no-script-url
    const badUrl = 'javascript:alert("")';

    beforeEach(() => {
      const vulnerability = makeVulnerability({
        blob_path: badUrl,
        location: {
          file: 'badFile.lock',
        },
        links: [{ url: badUrl }],
        identifiers: [{ name: 'BAD_URL', url: badUrl }],
        instances: [{ method: 'GET', uri: badUrl }],
      });

      componentFactory(vulnerability);
    });

    it('for the link field', () => {
      expectSafeLink(findLink('links'), {
        href: badUrl,
        text: badUrl,
      });
    });

    it('for the identifiers field', () => {
      expectSafeLink(findLink('identifiers'), {
        href: badUrl,
        text: 'BAD_URL',
      });
    });

    it('for the file field', () => {
      expectSafeLink(findLink('file'), {
        href: badUrl,
        text: 'badFile.lock',
      });
    });

    it('for the instances field', () => {
      expectSafeLink(wrapper.find('.report-block-list-issue-description-link .break-link'), {
        href: badUrl,
        text: badUrl,
      });
    });
  });

  describe('with instances', () => {
    beforeEach(() => {
      const vulnerability = makeVulnerability({
        instances: [
          { uri: 'http://192.168.32.236:3001/explore?sort=latest_activity_desc' },
          { uri: 'http://192.168.32.236:3001/help/user/group/subgroups/index.md' },
        ],
      });

      componentFactory(vulnerability);
    });

    it('renders instances list', () => {
      const instances = wrapper.findAll('.report-block-list li').wrappers;

      expect(instances[0].text()).toContain(
        'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
      );

      expect(instances[1].text()).toContain(
        'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
      );
    });
  });

  describe('pin test', () => {
    const factory = vulnFinding => {
      wrapper = shallowMount(VulnerabilityDetails, {
        propsData: {
          vulnerability: vulnFinding,
        },
      });
    };

    it('renders correctly', () => {
      factory(
        makeVulnerability({
          instances: [
            {
              method: 'POST',
              evidence: 'foo',
              uri: '/bar',
            },
          ],
        }),
      );

      expect(wrapper.element).toMatchSnapshot();
    });
  });
});
