diff --git a/.changeset/weak-readers-know.md b/.changeset/weak-readers-know.md new file mode 100644 index 0000000000..24cf29a5db --- /dev/null +++ b/.changeset/weak-readers-know.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-code-coverage': patch +--- + +Addresses bug when file path contains multiple directories with the same name. diff --git a/plugins/code-coverage/src/components/FileExplorer/FileExplorer.test.tsx b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.test.tsx new file mode 100644 index 0000000000..4163b22ac1 --- /dev/null +++ b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.test.tsx @@ -0,0 +1,222 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { groupByPath, buildFileStructure } from './FileExplorer'; + +const dummyFiles = [ + { + filename: 'dir1/file1', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir1/file2', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir2/file3', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir3/dir2/dir1/file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir3/dir2/dir3/file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, +]; + +const dummyDataGroupedByPath = { + dir1: [ + { + filename: 'dir1/file1', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir1/file2', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + ], + dir2: [ + { + filename: 'dir2/file3', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + ], + dir3: [ + { + filename: 'dir3/dir2/dir1/file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + { + filename: 'dir3/dir2/dir3/file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + path: '', + }, + ], +}; + +const coverageTableRow = { + files: dummyFiles, + coverage: 1, + missing: 1, + tracked: 1, + path: '', +}; + +const coverageTableRowResults = { + files: [ + { + path: 'dir1', + files: [ + { + path: 'file1', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + }, + { + path: 'file2', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + }, + ], + coverage: 1, + missing: 2, + tracked: 2, + }, + { + path: 'dir2', + files: [ + { + path: 'file3', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + }, + ], + coverage: 1, + missing: 1, + tracked: 1, + }, + { + path: 'dir3', + files: [ + { + path: 'dir2', + files: [ + { + path: 'dir1', + files: [ + { + path: 'file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + }, + ], + coverage: 1, + missing: 1, + tracked: 1, + }, + { + path: 'dir3', + files: [ + { + path: 'file4', + files: [], + coverage: 1, + missing: 1, + tracked: 1, + }, + ], + coverage: 1, + missing: 1, + tracked: 1, + }, + ], + coverage: 1, + missing: 2, + tracked: 2, + }, + ], + coverage: 1, + missing: 2, + tracked: 2, + }, + ], + coverage: 1, + missing: 1, + tracked: 1, + path: '', +}; + +describe('groupByPath function', () => { + it('should group files by their root directory,as per their filename', () => { + expect(groupByPath(dummyFiles)).toStrictEqual(dummyDataGroupedByPath); + }); +}); + +describe('buildFileStructure function', () => { + it('should group files by their root directory,as per their filename', () => { + expect(buildFileStructure(coverageTableRow)).toStrictEqual( + coverageTableRowResults, + ); + }); +}); diff --git a/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx index 21052c0793..49379551ad 100644 --- a/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx +++ b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx @@ -30,7 +30,6 @@ import { useAsync } from 'react-use'; import { codeCoverageApiRef } from '../../api'; import { FileEntry } from '../../types'; import { FileContent } from './FileContent'; - import { Progress, ResponseErrorPanel, @@ -51,33 +50,46 @@ type CoverageTableRow = { tableData?: { id: number }; }; -const buildFileStructure = (row: CoverageTableRow) => { - const dataGroupedByPath: FileStructureObject = row.files.reduce( - (acc: FileStructureObject, cur: CoverageTableRow) => { - let path = cur.filename; - if (row.path) { - path = path?.split(`${row.path}/`)[1]; - } - const pathArray = path?.split('/'); - - if (!pathArray) { - return acc; - } +export const groupByPath = (files: CoverageTableRow[]) => { + const acc: FileStructureObject = {}; + files.forEach(file => { + const filename = file.filename; + if (!file.filename) return; + const pathArray = filename?.split('/').filter(el => el !== ''); + if (pathArray) { if (!acc.hasOwnProperty(pathArray[0])) { acc[pathArray[0]] = []; } - acc[pathArray[0]].push(cur); - return acc; - }, - {}, - ); + acc[pathArray[0]].push(file); + } + }); + return acc; +}; +const removeVisitedPathGroup = ( + files: CoverageTableRow[], + pathGroup: string, +) => { + return files.map(file => { + return { + ...file, + filename: file.filename + ? file.filename.substring( + file.filename?.indexOf(pathGroup) + pathGroup.length + 1, + ) + : file.filename, + }; + }); +}; + +export const buildFileStructure = (row: CoverageTableRow) => { + const dataGroupedByPath: FileStructureObject = groupByPath(row.files); row.files = Object.keys(dataGroupedByPath).map(pathGroup => { return buildFileStructure({ path: pathGroup, files: dataGroupedByPath.hasOwnProperty('files') - ? dataGroupedByPath.files - : dataGroupedByPath[pathGroup], + ? removeVisitedPathGroup(dataGroupedByPath.files, pathGroup) + : removeVisitedPathGroup(dataGroupedByPath[pathGroup], pathGroup), coverage: dataGroupedByPath[pathGroup].reduce( (acc: number, cur: CoverageTableRow) => acc + cur.coverage,