Commit 0b11dd4f authored by Phil Hughes's avatar Phil Hughes

Merge branch 'feature/file-review-code' into 'master'

Mark files as viewed

See merge request gitlab-org/gitlab!51513
parents 069d0b03 dc2558cc
...@@ -26,6 +26,7 @@ import CollapsedFilesWarning from './collapsed_files_warning.vue'; ...@@ -26,6 +26,7 @@ import CollapsedFilesWarning from './collapsed_files_warning.vue';
import { diffsApp } from '../utils/performance'; import { diffsApp } from '../utils/performance';
import { fileByFile } from '../utils/preferences'; import { fileByFile } from '../utils/preferences';
import { reviewStatuses } from '../utils/file_reviews';
import { import {
TREE_LIST_WIDTH_STORAGE_KEY, TREE_LIST_WIDTH_STORAGE_KEY,
...@@ -169,12 +170,7 @@ export default { ...@@ -169,12 +170,7 @@ export default {
'hasConflicts', 'hasConflicts',
'viewDiffsFileByFile', 'viewDiffsFileByFile',
]), ]),
...mapGetters('diffs', [ ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']),
'whichCollapsedTypes',
'isParallelView',
'currentDiffIndex',
'fileReviews',
]),
...mapGetters(['isNotesFetched', 'getNoteableData']), ...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() { diffs() {
if (!this.viewDiffsFileByFile) { if (!this.viewDiffsFileByFile) {
...@@ -232,6 +228,9 @@ export default { ...@@ -232,6 +228,9 @@ export default {
return visible; return visible;
}, },
fileReviews() {
return reviewStatuses(this.diffFiles, this.mrReviews);
},
}, },
watch: { watch: {
commit(newCommit, oldCommit) { commit(newCommit, oldCommit) {
......
...@@ -10,7 +10,9 @@ import notesEventHub from '../../notes/event_hub'; ...@@ -10,7 +10,9 @@ import notesEventHub from '../../notes/event_hub';
import DiffFileHeader from './diff_file_header.vue'; import DiffFileHeader from './diff_file_header.vue';
import DiffContent from './diff_content.vue'; import DiffContent from './diff_content.vue';
import { diffViewerErrors } from '~/ide/constants'; import { diffViewerErrors } from '~/ide/constants';
import { collapsedType, isCollapsed } from '../utils/diff_file'; import { collapsedType, isCollapsed } from '../utils/diff_file';
import { import {
DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_AUTOMATIC_COLLAPSE,
DIFF_FILE_MANUAL_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE,
...@@ -144,6 +146,12 @@ export default { ...@@ -144,6 +146,12 @@ export default {
showContent() { showContent() {
return !this.isCollapsed && !this.isFileTooLarge; return !this.isCollapsed && !this.isFileTooLarge;
}, },
showLocalFileReviews() {
const loggedIn = Boolean(gon.current_user_id);
const featureOn = this.glFeatures.localFileReviews;
return loggedIn && featureOn;
},
}, },
watch: { watch: {
'file.file_hash': { 'file.file_hash': {
...@@ -181,6 +189,10 @@ export default { ...@@ -181,6 +189,10 @@ export default {
if (this.hasDiff) { if (this.hasDiff) {
this.postRender(); this.postRender();
} }
if (this.reviewed && !this.isCollapsed && this.showLocalFileReviews) {
this.handleToggle();
}
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off(EVT_EXPAND_ALL_FILES, this.expandAllListener); eventHub.$off(EVT_EXPAND_ALL_FILES, this.expandAllListener);
...@@ -273,9 +285,11 @@ export default { ...@@ -273,9 +285,11 @@ export default {
:can-current-user-fork="canCurrentUserFork" :can-current-user-fork="canCurrentUserFork"
:diff-file="file" :diff-file="file"
:collapsible="true" :collapsible="true"
:reviewed="reviewed"
:expanded="!isCollapsed" :expanded="!isCollapsed"
:add-merge-request-buttons="true" :add-merge-request-buttons="true"
:view-diffs-file-by-file="viewDiffsFileByFile" :view-diffs-file-by-file="viewDiffsFileByFile"
:show-local-file-reviews="showLocalFileReviews"
class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100" class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100"
:class="hasBodyClasses.header" :class="hasBodyClasses.header"
@toggleFile="handleToggle" @toggleFile="handleToggle"
......
<script> <script>
import { escape } from 'lodash'; import { escape } from 'lodash';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { import {
GlTooltipDirective, GlTooltipDirective,
GlSafeHtmlDirective, GlSafeHtmlDirective,
...@@ -10,16 +10,23 @@ import { ...@@ -10,16 +10,23 @@ import {
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
GlDropdownDivider, GlDropdownDivider,
GlFormCheckbox,
GlLoadingIcon, GlLoadingIcon,
} from '@gitlab/ui'; } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue';
import { truncateSha } from '~/lib/utils/text_utility'; import { truncateSha } from '~/lib/utils/text_utility';
import { __, s__, sprintf } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import { diffViewerModes } from '~/ide/constants';
import DiffStats from './diff_stats.vue'; import DiffStats from './diff_stats.vue';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement } from '~/lib/utils/common_utils';
import { isCollapsed } from '../utils/diff_file';
import { collapsedType, isCollapsed } from '../utils/diff_file';
import { reviewable } from '../utils/file_reviews';
import { diffViewerModes } from '~/ide/constants';
import { DIFF_FILE_AUTOMATIC_COLLAPSE } from '../constants';
import { DIFF_FILE_HEADER } from '../i18n'; import { DIFF_FILE_HEADER } from '../i18n';
export default { export default {
...@@ -33,12 +40,14 @@ export default { ...@@ -33,12 +40,14 @@ export default {
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
GlDropdownDivider, GlDropdownDivider,
GlFormCheckbox,
GlLoadingIcon, GlLoadingIcon,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
SafeHtml: GlSafeHtmlDirective, SafeHtml: GlSafeHtmlDirective,
}, },
mixins: [glFeatureFlagsMixin()],
i18n: { i18n: {
...DIFF_FILE_HEADER, ...DIFF_FILE_HEADER,
}, },
...@@ -76,6 +85,16 @@ export default { ...@@ -76,6 +85,16 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
showLocalFileReviews: {
type: Boolean,
required: false,
default: false,
},
reviewed: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
...@@ -83,6 +102,7 @@ export default { ...@@ -83,6 +102,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState('diffs', ['latestDiff']),
...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']), ...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']),
diffContentIDSelector() { diffContentIDSelector() {
return `#diff-content-${this.diffFile.file_hash}`; return `#diff-content-${this.diffFile.file_hash}`;
...@@ -170,6 +190,9 @@ export default { ...@@ -170,6 +190,9 @@ export default {
(this.diffFile.edit_path || this.diffFile.ide_edit_path) (this.diffFile.edit_path || this.diffFile.ide_edit_path)
); );
}, },
isReviewable() {
return reviewable(this.diffFile);
},
}, },
methods: { methods: {
...mapActions('diffs', [ ...mapActions('diffs', [
...@@ -177,6 +200,8 @@ export default { ...@@ -177,6 +200,8 @@ export default {
'toggleFileDiscussionWrappers', 'toggleFileDiscussionWrappers',
'toggleFullDiff', 'toggleFullDiff',
'toggleActiveFileByHash', 'toggleActiveFileByHash',
'reviewFile',
'setFileCollapsedByUser',
]), ]),
handleToggleFile() { handleToggleFile() {
this.$emit('toggleFile'); this.$emit('toggleFile');
...@@ -204,6 +229,26 @@ export default { ...@@ -204,6 +229,26 @@ export default {
setMoreActionsShown(val) { setMoreActionsShown(val) {
this.moreActionsShown = val; this.moreActionsShown = val;
}, },
toggleReview(newReviewedStatus) {
const autoCollapsed =
this.isCollapsed && collapsedType(this.diffFile) === DIFF_FILE_AUTOMATIC_COLLAPSE;
const open = this.expanded;
const closed = !open;
const reviewed = newReviewedStatus;
this.reviewFile({ file: this.diffFile, reviewed });
if (reviewed && autoCollapsed) {
this.setFileCollapsedByUser({
filePath: this.diffFile.file_path,
collapsed: true,
});
}
if ((open && reviewed) || (closed && !reviewed)) {
this.$emit('toggleFile');
}
},
}, },
}; };
</script> </script>
...@@ -291,6 +336,19 @@ export default { ...@@ -291,6 +336,19 @@ export default {
class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start" class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start"
> >
<diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" /> <diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
<gl-form-checkbox
v-if="isReviewable && showLocalFileReviews"
v-gl-tooltip.hover
data-testid="fileReviewCheckbox"
class="gl-mb-0"
:title="$options.i18n.fileReviewTooltip"
:checked="reviewed"
@change="toggleReview"
>
<span class="gl-line-height-20">
{{ $options.i18n.fileReviewLabel }}
</span>
</gl-form-checkbox>
<gl-button-group class="gl-pt-0!"> <gl-button-group class="gl-pt-0!">
<gl-button <gl-button
v-if="diffFile.external_url" v-if="diffFile.external_url"
......
...@@ -4,6 +4,8 @@ export const GENERIC_ERROR = __('Something went wrong on our end. Please try aga ...@@ -4,6 +4,8 @@ export const GENERIC_ERROR = __('Something went wrong on our end. Please try aga
export const DIFF_FILE_HEADER = { export const DIFF_FILE_HEADER = {
optionsDropdownTitle: __('Options'), optionsDropdownTitle: __('Options'),
fileReviewLabel: __('Viewed'),
fileReviewTooltip: __('Collapses this file (only for you) until it’s changed again.'),
}; };
export const DIFF_FILE = { export const DIFF_FILE = {
......
...@@ -749,12 +749,10 @@ export const setFileByFile = ({ commit }, { fileByFile }) => { ...@@ -749,12 +749,10 @@ export const setFileByFile = ({ commit }, { fileByFile }) => {
); );
}; };
export function reviewFile({ commit, state, getters }, { file, reviewed = true }) { export function reviewFile({ commit, state }, { file, reviewed = true }) {
const { mrPath } = getDerivedMergeRequestInformation({ endpoint: file.load_collapsed_diff_url }); const { mrPath } = getDerivedMergeRequestInformation({ endpoint: file.load_collapsed_diff_url });
const reviews = setReviewsForMergeRequest( const reviews = markFileReview(state.mrReviews, file, reviewed);
mrPath,
markFileReview(getters.fileReviews(state), file, reviewed),
);
setReviewsForMergeRequest(mrPath, reviews);
commit(types.SET_MR_FILE_REVIEWS, reviews); commit(types.SET_MR_FILE_REVIEWS, reviews);
} }
import { __, n__ } from '~/locale'; import { __, n__ } from '~/locale';
import { parallelizeDiffLines } from './utils'; import { parallelizeDiffLines } from './utils';
import { isFileReviewed } from '../utils/file_reviews';
import { import {
PARALLEL_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE,
INLINE_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE,
...@@ -155,7 +154,3 @@ export const diffLines = (state) => (file, unifiedDiffComponents) => { ...@@ -155,7 +154,3 @@ export const diffLines = (state) => (file, unifiedDiffComponents) => {
state.diffViewType === INLINE_DIFF_VIEW_TYPE, state.diffViewType === INLINE_DIFF_VIEW_TYPE,
); );
}; };
export function fileReviews(state) {
return state.diffFiles.map((file) => isFileReviewed(state.mrReviews, file));
}
...@@ -47,4 +47,5 @@ export default () => ({ ...@@ -47,4 +47,5 @@ export default () => ({
showSuggestPopover: true, showSuggestPopover: true,
defaultSuggestionCommitMessage: '', defaultSuggestionCommitMessage: '',
mrReviews: {}, mrReviews: {},
latestDiff: true,
}); });
...@@ -2,6 +2,16 @@ function getFileReviewsKey(mrPath) { ...@@ -2,6 +2,16 @@ function getFileReviewsKey(mrPath) {
return `${mrPath}-file-reviews`; return `${mrPath}-file-reviews`;
} }
export function isFileReviewed(reviews, file) {
const fileReviews = reviews[file.file_identifier_hash];
return file?.id && fileReviews?.length ? new Set(fileReviews).has(file.id) : false;
}
export function reviewStatuses(files, reviews) {
return files.map((file) => isFileReviewed(reviews, file));
}
export function getReviewsForMergeRequest(mrPath) { export function getReviewsForMergeRequest(mrPath) {
const reviewsForMr = localStorage.getItem(getFileReviewsKey(mrPath)); const reviewsForMr = localStorage.getItem(getFileReviewsKey(mrPath));
let reviews = {}; let reviews = {};
...@@ -23,23 +33,17 @@ export function setReviewsForMergeRequest(mrPath, reviews) { ...@@ -23,23 +33,17 @@ export function setReviewsForMergeRequest(mrPath, reviews) {
return reviews; return reviews;
} }
export function isFileReviewed(reviews, file) {
const fileReviews = reviews[file.file_identifier_hash];
return file?.id && fileReviews?.length ? new Set(fileReviews).has(file.id) : false;
}
export function reviewable(file) { export function reviewable(file) {
return Boolean(file.id) && Boolean(file.file_identifier_hash); return Boolean(file.id) && Boolean(file.file_identifier_hash);
} }
export function markFileReview(reviews, file, reviewed = true) { export function markFileReview(reviews, file, reviewed = true) {
const usableReviews = { ...(reviews || {}) }; const usableReviews = { ...(reviews || {}) };
let updatedReviews = usableReviews; const updatedReviews = usableReviews;
let fileReviews; let fileReviews;
if (reviewable(file)) { if (reviewable(file)) {
fileReviews = new Set([...(usableReviews[file.file_identifier_hash] || [])]); fileReviews = new Set(usableReviews[file.file_identifier_hash] || []);
if (reviewed) { if (reviewed) {
fileReviews.add(file.id); fileReviews.add(file.id);
...@@ -47,10 +51,7 @@ export function markFileReview(reviews, file, reviewed = true) { ...@@ -47,10 +51,7 @@ export function markFileReview(reviews, file, reviewed = true) {
fileReviews.delete(file.id); fileReviews.delete(file.id);
} }
updatedReviews = { updatedReviews[file.file_identifier_hash] = Array.from(fileReviews);
...usableReviews,
[file.file_identifier_hash]: Array.from(fileReviews),
};
if (updatedReviews[file.file_identifier_hash].length === 0) { if (updatedReviews[file.file_identifier_hash].length === 0) {
delete updatedReviews[file.file_identifier_hash]; delete updatedReviews[file.file_identifier_hash];
......
...@@ -42,6 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -42,6 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:diffs_gradual_load, @project, default_enabled: true) push_frontend_feature_flag(:diffs_gradual_load, @project, default_enabled: true)
push_frontend_feature_flag(:codequality_mr_diff, @project) push_frontend_feature_flag(:codequality_mr_diff, @project)
push_frontend_feature_flag(:suggestions_custom_commit, @project) push_frontend_feature_flag(:suggestions_custom_commit, @project)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
record_experiment_user(:invite_members_version_a) record_experiment_user(:invite_members_version_a)
record_experiment_user(:invite_members_version_b) record_experiment_user(:invite_members_version_b)
......
---
title: Mark files as reviewed locally
merge_request: 51513
author:
type: added
---
name: local_file_reviews
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48976
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296674
milestone: '13.8'
type: development
group: group::code review
default_enabled: false
...@@ -7081,6 +7081,9 @@ msgstr "" ...@@ -7081,6 +7081,9 @@ msgstr ""
msgid "Collapse sidebar" msgid "Collapse sidebar"
msgstr "" msgstr ""
msgid "Collapses this file (only for you) until it’s changed again."
msgstr ""
msgid "Collector hostname" msgid "Collector hostname"
msgstr "" msgstr ""
...@@ -31401,6 +31404,9 @@ msgstr "" ...@@ -31401,6 +31404,9 @@ msgstr ""
msgid "View users statistics" msgid "View users statistics"
msgstr "" msgstr ""
msgid "Viewed"
msgstr ""
msgid "Viewing commit" msgid "Viewing commit"
msgstr "" msgstr ""
......
...@@ -66,7 +66,7 @@ function markFileToBeRendered(store, index = 0) { ...@@ -66,7 +66,7 @@ function markFileToBeRendered(store, index = 0) {
}); });
} }
function createComponent({ file, first = false, last = false }) { function createComponent({ file, first = false, last = false, options = {}, props = {} }) {
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
...@@ -89,7 +89,9 @@ function createComponent({ file, first = false, last = false }) { ...@@ -89,7 +89,9 @@ function createComponent({ file, first = false, last = false }) {
viewDiffsFileByFile: false, viewDiffsFileByFile: false,
isFirstFile: first, isFirstFile: first,
isLastFile: last, isLastFile: last,
...props,
}, },
...options,
}); });
return { return {
...@@ -220,6 +222,53 @@ describe('DiffFile', () => { ...@@ -220,6 +222,53 @@ describe('DiffFile', () => {
}); });
}); });
describe('computed', () => {
describe('showLocalFileReviews', () => {
let gon;
function setLoggedIn(bool) {
window.gon.current_user_id = bool;
}
beforeAll(() => {
gon = window.gon;
window.gon = {};
});
afterEach(() => {
window.gon = gon;
});
it.each`
loggedIn | featureOn | bool
${true} | ${true} | ${true}
${false} | ${true} | ${false}
${true} | ${false} | ${false}
${false} | ${false} | ${false}
`(
'should be $bool when { userIsLoggedIn: $loggedIn, featureEnabled: $featureOn }',
({ loggedIn, featureOn, bool }) => {
setLoggedIn(loggedIn);
({ wrapper } = createComponent({
options: {
provide: {
glFeatures: {
localFileReviews: featureOn,
},
},
},
props: {
file: store.state.diffs.diffFiles[0],
},
}));
expect(wrapper.vm.showLocalFileReviews).toBe(bool);
},
);
});
});
describe('collapsing', () => { describe('collapsing', () => {
describe(`\`${EVT_EXPAND_ALL_FILES}\` event`, () => { describe(`\`${EVT_EXPAND_ALL_FILES}\` event`, () => {
beforeEach(() => { beforeEach(() => {
......
...@@ -375,26 +375,4 @@ describe('Diffs Module Getters', () => { ...@@ -375,26 +375,4 @@ describe('Diffs Module Getters', () => {
}); });
}); });
}); });
describe('fileReviews', () => {
const file1 = { id: '123', file_identifier_hash: 'abc' };
const file2 = { id: '098', file_identifier_hash: 'abc' };
it.each`
reviews | files | fileReviews
${{}} | ${[file1, file2]} | ${[false, false]}
${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]}
${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]}
${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]}
${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]}
`(
'returns $fileReviews based on the diff files in state and the existing reviews $reviews',
({ reviews, files, fileReviews }) => {
localState.diffFiles = files;
localState.mrReviews = reviews;
expect(getters.fileReviews(localState)).toStrictEqual(fileReviews);
},
);
});
}); });
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
setReviewsForMergeRequest, setReviewsForMergeRequest,
isFileReviewed, isFileReviewed,
markFileReview, markFileReview,
reviewStatuses,
reviewable, reviewable,
} from '~/diffs/utils/file_reviews'; } from '~/diffs/utils/file_reviews';
...@@ -28,6 +29,39 @@ describe('File Review(s) utilities', () => { ...@@ -28,6 +29,39 @@ describe('File Review(s) utilities', () => {
localStorage.clear(); localStorage.clear();
}); });
describe('isFileReviewed', () => {
it.each`
description | diffFile | fileReviews
${'the file does not have an `id`'} | ${{ ...file, id: undefined }} | ${getDefaultReviews()}
${'there are no reviews for the file'} | ${file} | ${{ ...getDefaultReviews(), abc: undefined }}
`('returns `false` if $description', ({ diffFile, fileReviews }) => {
expect(isFileReviewed(fileReviews, diffFile)).toBe(false);
});
it("returns `true` for a file if it's available in the provided reviews", () => {
expect(isFileReviewed(reviews, file)).toBe(true);
});
});
describe('reviewStatuses', () => {
const file1 = { id: '123', file_identifier_hash: 'abc' };
const file2 = { id: '098', file_identifier_hash: 'abc' };
it.each`
mrReviews | files | fileReviews
${{}} | ${[file1, file2]} | ${[false, false]}
${{ abc: ['123'] }} | ${[file1, file2]} | ${[true, false]}
${{ abc: ['098'] }} | ${[file1, file2]} | ${[false, true]}
${{ def: ['123'] }} | ${[file1, file2]} | ${[false, false]}
${{ abc: ['123'], def: ['098'] }} | ${[]} | ${[]}
`(
'returns $fileReviews based on the diff files in state and the existing reviews $reviews',
({ mrReviews, files, fileReviews }) => {
expect(reviewStatuses(files, mrReviews)).toStrictEqual(fileReviews);
},
);
});
describe('getReviewsForMergeRequest', () => { describe('getReviewsForMergeRequest', () => {
it('fetches the appropriate stored reviews from localStorage', () => { it('fetches the appropriate stored reviews from localStorage', () => {
getReviewsForMergeRequest(mrPath); getReviewsForMergeRequest(mrPath);
...@@ -73,20 +107,6 @@ describe('File Review(s) utilities', () => { ...@@ -73,20 +107,6 @@ describe('File Review(s) utilities', () => {
}); });
}); });
describe('isFileReviewed', () => {
it.each`
description | diffFile | fileReviews
${'the file does not have an `id`'} | ${{ ...file, id: undefined }} | ${getDefaultReviews()}
${'there are no reviews for the file'} | ${file} | ${{ ...getDefaultReviews(), abc: undefined }}
`('returns `false` if $description', ({ diffFile, fileReviews }) => {
expect(isFileReviewed(fileReviews, diffFile)).toBe(false);
});
it("returns `true` for a file if it's available in the provided reviews", () => {
expect(isFileReviewed(reviews, file)).toBe(true);
});
});
describe('reviewable', () => { describe('reviewable', () => {
it.each` it.each`
response | diffFile | description response | diffFile | description
......
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