diff options
Diffstat (limited to 'spec/frontend/packages/list/coming_soon')
3 files changed, 264 insertions, 0 deletions
diff --git a/spec/frontend/packages/list/coming_soon/helpers_spec.js b/spec/frontend/packages/list/coming_soon/helpers_spec.js new file mode 100644 index 00000000000..4a996bfad76 --- /dev/null +++ b/spec/frontend/packages/list/coming_soon/helpers_spec.js @@ -0,0 +1,36 @@ +import * as comingSoon from '~/packages/list/coming_soon/helpers'; +import { fakeIssues, asGraphQLResponse, asViewModel } from './mock_data'; + +jest.mock('~/api.js'); + +describe('Coming Soon Helpers', () => { + const [noLabels, acceptingMergeRequestLabel, workflowLabel] = fakeIssues; + + describe('toViewModel', () => { + it('formats a GraphQL response correctly', () => { + expect(comingSoon.toViewModel(asGraphQLResponse)).toEqual(asViewModel); + }); + }); + + describe('findWorkflowLabel', () => { + it('finds a workflow label', () => { + expect(comingSoon.findWorkflowLabel(workflowLabel.labels)).toEqual(workflowLabel.labels[0]); + }); + + it("returns undefined when there isn't one", () => { + expect(comingSoon.findWorkflowLabel(noLabels.labels)).toBeUndefined(); + }); + }); + + describe('findAcceptingContributionsLabel', () => { + it('finds the correct label when it exists', () => { + expect(comingSoon.findAcceptingContributionsLabel(acceptingMergeRequestLabel.labels)).toEqual( + acceptingMergeRequestLabel.labels[0], + ); + }); + + it("returns undefined when there isn't one", () => { + expect(comingSoon.findAcceptingContributionsLabel(noLabels.labels)).toBeUndefined(); + }); + }); +}); diff --git a/spec/frontend/packages/list/coming_soon/mock_data.js b/spec/frontend/packages/list/coming_soon/mock_data.js new file mode 100644 index 00000000000..bb4568e4bd5 --- /dev/null +++ b/spec/frontend/packages/list/coming_soon/mock_data.js @@ -0,0 +1,90 @@ +export const fakeIssues = [ + { + id: 1, + iid: 1, + title: 'issue one', + webUrl: 'foo', + }, + { + id: 2, + iid: 2, + title: 'issue two', + labels: [{ title: 'Accepting merge requests', color: '#69d100' }], + milestone: { + title: '12.10', + }, + webUrl: 'foo', + }, + { + id: 3, + iid: 3, + title: 'issue three', + labels: [{ title: 'workflow::In dev', color: '#428bca' }], + webUrl: 'foo', + }, + { + id: 4, + iid: 4, + title: 'issue four', + labels: [ + { title: 'Accepting merge requests', color: '#69d100' }, + { title: 'workflow::In dev', color: '#428bca' }, + ], + webUrl: 'foo', + }, +]; + +export const asGraphQLResponse = { + project: { + issues: { + nodes: fakeIssues.map(x => ({ + ...x, + labels: { + nodes: x.labels, + }, + })), + }, + }, +}; + +export const asViewModel = [ + { + ...fakeIssues[0], + labels: [], + }, + { + ...fakeIssues[1], + labels: [ + { + title: 'Accepting merge requests', + color: '#69d100', + scoped: false, + }, + ], + }, + { + ...fakeIssues[2], + labels: [ + { + title: 'workflow::In dev', + color: '#428bca', + scoped: true, + }, + ], + }, + { + ...fakeIssues[3], + labels: [ + { + title: 'workflow::In dev', + color: '#428bca', + scoped: true, + }, + { + title: 'Accepting merge requests', + color: '#69d100', + scoped: false, + }, + ], + }, +]; diff --git a/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js b/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js new file mode 100644 index 00000000000..c4cdadc45e6 --- /dev/null +++ b/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js @@ -0,0 +1,138 @@ +import { GlEmptyState, GlSkeletonLoader, GlLabel } from '@gitlab/ui'; +import { mount, createLocalVue } from '@vue/test-utils'; +import VueApollo, { ApolloQuery } from 'vue-apollo'; +import ComingSoon from '~/packages/list/coming_soon/packages_coming_soon.vue'; +import { TrackingActions } from '~/packages/shared/constants'; +import { asViewModel } from './mock_data'; +import Tracking from '~/tracking'; + +jest.mock('~/packages/list/coming_soon/helpers.js'); + +const localVue = createLocalVue(); +localVue.use(VueApollo); + +describe('packages_coming_soon', () => { + let wrapper; + + const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); + const findAllIssues = () => wrapper.findAll('[data-testid="issue-row"]'); + const findIssuesData = () => + findAllIssues().wrappers.map(x => { + const titleLink = x.find('[data-testid="issue-title-link"]'); + const milestone = x.find('[data-testid="milestone"]'); + const issueIdLink = x.find('[data-testid="issue-id-link"]'); + const labels = x.findAll(GlLabel); + + const issueId = Number(issueIdLink.text().substr(1)); + + return { + id: issueId, + iid: issueId, + title: titleLink.text(), + webUrl: titleLink.attributes('href'), + labels: labels.wrappers.map(label => ({ + color: label.props('backgroundColor'), + title: label.props('title'), + scoped: label.props('scoped'), + })), + ...(milestone.exists() ? { milestone: { title: milestone.text() } } : {}), + }; + }); + const findIssueTitleLink = () => wrapper.find('[data-testid="issue-title-link"]'); + const findIssueIdLink = () => wrapper.find('[data-testid="issue-id-link"]'); + const findEmptyState = () => wrapper.find(GlEmptyState); + + const mountComponent = (testParams = {}) => { + const $apolloData = { + loading: testParams.isLoading || false, + }; + + wrapper = mount(ComingSoon, { + localVue, + propsData: { + illustration: 'foo', + projectPath: 'foo', + suggestedContributionsPath: 'foo', + }, + stubs: { + ApolloQuery, + GlLink: true, + }, + mocks: { + $apolloData, + }, + }); + + // Mock the GraphQL query result + wrapper.find(ApolloQuery).setData({ + result: { + data: testParams.issues || asViewModel, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('when loading', () => { + beforeEach(() => mountComponent({ isLoading: true })); + + it('renders the skeleton loader', () => { + expect(findSkeletonLoader().exists()).toBe(true); + }); + }); + + describe('when there are no issues', () => { + beforeEach(() => mountComponent({ issues: [] })); + + it('renders the empty state', () => { + expect(findEmptyState().exists()).toBe(true); + }); + }); + + describe('when there are issues', () => { + beforeEach(() => mountComponent()); + + it('renders each issue', () => { + expect(findIssuesData()).toEqual(asViewModel); + }); + }); + + describe('tracking', () => { + const firstIssue = asViewModel[0]; + let eventSpy; + + beforeEach(() => { + eventSpy = jest.spyOn(Tracking, 'event'); + mountComponent(); + }); + + it('tracks when mounted', () => { + expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_REQUESTED, {}); + }); + + it('tracks when an issue title link is clicked', () => { + eventSpy.mockClear(); + + findIssueTitleLink().vm.$emit('click'); + + expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, { + label: firstIssue.title, + value: firstIssue.iid, + }); + }); + + it('tracks when an issue id link is clicked', () => { + eventSpy.mockClear(); + + findIssueIdLink().vm.$emit('click'); + + expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, { + label: firstIssue.title, + value: firstIssue.iid, + }); + }); + }); +}); |