mirror of
https://gitlab.com/gitlab-org/gitlab-foss.git
synced 2025-08-01 16:04:19 +00:00
450 lines
14 KiB
JavaScript
450 lines
14 KiB
JavaScript
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
|
|
import { nextTick } from 'vue';
|
|
import mockDeploymentFixture from 'test_fixtures/graphql/deployments/graphql/queries/deployment.query.graphql.json';
|
|
import mockEnvironmentFixture from 'test_fixtures/graphql/deployments/graphql/queries/environment.query.graphql.json';
|
|
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
|
import ShowMore from '~/vue_shared/components/show_more.vue';
|
|
import DeploymentAside from '~/deployments/components/deployment_aside.vue';
|
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
|
import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper';
|
|
import { CLICK_PIPELINE_LINK_ON_DEPLOYMENT_PAGE } from '~/deployments/utils';
|
|
|
|
const {
|
|
data: {
|
|
project: { deployment },
|
|
},
|
|
} = mockDeploymentFixture;
|
|
const {
|
|
data: {
|
|
project: { environment },
|
|
},
|
|
} = mockEnvironmentFixture;
|
|
const { bindInternalEventDocument } = useMockInternalEventsTracking();
|
|
|
|
describe('~/deployments/components/deployment_aside.vue', () => {
|
|
let wrapper;
|
|
|
|
const findSidebarToggleButton = () => wrapper.findByTestId('deployment-sidebar-toggle-button');
|
|
const findSidebar = () => wrapper.findByTestId('deployment-sidebar');
|
|
const findSidebarItems = () => wrapper.findByTestId('deployment-sidebar-items');
|
|
const findUrlButtonWrapper = () => wrapper.findByTestId('deployment-url-button-wrapper');
|
|
const findTriggererItem = () => wrapper.findByTestId('deployment-triggerer-item');
|
|
const findPipelineSection = () => wrapper.findByTestId('deployment-pipeline');
|
|
const findPipelineLink = () => wrapper.findByTestId('deployment-pipeline-link');
|
|
const findJobLink = () => wrapper.findByTestId('deployment-job');
|
|
|
|
const createComponent = ({ propsData = {} } = {}) => {
|
|
wrapper = mountExtended(DeploymentAside, {
|
|
propsData: {
|
|
deployment,
|
|
environment,
|
|
loading: false,
|
|
...propsData,
|
|
},
|
|
});
|
|
};
|
|
|
|
describe('loading', () => {
|
|
it('hides everything', () => {
|
|
createComponent({ propsData: { loading: true } });
|
|
|
|
expect(wrapper.find('aside').exists()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('with all properties', () => {
|
|
beforeEach(() => {
|
|
createComponent();
|
|
});
|
|
|
|
it('shows a link to the external url', () => {
|
|
const link = wrapper.findByRole('link', { name: 'Open URL' });
|
|
|
|
expect(link.attributes('href')).toBe(environment.externalUrl);
|
|
});
|
|
|
|
it('shows a link to the triggerer', () => {
|
|
const link = wrapper.findByTestId('deployment-triggerer');
|
|
|
|
expect(link.attributes('href')).toBe(deployment.triggerer.webUrl);
|
|
expect(link.text()).toContain(deployment.triggerer.name);
|
|
});
|
|
|
|
it('shows a section with a link to the Pipeline', () => {
|
|
expect(findPipelineSection().exists()).toBe(true);
|
|
expect(findPipelineSection().text()).toContain('Pipeline');
|
|
|
|
expect(findPipelineLink().exists()).toBe(true);
|
|
expect(findPipelineLink().attributes('href')).toBe(deployment.job.pipeline.path);
|
|
expect(findPipelineLink().text()).toBe(`#${getIdFromGraphQLId(deployment.job.pipeline.id)}`);
|
|
});
|
|
|
|
it('should call trackEvent method when pipeline link is clicked', async () => {
|
|
const { trackEventSpy } = bindInternalEventDocument(wrapper.element);
|
|
|
|
await findPipelineLink().vm.$emit('click');
|
|
|
|
expect(trackEventSpy).toHaveBeenCalledTimes(1);
|
|
expect(trackEventSpy).toHaveBeenCalledWith(
|
|
CLICK_PIPELINE_LINK_ON_DEPLOYMENT_PAGE,
|
|
{},
|
|
undefined,
|
|
);
|
|
});
|
|
|
|
it('shows a link to the tags of a deployment', () => {
|
|
deployment.tags.forEach((tag) => {
|
|
const link = wrapper.findByRole('link', { name: tag.name });
|
|
|
|
expect(link.attributes('href')).toBe(tag.webPath);
|
|
});
|
|
});
|
|
|
|
it('links to the deployment ref', () => {
|
|
const link = wrapper.findByRole('link', { name: deployment.ref });
|
|
|
|
expect(link.attributes('href')).toBe(deployment.refPath);
|
|
});
|
|
|
|
it('displays if the ref is a branch', () => {
|
|
const ref = wrapper.findByTestId('deployment-ref');
|
|
|
|
expect(ref.find('span').text()).toBe('Branch');
|
|
});
|
|
});
|
|
|
|
describe('link to the job page', () => {
|
|
it('displays a link when webPath is available', () => {
|
|
createComponent();
|
|
|
|
expect(findJobLink().attributes('href')).toBe(deployment.job.webPath);
|
|
expect(findJobLink().text()).toBe(deployment.job.name);
|
|
});
|
|
|
|
it('displays job name without a link when webPath is not available', () => {
|
|
const deploymentWithNoJobPath = {
|
|
...deployment,
|
|
job: {
|
|
...deployment.job,
|
|
webPath: null,
|
|
},
|
|
};
|
|
|
|
createComponent({ propsData: { deployment: deploymentWithNoJobPath } });
|
|
|
|
expect(findJobLink().attributes('href')).toBeUndefined();
|
|
expect(findJobLink().text()).toBe(deploymentWithNoJobPath.job.name);
|
|
});
|
|
});
|
|
|
|
describe('without optional properties', () => {
|
|
beforeEach(() => {
|
|
createComponent({
|
|
propsData: {
|
|
deployment: {
|
|
...deployment,
|
|
tags: [],
|
|
job: null,
|
|
tag: true,
|
|
},
|
|
environment: {
|
|
...environment,
|
|
externalUrl: '',
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it('does not show a link to the external url', () => {
|
|
const link = wrapper.findByRole('link', { name: 'Open URL' });
|
|
|
|
expect(link.exists()).toBe(false);
|
|
});
|
|
|
|
it('does not show a link to the tags of a deployment', () => {
|
|
const showMore = wrapper.findComponent(ShowMore);
|
|
|
|
expect(showMore.exists()).toBe(false);
|
|
});
|
|
|
|
it('displays if the ref is a branch', () => {
|
|
const ref = wrapper.findByTestId('deployment-ref');
|
|
|
|
expect(ref.find('span').text()).toBe('Tag');
|
|
});
|
|
});
|
|
|
|
describe('toggle button', () => {
|
|
beforeEach(() => {
|
|
createComponent();
|
|
});
|
|
|
|
it('is exist', () => {
|
|
const button = findSidebarToggleButton();
|
|
|
|
expect(button.exists()).toBe(true);
|
|
expect(button.classes()).toContain('lg:gl-hidden');
|
|
});
|
|
|
|
describe('on mobile', () => {
|
|
describe('when the sidebar is collapsed', () => {
|
|
beforeEach(() => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
});
|
|
|
|
it('has correct attributes', () => {
|
|
const button = findSidebarToggleButton();
|
|
|
|
expect(button.attributes('title')).toBe('Expand sidebar');
|
|
expect(button.attributes('aria-label')).toBe('Expand sidebar');
|
|
expect(button.props('category')).toBe('secondary');
|
|
expect(wrapper.findByTestId('chevron-double-lg-left-icon').isVisible()).toBe(true);
|
|
});
|
|
|
|
it('expands the sidebar on click', async () => {
|
|
let sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(false);
|
|
|
|
const button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('when the sidebar is expanded', () => {
|
|
let button;
|
|
|
|
beforeEach(async () => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
|
|
button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
});
|
|
|
|
it('has correct attributes', () => {
|
|
expect(button.attributes('title')).toBe('Collapse sidebar');
|
|
expect(button.attributes('aria-label')).toBe('Collapse sidebar');
|
|
expect(button.props('category')).toBe('tertiary');
|
|
expect(wrapper.findByTestId('chevron-double-lg-right-icon').isVisible()).toBe(true);
|
|
});
|
|
|
|
it('collapses the sidebar on click', async () => {
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
const sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('sidebar', () => {
|
|
describe('on desktop', () => {
|
|
it('has correct CSS classes', () => {
|
|
createComponent();
|
|
|
|
const sidebarItems = findSidebar();
|
|
|
|
expect(sidebarItems.classes()).not.toContain('right-sidebar');
|
|
expect(sidebarItems.classes()).not.toContain('right-sidebar-expanded');
|
|
expect(sidebarItems.classes()).not.toContain('gl-shadow-md');
|
|
expect(sidebarItems.classes()).not.toContain('gl-fixed');
|
|
expect(sidebarItems.classes()).not.toContain('gl-right-0');
|
|
});
|
|
});
|
|
|
|
describe('on mobile', () => {
|
|
let button;
|
|
|
|
beforeEach(async () => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
|
|
button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
});
|
|
|
|
describe('when the sidebar is expanded', () => {
|
|
it('has correct CSS classes', () => {
|
|
const sidebarItems = findSidebar();
|
|
|
|
expect(sidebarItems.classes()).toContain('right-sidebar');
|
|
expect(sidebarItems.classes()).toContain('right-sidebar-expanded');
|
|
expect(sidebarItems.classes()).toContain('gl-shadow-md');
|
|
expect(sidebarItems.classes()).not.toContain('gl-fixed');
|
|
expect(sidebarItems.classes()).not.toContain('gl-right-0');
|
|
});
|
|
});
|
|
|
|
describe('when the sidebar is collapsed', () => {
|
|
it('has correct CSS classes', async () => {
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
const sidebarItems = findSidebar();
|
|
|
|
expect(sidebarItems.classes()).not.toContain('right-sidebar');
|
|
expect(sidebarItems.classes()).not.toContain('right-sidebar-expanded');
|
|
expect(sidebarItems.classes()).not.toContain('gl-shadow-md');
|
|
expect(sidebarItems.classes()).toContain('gl-fixed');
|
|
expect(sidebarItems.classes()).toContain('gl-right-0');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('sidebar items', () => {
|
|
describe('on desktop', () => {
|
|
beforeEach(() => {
|
|
createComponent();
|
|
});
|
|
|
|
it('shows the sidebar items', () => {
|
|
const sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(true);
|
|
});
|
|
|
|
it('does not have CSS classes', () => {
|
|
const sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.classes()).not.toContain('gl-border-t-1');
|
|
expect(sidebarItems.classes()).not.toContain('gl-mt-5');
|
|
expect(sidebarItems.classes()).not.toContain('gl-border-default');
|
|
expect(sidebarItems.classes()).not.toContain('gl-border-t-solid');
|
|
});
|
|
});
|
|
|
|
describe('on mobile', () => {
|
|
beforeEach(() => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
});
|
|
|
|
it('hides the sidebar items by default', () => {
|
|
createComponent();
|
|
|
|
const sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(false);
|
|
});
|
|
|
|
it('has correct CSS classes when the sidebar is expanded', async () => {
|
|
createComponent();
|
|
|
|
const button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
const sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.classes()).toContain('gl-border-t');
|
|
expect(sidebarItems.classes()).toContain('gl-mt-5');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('url button wrapper', () => {
|
|
describe('on desktop', () => {
|
|
it('does not have CSS classes', () => {
|
|
createComponent();
|
|
|
|
const urlButtonWrapper = findUrlButtonWrapper();
|
|
|
|
expect(urlButtonWrapper.classes()).not.toContain('gl-mt-5');
|
|
expect(urlButtonWrapper.classes()).not.toContain('gl-border-b-1');
|
|
expect(urlButtonWrapper.classes()).not.toContain('gl-border-default');
|
|
expect(urlButtonWrapper.classes()).not.toContain('gl-pb-5');
|
|
expect(urlButtonWrapper.classes()).not.toContain('gl-border-b-solid');
|
|
});
|
|
});
|
|
|
|
describe('on mobile', () => {
|
|
it('has correct CSS classes', async () => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
|
|
const button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
const urlButtonWrapper = findUrlButtonWrapper();
|
|
|
|
expect(urlButtonWrapper.classes()).toContain('gl-mt-5');
|
|
expect(urlButtonWrapper.classes()).toContain('gl-border-b');
|
|
expect(urlButtonWrapper.classes()).toContain('gl-pb-5');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('triggerer item', () => {
|
|
describe('on desktop', () => {
|
|
it('has correct CSS classes', () => {
|
|
createComponent();
|
|
|
|
const triggererItem = findTriggererItem();
|
|
|
|
expect(triggererItem.classes()).toContain('gl-mt-8');
|
|
expect(triggererItem.classes()).toContain('gl-border-subtle');
|
|
expect(triggererItem.classes()).toContain('gl-border-b');
|
|
expect(triggererItem.classes()).not.toContain('gl-mt-5');
|
|
});
|
|
});
|
|
|
|
describe('on mobile', () => {
|
|
it('has correct CSS classes', async () => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
|
|
const button = findSidebarToggleButton();
|
|
button.trigger('click');
|
|
await nextTick();
|
|
|
|
const triggererItem = findTriggererItem();
|
|
|
|
expect(triggererItem.classes()).toContain('gl-mt-5');
|
|
expect(triggererItem.classes()).toContain('gl-border-b');
|
|
expect(triggererItem.classes()).not.toContain('gl-mt-8');
|
|
expect(triggererItem.classes()).not.toContain('gl-border-subtle');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('on window resize after transition from mobile to desktop', () => {
|
|
beforeEach(() => {
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
|
|
|
|
createComponent();
|
|
});
|
|
|
|
it('the sidebar is visible', async () => {
|
|
let sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(false);
|
|
|
|
jest.spyOn(bp, 'isDesktop').mockReturnValue(true);
|
|
window.dispatchEvent(new Event('resize'));
|
|
await nextTick();
|
|
|
|
sidebarItems = findSidebarItems();
|
|
|
|
expect(sidebarItems.exists()).toBe(true);
|
|
});
|
|
});
|
|
});
|