Commit a230569e authored by Natalia Tepluhina's avatar Natalia Tepluhina Committed by Vitaly Slobodin

Fixed test cases count

Applied a fix to test cases count
Fixed a query shape

Fixed a loading state test

Made test passing

Removed unnnecessary $apollo properties

Added changelog entry
parent a0d465de
......@@ -13,7 +13,6 @@ import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/auth
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import projectTestCases from '../queries/project_test_cases.query.graphql';
import projectTestCasesCount from '../queries/project_test_cases_count.query.graphql';
import { TestCaseTabs, AvailableSortOptions, DEFAULT_PAGE_SIZE } from '../constants';
import TestCaseListEmptyState from './test_case_list_empty_state.vue';
......@@ -47,7 +46,7 @@ export default {
},
},
apollo: {
testCases: {
project: {
query: projectTestCases,
variables() {
const queryVariables = {
......@@ -78,14 +77,6 @@ export default {
return queryVariables;
},
update(data) {
const testCasesRoot = data.project?.issues;
return {
list: testCasesRoot?.nodes || [],
pageInfo: testCasesRoot?.pageInfo || {},
};
},
error(error) {
createFlash({
message: s__('TestCases|Something went wrong while fetching test cases list.'),
......@@ -94,31 +85,6 @@ export default {
});
},
},
testCasesCount: {
query: projectTestCasesCount,
variables() {
return {
projectPath: this.projectFullPath,
types: ['TEST_CASE'],
};
},
update(data) {
const { opened, closed, all } = data.project?.issueStatusCounts;
return {
opened,
closed,
all,
};
},
error(error) {
createFlash({
message: s__('TestCases|Something went wrong while fetching count of test cases.'),
captureError: true,
error,
});
},
},
},
data() {
return {
......@@ -128,23 +94,32 @@ export default {
nextPageCursor: this.next,
filterParams: this.initialFilterParams,
sortedBy: this.initialSortBy,
testCases: {
list: [],
pageInfo: {},
},
testCasesCount: {
opened: 0,
closed: 0,
all: 0,
project: {
issueStatusCounts: {},
issues: {},
},
};
},
computed: {
testCases() {
return {
list: this.project?.issues?.nodes || [],
pageInfo: this.project?.issues?.pageInfo || {},
};
},
testCasesCount() {
const { opened = 0, closed = 0, all = 0 } = this.project?.issueStatusCounts || {};
return {
opened,
closed,
all,
};
},
testCaseListLoading() {
return this.$apollo.queries.testCases.loading;
return this.$apollo.queries.project.loading;
},
testCaseListEmpty() {
return !this.$apollo.queries.testCases.loading && !this.testCases.list.length;
return !this.$apollo.queries.project.loading && !this.testCases.list.length;
},
showPaginationControls() {
const { hasPreviousPage, hasNextPage } = this.testCases.pageInfo;
......
......@@ -17,6 +17,16 @@ query projectIssues(
) {
project(fullPath: $projectPath) {
name
issueStatusCounts(
types: $types
authorUsername: $authorUsername
labelName: $labelName
search: $search
) {
opened
closed
all
}
issues(
types: $types
state: $state
......
query projectIssueCounts($projectPath: ID!, $types: [IssueType!]) {
project(fullPath: $projectPath) {
issueStatusCounts(types: $types) {
opened
closed
all
}
}
}
---
title: Resolve Filter count does not get reflected in Test Cases
merge_request: 52889
author:
type: fixed
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import TestCaseListRoot from 'ee/test_case_list/components/test_case_list_root.vue';
import { TestCaseTabs, AvailableSortOptions } from 'ee/test_case_list/constants';
import { TEST_HOST } from 'helpers/test_constants';
import { mockIssuable } from 'jest/issuable_list/mock_data';
......@@ -31,94 +31,62 @@ const mockPageInfo = {
endCursor: 'eyJpZCI6IjIxIiwiY3JlYXRlZF9hdCI6IjIwMjAtMDMtMzEgMTM6MzE6MTUgVVRDIn0',
};
const createComponent = ({
describe('TestCaseListRoot', () => {
let wrapper;
const getIssuableList = () => wrapper.find(IssuableList);
const createComponent = ({
provide = mockProvide,
initialFilterParams = {},
testCasesLoading = false,
testCasesList = [],
} = {}) =>
shallowMount(TestCaseListRoot, {
data = {},
} = {}) => {
wrapper = shallowMount(TestCaseListRoot, {
propsData: {
initialFilterParams,
},
data() {
return data;
},
provide,
mocks: {
$apollo: {
queries: {
testCases: {
loading: testCasesLoading,
list: testCasesList,
pageInfo: mockPageInfo,
},
testCasesCount: {
project: {
loading: testCasesLoading,
opened: 5,
closed: 0,
all: 5,
},
},
},
},
});
describe('TestCaseListRoot', () => {
let wrapper;
beforeEach(() => {
wrapper = createComponent();
});
};
afterEach(() => {
wrapper.destroy();
});
describe('computed', () => {
describe('testCaseListLoading', () => {
describe('passes a correct loading state to Issuables List', () => {
it.each`
testCasesLoading | returnValue
${true} | ${true}
${false} | ${false}
`(
'returns $returnValue when testCases query loading is $loadingValue',
'passes $returnValue to Issuables List prop when query loading is $testCasesLoading',
({ testCasesLoading, returnValue }) => {
const wrapperTemp = createComponent({
createComponent({
provide: mockProvide,
initialFilterParams: {},
testCasesList: [],
testCasesLoading,
});
expect(wrapperTemp.vm.testCaseListLoading).toBe(returnValue);
wrapperTemp.destroy();
},
);
});
describe('testCaseListEmpty', () => {
it.each`
testCasesLoading | testCasesList | testCaseListDescription | returnValue
${true} | ${[]} | ${'empty'} | ${false}
${true} | ${[mockIssuable]} | ${'not empty'} | ${false}
${false} | ${[]} | ${'not empty'} | ${true}
${false} | ${[mockIssuable]} | ${'empty'} | ${true}
`(
'returns $returnValue when testCases query loading is $testCasesLoading and testCases array is $testCaseListDescription',
({ testCasesLoading, testCasesList, returnValue }) => {
const wrapperTemp = createComponent({
provide: mockProvide,
initialFilterParams: {},
testCasesLoading,
testCasesList,
});
expect(wrapperTemp.vm.testCaseListEmpty).toBe(returnValue);
wrapperTemp.destroy();
expect(getIssuableList().props('issuablesLoading')).toBe(returnValue);
},
);
});
describe('computed', () => {
describe('showPaginationControls', () => {
it.each`
hasPreviousPage | hasNextPage | returnValue
......@@ -131,18 +99,20 @@ describe('TestCaseListRoot', () => {
`(
'returns $returnValue when hasPreviousPage is $hasPreviousPage and hasNextPage is $hasNextPage within `testCases.pageInfo`',
async ({ hasPreviousPage, hasNextPage, returnValue }) => {
wrapper.setData({
testCases: {
createComponent({
data: {
project: {
issues: {
pageInfo: {
hasPreviousPage,
hasNextPage,
},
},
},
},
});
await wrapper.vm.$nextTick();
expect(wrapper.vm.showPaginationControls).toBe(returnValue);
expect(getIssuableList().props('showPaginationControls')).toBe(returnValue);
},
);
......@@ -153,39 +123,45 @@ describe('TestCaseListRoot', () => {
`(
'returns $returnValue when testCases array is $testCaseListDescription',
async ({ testCasesList, returnValue }) => {
wrapper.setData({
testCases: {
list: testCasesList,
createComponent({
data: {
project: {
issues: {
nodes: testCasesList,
},
},
},
});
await wrapper.vm.$nextTick();
expect(wrapper.vm.showPaginationControls).toBe(returnValue);
expect(getIssuableList().props('showPaginationControls')).toBe(returnValue);
},
);
});
describe('previousPage', () => {
it('returns number representing previous page based on currentPage value', () => {
wrapper.setData({
createComponent({
data: {
currentPage: 3,
},
});
return wrapper.vm.$nextTick(() => {
expect(wrapper.vm.previousPage).toBe(2);
});
expect(getIssuableList().props('previousPage')).toBe(2);
});
});
describe('nextPage', () => {
beforeEach(() => {
wrapper.setData({
testCasesCount: {
createComponent({
data: {
project: {
issueStatusCounts: {
opened: 5,
closed: 0,
all: 5,
},
},
},
});
});
......@@ -194,9 +170,9 @@ describe('TestCaseListRoot', () => {
currentPage: 1,
});
await wrapper.vm.$nextTick();
await nextTick;
expect(wrapper.vm.nextPage).toBe(2);
expect(getIssuableList().props('nextPage')).toBe(2);
});
it('returns `null` when currentPage is already last page', async () => {
......@@ -204,9 +180,9 @@ describe('TestCaseListRoot', () => {
currentPage: 3,
});
await wrapper.vm.$nextTick();
await nextTick;
expect(wrapper.vm.nextPage).toBeNull();
expect(getIssuableList().props('nextPage')).toBeNull();
});
});
});
......@@ -214,7 +190,8 @@ describe('TestCaseListRoot', () => {
describe('methods', () => {
describe('updateUrl', () => {
it('updates window URL based on presence of props for filtered search and sort criteria', async () => {
wrapper.setData({
createComponent({
data: {
currentState: 'opened',
currentPage: 2,
nextPageCursor: 'abc123',
......@@ -224,10 +201,9 @@ describe('TestCaseListRoot', () => {
search: 'foo',
labelName: ['bug'],
},
},
});
await wrapper.vm.$nextTick();
wrapper.vm.updateUrl();
expect(global.window.location.href).toBe(
......@@ -238,49 +214,22 @@ describe('TestCaseListRoot', () => {
});
describe('template', () => {
const getIssuableList = () => wrapper.find(IssuableList);
it('renders issuable-list component', () => {
expect(getIssuableList().exists()).toBe(true);
expect(getIssuableList().props()).toMatchObject({
namespace: mockProvide.projectFullPath,
tabs: TestCaseTabs,
tabCounts: {
opened: 0,
closed: 0,
all: 0,
},
currentTab: 'opened',
searchInputPlaceholder: 'Search test cases',
searchTokens: expect.any(Array),
sortOptions: AvailableSortOptions,
initialSortBy: 'created_desc',
issuables: [],
issuablesLoading: false,
showPaginationControls: wrapper.vm.showPaginationControls,
defaultPageSize: 2, // mocked value in tests
currentPage: 1,
previousPage: 0,
nextPage: null,
recentSearchesStorageKey: 'test_cases',
issuableSymbol: '#',
});
});
describe('issuable-list events', () => {
beforeEach(() => {
createComponent();
jest.spyOn(wrapper.vm, 'updateUrl').mockImplementation(jest.fn);
});
it('click-tab event changes currentState value and calls updateUrl', () => {
it('click-tab event changes currentState value and calls updateUrl', async () => {
getIssuableList().vm.$emit('click-tab', 'closed');
expect(wrapper.vm.currentState).toBe('closed');
await nextTick;
expect(getIssuableList().props('currentTab')).toBe('closed');
expect(wrapper.vm.updateUrl).toHaveBeenCalled();
});
it('page-change event changes prevPageCursor and nextPageCursor values based on based on currentPage and calls updateUrl', () => {
wrapper.setData({
it('page-change event changes prevPageCursor and nextPageCursor values based on based on currentPage and calls updateUrl', async () => {
await wrapper.setData({
testCases: {
pageInfo: mockPageInfo,
},
......@@ -293,7 +242,7 @@ describe('TestCaseListRoot', () => {
expect(wrapper.vm.updateUrl).toHaveBeenCalled();
});
it('filter event changes filterParams value and calls updateUrl', () => {
it('filter event changes filterParams value and calls updateUrl', async () => {
getIssuableList().vm.$emit('filter', [
{
type: 'author_username',
......@@ -315,18 +264,22 @@ describe('TestCaseListRoot', () => {
},
]);
expect(wrapper.vm.filterParams).toEqual({
authorUsername: 'root',
labelName: ['bug'],
search: 'foo',
});
await nextTick;
expect(getIssuableList().props('initialFilterValue')).toEqual([
{ type: 'author_username', value: { data: 'root' } },
{ type: 'label_name', value: { data: 'bug' } },
'foo',
]);
expect(wrapper.vm.updateUrl).toHaveBeenCalled();
});
it('sort event changes sortedBy value and calls updateUrl', () => {
it('sort event changes sortedBy value and calls updateUrl', async () => {
getIssuableList().vm.$emit('sort', 'updated_desc');
expect(wrapper.vm.sortedBy).toEqual('updated_desc');
await nextTick;
expect(getIssuableList().props('initialSortBy')).toBe('updated_desc');
expect(wrapper.vm.updateUrl).toHaveBeenCalled();
});
});
......
......@@ -28475,9 +28475,6 @@ msgstr ""
msgid "TestCases|Something went wrong while creating a test case."
msgstr ""
msgid "TestCases|Something went wrong while fetching count of test cases."
msgstr ""
msgid "TestCases|Something went wrong while fetching test case."
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment