Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/issues_list')
-rw-r--r--spec/frontend/issues_list/components/__snapshots__/issuables_list_app_spec.js.snap14
-rw-r--r--spec/frontend/issues_list/components/issuable_spec.js508
-rw-r--r--spec/frontend/issues_list/components/issuables_list_app_spec.js653
-rw-r--r--spec/frontend/issues_list/components/issue_card_time_info_spec.js122
-rw-r--r--spec/frontend/issues_list/components/issues_list_app_spec.js829
-rw-r--r--spec/frontend/issues_list/components/jira_issues_import_status_app_spec.js117
-rw-r--r--spec/frontend/issues_list/components/new_issue_dropdown_spec.js131
-rw-r--r--spec/frontend/issues_list/issuable_list_test_data.js77
-rw-r--r--spec/frontend/issues_list/mock_data.js310
-rw-r--r--spec/frontend/issues_list/service_desk_helper_spec.js28
-rw-r--r--spec/frontend/issues_list/utils_spec.js127
11 files changed, 0 insertions, 2916 deletions
diff --git a/spec/frontend/issues_list/components/__snapshots__/issuables_list_app_spec.js.snap b/spec/frontend/issues_list/components/__snapshots__/issuables_list_app_spec.js.snap
deleted file mode 100644
index c327b7de827..00000000000
--- a/spec/frontend/issues_list/components/__snapshots__/issuables_list_app_spec.js.snap
+++ /dev/null
@@ -1,14 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Issuables list component with empty issues response with all state should display a catch-all if there are no issues to show 1`] = `
-<gl-empty-state-stub
- svgpath="/emptySvg"
- title="There are no issues to show"
-/>
-`;
-
-exports[`Issuables list component with empty issues response with closed state should display a message "There are no closed issues" if there are no closed issues 1`] = `"There are no closed issues"`;
-
-exports[`Issuables list component with empty issues response with empty query should display the message "There are no open issues" 1`] = `"There are no open issues"`;
-
-exports[`Issuables list component with empty issues response with query in window location should display "Sorry, your filter produced no results" if filters are too specific 1`] = `"Sorry, your filter produced no results"`;
diff --git a/spec/frontend/issues_list/components/issuable_spec.js b/spec/frontend/issues_list/components/issuable_spec.js
deleted file mode 100644
index f3c2ae1f9dc..00000000000
--- a/spec/frontend/issues_list/components/issuable_spec.js
+++ /dev/null
@@ -1,508 +0,0 @@
-import { GlSprintf, GlLabel, GlIcon, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { TEST_HOST } from 'helpers/test_constants';
-import { trimText } from 'helpers/text_helper';
-import Issuable from '~/issues_list/components/issuable.vue';
-import { isScopedLabel } from '~/lib/utils/common_utils';
-import { formatDate } from '~/lib/utils/datetime_utility';
-import { mergeUrlParams } from '~/lib/utils/url_utility';
-import initUserPopovers from '~/user_popovers';
-import IssueAssignees from '~/issuable/components/issue_assignees.vue';
-import { simpleIssue, testAssignees, testLabels } from '../issuable_list_test_data';
-
-jest.mock('~/user_popovers');
-
-const TODAY = new Date();
-
-const createTestDateFromDelta = (timeDelta) =>
- formatDate(new Date(TODAY.getTime() + timeDelta), 'yyyy-mm-dd');
-
-// TODO: Encapsulate date helpers https://gitlab.com/gitlab-org/gitlab/-/issues/320883
-const MONTHS_IN_MS = 1000 * 60 * 60 * 24 * 31;
-const TEST_MONTH_AGO = createTestDateFromDelta(-MONTHS_IN_MS);
-const TEST_MONTH_LATER = createTestDateFromDelta(MONTHS_IN_MS);
-const DATE_FORMAT = 'mmm d, yyyy';
-const TEST_USER_NAME = 'Tyler Durden';
-const TEST_BASE_URL = `${TEST_HOST}/issues`;
-const TEST_TASK_STATUS = '50 of 100 tasks completed';
-const TEST_MILESTONE = {
- title: 'Milestone title',
- web_url: `${TEST_HOST}/milestone/1`,
-};
-const TEXT_CLOSED = 'CLOSED';
-const TEST_META_COUNT = 100;
-const MOCK_GITLAB_URL = 'http://0.0.0.0:3000';
-
-describe('Issuable component', () => {
- let issuable;
- let wrapper;
-
- const factory = (props = {}, scopedLabelsAvailable = false) => {
- wrapper = shallowMount(Issuable, {
- propsData: {
- issuable: simpleIssue,
- baseUrl: TEST_BASE_URL,
- ...props,
- },
- provide: {
- scopedLabelsAvailable,
- },
- stubs: {
- 'gl-sprintf': GlSprintf,
- },
- });
- };
-
- beforeEach(() => {
- issuable = { ...simpleIssue };
- gon.gitlab_url = MOCK_GITLAB_URL;
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- const checkExists = (findFn) => () => findFn().exists();
- const hasIcon = (iconName, iconWrapper = wrapper) =>
- iconWrapper.findAll(GlIcon).wrappers.some((icon) => icon.props('name') === iconName);
- const hasConfidentialIcon = () => hasIcon('eye-slash');
- const findTaskStatus = () => wrapper.find('.task-status');
- const findOpenedAgoContainer = () => wrapper.find('[data-testid="openedByMessage"]');
- const findAuthor = () => wrapper.find({ ref: 'openedAgoByContainer' });
- const findMilestone = () => wrapper.find('.js-milestone');
- const findMilestoneTooltip = () => findMilestone().attributes('title');
- const findDueDate = () => wrapper.find('.js-due-date');
- const findLabels = () => wrapper.findAll(GlLabel);
- const findWeight = () => wrapper.find('[data-testid="weight"]');
- const findAssignees = () => wrapper.find(IssueAssignees);
- const findBlockingIssuesCount = () => wrapper.find('[data-testid="blocking-issues"]');
- const findMergeRequestsCount = () => wrapper.find('[data-testid="merge-requests"]');
- const findUpvotes = () => wrapper.find('[data-testid="upvotes"]');
- const findDownvotes = () => wrapper.find('[data-testid="downvotes"]');
- const findNotes = () => wrapper.find('[data-testid="notes-count"]');
- const findBulkCheckbox = () => wrapper.find('input.selected-issuable');
- const findScopedLabels = () => findLabels().filter((w) => isScopedLabel({ title: w.text() }));
- const findUnscopedLabels = () => findLabels().filter((w) => !isScopedLabel({ title: w.text() }));
- const findIssuableTitle = () => wrapper.find('[data-testid="issuable-title"]');
- const findIssuableStatus = () => wrapper.find('[data-testid="issuable-status"]');
- const containsJiraLogo = () => wrapper.find('[data-testid="jira-logo"]').exists();
- const findHealthStatus = () => wrapper.find('.health-status');
-
- describe('when mounted', () => {
- it('initializes user popovers', () => {
- expect(initUserPopovers).not.toHaveBeenCalled();
-
- factory();
-
- expect(initUserPopovers).toHaveBeenCalledWith([wrapper.vm.$refs.openedAgoByContainer.$el]);
- });
- });
-
- describe('when scopedLabels feature is available', () => {
- beforeEach(() => {
- issuable.labels = [...testLabels];
-
- factory({ issuable }, true);
- });
-
- describe('when label is scoped', () => {
- it('returns label with correct props', () => {
- const scopedLabel = findScopedLabels().at(0);
-
- expect(scopedLabel.props('scoped')).toBe(true);
- });
- });
-
- describe('when label is not scoped', () => {
- it('returns label with correct props', () => {
- const notScopedLabel = findUnscopedLabels().at(0);
-
- expect(notScopedLabel.props('scoped')).toBe(false);
- });
- });
- });
-
- describe('when scopedLabels feature is not available', () => {
- beforeEach(() => {
- issuable.labels = [...testLabels];
-
- factory({ issuable });
- });
-
- describe('when label is scoped', () => {
- it('label scoped props is false', () => {
- const scopedLabel = findScopedLabels().at(0);
-
- expect(scopedLabel.props('scoped')).toBe(false);
- });
- });
-
- describe('when label is not scoped', () => {
- it('label scoped props is false', () => {
- const notScopedLabel = findUnscopedLabels().at(0);
-
- expect(notScopedLabel.props('scoped')).toBe(false);
- });
- });
- });
-
- describe('with simple issuable', () => {
- beforeEach(() => {
- Object.assign(issuable, {
- has_tasks: false,
- task_status: TEST_TASK_STATUS,
- created_at: TEST_MONTH_AGO,
- author: {
- ...issuable.author,
- name: TEST_USER_NAME,
- },
- labels: [],
- });
-
- factory({ issuable });
- });
-
- it.each`
- desc | check
- ${'bulk editing checkbox'} | ${checkExists(findBulkCheckbox)}
- ${'confidential icon'} | ${hasConfidentialIcon}
- ${'task status'} | ${checkExists(findTaskStatus)}
- ${'milestone'} | ${checkExists(findMilestone)}
- ${'due date'} | ${checkExists(findDueDate)}
- ${'labels'} | ${checkExists(findLabels)}
- ${'weight'} | ${checkExists(findWeight)}
- ${'blocking issues count'} | ${checkExists(findBlockingIssuesCount)}
- ${'merge request count'} | ${checkExists(findMergeRequestsCount)}
- ${'upvotes'} | ${checkExists(findUpvotes)}
- ${'downvotes'} | ${checkExists(findDownvotes)}
- `('does not render $desc', ({ check }) => {
- expect(check()).toBe(false);
- });
-
- it('show relative reference path', () => {
- expect(wrapper.find('.js-ref-path').text()).toBe(issuable.references.relative);
- });
-
- it('does not have closed text', () => {
- expect(wrapper.text()).not.toContain(TEXT_CLOSED);
- });
-
- it('does not have closed class', () => {
- expect(wrapper.classes('closed')).toBe(false);
- });
-
- it('renders fuzzy created date and author', () => {
- expect(trimText(findOpenedAgoContainer().text())).toContain(
- `created 1 month ago by ${TEST_USER_NAME}`,
- );
- });
-
- it('renders no comments', () => {
- expect(findNotes().classes('no-comments')).toBe(true);
- });
-
- it.each`
- gitlabWebUrl | webUrl | expectedHref | expectedTarget | isExternal
- ${undefined} | ${`${MOCK_GITLAB_URL}/issue`} | ${`${MOCK_GITLAB_URL}/issue`} | ${undefined} | ${false}
- ${undefined} | ${'https://jira.com/issue'} | ${'https://jira.com/issue'} | ${'_blank'} | ${true}
- ${'/gitlab-org/issue'} | ${'https://jira.com/issue'} | ${'/gitlab-org/issue'} | ${undefined} | ${false}
- `(
- 'renders issuable title correctly when `gitlabWebUrl` is `$gitlabWebUrl` and webUrl is `$webUrl`',
- async ({ webUrl, gitlabWebUrl, expectedHref, expectedTarget, isExternal }) => {
- factory({
- issuable: {
- ...issuable,
- web_url: webUrl,
- gitlab_web_url: gitlabWebUrl,
- },
- });
-
- const titleEl = findIssuableTitle();
-
- expect(titleEl.exists()).toBe(true);
- expect(titleEl.find(GlLink).attributes('href')).toBe(expectedHref);
- expect(titleEl.find(GlLink).attributes('target')).toBe(expectedTarget);
- expect(titleEl.find(GlLink).text()).toBe(issuable.title);
-
- expect(titleEl.find(GlIcon).exists()).toBe(isExternal);
- },
- );
- });
-
- describe('with confidential issuable', () => {
- beforeEach(() => {
- issuable.confidential = true;
-
- factory({ issuable });
- });
-
- it('renders the confidential icon', () => {
- expect(hasConfidentialIcon()).toBe(true);
- });
- });
-
- describe('with Jira issuable', () => {
- beforeEach(() => {
- issuable.external_tracker = 'jira';
-
- factory({ issuable });
- });
-
- it('renders the Jira icon', () => {
- expect(containsJiraLogo()).toBe(true);
- });
-
- it('opens issuable in a new tab', () => {
- expect(findIssuableTitle().props('target')).toBe('_blank');
- });
-
- it('opens author in a new tab', () => {
- expect(findAuthor().props('target')).toBe('_blank');
- });
-
- describe('with Jira status', () => {
- const expectedStatus = 'In Progress';
-
- beforeEach(() => {
- issuable.status = expectedStatus;
-
- factory({ issuable });
- });
-
- it('renders the Jira status', () => {
- expect(findIssuableStatus().text()).toBe(expectedStatus);
- });
- });
- });
-
- describe('with task status', () => {
- beforeEach(() => {
- Object.assign(issuable, {
- has_tasks: true,
- task_status: TEST_TASK_STATUS,
- });
-
- factory({ issuable });
- });
-
- it('renders task status', () => {
- expect(findTaskStatus().exists()).toBe(true);
- expect(findTaskStatus().text()).toBe(TEST_TASK_STATUS);
- });
- });
-
- describe.each`
- desc | dueDate | expectedTooltipPart
- ${'past due'} | ${TEST_MONTH_AGO} | ${'Past due'}
- ${'future due'} | ${TEST_MONTH_LATER} | ${'1 month remaining'}
- `('with milestone with $desc', ({ dueDate, expectedTooltipPart }) => {
- beforeEach(() => {
- issuable.milestone = { ...TEST_MILESTONE, due_date: dueDate };
-
- factory({ issuable });
- });
-
- it('renders milestone', () => {
- expect(findMilestone().exists()).toBe(true);
- expect(hasIcon('clock', findMilestone())).toBe(true);
- expect(findMilestone().text()).toEqual(TEST_MILESTONE.title);
- });
-
- it('renders tooltip', () => {
- expect(findMilestoneTooltip()).toBe(
- `${formatDate(dueDate, DATE_FORMAT)} (${expectedTooltipPart})`,
- );
- });
-
- it('renders milestone with the correct href', () => {
- const { title } = issuable.milestone;
- const expected = mergeUrlParams({ milestone_title: title }, TEST_BASE_URL);
-
- expect(findMilestone().attributes('href')).toBe(expected);
- });
- });
-
- describe.each`
- dueDate | hasClass | desc
- ${TEST_MONTH_LATER} | ${false} | ${'with future due date'}
- ${TEST_MONTH_AGO} | ${true} | ${'with past due date'}
- `('$desc', ({ dueDate, hasClass }) => {
- beforeEach(() => {
- issuable.due_date = dueDate;
-
- factory({ issuable });
- });
-
- it('renders due date', () => {
- expect(findDueDate().exists()).toBe(true);
- expect(findDueDate().text()).toBe(formatDate(dueDate, DATE_FORMAT));
- });
-
- it(hasClass ? 'has cred class' : 'does not have cred class', () => {
- expect(findDueDate().classes('cred')).toEqual(hasClass);
- });
- });
-
- describe('with labels', () => {
- beforeEach(() => {
- issuable.labels = [...testLabels];
-
- factory({ issuable });
- });
-
- it('renders labels', () => {
- factory({ issuable });
-
- const labels = findLabels().wrappers.map((label) => ({
- href: label.props('target'),
- text: label.text(),
- tooltip: label.attributes('description'),
- }));
-
- const expected = testLabels.map((label) => ({
- href: mergeUrlParams({ 'label_name[]': label.name }, TEST_BASE_URL),
- text: label.name,
- tooltip: label.description,
- }));
-
- expect(labels).toEqual(expected);
- });
- });
-
- describe('with labels for Jira issuable', () => {
- beforeEach(() => {
- issuable.labels = [...testLabels];
- issuable.external_tracker = 'jira';
-
- factory({ issuable });
- });
-
- it('renders labels', () => {
- factory({ issuable });
-
- const labels = findLabels().wrappers.map((label) => ({
- href: label.props('target'),
- text: label.text(),
- tooltip: label.attributes('description'),
- }));
-
- const expected = testLabels.map((label) => ({
- href: mergeUrlParams({ 'labels[]': label.name }, TEST_BASE_URL),
- text: label.name,
- tooltip: label.description,
- }));
-
- expect(labels).toEqual(expected);
- });
- });
-
- describe.each`
- weight
- ${0}
- ${10}
- ${12345}
- `('with weight $weight', ({ weight }) => {
- beforeEach(() => {
- issuable.weight = weight;
-
- factory({ issuable });
- });
-
- it('renders weight', () => {
- expect(findWeight().exists()).toBe(true);
- expect(findWeight().text()).toEqual(weight.toString());
- });
- });
-
- describe('with closed state', () => {
- beforeEach(() => {
- issuable.state = 'closed';
-
- factory({ issuable });
- });
-
- it('renders closed text', () => {
- expect(wrapper.text()).toContain(TEXT_CLOSED);
- });
-
- it('has closed class', () => {
- expect(wrapper.classes('closed')).toBe(true);
- });
- });
-
- describe('with assignees', () => {
- beforeEach(() => {
- issuable.assignees = testAssignees;
-
- factory({ issuable });
- });
-
- it('renders assignees', () => {
- expect(findAssignees().exists()).toBe(true);
- expect(findAssignees().props('assignees')).toEqual(testAssignees);
- });
- });
-
- describe.each`
- desc | key | finder
- ${'with blocking issues count'} | ${'blocking_issues_count'} | ${findBlockingIssuesCount}
- ${'with merge requests count'} | ${'merge_requests_count'} | ${findMergeRequestsCount}
- ${'with upvote count'} | ${'upvotes'} | ${findUpvotes}
- ${'with downvote count'} | ${'downvotes'} | ${findDownvotes}
- ${'with notes count'} | ${'user_notes_count'} | ${findNotes}
- `('$desc', ({ key, finder }) => {
- beforeEach(() => {
- issuable[key] = TEST_META_COUNT;
-
- factory({ issuable });
- });
-
- it('renders correct count', () => {
- expect(finder().exists()).toBe(true);
- expect(finder().text()).toBe(TEST_META_COUNT.toString());
- expect(finder().classes('no-comments')).toBe(false);
- });
- });
-
- describe('with bulk editing', () => {
- describe.each`
- selected | desc
- ${true} | ${'when selected'}
- ${false} | ${'when unselected'}
- `('$desc', ({ selected }) => {
- beforeEach(() => {
- factory({ isBulkEditing: true, selected });
- });
-
- it(`renders checked is ${selected}`, () => {
- expect(findBulkCheckbox().element.checked).toBe(selected);
- });
-
- it('emits select when clicked', () => {
- expect(wrapper.emitted().select).toBeUndefined();
-
- findBulkCheckbox().trigger('click');
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted().select).toEqual([[{ issuable, selected: !selected }]]);
- });
- });
- });
- });
-
- if (IS_EE) {
- describe('with health status', () => {
- it('renders health status tag', () => {
- factory({ issuable });
- expect(findHealthStatus().exists()).toBe(true);
- });
-
- it('does not render when health status is absent', () => {
- issuable.health_status = null;
- factory({ issuable });
- expect(findHealthStatus().exists()).toBe(false);
- });
- });
- }
-});
diff --git a/spec/frontend/issues_list/components/issuables_list_app_spec.js b/spec/frontend/issues_list/components/issuables_list_app_spec.js
deleted file mode 100644
index 11854db534e..00000000000
--- a/spec/frontend/issues_list/components/issuables_list_app_spec.js
+++ /dev/null
@@ -1,653 +0,0 @@
-import {
- GlEmptyState,
- GlPagination,
- GlDeprecatedSkeletonLoading as GlSkeletonLoading,
-} from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import axios from 'axios';
-import MockAdapter from 'axios-mock-adapter';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
-import Issuable from '~/issues_list/components/issuable.vue';
-import IssuablesListApp from '~/issues_list/components/issuables_list_app.vue';
-import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issues_list/constants';
-import issuablesEventBus from '~/issues_list/eventhub';
-import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
-
-jest.mock('~/flash');
-jest.mock('~/issues_list/eventhub');
-jest.mock('~/lib/utils/common_utils', () => ({
- ...jest.requireActual('~/lib/utils/common_utils'),
- scrollToElement: () => {},
-}));
-
-const TEST_LOCATION = `${TEST_HOST}/issues`;
-const TEST_ENDPOINT = '/issues';
-const TEST_CREATE_ISSUES_PATH = '/createIssue';
-const TEST_SVG_PATH = '/emptySvg';
-
-const MOCK_ISSUES = Array(PAGE_SIZE_MANUAL)
- .fill(0)
- .map((_, i) => ({
- id: i,
- web_url: `url${i}`,
- }));
-
-describe('Issuables list component', () => {
- let mockAxios;
- let wrapper;
- let apiSpy;
-
- const setupApiMock = (cb) => {
- apiSpy = jest.fn(cb);
-
- mockAxios.onGet(TEST_ENDPOINT).reply((cfg) => apiSpy(cfg));
- };
-
- const factory = (props = { sortKey: 'priority' }) => {
- const emptyStateMeta = {
- createIssuePath: TEST_CREATE_ISSUES_PATH,
- svgPath: TEST_SVG_PATH,
- };
-
- wrapper = shallowMount(IssuablesListApp, {
- propsData: {
- endpoint: TEST_ENDPOINT,
- emptyStateMeta,
- ...props,
- },
- });
- };
-
- const findLoading = () => wrapper.find(GlSkeletonLoading);
- const findIssuables = () => wrapper.findAll(Issuable);
- const findFilteredSearchBar = () => wrapper.find(FilteredSearchBar);
- const findFirstIssuable = () => findIssuables().wrappers[0];
- const findEmptyState = () => wrapper.find(GlEmptyState);
-
- beforeEach(() => {
- mockAxios = new MockAdapter(axios);
-
- setWindowLocation(TEST_LOCATION);
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- mockAxios.restore();
- });
-
- describe('with failed issues response', () => {
- beforeEach(() => {
- setupApiMock(() => [500]);
-
- factory();
-
- return waitForPromises();
- });
-
- it('does not show loading', () => {
- expect(wrapper.vm.loading).toBe(false);
- });
-
- it('flashes an error', () => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('with successful issues response', () => {
- beforeEach(() => {
- setupApiMock(() => [
- 200,
- MOCK_ISSUES.slice(0, PAGE_SIZE),
- {
- 'x-total': 100,
- 'x-page': 2,
- },
- ]);
- });
-
- it('has default props and data', () => {
- factory();
- expect(wrapper.vm).toMatchObject({
- // Props
- canBulkEdit: false,
- emptyStateMeta: {
- createIssuePath: TEST_CREATE_ISSUES_PATH,
- svgPath: TEST_SVG_PATH,
- },
- // Data
- filters: {
- state: 'opened',
- },
- isBulkEditing: false,
- issuables: [],
- loading: true,
- page: 1,
- selection: {},
- totalItems: 0,
- });
- });
-
- it('does not call API until mounted', () => {
- factory();
- expect(apiSpy).not.toHaveBeenCalled();
- });
-
- describe('when mounted', () => {
- beforeEach(() => {
- factory();
- });
-
- it('calls API', () => {
- expect(apiSpy).toHaveBeenCalled();
- });
-
- it('shows loading', () => {
- expect(findLoading().exists()).toBe(true);
- expect(findIssuables().length).toBe(0);
- expect(findEmptyState().exists()).toBe(false);
- });
- });
-
- describe('when finished loading', () => {
- beforeEach(() => {
- factory();
-
- return waitForPromises();
- });
-
- it('does not display empty state', () => {
- expect(wrapper.vm.issuables.length).toBeGreaterThan(0);
- expect(wrapper.vm.emptyState).toEqual({});
- expect(wrapper.find(GlEmptyState).exists()).toBe(false);
- });
-
- it('sets the proper page and total items', () => {
- expect(wrapper.vm.totalItems).toBe(100);
- expect(wrapper.vm.page).toBe(2);
- });
-
- it('renders one page of issuables and pagination', () => {
- expect(findIssuables().length).toBe(PAGE_SIZE);
- expect(wrapper.find(GlPagination).exists()).toBe(true);
- });
- });
-
- it('does not render FilteredSearchBar', () => {
- factory();
-
- expect(findFilteredSearchBar().exists()).toBe(false);
- });
- });
-
- describe('with bulk editing enabled', () => {
- beforeEach(() => {
- issuablesEventBus.$on.mockReset();
- issuablesEventBus.$emit.mockReset();
-
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory({ canBulkEdit: true });
-
- return waitForPromises();
- });
-
- it('is not enabled by default', () => {
- expect(wrapper.vm.isBulkEditing).toBe(false);
- });
-
- it('does not select issues by default', () => {
- expect(wrapper.vm.selection).toEqual({});
- });
-
- it('"Select All" checkbox toggles all visible issuables"', () => {
- wrapper.vm.onSelectAll();
- expect(wrapper.vm.selection).toEqual(
- wrapper.vm.issuables.reduce((acc, i) => ({ ...acc, [i.id]: true }), {}),
- );
-
- wrapper.vm.onSelectAll();
- expect(wrapper.vm.selection).toEqual({});
- });
-
- it('"Select All checkbox" selects all issuables if only some are selected"', () => {
- wrapper.vm.selection = { [wrapper.vm.issuables[0].id]: true };
- wrapper.vm.onSelectAll();
- expect(wrapper.vm.selection).toEqual(
- wrapper.vm.issuables.reduce((acc, i) => ({ ...acc, [i.id]: true }), {}),
- );
- });
-
- it('selects and deselects issuables', () => {
- const [i0, i1, i2] = wrapper.vm.issuables;
-
- expect(wrapper.vm.selection).toEqual({});
- wrapper.vm.onSelectIssuable({ issuable: i0, selected: false });
- expect(wrapper.vm.selection).toEqual({});
- wrapper.vm.onSelectIssuable({ issuable: i1, selected: true });
- expect(wrapper.vm.selection).toEqual({ 1: true });
- wrapper.vm.onSelectIssuable({ issuable: i0, selected: true });
- expect(wrapper.vm.selection).toEqual({ 1: true, 0: true });
- wrapper.vm.onSelectIssuable({ issuable: i2, selected: true });
- expect(wrapper.vm.selection).toEqual({ 1: true, 0: true, 2: true });
- wrapper.vm.onSelectIssuable({ issuable: i2, selected: true });
- expect(wrapper.vm.selection).toEqual({ 1: true, 0: true, 2: true });
- wrapper.vm.onSelectIssuable({ issuable: i0, selected: false });
- expect(wrapper.vm.selection).toEqual({ 1: true, 2: true });
- });
-
- it('broadcasts a message to the bulk edit sidebar when a value is added to selection', () => {
- issuablesEventBus.$emit.mockReset();
- const i1 = wrapper.vm.issuables[1];
-
- wrapper.vm.onSelectIssuable({ issuable: i1, selected: true });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(issuablesEventBus.$emit).toHaveBeenCalledTimes(1);
- expect(issuablesEventBus.$emit).toHaveBeenCalledWith('issuables:updateBulkEdit');
- });
- });
-
- it('does not broadcast a message to the bulk edit sidebar when a value is not added to selection', () => {
- issuablesEventBus.$emit.mockReset();
-
- return wrapper.vm
- .$nextTick()
- .then(waitForPromises)
- .then(() => {
- const i1 = wrapper.vm.issuables[1];
-
- wrapper.vm.onSelectIssuable({ issuable: i1, selected: false });
- })
- .then(wrapper.vm.$nextTick)
- .then(() => {
- expect(issuablesEventBus.$emit).toHaveBeenCalledTimes(0);
- });
- });
-
- it('listens to a message to toggle bulk editing', () => {
- expect(wrapper.vm.isBulkEditing).toBe(false);
- expect(issuablesEventBus.$on.mock.calls[0][0]).toBe('issuables:toggleBulkEdit');
- issuablesEventBus.$on.mock.calls[0][1](true); // Call the message handler
-
- return waitForPromises()
- .then(() => {
- expect(wrapper.vm.isBulkEditing).toBe(true);
- issuablesEventBus.$on.mock.calls[0][1](false);
- })
- .then(() => {
- expect(wrapper.vm.isBulkEditing).toBe(false);
- });
- });
- });
-
- describe('with query params in window.location', () => {
- const expectedFilters = {
- assignee_username: 'root',
- author_username: 'root',
- confidential: 'yes',
- my_reaction_emoji: 'airplane',
- scope: 'all',
- state: 'opened',
- weight: '0',
- milestone: 'v3.0',
- labels: 'Aquapod,Astro',
- order_by: 'milestone_due',
- sort: 'desc',
- };
-
- describe('when page is not present in params', () => {
- const query =
- '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&weight=0&not[label_name][]=Afterpod&not[milestone_title][]=13';
-
- beforeEach(() => {
- setWindowLocation(query);
-
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory({ sortKey: 'milestone_due_desc' });
-
- return waitForPromises();
- });
-
- afterEach(() => {
- apiSpy.mockClear();
- });
-
- it('applies filters and sorts', () => {
- expect(wrapper.vm.hasFilters).toBe(true);
- expect(wrapper.vm.filters).toEqual({
- ...expectedFilters,
- 'not[milestone]': ['13'],
- 'not[labels]': ['Afterpod'],
- });
-
- expect(apiSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- params: {
- ...expectedFilters,
- with_labels_details: true,
- page: 1,
- per_page: PAGE_SIZE,
- 'not[milestone]': ['13'],
- 'not[labels]': ['Afterpod'],
- },
- }),
- );
- });
-
- it('passes the base url to issuable', () => {
- expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
- });
- });
-
- describe('when page is present in the param', () => {
- const query =
- '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&weight=0&page=3';
-
- beforeEach(() => {
- setWindowLocation(query);
-
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory({ sortKey: 'milestone_due_desc' });
-
- return waitForPromises();
- });
-
- afterEach(() => {
- apiSpy.mockClear();
- });
-
- it('applies filters and sorts', () => {
- expect(apiSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- params: {
- ...expectedFilters,
- with_labels_details: true,
- page: 3,
- per_page: PAGE_SIZE,
- },
- }),
- );
- });
- });
- });
-
- describe('with hash in window.location', () => {
- beforeEach(() => {
- setWindowLocation(`${TEST_LOCATION}#stuff`);
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory();
- return waitForPromises();
- });
-
- it('passes the base url to issuable', () => {
- expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
- });
- });
-
- describe('with manual sort', () => {
- beforeEach(() => {
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory({ sortKey: RELATIVE_POSITION });
- });
-
- it('uses manual page size', () => {
- expect(apiSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- params: expect.objectContaining({
- per_page: PAGE_SIZE_MANUAL,
- }),
- }),
- );
- });
- });
-
- describe('with empty issues response', () => {
- beforeEach(() => {
- setupApiMock(() => [200, []]);
- });
-
- describe('with query in window location', () => {
- beforeEach(() => {
- setWindowLocation('?weight=Any');
-
- factory();
-
- return waitForPromises().then(() => wrapper.vm.$nextTick());
- });
-
- it('should display "Sorry, your filter produced no results" if filters are too specific', () => {
- expect(findEmptyState().props('title')).toMatchSnapshot();
- });
- });
-
- describe('with closed state', () => {
- beforeEach(() => {
- setWindowLocation('?state=closed');
-
- factory();
-
- return waitForPromises().then(() => wrapper.vm.$nextTick());
- });
-
- it('should display a message "There are no closed issues" if there are no closed issues', () => {
- expect(findEmptyState().props('title')).toMatchSnapshot();
- });
- });
-
- describe('with all state', () => {
- beforeEach(() => {
- setWindowLocation('?state=all');
-
- factory();
-
- return waitForPromises().then(() => wrapper.vm.$nextTick());
- });
-
- it('should display a catch-all if there are no issues to show', () => {
- expect(findEmptyState().element).toMatchSnapshot();
- });
- });
-
- describe('with empty query', () => {
- beforeEach(() => {
- factory();
-
- return wrapper.vm.$nextTick().then(waitForPromises);
- });
-
- it('should display the message "There are no open issues"', () => {
- expect(findEmptyState().props('title')).toMatchSnapshot();
- });
- });
- });
-
- describe('when paginates', () => {
- const newPage = 3;
-
- describe('when total-items is defined in response headers', () => {
- beforeEach(() => {
- window.history.pushState = jest.fn();
- setupApiMock(() => [
- 200,
- MOCK_ISSUES.slice(0, PAGE_SIZE),
- {
- 'x-total': 100,
- 'x-page': 2,
- },
- ]);
-
- factory();
-
- return waitForPromises();
- });
-
- afterEach(() => {
- // reset to original value
- window.history.pushState.mockRestore();
- });
-
- it('calls window.history.pushState one time', () => {
- // Trigger pagination
- wrapper.find(GlPagination).vm.$emit('input', newPage);
-
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- });
-
- it('sets params in the url', () => {
- // Trigger pagination
- wrapper.find(GlPagination).vm.$emit('input', newPage);
-
- expect(window.history.pushState).toHaveBeenCalledWith(
- {},
- '',
- `${TEST_LOCATION}?state=opened&order_by=priority&sort=asc&page=${newPage}`,
- );
- });
- });
-
- describe('when total-items is not defined in the headers', () => {
- const page = 2;
- const prevPage = page - 1;
- const nextPage = page + 1;
-
- beforeEach(() => {
- setupApiMock(() => [
- 200,
- MOCK_ISSUES.slice(0, PAGE_SIZE),
- {
- 'x-page': page,
- },
- ]);
-
- factory();
-
- return waitForPromises();
- });
-
- it('finds the correct props applied to GlPagination', () => {
- expect(wrapper.find(GlPagination).props()).toMatchObject({
- nextPage,
- prevPage,
- value: page,
- });
- });
- });
- });
-
- describe('when type is "jira"', () => {
- it('renders FilteredSearchBar', () => {
- factory({ type: 'jira' });
-
- expect(findFilteredSearchBar().exists()).toBe(true);
- });
-
- describe('initialSortBy', () => {
- const query = '?sort=updated_asc';
-
- it('sets default value', () => {
- factory({ type: 'jira' });
-
- expect(findFilteredSearchBar().props('initialSortBy')).toBe('created_desc');
- });
-
- it('sets value according to query', () => {
- setWindowLocation(query);
-
- factory({ type: 'jira' });
-
- expect(findFilteredSearchBar().props('initialSortBy')).toBe('updated_asc');
- });
- });
-
- describe('initialFilterValue', () => {
- it('does not set value when no query', () => {
- factory({ type: 'jira' });
-
- expect(findFilteredSearchBar().props('initialFilterValue')).toEqual([]);
- });
-
- it('sets value according to query', () => {
- const query = '?search=free+text';
-
- setWindowLocation(query);
-
- factory({ type: 'jira' });
-
- expect(findFilteredSearchBar().props('initialFilterValue')).toEqual(['free text']);
- });
- });
-
- describe('on filter search', () => {
- beforeEach(() => {
- factory({ type: 'jira' });
-
- window.history.pushState = jest.fn();
- });
-
- afterEach(() => {
- window.history.pushState.mockRestore();
- });
-
- const emitOnFilter = (filter) => findFilteredSearchBar().vm.$emit('onFilter', filter);
-
- describe('empty filter', () => {
- const mockFilter = [];
-
- it('updates URL with correct params', () => {
- emitOnFilter(mockFilter);
-
- expect(window.history.pushState).toHaveBeenCalledWith(
- {},
- '',
- `${TEST_LOCATION}?state=opened`,
- );
- });
- });
-
- describe('filter with search term', () => {
- const mockFilter = [
- {
- type: 'filtered-search-term',
- value: { data: 'free' },
- },
- ];
-
- it('updates URL with correct params', () => {
- emitOnFilter(mockFilter);
-
- expect(window.history.pushState).toHaveBeenCalledWith(
- {},
- '',
- `${TEST_LOCATION}?state=opened&search=free`,
- );
- });
- });
-
- describe('filter with multiple search terms', () => {
- const mockFilter = [
- {
- type: 'filtered-search-term',
- value: { data: 'free' },
- },
- {
- type: 'filtered-search-term',
- value: { data: 'text' },
- },
- ];
-
- it('updates URL with correct params', () => {
- emitOnFilter(mockFilter);
-
- expect(window.history.pushState).toHaveBeenCalledWith(
- {},
- '',
- `${TEST_LOCATION}?state=opened&search=free+text`,
- );
- });
- });
- });
- });
-});
diff --git a/spec/frontend/issues_list/components/issue_card_time_info_spec.js b/spec/frontend/issues_list/components/issue_card_time_info_spec.js
deleted file mode 100644
index 7c5faeb8dc1..00000000000
--- a/spec/frontend/issues_list/components/issue_card_time_info_spec.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import { GlIcon, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { useFakeDate } from 'helpers/fake_date';
-import IssueCardTimeInfo from '~/issues_list/components/issue_card_time_info.vue';
-
-describe('CE IssueCardTimeInfo component', () => {
- useFakeDate(2020, 11, 11);
-
- let wrapper;
-
- const issue = {
- milestone: {
- dueDate: '2020-12-17',
- startDate: '2020-12-10',
- title: 'My milestone',
- webPath: '/milestone/webPath',
- },
- dueDate: '2020-12-12',
- humanTimeEstimate: '1w',
- };
-
- const findMilestone = () => wrapper.find('[data-testid="issuable-milestone"]');
- const findMilestoneTitle = () => findMilestone().find(GlLink).attributes('title');
- const findDueDate = () => wrapper.find('[data-testid="issuable-due-date"]');
-
- const mountComponent = ({
- closedAt = null,
- dueDate = issue.dueDate,
- milestoneDueDate = issue.milestone.dueDate,
- milestoneStartDate = issue.milestone.startDate,
- } = {}) =>
- shallowMount(IssueCardTimeInfo, {
- propsData: {
- issue: {
- ...issue,
- milestone: {
- ...issue.milestone,
- dueDate: milestoneDueDate,
- startDate: milestoneStartDate,
- },
- closedAt,
- dueDate,
- },
- },
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('milestone', () => {
- it('renders', () => {
- wrapper = mountComponent();
-
- const milestone = findMilestone();
-
- expect(milestone.text()).toBe(issue.milestone.title);
- expect(milestone.find(GlIcon).props('name')).toBe('clock');
- expect(milestone.find(GlLink).attributes('href')).toBe(issue.milestone.webPath);
- });
-
- describe.each`
- time | text | milestoneDueDate | milestoneStartDate | expected
- ${'due date is in past'} | ${'Past due'} | ${'2020-09-09'} | ${null} | ${'Sep 9, 2020 (Past due)'}
- ${'due date is today'} | ${'Today'} | ${'2020-12-11'} | ${null} | ${'Dec 11, 2020 (Today)'}
- ${'start date is in future'} | ${'Upcoming'} | ${'2021-03-01'} | ${'2021-02-01'} | ${'Mar 1, 2021 (Upcoming)'}
- ${'due date is in future'} | ${'2 weeks remaining'} | ${'2020-12-25'} | ${null} | ${'Dec 25, 2020 (2 weeks remaining)'}
- `('when $description', ({ text, milestoneDueDate, milestoneStartDate, expected }) => {
- it(`renders with "${text}"`, () => {
- wrapper = mountComponent({ milestoneDueDate, milestoneStartDate });
-
- expect(findMilestoneTitle()).toBe(expected);
- });
- });
- });
-
- describe('due date', () => {
- describe('when upcoming', () => {
- it('renders', () => {
- wrapper = mountComponent();
-
- const dueDate = findDueDate();
-
- expect(dueDate.text()).toBe('Dec 12, 2020');
- expect(dueDate.attributes('title')).toBe('Due date');
- expect(dueDate.find(GlIcon).props('name')).toBe('calendar');
- expect(dueDate.classes()).not.toContain('gl-text-red-500');
- });
- });
-
- describe('when in the past', () => {
- describe('when issue is open', () => {
- it('renders in red', () => {
- wrapper = mountComponent({ dueDate: new Date('2020-10-10') });
-
- expect(findDueDate().classes()).toContain('gl-text-red-500');
- });
- });
-
- describe('when issue is closed', () => {
- it('does not render in red', () => {
- wrapper = mountComponent({
- dueDate: new Date('2020-10-10'),
- closedAt: '2020-09-05T13:06:25Z',
- });
-
- expect(findDueDate().classes()).not.toContain('gl-text-red-500');
- });
- });
- });
- });
-
- it('renders time estimate', () => {
- wrapper = mountComponent();
-
- const timeEstimate = wrapper.find('[data-testid="time-estimate"]');
-
- expect(timeEstimate.text()).toBe(issue.humanTimeEstimate);
- expect(timeEstimate.attributes('title')).toBe('Estimate');
- expect(timeEstimate.find(GlIcon).props('name')).toBe('timer');
- });
-});
diff --git a/spec/frontend/issues_list/components/issues_list_app_spec.js b/spec/frontend/issues_list/components/issues_list_app_spec.js
deleted file mode 100644
index f24c090fa92..00000000000
--- a/spec/frontend/issues_list/components/issues_list_app_spec.js
+++ /dev/null
@@ -1,829 +0,0 @@
-import { GlButton, GlEmptyState, GlLink } from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
-import { mount, shallowMount } from '@vue/test-utils';
-import AxiosMockAdapter from 'axios-mock-adapter';
-import { cloneDeep } from 'lodash';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql';
-import getIssuesCountsQuery from 'ee_else_ce/issues_list/queries/get_issues_counts.query.graphql';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import waitForPromises from 'helpers/wait_for_promises';
-import {
- getIssuesCountsQueryResponse,
- getIssuesQueryResponse,
- filteredTokens,
- locationSearch,
- urlParams,
-} from 'jest/issues_list/mock_data';
-import createFlash, { FLASH_TYPES } from '~/flash';
-import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
-import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
-import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
-import IssuesListApp from '~/issues_list/components/issues_list_app.vue';
-import NewIssueDropdown from '~/issues_list/components/new_issue_dropdown.vue';
-import {
- CREATED_DESC,
- DUE_DATE_OVERDUE,
- PARAM_DUE_DATE,
- RELATIVE_POSITION,
- RELATIVE_POSITION_ASC,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_AUTHOR,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_TYPE,
- urlSortParams,
-} from '~/issues_list/constants';
-import eventHub from '~/issues_list/eventhub';
-import { getSortOptions } from '~/issues_list/utils';
-import axios from '~/lib/utils/axios_utils';
-import { scrollUp } from '~/lib/utils/scroll_utils';
-import { joinPaths } from '~/lib/utils/url_utility';
-
-jest.mock('@sentry/browser');
-jest.mock('~/flash');
-jest.mock('~/lib/utils/scroll_utils', () => ({
- scrollUp: jest.fn().mockName('scrollUpMock'),
-}));
-
-describe('CE IssuesListApp component', () => {
- let axiosMock;
- let wrapper;
-
- Vue.use(VueApollo);
-
- const defaultProvide = {
- calendarPath: 'calendar/path',
- canBulkUpdate: false,
- emptyStateSvgPath: 'empty-state.svg',
- exportCsvPath: 'export/csv/path',
- fullPath: 'path/to/project',
- hasAnyIssues: true,
- hasAnyProjects: true,
- hasBlockedIssuesFeature: true,
- hasIssuableHealthStatusFeature: true,
- hasIssueWeightsFeature: true,
- hasIterationsFeature: true,
- isProject: true,
- isSignedIn: true,
- jiraIntegrationPath: 'jira/integration/path',
- newIssuePath: 'new/issue/path',
- rssPath: 'rss/path',
- showNewIssueLink: true,
- signInPath: 'sign/in/path',
- };
-
- let defaultQueryResponse = getIssuesQueryResponse;
- if (IS_EE) {
- defaultQueryResponse = cloneDeep(getIssuesQueryResponse);
- defaultQueryResponse.data.project.issues.nodes[0].blockingCount = 1;
- defaultQueryResponse.data.project.issues.nodes[0].healthStatus = null;
- defaultQueryResponse.data.project.issues.nodes[0].weight = 5;
- }
-
- const findCsvImportExportButtons = () => wrapper.findComponent(CsvImportExportButtons);
- const findIssuableByEmail = () => wrapper.findComponent(IssuableByEmail);
- const findGlButton = () => wrapper.findComponent(GlButton);
- const findGlButtons = () => wrapper.findAllComponents(GlButton);
- const findGlButtonAt = (index) => findGlButtons().at(index);
- const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findGlLink = () => wrapper.findComponent(GlLink);
- const findIssuableList = () => wrapper.findComponent(IssuableList);
- const findNewIssueDropdown = () => wrapper.findComponent(NewIssueDropdown);
-
- const mountComponent = ({
- provide = {},
- issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse),
- issuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse),
- mountFn = shallowMount,
- } = {}) => {
- const requestHandlers = [
- [getIssuesQuery, issuesQueryResponse],
- [getIssuesCountsQuery, issuesCountsQueryResponse],
- ];
- const apolloProvider = createMockApollo(requestHandlers);
-
- return mountFn(IssuesListApp, {
- apolloProvider,
- provide: {
- ...defaultProvide,
- ...provide,
- },
- });
- };
-
- beforeEach(() => {
- setWindowLocation(TEST_HOST);
- axiosMock = new AxiosMockAdapter(axios);
- });
-
- afterEach(() => {
- axiosMock.reset();
- wrapper.destroy();
- });
-
- describe('IssuableList', () => {
- beforeEach(() => {
- wrapper = mountComponent();
- jest.runOnlyPendingTimers();
- });
-
- it('renders', () => {
- expect(findIssuableList().props()).toMatchObject({
- namespace: defaultProvide.fullPath,
- recentSearchesStorageKey: 'issues',
- searchInputPlaceholder: IssuesListApp.i18n.searchPlaceholder,
- sortOptions: getSortOptions(true, true),
- initialSortBy: CREATED_DESC,
- issuables: getIssuesQueryResponse.data.project.issues.nodes,
- tabs: IssuableListTabs,
- currentTab: IssuableStates.Opened,
- tabCounts: {
- opened: 1,
- closed: 1,
- all: 1,
- },
- issuablesLoading: false,
- isManualOrdering: false,
- showBulkEditSidebar: false,
- showPaginationControls: true,
- useKeysetPagination: true,
- hasPreviousPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasPreviousPage,
- hasNextPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasNextPage,
- urlParams: {
- sort: urlSortParams[CREATED_DESC],
- state: IssuableStates.Opened,
- },
- });
- });
- });
-
- describe('header action buttons', () => {
- it('renders rss button', () => {
- wrapper = mountComponent({ mountFn: mount });
-
- expect(findGlButtonAt(0).props('icon')).toBe('rss');
- expect(findGlButtonAt(0).attributes()).toMatchObject({
- href: defaultProvide.rssPath,
- 'aria-label': IssuesListApp.i18n.rssLabel,
- });
- });
-
- it('renders calendar button', () => {
- wrapper = mountComponent({ mountFn: mount });
-
- expect(findGlButtonAt(1).props('icon')).toBe('calendar');
- expect(findGlButtonAt(1).attributes()).toMatchObject({
- href: defaultProvide.calendarPath,
- 'aria-label': IssuesListApp.i18n.calendarLabel,
- });
- });
-
- describe('csv import/export component', () => {
- describe('when user is signed in', () => {
- const search = '?search=refactor&sort=created_date&state=opened';
-
- beforeEach(() => {
- setWindowLocation(search);
-
- wrapper = mountComponent({ provide: { isSignedIn: true }, mountFn: mount });
-
- jest.runOnlyPendingTimers();
- });
-
- it('renders', () => {
- expect(findCsvImportExportButtons().props()).toMatchObject({
- exportCsvPath: `${defaultProvide.exportCsvPath}${search}`,
- issuableCount: 1,
- });
- });
- });
-
- describe('when user is not signed in', () => {
- it('does not render', () => {
- wrapper = mountComponent({ provide: { isSignedIn: false }, mountFn: mount });
-
- expect(findCsvImportExportButtons().exists()).toBe(false);
- });
- });
-
- describe('when in a group context', () => {
- it('does not render', () => {
- wrapper = mountComponent({ provide: { isProject: false }, mountFn: mount });
-
- expect(findCsvImportExportButtons().exists()).toBe(false);
- });
- });
- });
-
- describe('bulk edit button', () => {
- it('renders when user has permissions', () => {
- wrapper = mountComponent({ provide: { canBulkUpdate: true }, mountFn: mount });
-
- expect(findGlButtonAt(2).text()).toBe('Edit issues');
- });
-
- it('does not render when user does not have permissions', () => {
- wrapper = mountComponent({ provide: { canBulkUpdate: false }, mountFn: mount });
-
- expect(findGlButtons().filter((button) => button.text() === 'Edit issues')).toHaveLength(0);
- });
-
- it('emits "issuables:enableBulkEdit" event to legacy bulk edit class', async () => {
- wrapper = mountComponent({ provide: { canBulkUpdate: true }, mountFn: mount });
-
- jest.spyOn(eventHub, '$emit');
-
- findGlButtonAt(2).vm.$emit('click');
-
- await waitForPromises();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('issuables:enableBulkEdit');
- });
- });
-
- describe('new issue button', () => {
- it('renders when user has permissions', () => {
- wrapper = mountComponent({ provide: { showNewIssueLink: true }, mountFn: mount });
-
- expect(findGlButtonAt(2).text()).toBe('New issue');
- expect(findGlButtonAt(2).attributes('href')).toBe(defaultProvide.newIssuePath);
- });
-
- it('does not render when user does not have permissions', () => {
- wrapper = mountComponent({ provide: { showNewIssueLink: false }, mountFn: mount });
-
- expect(findGlButtons().filter((button) => button.text() === 'New issue')).toHaveLength(0);
- });
- });
-
- describe('new issue split dropdown', () => {
- it('does not render in a project context', () => {
- wrapper = mountComponent({ provide: { isProject: true }, mountFn: mount });
-
- expect(findNewIssueDropdown().exists()).toBe(false);
- });
-
- it('renders in a group context', () => {
- wrapper = mountComponent({ provide: { isProject: false }, mountFn: mount });
-
- expect(findNewIssueDropdown().exists()).toBe(true);
- });
- });
- });
-
- describe('initial url params', () => {
- describe('due_date', () => {
- it('is set from the url params', () => {
- setWindowLocation(`?${PARAM_DUE_DATE}=${DUE_DATE_OVERDUE}`);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props('urlParams')).toMatchObject({ due_date: DUE_DATE_OVERDUE });
- });
- });
-
- describe('search', () => {
- it('is set from the url params', () => {
- setWindowLocation(locationSearch);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props('urlParams')).toMatchObject({ search: 'find issues' });
- });
- });
-
- describe('sort', () => {
- it.each(Object.keys(urlSortParams))('is set as %s from the url params', (sortKey) => {
- setWindowLocation(`?sort=${urlSortParams[sortKey]}`);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props()).toMatchObject({
- initialSortBy: sortKey,
- urlParams: {
- sort: urlSortParams[sortKey],
- },
- });
- });
-
- describe('when issue repositioning is disabled and the sort is manual', () => {
- beforeEach(() => {
- setWindowLocation(`?sort=${RELATIVE_POSITION}`);
- wrapper = mountComponent({ provide: { isIssueRepositioningDisabled: true } });
- });
-
- it('changes the sort to the default of created descending', () => {
- expect(findIssuableList().props()).toMatchObject({
- initialSortBy: CREATED_DESC,
- urlParams: {
- sort: urlSortParams[CREATED_DESC],
- },
- });
- });
-
- it('shows an alert to tell the user that manual reordering is disabled', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: IssuesListApp.i18n.issueRepositioningMessage,
- type: FLASH_TYPES.NOTICE,
- });
- });
- });
- });
-
- describe('state', () => {
- it('is set from the url params', () => {
- const initialState = IssuableStates.All;
-
- setWindowLocation(`?state=${initialState}`);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props('currentTab')).toBe(initialState);
- });
- });
-
- describe('filter tokens', () => {
- it('is set from the url params', () => {
- setWindowLocation(locationSearch);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props('initialFilterValue')).toEqual(filteredTokens);
- });
-
- describe('when anonymous searching is performed', () => {
- beforeEach(() => {
- setWindowLocation(locationSearch);
-
- wrapper = mountComponent({
- provide: { isAnonymousSearchDisabled: true, isSignedIn: false },
- });
- });
-
- it('is not set from url params', () => {
- expect(findIssuableList().props('initialFilterValue')).toEqual([]);
- });
-
- it('shows an alert to tell the user they must be signed in to search', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: IssuesListApp.i18n.anonymousSearchingMessage,
- type: FLASH_TYPES.NOTICE,
- });
- });
- });
- });
- });
-
- describe('bulk edit', () => {
- describe.each([true, false])(
- 'when "issuables:toggleBulkEdit" event is received with payload `%s`',
- (isBulkEdit) => {
- beforeEach(() => {
- wrapper = mountComponent();
-
- eventHub.$emit('issuables:toggleBulkEdit', isBulkEdit);
- });
-
- it(`${isBulkEdit ? 'enables' : 'disables'} bulk edit`, () => {
- expect(findIssuableList().props('showBulkEditSidebar')).toBe(isBulkEdit);
- });
- },
- );
- });
-
- describe('IssuableByEmail component', () => {
- describe.each([true, false])(`when issue creation by email is enabled=%s`, (enabled) => {
- it(`${enabled ? 'renders' : 'does not render'}`, () => {
- wrapper = mountComponent({ provide: { initialEmail: enabled } });
-
- expect(findIssuableByEmail().exists()).toBe(enabled);
- });
- });
- });
-
- describe('empty states', () => {
- describe('when there are issues', () => {
- describe('when search returns no results', () => {
- beforeEach(() => {
- setWindowLocation(`?search=no+results`);
-
- wrapper = mountComponent({ provide: { hasAnyIssues: true }, mountFn: mount });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: IssuesListApp.i18n.noSearchResultsDescription,
- title: IssuesListApp.i18n.noSearchResultsTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
-
- describe('when "Open" tab has no issues', () => {
- beforeEach(() => {
- wrapper = mountComponent({ provide: { hasAnyIssues: true }, mountFn: mount });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: IssuesListApp.i18n.noOpenIssuesDescription,
- title: IssuesListApp.i18n.noOpenIssuesTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
-
- describe('when "Closed" tab has no issues', () => {
- beforeEach(() => {
- setWindowLocation(`?state=${IssuableStates.Closed}`);
-
- wrapper = mountComponent({ provide: { hasAnyIssues: true }, mountFn: mount });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- title: IssuesListApp.i18n.noClosedIssuesTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
- });
-
- describe('when there are no issues', () => {
- describe('when user is logged in', () => {
- beforeEach(() => {
- wrapper = mountComponent({
- provide: { hasAnyIssues: false, isSignedIn: true },
- mountFn: mount,
- });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: IssuesListApp.i18n.noIssuesSignedInDescription,
- title: IssuesListApp.i18n.noIssuesSignedInTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
-
- it('shows "New issue" and import/export buttons', () => {
- expect(findGlButton().text()).toBe(IssuesListApp.i18n.newIssueLabel);
- expect(findGlButton().attributes('href')).toBe(defaultProvide.newIssuePath);
- expect(findCsvImportExportButtons().props()).toMatchObject({
- exportCsvPath: defaultProvide.exportCsvPath,
- issuableCount: 0,
- });
- });
-
- it('shows Jira integration information', () => {
- const paragraphs = wrapper.findAll('p');
- expect(paragraphs.at(1).text()).toContain(IssuesListApp.i18n.jiraIntegrationTitle);
- expect(paragraphs.at(2).text()).toContain(
- 'Enable the Jira integration to view your Jira issues in GitLab.',
- );
- expect(paragraphs.at(3).text()).toContain(
- IssuesListApp.i18n.jiraIntegrationSecondaryMessage,
- );
- expect(findGlLink().text()).toBe('Enable the Jira integration');
- expect(findGlLink().attributes('href')).toBe(defaultProvide.jiraIntegrationPath);
- });
- });
-
- describe('when user is logged out', () => {
- beforeEach(() => {
- wrapper = mountComponent({
- provide: { hasAnyIssues: false, isSignedIn: false },
- });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: IssuesListApp.i18n.noIssuesSignedOutDescription,
- title: IssuesListApp.i18n.noIssuesSignedOutTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- primaryButtonText: IssuesListApp.i18n.noIssuesSignedOutButtonText,
- primaryButtonLink: defaultProvide.signInPath,
- });
- });
- });
- });
- });
-
- describe('tokens', () => {
- const mockCurrentUser = {
- id: 1,
- name: 'Administrator',
- username: 'root',
- avatar_url: 'avatar/url',
- };
-
- describe('when user is signed out', () => {
- beforeEach(() => {
- wrapper = mountComponent({ provide: { isSignedIn: false } });
- });
-
- it('does not render My-Reaction or Confidential tokens', () => {
- expect(findIssuableList().props('searchTokens')).not.toMatchObject([
- { type: TOKEN_TYPE_AUTHOR, preloadedAuthors: [mockCurrentUser] },
- { type: TOKEN_TYPE_ASSIGNEE, preloadedAuthors: [mockCurrentUser] },
- { type: TOKEN_TYPE_MY_REACTION },
- { type: TOKEN_TYPE_CONFIDENTIAL },
- ]);
- });
- });
-
- describe('when all tokens are available', () => {
- const originalGon = window.gon;
-
- beforeEach(() => {
- window.gon = {
- ...originalGon,
- current_user_id: mockCurrentUser.id,
- current_user_fullname: mockCurrentUser.name,
- current_username: mockCurrentUser.username,
- current_user_avatar_url: mockCurrentUser.avatar_url,
- };
-
- wrapper = mountComponent({ provide: { isSignedIn: true } });
- });
-
- afterEach(() => {
- window.gon = originalGon;
- });
-
- it('renders all tokens alphabetically', () => {
- const preloadedAuthors = [
- { ...mockCurrentUser, id: convertToGraphQLId('User', mockCurrentUser.id) },
- ];
-
- expect(findIssuableList().props('searchTokens')).toMatchObject([
- { type: TOKEN_TYPE_ASSIGNEE, preloadedAuthors },
- { type: TOKEN_TYPE_AUTHOR, preloadedAuthors },
- { type: TOKEN_TYPE_CONFIDENTIAL },
- { type: TOKEN_TYPE_LABEL },
- { type: TOKEN_TYPE_MILESTONE },
- { type: TOKEN_TYPE_MY_REACTION },
- { type: TOKEN_TYPE_RELEASE },
- { type: TOKEN_TYPE_TYPE },
- ]);
- });
- });
- });
-
- describe('errors', () => {
- describe.each`
- error | mountOption | message
- ${'fetching issues'} | ${'issuesQueryResponse'} | ${IssuesListApp.i18n.errorFetchingIssues}
- ${'fetching issue counts'} | ${'issuesCountsQueryResponse'} | ${IssuesListApp.i18n.errorFetchingCounts}
- `('when there is an error $error', ({ mountOption, message }) => {
- beforeEach(() => {
- wrapper = mountComponent({
- [mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')),
- });
- jest.runOnlyPendingTimers();
- });
-
- it('shows an error message', () => {
- expect(findIssuableList().props('error')).toBe(message);
- expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Network error: ERROR'));
- });
- });
-
- it('clears error message when "dismiss-alert" event is emitted from IssuableList', () => {
- wrapper = mountComponent({ issuesQueryResponse: jest.fn().mockRejectedValue(new Error()) });
-
- findIssuableList().vm.$emit('dismiss-alert');
-
- expect(findIssuableList().props('error')).toBeNull();
- });
- });
-
- describe('events', () => {
- describe('when "click-tab" event is emitted by IssuableList', () => {
- beforeEach(() => {
- wrapper = mountComponent();
-
- findIssuableList().vm.$emit('click-tab', IssuableStates.Closed);
- });
-
- it('updates to the new tab', () => {
- expect(findIssuableList().props('currentTab')).toBe(IssuableStates.Closed);
- });
- });
-
- describe.each(['next-page', 'previous-page'])(
- 'when "%s" event is emitted by IssuableList',
- (event) => {
- beforeEach(() => {
- wrapper = mountComponent();
-
- findIssuableList().vm.$emit(event);
- });
-
- it('scrolls to the top', () => {
- expect(scrollUp).toHaveBeenCalled();
- });
- },
- );
-
- describe('when "reorder" event is emitted by IssuableList', () => {
- const issueOne = {
- ...defaultQueryResponse.data.project.issues.nodes[0],
- id: 'gid://gitlab/Issue/1',
- iid: '101',
- reference: 'group/project#1',
- webPath: '/group/project/-/issues/1',
- };
- const issueTwo = {
- ...defaultQueryResponse.data.project.issues.nodes[0],
- id: 'gid://gitlab/Issue/2',
- iid: '102',
- reference: 'group/project#2',
- webPath: '/group/project/-/issues/2',
- };
- const issueThree = {
- ...defaultQueryResponse.data.project.issues.nodes[0],
- id: 'gid://gitlab/Issue/3',
- iid: '103',
- reference: 'group/project#3',
- webPath: '/group/project/-/issues/3',
- };
- const issueFour = {
- ...defaultQueryResponse.data.project.issues.nodes[0],
- id: 'gid://gitlab/Issue/4',
- iid: '104',
- reference: 'group/project#4',
- webPath: '/group/project/-/issues/4',
- };
- const response = (isProject = true) => ({
- data: {
- [isProject ? 'project' : 'group']: {
- id: '1',
- issues: {
- ...defaultQueryResponse.data.project.issues,
- nodes: [issueOne, issueTwo, issueThree, issueFour],
- },
- },
- },
- });
-
- describe('when successful', () => {
- describe.each([true, false])('when isProject=%s', (isProject) => {
- describe.each`
- description | issueToMove | oldIndex | newIndex | moveBeforeId | moveAfterId
- ${'to the beginning of the list'} | ${issueThree} | ${2} | ${0} | ${null} | ${issueOne.id}
- ${'down the list'} | ${issueOne} | ${0} | ${1} | ${issueTwo.id} | ${issueThree.id}
- ${'up the list'} | ${issueThree} | ${2} | ${1} | ${issueOne.id} | ${issueTwo.id}
- ${'to the end of the list'} | ${issueTwo} | ${1} | ${3} | ${issueFour.id} | ${null}
- `(
- 'when moving issue $description',
- ({ issueToMove, oldIndex, newIndex, moveBeforeId, moveAfterId }) => {
- beforeEach(() => {
- wrapper = mountComponent({
- provide: { isProject },
- issuesQueryResponse: jest.fn().mockResolvedValue(response(isProject)),
- });
- jest.runOnlyPendingTimers();
- });
-
- it('makes API call to reorder the issue', async () => {
- findIssuableList().vm.$emit('reorder', { oldIndex, newIndex });
-
- await waitForPromises();
-
- expect(axiosMock.history.put[0]).toMatchObject({
- url: joinPaths(issueToMove.webPath, 'reorder'),
- data: JSON.stringify({
- move_before_id: getIdFromGraphQLId(moveBeforeId),
- move_after_id: getIdFromGraphQLId(moveAfterId),
- group_full_path: isProject ? undefined : defaultProvide.fullPath,
- }),
- });
- });
- },
- );
- });
- });
-
- describe('when unsuccessful', () => {
- beforeEach(() => {
- wrapper = mountComponent({
- issuesQueryResponse: jest.fn().mockResolvedValue(response()),
- });
- jest.runOnlyPendingTimers();
- });
-
- it('displays an error message', async () => {
- axiosMock.onPut(joinPaths(issueOne.webPath, 'reorder')).reply(500);
-
- findIssuableList().vm.$emit('reorder', { oldIndex: 0, newIndex: 1 });
-
- await waitForPromises();
-
- expect(findIssuableList().props('error')).toBe(IssuesListApp.i18n.reorderError);
- expect(Sentry.captureException).toHaveBeenCalledWith(
- new Error('Request failed with status code 500'),
- );
- });
- });
- });
-
- describe('when "sort" event is emitted by IssuableList', () => {
- it.each(Object.keys(urlSortParams))(
- 'updates to the new sort when payload is `%s`',
- async (sortKey) => {
- wrapper = mountComponent();
-
- findIssuableList().vm.$emit('sort', sortKey);
-
- jest.runOnlyPendingTimers();
- await nextTick();
-
- expect(findIssuableList().props('urlParams')).toMatchObject({
- sort: urlSortParams[sortKey],
- });
- },
- );
-
- describe('when issue repositioning is disabled', () => {
- const initialSort = CREATED_DESC;
-
- beforeEach(() => {
- setWindowLocation(`?sort=${initialSort}`);
- wrapper = mountComponent({ provide: { isIssueRepositioningDisabled: true } });
-
- findIssuableList().vm.$emit('sort', RELATIVE_POSITION_ASC);
- });
-
- it('does not update the sort to manual', () => {
- expect(findIssuableList().props('urlParams')).toMatchObject({
- sort: urlSortParams[initialSort],
- });
- });
-
- it('shows an alert to tell the user that manual reordering is disabled', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: IssuesListApp.i18n.issueRepositioningMessage,
- type: FLASH_TYPES.NOTICE,
- });
- });
- });
- });
-
- describe('when "update-legacy-bulk-edit" event is emitted by IssuableList', () => {
- beforeEach(() => {
- wrapper = mountComponent();
- jest.spyOn(eventHub, '$emit');
-
- findIssuableList().vm.$emit('update-legacy-bulk-edit');
- });
-
- it('emits an "issuables:updateBulkEdit" event to the legacy bulk edit class', () => {
- expect(eventHub.$emit).toHaveBeenCalledWith('issuables:updateBulkEdit');
- });
- });
-
- describe('when "filter" event is emitted by IssuableList', () => {
- it('updates IssuableList with url params', async () => {
- wrapper = mountComponent();
-
- findIssuableList().vm.$emit('filter', filteredTokens);
- await nextTick();
-
- expect(findIssuableList().props('urlParams')).toMatchObject(urlParams);
- });
-
- describe('when anonymous searching is performed', () => {
- beforeEach(() => {
- wrapper = mountComponent({
- provide: { isAnonymousSearchDisabled: true, isSignedIn: false },
- });
-
- findIssuableList().vm.$emit('filter', filteredTokens);
- });
-
- it('does not update IssuableList with url params ', async () => {
- const defaultParams = { sort: 'created_date', state: 'opened' };
-
- expect(findIssuableList().props('urlParams')).toEqual(defaultParams);
- });
-
- it('shows an alert to tell the user they must be signed in to search', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: IssuesListApp.i18n.anonymousSearchingMessage,
- type: FLASH_TYPES.NOTICE,
- });
- });
- });
- });
- });
-});
diff --git a/spec/frontend/issues_list/components/jira_issues_import_status_app_spec.js b/spec/frontend/issues_list/components/jira_issues_import_status_app_spec.js
deleted file mode 100644
index 633799816d8..00000000000
--- a/spec/frontend/issues_list/components/jira_issues_import_status_app_spec.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import { GlAlert, GlLabel } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import JiraIssuesImportStatus from '~/issues_list/components/jira_issues_import_status_app.vue';
-
-describe('JiraIssuesImportStatus', () => {
- const issuesPath = 'gitlab-org/gitlab-test/-/issues';
- const label = {
- color: '#333',
- title: 'jira-import::MTG-3',
- };
- let wrapper;
-
- const findAlert = () => wrapper.find(GlAlert);
-
- const findAlertLabel = () => wrapper.find(GlAlert).find(GlLabel);
-
- const mountComponent = ({
- shouldShowFinishedAlert = false,
- shouldShowInProgressAlert = false,
- } = {}) =>
- shallowMount(JiraIssuesImportStatus, {
- propsData: {
- canEdit: true,
- isJiraConfigured: true,
- issuesPath,
- projectPath: 'gitlab-org/gitlab-test',
- },
- data() {
- return {
- jiraImport: {
- importedIssuesCount: 1,
- label,
- shouldShowFinishedAlert,
- shouldShowInProgressAlert,
- },
- };
- },
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when Jira import is neither in progress nor finished', () => {
- beforeEach(() => {
- wrapper = mountComponent();
- });
-
- it('does not show an alert', () => {
- expect(wrapper.find(GlAlert).exists()).toBe(false);
- });
- });
-
- describe('when Jira import is in progress', () => {
- it('shows an alert that tells the user a Jira import is in progress', () => {
- wrapper = mountComponent({
- shouldShowInProgressAlert: true,
- });
-
- expect(findAlert().text()).toBe(
- 'Import in progress. Refresh page to see newly added issues.',
- );
- });
- });
-
- describe('when Jira import has finished', () => {
- beforeEach(() => {
- wrapper = mountComponent({
- shouldShowFinishedAlert: true,
- });
- });
-
- describe('shows an alert', () => {
- it('tells the user the Jira import has finished', () => {
- expect(findAlert().text()).toBe('1 issue successfully imported with the label');
- });
-
- it('contains the label title associated with the Jira import', () => {
- const alertLabelTitle = findAlertLabel().props('title');
-
- expect(alertLabelTitle).toBe(label.title);
- });
-
- it('contains the correct label color', () => {
- const alertLabelTitle = findAlertLabel().props('backgroundColor');
-
- expect(alertLabelTitle).toBe(label.color);
- });
-
- it('contains a link within the label', () => {
- const alertLabelTarget = findAlertLabel().props('target');
-
- expect(alertLabelTarget).toBe(
- `${issuesPath}?label_name[]=${encodeURIComponent(label.title)}`,
- );
- });
- });
- });
-
- describe('alert message', () => {
- it('is hidden when dismissed', () => {
- wrapper = mountComponent({
- shouldShowInProgressAlert: true,
- });
-
- expect(wrapper.find(GlAlert).exists()).toBe(true);
-
- findAlert().vm.$emit('dismiss');
-
- return Vue.nextTick(() => {
- expect(wrapper.find(GlAlert).exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/issues_list/components/new_issue_dropdown_spec.js b/spec/frontend/issues_list/components/new_issue_dropdown_spec.js
deleted file mode 100644
index 1c9a87e8af2..00000000000
--- a/spec/frontend/issues_list/components/new_issue_dropdown_spec.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
-import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import NewIssueDropdown from '~/issues_list/components/new_issue_dropdown.vue';
-import searchProjectsQuery from '~/issues_list/queries/search_projects.query.graphql';
-import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility';
-import {
- emptySearchProjectsQueryResponse,
- project1,
- project3,
- searchProjectsQueryResponse,
-} from '../mock_data';
-
-describe('NewIssueDropdown component', () => {
- let wrapper;
-
- const localVue = createLocalVue();
- localVue.use(VueApollo);
-
- const mountComponent = ({
- search = '',
- queryResponse = searchProjectsQueryResponse,
- mountFn = shallowMount,
- } = {}) => {
- const requestHandlers = [[searchProjectsQuery, jest.fn().mockResolvedValue(queryResponse)]];
- const apolloProvider = createMockApollo(requestHandlers);
-
- return mountFn(NewIssueDropdown, {
- localVue,
- apolloProvider,
- provide: {
- fullPath: 'mushroom-kingdom',
- },
- data() {
- return { search };
- },
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findInput = () => wrapper.findComponent(GlSearchBoxByType);
- const showDropdown = async () => {
- findDropdown().vm.$emit('shown');
- await wrapper.vm.$apollo.queries.projects.refetch();
- jest.runOnlyPendingTimers();
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders a split dropdown', () => {
- wrapper = mountComponent();
-
- expect(findDropdown().props('split')).toBe(true);
- });
-
- it('renders a label for the dropdown toggle button', () => {
- wrapper = mountComponent();
-
- expect(findDropdown().attributes('toggle-text')).toBe(NewIssueDropdown.i18n.toggleButtonLabel);
- });
-
- it('focuses on input when dropdown is shown', async () => {
- wrapper = mountComponent({ mountFn: mount });
-
- const inputSpy = jest.spyOn(findInput().vm, 'focusInput');
-
- await showDropdown();
-
- expect(inputSpy).toHaveBeenCalledTimes(1);
- });
-
- it('renders projects with issues enabled', async () => {
- wrapper = mountComponent({ mountFn: mount });
-
- await showDropdown();
-
- const listItems = wrapper.findAll('li');
-
- expect(listItems.at(0).text()).toBe(project1.nameWithNamespace);
- expect(listItems.at(1).text()).toBe(project3.nameWithNamespace);
- });
-
- it('renders `No matches found` when there are no matches', async () => {
- wrapper = mountComponent({
- search: 'no matches',
- queryResponse: emptySearchProjectsQueryResponse,
- mountFn: mount,
- });
-
- await showDropdown();
-
- expect(wrapper.find('li').text()).toBe(NewIssueDropdown.i18n.noMatchesFound);
- });
-
- describe('when no project is selected', () => {
- beforeEach(() => {
- wrapper = mountComponent();
- });
-
- it('dropdown button is not a link', () => {
- expect(findDropdown().attributes('split-href')).toBeUndefined();
- });
-
- it('displays default text on the dropdown button', () => {
- expect(findDropdown().props('text')).toBe(NewIssueDropdown.i18n.defaultDropdownText);
- });
- });
-
- describe('when a project is selected', () => {
- beforeEach(async () => {
- wrapper = mountComponent({ mountFn: mount });
-
- await showDropdown();
-
- wrapper.findComponent(GlDropdownItem).vm.$emit('click', project1);
- });
-
- it('dropdown button is a link', () => {
- const href = joinPaths(project1.webUrl, DASH_SCOPE, 'issues/new');
-
- expect(findDropdown().attributes('split-href')).toBe(href);
- });
-
- it('displays project name on the dropdown button', () => {
- expect(findDropdown().props('text')).toBe(`New issue in ${project1.name}`);
- });
- });
-});
diff --git a/spec/frontend/issues_list/issuable_list_test_data.js b/spec/frontend/issues_list/issuable_list_test_data.js
deleted file mode 100644
index 313aa15bd31..00000000000
--- a/spec/frontend/issues_list/issuable_list_test_data.js
+++ /dev/null
@@ -1,77 +0,0 @@
-export const simpleIssue = {
- id: 442,
- iid: 31,
- title: 'Dismiss Cipher with no integrity',
- state: 'opened',
- created_at: '2019-08-26T19:06:32.667Z',
- updated_at: '2019-08-28T19:53:58.314Z',
- labels: [],
- milestone: null,
- assignees: [],
- author: {
- id: 3,
- name: 'Elnora Bernhard',
- username: 'treva.lesch',
- state: 'active',
- avatar_url: 'https://www.gravatar.com/avatar/a8c0d9c2882406cf2a9b71494625a796?s=80&d=identicon',
- web_url: 'http://localhost:3001/treva.lesch',
- },
- assignee: null,
- user_notes_count: 0,
- blocking_issues_count: 0,
- merge_requests_count: 0,
- upvotes: 0,
- downvotes: 0,
- due_date: null,
- confidential: false,
- web_url: 'http://localhost:3001/h5bp/html5-boilerplate/issues/31',
- has_tasks: false,
- weight: null,
- references: {
- relative: 'html-boilerplate#45',
- },
- health_status: 'on_track',
-};
-
-export const testLabels = [
- {
- id: 1,
- name: 'Tanuki',
- description: 'A cute animal',
- color: '#ff0000',
- text_color: '#ffffff',
- },
- {
- id: 2,
- name: 'Octocat',
- description: 'A grotesque mish-mash of whiskers and tentacles',
- color: '#333333',
- text_color: '#000000',
- },
- {
- id: 3,
- name: 'scoped::label',
- description: 'A scoped label',
- color: '#00ff00',
- text_color: '#ffffff',
- },
-];
-
-export const testAssignees = [
- {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://localhost:3001/root',
- },
- {
- id: 22,
- name: 'User 0',
- username: 'user0',
- state: 'active',
- avatar_url: 'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80&d=identicon',
- web_url: 'http://localhost:3001/user0',
- },
-];
diff --git a/spec/frontend/issues_list/mock_data.js b/spec/frontend/issues_list/mock_data.js
deleted file mode 100644
index 948699876ce..00000000000
--- a/spec/frontend/issues_list/mock_data.js
+++ /dev/null
@@ -1,310 +0,0 @@
-import {
- OPERATOR_IS,
- OPERATOR_IS_NOT,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-
-export const getIssuesQueryResponse = {
- data: {
- project: {
- id: '1',
- issues: {
- pageInfo: {
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'startcursor',
- endCursor: 'endcursor',
- },
- nodes: [
- {
- id: 'gid://gitlab/Issue/123456',
- iid: '789',
- closedAt: null,
- confidential: false,
- createdAt: '2021-05-22T04:08:01Z',
- downvotes: 2,
- dueDate: '2021-05-29',
- hidden: false,
- humanTimeEstimate: null,
- mergeRequestsCount: false,
- moved: false,
- title: 'Issue title',
- updatedAt: '2021-05-22T04:08:01Z',
- upvotes: 3,
- userDiscussionsCount: 4,
- webPath: 'project/-/issues/789',
- webUrl: 'project/-/issues/789',
- assignees: {
- nodes: [
- {
- id: 'gid://gitlab/User/234',
- avatarUrl: 'avatar/url',
- name: 'Marge Simpson',
- username: 'msimpson',
- webUrl: 'url/msimpson',
- },
- ],
- },
- author: {
- id: 'gid://gitlab/User/456',
- avatarUrl: 'avatar/url',
- name: 'Homer Simpson',
- username: 'hsimpson',
- webUrl: 'url/hsimpson',
- },
- labels: {
- nodes: [
- {
- id: 'gid://gitlab/ProjectLabel/456',
- color: '#333',
- title: 'Label title',
- description: 'Label description',
- },
- ],
- },
- milestone: null,
- taskCompletionStatus: {
- completedCount: 1,
- count: 2,
- },
- },
- ],
- },
- },
- },
-};
-
-export const getIssuesCountsQueryResponse = {
- data: {
- project: {
- id: '1',
- openedIssues: {
- count: 1,
- },
- closedIssues: {
- count: 1,
- },
- allIssues: {
- count: 1,
- },
- },
- },
-};
-
-export const locationSearch = [
- '?search=find+issues',
- 'author_username=homer',
- 'not[author_username]=marge',
- 'assignee_username[]=bart',
- 'assignee_username[]=lisa',
- 'not[assignee_username][]=patty',
- 'not[assignee_username][]=selma',
- 'milestone_title=season+3',
- 'milestone_title=season+4',
- 'not[milestone_title]=season+20',
- 'not[milestone_title]=season+30',
- 'label_name[]=cartoon',
- 'label_name[]=tv',
- 'not[label_name][]=live action',
- 'not[label_name][]=drama',
- 'release_tag=v3',
- 'release_tag=v4',
- 'not[release_tag]=v20',
- 'not[release_tag]=v30',
- 'type[]=issue',
- 'type[]=feature',
- 'not[type][]=bug',
- 'not[type][]=incident',
- 'my_reaction_emoji=thumbsup',
- 'not[my_reaction_emoji]=thumbsdown',
- 'confidential=yes',
- 'iteration_id=4',
- 'iteration_id=12',
- 'not[iteration_id]=20',
- 'not[iteration_id]=42',
- 'epic_id=12',
- 'not[epic_id]=34',
- 'weight=1',
- 'not[weight]=3',
-].join('&');
-
-export const locationSearchWithSpecialValues = [
- 'assignee_id=123',
- 'assignee_username=bart',
- 'my_reaction_emoji=None',
- 'iteration_id=Current',
- 'label_name[]=None',
- 'release_tag=None',
- 'milestone_title=Upcoming',
- 'epic_id=None',
- 'weight=None',
-].join('&');
-
-export const filteredTokens = [
- { type: 'author_username', value: { data: 'homer', operator: OPERATOR_IS } },
- { type: 'author_username', value: { data: 'marge', operator: OPERATOR_IS_NOT } },
- { type: 'assignee_username', value: { data: 'bart', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'lisa', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'patty', operator: OPERATOR_IS_NOT } },
- { type: 'assignee_username', value: { data: 'selma', operator: OPERATOR_IS_NOT } },
- { type: 'milestone', value: { data: 'season 3', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'season 4', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'season 20', operator: OPERATOR_IS_NOT } },
- { type: 'milestone', value: { data: 'season 30', operator: OPERATOR_IS_NOT } },
- { type: 'labels', value: { data: 'cartoon', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'tv', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'live action', operator: OPERATOR_IS_NOT } },
- { type: 'labels', value: { data: 'drama', operator: OPERATOR_IS_NOT } },
- { type: 'release', value: { data: 'v3', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'v4', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'v20', operator: OPERATOR_IS_NOT } },
- { type: 'release', value: { data: 'v30', operator: OPERATOR_IS_NOT } },
- { type: 'type', value: { data: 'issue', operator: OPERATOR_IS } },
- { type: 'type', value: { data: 'feature', operator: OPERATOR_IS } },
- { type: 'type', value: { data: 'bug', operator: OPERATOR_IS_NOT } },
- { type: 'type', value: { data: 'incident', operator: OPERATOR_IS_NOT } },
- { type: 'my_reaction_emoji', value: { data: 'thumbsup', operator: OPERATOR_IS } },
- { type: 'my_reaction_emoji', value: { data: 'thumbsdown', operator: OPERATOR_IS_NOT } },
- { type: 'confidential', value: { data: 'yes', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '4', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '12', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '20', operator: OPERATOR_IS_NOT } },
- { type: 'iteration', value: { data: '42', operator: OPERATOR_IS_NOT } },
- { type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } },
- { type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } },
- { type: 'weight', value: { data: '1', operator: OPERATOR_IS } },
- { type: 'weight', value: { data: '3', operator: OPERATOR_IS_NOT } },
- { type: 'filtered-search-term', value: { data: 'find' } },
- { type: 'filtered-search-term', value: { data: 'issues' } },
-];
-
-export const filteredTokensWithSpecialValues = [
- { type: 'assignee_username', value: { data: '123', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'bart', operator: OPERATOR_IS } },
- { type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'Upcoming', operator: OPERATOR_IS } },
- { type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'weight', value: { data: 'None', operator: OPERATOR_IS } },
-];
-
-export const apiParams = {
- authorUsername: 'homer',
- assigneeUsernames: ['bart', 'lisa'],
- milestoneTitle: ['season 3', 'season 4'],
- labelName: ['cartoon', 'tv'],
- releaseTag: ['v3', 'v4'],
- types: ['ISSUE', 'FEATURE'],
- myReactionEmoji: 'thumbsup',
- confidential: true,
- iterationId: ['4', '12'],
- epicId: '12',
- weight: '1',
- not: {
- authorUsername: 'marge',
- assigneeUsernames: ['patty', 'selma'],
- milestoneTitle: ['season 20', 'season 30'],
- labelName: ['live action', 'drama'],
- releaseTag: ['v20', 'v30'],
- types: ['BUG', 'INCIDENT'],
- myReactionEmoji: 'thumbsdown',
- iterationId: ['20', '42'],
- epicId: '34',
- weight: '3',
- },
-};
-
-export const apiParamsWithSpecialValues = {
- assigneeId: '123',
- assigneeUsernames: 'bart',
- labelName: 'None',
- myReactionEmoji: 'None',
- releaseTagWildcardId: 'NONE',
- iterationWildcardId: 'CURRENT',
- milestoneWildcardId: 'UPCOMING',
- epicId: 'None',
- weight: 'None',
-};
-
-export const urlParams = {
- author_username: 'homer',
- 'not[author_username]': 'marge',
- 'assignee_username[]': ['bart', 'lisa'],
- 'not[assignee_username][]': ['patty', 'selma'],
- milestone_title: ['season 3', 'season 4'],
- 'not[milestone_title]': ['season 20', 'season 30'],
- 'label_name[]': ['cartoon', 'tv'],
- 'not[label_name][]': ['live action', 'drama'],
- release_tag: ['v3', 'v4'],
- 'not[release_tag]': ['v20', 'v30'],
- 'type[]': ['issue', 'feature'],
- 'not[type][]': ['bug', 'incident'],
- my_reaction_emoji: 'thumbsup',
- 'not[my_reaction_emoji]': 'thumbsdown',
- confidential: 'yes',
- iteration_id: ['4', '12'],
- 'not[iteration_id]': ['20', '42'],
- epic_id: '12',
- 'not[epic_id]': '34',
- weight: '1',
- 'not[weight]': '3',
-};
-
-export const urlParamsWithSpecialValues = {
- assignee_id: '123',
- 'assignee_username[]': 'bart',
- 'label_name[]': 'None',
- release_tag: 'None',
- my_reaction_emoji: 'None',
- iteration_id: 'Current',
- milestone_title: 'Upcoming',
- epic_id: 'None',
- weight: 'None',
-};
-
-export const project1 = {
- id: 'gid://gitlab/Group/26',
- issuesEnabled: true,
- name: 'Super Mario Project',
- nameWithNamespace: 'Mushroom Kingdom / Super Mario Project',
- webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/super-mario-project',
-};
-
-export const project2 = {
- id: 'gid://gitlab/Group/59',
- issuesEnabled: false,
- name: 'Mario Kart Project',
- nameWithNamespace: 'Mushroom Kingdom / Mario Kart Project',
- webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-kart-project',
-};
-
-export const project3 = {
- id: 'gid://gitlab/Group/103',
- issuesEnabled: true,
- name: 'Mario Party Project',
- nameWithNamespace: 'Mushroom Kingdom / Mario Party Project',
- webUrl: 'https://127.0.0.1:3000/mushroom-kingdom/mario-party-project',
-};
-
-export const searchProjectsQueryResponse = {
- data: {
- group: {
- id: '1',
- projects: {
- nodes: [project1, project2, project3],
- },
- },
- },
-};
-
-export const emptySearchProjectsQueryResponse = {
- data: {
- group: {
- id: '1',
- projects: {
- nodes: [],
- },
- },
- },
-};
diff --git a/spec/frontend/issues_list/service_desk_helper_spec.js b/spec/frontend/issues_list/service_desk_helper_spec.js
deleted file mode 100644
index 16aee853341..00000000000
--- a/spec/frontend/issues_list/service_desk_helper_spec.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { emptyStateHelper, generateMessages } from '~/issues_list/service_desk_helper';
-
-describe('service desk helper', () => {
- const emptyStateMessages = generateMessages({});
-
- // Note: isServiceDeskEnabled must not be true when isServiceDeskSupported is false (it's an invalid case).
- describe.each`
- isServiceDeskSupported | isServiceDeskEnabled | canEditProjectSettings | expectedMessage
- ${true} | ${true} | ${true} | ${'serviceDeskEnabledAndCanEditProjectSettings'}
- ${true} | ${true} | ${false} | ${'serviceDeskEnabledAndCannotEditProjectSettings'}
- ${true} | ${false} | ${true} | ${'serviceDeskDisabledAndCanEditProjectSettings'}
- ${true} | ${false} | ${false} | ${'serviceDeskDisabledAndCannotEditProjectSettings'}
- ${false} | ${false} | ${true} | ${'serviceDeskIsNotSupported'}
- ${false} | ${false} | ${false} | ${'serviceDeskIsNotEnabled'}
- `(
- 'isServiceDeskSupported = $isServiceDeskSupported, isServiceDeskEnabled = $isServiceDeskEnabled, canEditProjectSettings = $canEditProjectSettings',
- ({ isServiceDeskSupported, isServiceDeskEnabled, canEditProjectSettings, expectedMessage }) => {
- it(`displays ${expectedMessage} message`, () => {
- const emptyStateMeta = {
- isServiceDeskEnabled,
- isServiceDeskSupported,
- canEditProjectSettings,
- };
- expect(emptyStateHelper(emptyStateMeta)).toEqual(emptyStateMessages[expectedMessage]);
- });
- },
- );
-});
diff --git a/spec/frontend/issues_list/utils_spec.js b/spec/frontend/issues_list/utils_spec.js
deleted file mode 100644
index 8e1d70db92d..00000000000
--- a/spec/frontend/issues_list/utils_spec.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import {
- apiParams,
- apiParamsWithSpecialValues,
- filteredTokens,
- filteredTokensWithSpecialValues,
- locationSearch,
- locationSearchWithSpecialValues,
- urlParams,
- urlParamsWithSpecialValues,
-} from 'jest/issues_list/mock_data';
-import {
- defaultPageSizeParams,
- DUE_DATE_VALUES,
- largePageSizeParams,
- RELATIVE_POSITION_ASC,
- urlSortParams,
-} from '~/issues_list/constants';
-import {
- convertToApiParams,
- convertToSearchQuery,
- convertToUrlParams,
- getDueDateValue,
- getFilterTokens,
- getInitialPageParams,
- getSortKey,
- getSortOptions,
-} from '~/issues_list/utils';
-
-describe('getInitialPageParams', () => {
- it.each(Object.keys(urlSortParams))(
- 'returns the correct page params for sort key %s',
- (sortKey) => {
- const expectedPageParams =
- sortKey === RELATIVE_POSITION_ASC ? largePageSizeParams : defaultPageSizeParams;
-
- expect(getInitialPageParams(sortKey)).toBe(expectedPageParams);
- },
- );
-});
-
-describe('getSortKey', () => {
- it.each(Object.keys(urlSortParams))('returns %s given the correct inputs', (sortKey) => {
- const sort = urlSortParams[sortKey];
- expect(getSortKey(sort)).toBe(sortKey);
- });
-});
-
-describe('getDueDateValue', () => {
- it.each(DUE_DATE_VALUES)('returns the argument when it is `%s`', (value) => {
- expect(getDueDateValue(value)).toBe(value);
- });
-
- it('returns undefined when the argument is invalid', () => {
- expect(getDueDateValue('invalid value')).toBeUndefined();
- });
-});
-
-describe('getSortOptions', () => {
- describe.each`
- hasIssueWeightsFeature | hasBlockedIssuesFeature | length | containsWeight | containsBlocking
- ${false} | ${false} | ${9} | ${false} | ${false}
- ${true} | ${false} | ${10} | ${true} | ${false}
- ${false} | ${true} | ${10} | ${false} | ${true}
- ${true} | ${true} | ${11} | ${true} | ${true}
- `(
- 'when hasIssueWeightsFeature=$hasIssueWeightsFeature and hasBlockedIssuesFeature=$hasBlockedIssuesFeature',
- ({
- hasIssueWeightsFeature,
- hasBlockedIssuesFeature,
- length,
- containsWeight,
- containsBlocking,
- }) => {
- const sortOptions = getSortOptions(hasIssueWeightsFeature, hasBlockedIssuesFeature);
-
- it('returns the correct length of sort options', () => {
- expect(sortOptions).toHaveLength(length);
- });
-
- it(`${containsWeight ? 'contains' : 'does not contain'} weight option`, () => {
- expect(sortOptions.some((option) => option.title === 'Weight')).toBe(containsWeight);
- });
-
- it(`${containsBlocking ? 'contains' : 'does not contain'} blocking option`, () => {
- expect(sortOptions.some((option) => option.title === 'Blocking')).toBe(containsBlocking);
- });
- },
- );
-});
-
-describe('getFilterTokens', () => {
- it('returns filtered tokens given "window.location.search"', () => {
- expect(getFilterTokens(locationSearch)).toEqual(filteredTokens);
- });
-
- it('returns filtered tokens given "window.location.search" with special values', () => {
- expect(getFilterTokens(locationSearchWithSpecialValues)).toEqual(
- filteredTokensWithSpecialValues,
- );
- });
-});
-
-describe('convertToApiParams', () => {
- it('returns api params given filtered tokens', () => {
- expect(convertToApiParams(filteredTokens)).toEqual(apiParams);
- });
-
- it('returns api params given filtered tokens with special values', () => {
- expect(convertToApiParams(filteredTokensWithSpecialValues)).toEqual(apiParamsWithSpecialValues);
- });
-});
-
-describe('convertToUrlParams', () => {
- it('returns url params given filtered tokens', () => {
- expect(convertToUrlParams(filteredTokens)).toEqual(urlParams);
- });
-
- it('returns url params given filtered tokens with special values', () => {
- expect(convertToUrlParams(filteredTokensWithSpecialValues)).toEqual(urlParamsWithSpecialValues);
- });
-});
-
-describe('convertToSearchQuery', () => {
- it('returns search string given filtered tokens', () => {
- expect(convertToSearchQuery(filteredTokens)).toBe('find issues');
- });
-});