+
- No changes between
{{ sourceBranch }} and
-
{{ targetBranch }}
+
-
{{ __('Create commit') }}
+
{{
+ __('Create commit')
+ }}
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index 06ef4207d85..915cacb374f 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -17,6 +17,7 @@ export default function initDiffsApp(store) {
endpoint: dataset.endpoint,
projectPath: dataset.projectPath,
currentUser: JSON.parse(dataset.currentUserData) || {},
+ changesEmptyStateIllustration: dataset.changesEmptyStateIllustration,
};
},
computed: {
@@ -31,6 +32,7 @@ export default function initDiffsApp(store) {
currentUser: this.currentUser,
projectPath: this.projectPath,
shouldShow: this.activeTab === 'diffs',
+ changesEmptyStateIllustration: this.changesEmptyStateIllustration,
},
});
},
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index 4ebb029e48b..c178206dda4 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -77,7 +77,8 @@
#js-diffs-app.diffs.tab-pane{ data: { "is-locked" => @merge_request.discussion_locked?,
endpoint: diffs_project_merge_request_path(@project, @merge_request, 'json', request.query_parameters),
current_user_data: UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json,
- project_path: project_path(@merge_request.project)} }
+ project_path: project_path(@merge_request.project),
+ changes_empty_state_illustration: image_path('illustrations/merge_request_changes_empty.svg') } }
.mr-loading-status
= spinner
diff --git a/changelogs/unreleased/diff-empty-state-fixes.yml b/changelogs/unreleased/diff-empty-state-fixes.yml
new file mode 100644
index 00000000000..0d347dd17e4
--- /dev/null
+++ b/changelogs/unreleased/diff-empty-state-fixes.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed merge request diffs empty states
+merge_request:
+author:
+type: fixed
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 792b6c8cecc..a042caf0af1 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4368,6 +4368,9 @@ msgstr ""
msgid "No changes"
msgstr ""
+msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgstr ""
+
msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr ""
diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js
index 1e2f7ff4fd8..a2cbc0f3c72 100644
--- a/spec/javascripts/diffs/components/app_spec.js
+++ b/spec/javascripts/diffs/components/app_spec.js
@@ -1,33 +1,44 @@
-import Vue from 'vue';
-import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
import { TEST_HOST } from 'spec/test_constants';
import App from '~/diffs/components/app.vue';
+import NoChanges from '~/diffs/components/no_changes.vue';
+import DiffFile from '~/diffs/components/diff_file.vue';
import createDiffsStore from '../create_diffs_store';
describe('diffs/components/app', () => {
const oldMrTabs = window.mrTabs;
- const Component = Vue.extend(App);
-
+ let store;
let vm;
+ function createComponent(props = {}, extendStore = () => {}) {
+ const localVue = createLocalVue();
+
+ localVue.use(Vuex);
+
+ store = createDiffsStore();
+ store.state.diffs.isLoading = false;
+
+ extendStore(store);
+
+ vm = shallowMount(localVue.extend(App), {
+ localVue,
+ propsData: {
+ endpoint: `${TEST_HOST}/diff/endpoint`,
+ projectPath: 'namespace/project',
+ currentUser: {},
+ changesEmptyStateIllustration: '',
+ ...props,
+ },
+ store,
+ });
+ }
+
beforeEach(() => {
// setup globals (needed for component to mount :/)
window.mrTabs = jasmine.createSpyObj('mrTabs', ['resetViewContainer']);
window.mrTabs.expandViewContainer = jasmine.createSpy();
window.location.hash = 'ABC_123';
-
- // setup component
- const store = createDiffsStore();
- store.state.diffs.isLoading = false;
-
- vm = mountComponentWithStore(Component, {
- store,
- props: {
- endpoint: `${TEST_HOST}/diff/endpoint`,
- projectPath: 'namespace/project',
- currentUser: {},
- },
- });
});
afterEach(() => {
@@ -35,21 +46,53 @@ describe('diffs/components/app', () => {
window.mrTabs = oldMrTabs;
// reset component
- vm.$destroy();
+ vm.destroy();
});
it('does not show commit info', () => {
- expect(vm.$el).not.toContainElement('.blob-commit-info');
+ createComponent();
+
+ expect(vm.contains('.blob-commit-info')).toBe(false);
});
it('sets highlighted row if hash exists in location object', done => {
- vm.$props.shouldShow = true;
+ createComponent({
+ shouldShow: true,
+ });
- vm.$nextTick()
- .then(() => {
- expect(vm.$store.state.diffs.highlightedRow).toBe('ABC_123');
- })
- .then(done)
- .catch(done.fail);
+ // Component uses $nextTick so we wait until that has finished
+ setTimeout(() => {
+ expect(store.state.diffs.highlightedRow).toBe('ABC_123');
+
+ done();
+ });
+ });
+
+ describe('empty state', () => {
+ it('renders empty state when no diff files exist', () => {
+ createComponent();
+
+ expect(vm.contains(NoChanges)).toBe(true);
+ });
+
+ it('does not render empty state when diff files exist', () => {
+ createComponent({}, () => {
+ store.state.diffs.diffFiles.push({
+ id: 1,
+ });
+ });
+
+ expect(vm.contains(NoChanges)).toBe(false);
+ expect(vm.findAll(DiffFile).length).toBe(1);
+ });
+
+ it('does not render empty state when versions match', () => {
+ createComponent({}, () => {
+ store.state.diffs.startVersion = { version_index: 1 };
+ store.state.diffs.mergeRequestDiff = { version_index: 1 };
+ });
+
+ expect(vm.contains(NoChanges)).toBe(false);
+ });
});
});
diff --git a/spec/javascripts/diffs/components/no_changes_spec.js b/spec/javascripts/diffs/components/no_changes_spec.js
index 7237274eb43..e45d34bf9d5 100644
--- a/spec/javascripts/diffs/components/no_changes_spec.js
+++ b/spec/javascripts/diffs/components/no_changes_spec.js
@@ -1 +1,40 @@
-// TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { createStore } from '~/mr_notes/stores';
+import NoChanges from '~/diffs/components/no_changes.vue';
+
+describe('Diff no changes empty state', () => {
+ let vm;
+
+ function createComponent(extendStore = () => {}) {
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
+
+ const store = createStore();
+ extendStore(store);
+
+ vm = shallowMount(localVue.extend(NoChanges), {
+ localVue,
+ store,
+ propsData: {
+ changesEmptyStateIllustration: '',
+ },
+ });
+ }
+
+ afterEach(() => {
+ vm.destroy();
+ });
+
+ it('prevents XSS', () => {
+ createComponent(store => {
+ // eslint-disable-next-line no-param-reassign
+ store.state.notes.noteableData = {
+ source_branch: '',
+ target_branch: '',
+ };
+ });
+
+ expect(vm.contains('script')).toBe(false);
+ });
+});