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/sidebar/components')
-rw-r--r--spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js93
-rw-r--r--spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js36
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_spec.js285
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js202
4 files changed, 422 insertions, 194 deletions
diff --git a/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
new file mode 100644
index 00000000000..843ac1da4bb
--- /dev/null
+++ b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
@@ -0,0 +1,93 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import MilestoneDropdown from '~/sidebar/components/milestone/milestone_dropdown.vue';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
+
+describe('MilestoneDropdown component', () => {
+ let wrapper;
+
+ const propsData = {
+ attrWorkspacePath: 'full/path',
+ issuableType: IssuableType.Issue,
+ workspaceType: WorkspaceType.project,
+ };
+
+ const findHiddenInput = () => wrapper.find('input');
+ const findSidebarDropdown = () => wrapper.findComponent(SidebarDropdown);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(MilestoneDropdown, { propsData: { ...propsData, ...props } });
+ };
+
+ it('renders SidebarDropdown', () => {
+ createComponent();
+
+ expect(findSidebarDropdown().props()).toMatchObject({
+ attrWorkspacePath: propsData.attrWorkspacePath,
+ issuableAttribute: MilestoneDropdown.issuableAttribute,
+ issuableType: propsData.issuableType,
+ workspaceType: propsData.workspaceType,
+ });
+ });
+
+ it('renders hidden input', () => {
+ createComponent();
+
+ expect(findHiddenInput().attributes()).toEqual({
+ type: 'hidden',
+ name: 'update[milestone_id]',
+ value: undefined,
+ });
+ });
+
+ describe('when milestone ID and title is provided', () => {
+ it('is used in the dropdown and hidden input', () => {
+ const milestone = {
+ id: 'gid://gitlab/Milestone/52',
+ title: __('Milestone 52'),
+ };
+ createComponent({ milestoneId: milestone.id, milestoneTitle: milestone.title });
+
+ expect(findSidebarDropdown().props('currentAttribute')).toEqual(milestone);
+ expect(findHiddenInput().attributes('value')).toBe(
+ getIdFromGraphQLId(milestone.id).toString(),
+ );
+ });
+ });
+
+ describe('when SidebarDropdown emits `change` event', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('when valid milestone is emitted', () => {
+ it('updates the hidden input value', async () => {
+ const milestone = {
+ id: 'gid://gitlab/Milestone/52',
+ title: __('Milestone 52'),
+ };
+
+ findSidebarDropdown().vm.$emit('change', milestone);
+ await nextTick();
+
+ expect(findHiddenInput().attributes('value')).toBe(
+ getIdFromGraphQLId(milestone.id).toString(),
+ );
+ });
+ });
+
+ describe('when null milestone is emitted', () => {
+ it('updates the hidden input value to `0`', async () => {
+ const milestone = { id: null };
+
+ findSidebarDropdown().vm.$emit('change', milestone);
+ await nextTick();
+
+ expect(findHiddenInput().attributes('value')).toBe('0');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js
new file mode 100644
index 00000000000..277ef6d9561
--- /dev/null
+++ b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js
@@ -0,0 +1,36 @@
+import { shallowMount } from '@vue/test-utils';
+import SidebarReviewersInputs from '~/sidebar/components/reviewers/sidebar_reviewers_inputs.vue';
+import { state } from '~/sidebar/components/reviewers/sidebar_reviewers.vue';
+
+let wrapper;
+
+function factory() {
+ wrapper = shallowMount(SidebarReviewersInputs);
+}
+
+describe('Sidebar reviewers inputs component', () => {
+ it('renders hidden input', () => {
+ state.issuable.reviewers = {
+ nodes: [
+ {
+ id: 1,
+ avatarUrl: '',
+ name: 'root',
+ username: 'root',
+ mergeRequestInteraction: { canMerge: true },
+ },
+ {
+ id: 2,
+ avatarUrl: '',
+ name: 'root',
+ username: 'root',
+ mergeRequestInteraction: { canMerge: true },
+ },
+ ],
+ };
+
+ factory();
+
+ expect(wrapper.findAll('input[type="hidden"]').length).toBe(2);
+ });
+});
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
new file mode 100644
index 00000000000..83bc8cf7002
--- /dev/null
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
@@ -0,0 +1,285 @@
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlFormInput,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import { IssuableType } from '~/issues/constants';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
+import { IssuableAttributeType } from '~/sidebar/constants';
+import projectIssueMilestoneQuery from '~/sidebar/queries/project_issue_milestone.query.graphql';
+import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql';
+import {
+ emptyProjectMilestonesResponse,
+ mockIssue,
+ mockProjectMilestonesResponse,
+ noCurrentMilestoneResponse,
+} from '../mock_data';
+
+jest.mock('~/flash');
+
+describe('SidebarDropdown component', () => {
+ let wrapper;
+
+ const promiseData = { issuableSetAttribute: { issue: { attribute: { id: '123' } } } };
+ const mutationSuccess = () => jest.fn().mockResolvedValue({ data: promiseData });
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownText = () => wrapper.findComponent(GlDropdownText);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findDropdownItemWithText = (text) =>
+ findAllDropdownItems().wrappers.find((x) => x.text() === text);
+ const findAttributeItems = () => wrapper.findByTestId('milestone-items');
+ const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
+ const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
+
+ const toggleDropdown = async () => {
+ wrapper.vm.$refs.dropdown.show();
+ findDropdown().vm.$emit('show');
+
+ await nextTick();
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ };
+
+ const createComponentWithApollo = ({
+ requestHandlers = [],
+ projectMilestonesSpy = jest.fn().mockResolvedValue(mockProjectMilestonesResponse),
+ currentMilestoneSpy = jest.fn().mockResolvedValue(noCurrentMilestoneResponse),
+ } = {}) => {
+ Vue.use(VueApollo);
+
+ wrapper = mountExtended(SidebarDropdown, {
+ apolloProvider: createMockApollo([
+ [projectMilestonesQuery, projectMilestonesSpy],
+ [projectIssueMilestoneQuery, currentMilestoneSpy],
+ ...requestHandlers,
+ ]),
+ propsData: {
+ attrWorkspacePath: mockIssue.projectPath,
+ currentAttribute: {},
+ issuableType: IssuableType.Issue,
+ issuableAttribute: IssuableAttributeType.Milestone,
+ },
+ attachTo: document.body,
+ });
+ };
+
+ const createComponent = ({
+ props = {},
+ data = {},
+ mutationPromise = mutationSuccess,
+ queries = {},
+ } = {}) => {
+ wrapper = mountExtended(SidebarDropdown, {
+ propsData: {
+ attrWorkspacePath: mockIssue.projectPath,
+ currentAttribute: {},
+ issuableType: IssuableType.Issue,
+ issuableAttribute: IssuableAttributeType.Milestone,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ mocks: {
+ $apollo: {
+ mutate: mutationPromise(),
+ queries: {
+ currentAttribute: { loading: false },
+ attributesList: { loading: false },
+ ...queries,
+ },
+ },
+ },
+ });
+ };
+
+ describe('when a user can edit', () => {
+ describe('when user is editing', () => {
+ describe('when rendering the dropdown', () => {
+ it('shows a loading spinner while fetching a list of attributes', async () => {
+ createComponent({
+ queries: {
+ attributesList: { loading: true },
+ },
+ });
+
+ await toggleDropdown();
+
+ expect(findLoadingIconDropdown().exists()).toBe(true);
+ });
+
+ describe('GlDropdownItem with the right title and id', () => {
+ const id = 'id';
+ const title = 'title';
+
+ beforeEach(async () => {
+ createComponent({
+ props: { currentAttribute: { id, title } },
+ data: { attributesList: [{ id, title }] },
+ });
+
+ await toggleDropdown();
+ });
+
+ it('does not show a loading spinner', () => {
+ expect(findLoadingIconDropdown().exists()).toBe(false);
+ });
+
+ it('renders title $title', () => {
+ expect(findDropdownItemWithText(title).exists()).toBe(true);
+ });
+
+ it('checks the correct dropdown item', () => {
+ expect(
+ findAllDropdownItems()
+ .filter((w) => w.props('isChecked') === true)
+ .at(0)
+ .text(),
+ ).toBe(title);
+ });
+ });
+
+ describe('when no data is assigned', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await toggleDropdown();
+ });
+
+ it('finds GlDropdownItem with "No milestone"', () => {
+ expect(findNoAttributeItem().text()).toBe('No milestone');
+ });
+
+ it('"No milestone" is checked', () => {
+ expect(findAllDropdownItems('No milestone').at(0).props('isChecked')).toBe(true);
+ });
+
+ it('does not render any dropdown item', () => {
+ expect(findAttributeItems().exists()).toBe(false);
+ });
+ });
+
+ describe('when clicking on dropdown item', () => {
+ describe('when currentAttribute is equal to attribute id', () => {
+ it('does not call setIssueAttribute mutation', async () => {
+ createComponent({
+ props: { currentAttribute: { id: 'id', title: 'title' } },
+ data: { attributesList: [{ id: 'id', title: 'title' }] },
+ });
+
+ await toggleDropdown();
+
+ findDropdownItemWithText('title').vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
+ });
+ });
+ });
+ });
+
+ describe('when a user is searching', () => {
+ describe('when search result is not found', () => {
+ describe('when milestone', () => {
+ it('renders "No milestone found"', async () => {
+ createComponent();
+
+ await toggleDropdown();
+
+ findSearchBox().vm.$emit('input', 'non existing milestones');
+ await nextTick();
+
+ expect(findDropdownText().text()).toBe('No milestone found');
+ });
+ });
+ });
+ });
+ });
+ });
+
+ describe('with mock apollo', () => {
+ describe("when issuable type is 'issue'", () => {
+ describe('when dropdown is expanded and user can edit', () => {
+ it('renders the dropdown on clicking edit', async () => {
+ createComponentWithApollo();
+
+ await toggleDropdown();
+
+ expect(findDropdown().isVisible()).toBe(true);
+ });
+
+ it('focuses on the input when dropdown is shown', async () => {
+ createComponentWithApollo();
+
+ await toggleDropdown();
+
+ expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
+ });
+
+ describe('milestones', () => {
+ it('should call createAlert if milestones query fails', async () => {
+ createComponentWithApollo({
+ projectMilestonesSpy: jest.fn().mockRejectedValue(new Error()),
+ });
+
+ await toggleDropdown();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: wrapper.vm.i18n.listFetchError,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+
+ it('only fetches attributes when dropdown is opened', async () => {
+ const projectMilestonesSpy = jest
+ .fn()
+ .mockResolvedValueOnce(emptyProjectMilestonesResponse);
+ createComponentWithApollo({ projectMilestonesSpy });
+
+ expect(projectMilestonesSpy).not.toHaveBeenCalled();
+
+ await toggleDropdown();
+
+ expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
+ fullPath: mockIssue.projectPath,
+ state: 'active',
+ title: '',
+ });
+ });
+
+ describe('when a user is searching', () => {
+ it('sends a projectMilestones query with the entered search term "foo"', async () => {
+ const mockSearchTerm = 'foobar';
+ const projectMilestonesSpy = jest
+ .fn()
+ .mockResolvedValueOnce(emptyProjectMilestonesResponse);
+ createComponentWithApollo({ projectMilestonesSpy });
+
+ await toggleDropdown();
+
+ findSearchBox().vm.$emit('input', mockSearchTerm);
+ await nextTick();
+ jest.runOnlyPendingTimers(); // Account for debouncing
+
+ expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
+ fullPath: mockIssue.projectPath,
+ state: 'active',
+ title: mockSearchTerm,
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
index 8ab4d8ea051..cf5e220a705 100644
--- a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
@@ -1,12 +1,4 @@
-import {
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlLink,
- GlSearchBoxByType,
- GlFormInput,
- GlLoadingIcon,
-} from '@gitlab/ui';
+import { GlDropdown, GlLink, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { shallowMount, mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
@@ -19,6 +11,7 @@ import { createAlert } from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { IssuableType } from '~/issues/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { IssuableAttributeType } from '~/sidebar/constants';
@@ -32,7 +25,6 @@ import {
noCurrentMilestoneResponse,
mockMilestoneMutationResponse,
mockMilestone2,
- emptyProjectMilestonesResponse,
} from '../mock_data';
jest.mock('~/flash');
@@ -55,20 +47,11 @@ describe('SidebarDropdownWidget', () => {
const findGlLink = () => wrapper.findComponent(GlLink);
const findDateTooltip = () => getBinding(findGlLink().element, 'gl-tooltip');
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownText = () => wrapper.findComponent(GlDropdownText);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findDropdownItemWithText = (text) =>
- findAllDropdownItems().wrappers.find((x) => x.text() === text);
-
+ const findSidebarDropdown = () => wrapper.findComponent(SidebarDropdown);
const findSidebarEditableItem = () => wrapper.findComponent(SidebarEditableItem);
const findEditButton = () => findSidebarEditableItem().find('[data-testid="edit-button"]');
const findEditableLoadingIcon = () => findSidebarEditableItem().findComponent(GlLoadingIcon);
- const findAttributeItems = () => wrapper.findByTestId('milestone-items');
const findSelectedAttribute = () => wrapper.findByTestId('select-milestone');
- const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
- const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
const waitForDropdown = async () => {
// BDropdown first changes its `visible` property
@@ -167,6 +150,8 @@ describe('SidebarDropdownWidget', () => {
}),
);
+ wrapper.vm.$refs.dropdown.show = jest.fn();
+
// We need to mock out `showDropdown` which
// invokes `show` method of BDropdown used inside GlDropdown.
jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
@@ -261,86 +246,7 @@ describe('SidebarDropdownWidget', () => {
describe('when a user can edit', () => {
describe('when user is editing', () => {
describe('when rendering the dropdown', () => {
- it('shows a loading spinner while fetching a list of attributes', async () => {
- createComponent({
- queries: {
- attributesList: { loading: true },
- },
- });
-
- await toggleDropdown();
-
- expect(findLoadingIconDropdown().exists()).toBe(true);
- });
-
- describe('GlDropdownItem with the right title and id', () => {
- const id = 'id';
- const title = 'title';
-
- beforeEach(async () => {
- createComponent({
- data: { attributesList: [{ id, title }], currentAttribute: { id, title } },
- });
-
- await toggleDropdown();
- });
-
- it('does not show a loading spinner', () => {
- expect(findLoadingIconDropdown().exists()).toBe(false);
- });
-
- it('renders title $title', () => {
- expect(findDropdownItemWithText(title).exists()).toBe(true);
- });
-
- it('checks the correct dropdown item', () => {
- expect(
- findAllDropdownItems()
- .filter((w) => w.props('isChecked') === true)
- .at(0)
- .text(),
- ).toBe(title);
- });
- });
-
- describe('when no data is assigned', () => {
- beforeEach(async () => {
- createComponent();
-
- await toggleDropdown();
- });
-
- it('finds GlDropdownItem with "No milestone"', () => {
- expect(findNoAttributeItem().text()).toBe('No milestone');
- });
-
- it('"No milestone" is checked', () => {
- expect(findNoAttributeItem().props('isChecked')).toBe(true);
- });
-
- it('does not render any dropdown item', () => {
- expect(findAttributeItems().exists()).toBe(false);
- });
- });
-
describe('when clicking on dropdown item', () => {
- describe('when currentAttribute is equal to attribute id', () => {
- it('does not call setIssueAttribute mutation', async () => {
- createComponent({
- data: {
- attributesList: [{ id: 'id', title: 'title' }],
- currentAttribute: { id: 'id', title: 'title' },
- },
- });
-
- await toggleDropdown();
-
- findDropdownItemWithText('title').vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
- });
- });
-
describe('when currentAttribute is not equal to attribute id', () => {
describe('when error', () => {
const bootstrapComponent = (mutationResp) => {
@@ -350,7 +256,7 @@ describe('SidebarDropdownWidget', () => {
{ id: '123', title: '123' },
{ id: 'id', title: 'title' },
],
- currentAttribute: '123',
+ currentAttribute: { id: '123' },
},
mutationPromise: mutationResp,
});
@@ -366,7 +272,7 @@ describe('SidebarDropdownWidget', () => {
await toggleDropdown();
- findDropdownItemWithText('title').vm.$emit('click');
+ findSidebarDropdown().vm.$emit('change', { id: 'error' });
});
it(`calls createAlert with "${expectedMsg}"`, async () => {
@@ -382,24 +288,6 @@ describe('SidebarDropdownWidget', () => {
});
});
});
-
- describe('when a user is searching', () => {
- describe('when search result is not found', () => {
- describe('when milestone', () => {
- it('renders "No milestone found"', async () => {
- createComponent();
-
- await toggleDropdown();
-
- findSearchBox().vm.$emit('input', 'non existing milestones');
-
- await nextTick();
-
- expect(findDropdownText().text()).toBe('No milestone found');
- });
- });
- });
- });
});
});
@@ -424,18 +312,10 @@ describe('SidebarDropdownWidget', () => {
await clickEdit();
});
- it('renders the dropdown on clicking edit', async () => {
- expect(findDropdown().isVisible()).toBe(true);
- });
-
- it('focuses on the input when dropdown is shown', async () => {
- expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
- });
-
describe('when currentAttribute is not equal to attribute id', () => {
describe('when update is successful', () => {
it('calls setIssueAttribute mutation', () => {
- findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
+ findSidebarDropdown().vm.$emit('change', { id: mockMilestone2.id });
expect(milestoneMutationSpy).toHaveBeenCalledWith({
iid: mockIssue.iid,
@@ -443,72 +323,6 @@ describe('SidebarDropdownWidget', () => {
fullPath: mockIssue.projectPath,
});
});
-
- it('sets the value returned from the mutation to currentAttribute', async () => {
- findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
- await nextTick();
- expect(findSelectedAttribute().text()).toBe(mockMilestone2.title);
- });
- });
- });
-
- describe('milestones', () => {
- let projectMilestonesSpy;
-
- it('should call createAlert if milestones query fails', async () => {
- await createComponentWithApollo({
- projectMilestonesSpy: jest.fn().mockRejectedValue(error),
- });
-
- await clickEdit();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: wrapper.vm.i18n.listFetchError,
- captureError: true,
- error: expect.any(Error),
- });
- });
-
- it('only fetches attributes when dropdown is opened', async () => {
- projectMilestonesSpy = jest.fn().mockResolvedValueOnce(emptyProjectMilestonesResponse);
- await createComponentWithApollo({ projectMilestonesSpy });
-
- expect(projectMilestonesSpy).not.toHaveBeenCalled();
-
- await clickEdit();
-
- expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
- fullPath: mockIssue.projectPath,
- state: 'active',
- title: '',
- });
- });
-
- describe('when a user is searching', () => {
- const mockSearchTerm = 'foobar';
-
- beforeEach(async () => {
- projectMilestonesSpy = jest
- .fn()
- .mockResolvedValueOnce(emptyProjectMilestonesResponse);
- await createComponentWithApollo({ projectMilestonesSpy });
-
- await clickEdit();
- });
-
- it('sends a projectMilestones query with the entered search term "foo"', async () => {
- findSearchBox().vm.$emit('input', mockSearchTerm);
- await nextTick();
-
- // Account for debouncing
- jest.runAllTimers();
-
- expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
- fullPath: mockIssue.projectPath,
- state: 'active',
- title: mockSearchTerm,
- });
- });
});
});
});