import { GlPath, GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import Component from '~/cycle_analytics/components/path_navigation.vue';
import { transformedProjectStagePathData, selectedStage } from './mock_data';

describe('Project PathNavigation', () => {
  let wrapper = null;
  let trackingSpy = null;

  const createComponent = (props) => {
    return extendedWrapper(
      mount(Component, {
        propsData: {
          stages: transformedProjectStagePathData,
          selectedStage,
          loading: false,
          ...props,
        },
      }),
    );
  };

  const findPathNavigation = () => {
    return wrapper.findByTestId('gl-path-nav');
  };

  const findPathNavigationItems = () => {
    return findPathNavigation().findAll('li');
  };

  const findPathNavigationTitles = () => {
    return findPathNavigation()
      .findAll('li button')
      .wrappers.map((w) => w.html());
  };

  const clickItemAt = (index) => {
    findPathNavigationItems().at(index).find('button').trigger('click');
  };

  const pathItemContent = () => findPathNavigationItems().wrappers.map(extendedWrapper);
  const firstPopover = () => wrapper.findAllByTestId('stage-item-popover').at(0);

  beforeEach(() => {
    wrapper = createComponent();
    trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
  });

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

  describe('displays correctly', () => {
    it('has the correct props', () => {
      expect(wrapper.find(GlPath).props('items')).toMatchObject(transformedProjectStagePathData);
    });

    it('contains all the expected stages', () => {
      const stageContent = findPathNavigationTitles();
      transformedProjectStagePathData.forEach((stage, index) => {
        expect(stageContent[index]).toContain(stage.title);
      });
    });

    describe('loading', () => {
      describe('is false', () => {
        it('displays the gl-path component', () => {
          expect(wrapper.find(GlPath).exists()).toBe(true);
        });

        it('hides the gl-skeleton-loading component', () => {
          expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false);
        });

        it('renders each stage', () => {
          const result = findPathNavigationTitles();
          expect(result.length).toBe(transformedProjectStagePathData.length);
        });

        it('renders each stage with its median', () => {
          const result = findPathNavigationTitles();
          transformedProjectStagePathData.forEach(({ title, metric }, index) => {
            expect(result[index]).toContain(title);
            expect(result[index]).toContain(metric);
          });
        });

        describe('popovers', () => {
          beforeEach(() => {
            wrapper = createComponent({ stages: transformedProjectStagePathData });
          });

          it('renders popovers for all stages', () => {
            pathItemContent().forEach((stage) => {
              expect(stage.findByTestId('stage-item-popover').exists()).toBe(true);
            });
          });

          it('shows the median stage time for the first stage item', () => {
            expect(firstPopover().text()).toContain('Stage time (median)');
          });
        });
      });

      describe('is true', () => {
        beforeEach(() => {
          wrapper = createComponent({ loading: true });
        });

        it('hides the gl-path component', () => {
          expect(wrapper.find(GlPath).exists()).toBe(false);
        });

        it('displays the gl-skeleton-loading component', () => {
          expect(wrapper.find(GlSkeletonLoading).exists()).toBe(true);
        });
      });
    });
  });

  describe('event handling', () => {
    it('emits the selected event', () => {
      expect(wrapper.emitted('selected')).toBeUndefined();

      clickItemAt(0);
      clickItemAt(1);
      clickItemAt(2);

      expect(wrapper.emitted().selected).toEqual([
        [transformedProjectStagePathData[0]],
        [transformedProjectStagePathData[1]],
        [transformedProjectStagePathData[2]],
      ]);
    });

    it('sends tracking information', () => {
      clickItemAt(0);

      expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_path_navigation', {
        extra: { stage_id: selectedStage.slug },
      });
    });
  });
});
