summaryrefslogtreecommitdiff
path: root/spec/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/boards/mock_data.js2
-rw-r--r--spec/javascripts/boards/utils/query_data_spec.js27
-rw-r--r--spec/javascripts/diffs/components/diff_file_spec.js4
-rw-r--r--spec/javascripts/diffs/components/diff_line_gutter_content_spec.js46
-rw-r--r--spec/javascripts/diffs/components/parallel_diff_view_spec.js8
-rw-r--r--spec/javascripts/diffs/mock_data/diff_discussions.js10
-rw-r--r--spec/javascripts/diffs/mock_data/diff_file.js16
-rw-r--r--spec/javascripts/diffs/store/actions_spec.js230
-rw-r--r--spec/javascripts/diffs/store/getters_spec.js78
-rw-r--r--spec/javascripts/diffs/store/mutations_spec.js140
-rw-r--r--spec/javascripts/diffs/store/utils_spec.js106
-rw-r--r--spec/javascripts/dropzone_input_spec.js68
-rw-r--r--spec/javascripts/gfm_auto_complete_spec.js2
-rw-r--r--spec/javascripts/groups/components/app_spec.js105
-rw-r--r--spec/javascripts/helpers/vue_resource_helper.js1
-rw-r--r--spec/javascripts/ide/components/commit_sidebar/list_item_spec.js2
-rw-r--r--spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js4
-rw-r--r--spec/javascripts/ide/components/file_templates/bar_spec.js117
-rw-r--r--spec/javascripts/ide/components/file_templates/dropdown_spec.js201
-rw-r--r--spec/javascripts/ide/components/repo_commit_section_spec.js4
-rw-r--r--spec/javascripts/ide/helpers.js2
-rw-r--r--spec/javascripts/ide/stores/actions/file_spec.js15
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js26
-rw-r--r--spec/javascripts/ide/stores/modules/file_templates/actions_spec.js83
-rw-r--r--spec/javascripts/ide/stores/modules/file_templates/getters_spec.js51
-rw-r--r--spec/javascripts/ide/stores/mutations_spec.js8
-rw-r--r--spec/javascripts/lazy_loader_spec.js12
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js40
-rw-r--r--spec/javascripts/lib/utils/mock_data.js2
-rw-r--r--spec/javascripts/lib/utils/text_utility_spec.js6
-rw-r--r--spec/javascripts/monitoring/graph/flag_spec.js2
-rw-r--r--spec/javascripts/monitoring/graph_spec.js3
-rw-r--r--spec/javascripts/notes/components/note_actions_spec.js18
-rw-r--r--spec/javascripts/notes/components/note_awards_list_spec.js4
-rw-r--r--spec/javascripts/notes/components/note_form_spec.js18
-rw-r--r--spec/javascripts/notes/components/note_header_spec.js14
-rw-r--r--spec/javascripts/notes/mock_data.js46
-rw-r--r--spec/javascripts/projects/project_new_spec.js30
-rw-r--r--spec/javascripts/test_bundle.js5
-rw-r--r--spec/javascripts/vue_shared/components/file_icon_spec.js8
-rw-r--r--spec/javascripts/vue_shared/components/loading_icon_spec.js54
-rw-r--r--spec/javascripts/vue_shared/components/notes/system_note_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/pagination_links_spec.js72
43 files changed, 1372 insertions, 320 deletions
diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js
index 81f1a97112f..f380ef450db 100644
--- a/spec/javascripts/boards/mock_data.js
+++ b/spec/javascripts/boards/mock_data.js
@@ -27,7 +27,7 @@ export const listObjDuplicate = {
export const BoardsMockData = {
GET: {
- '/test/-/boards/1/lists/300/issues?id=300&page=1&=': {
+ '/test/-/boards/1/lists/300/issues?id=300&page=1': {
issues: [
{
title: 'Testing',
diff --git a/spec/javascripts/boards/utils/query_data_spec.js b/spec/javascripts/boards/utils/query_data_spec.js
deleted file mode 100644
index 922215ffc1d..00000000000
--- a/spec/javascripts/boards/utils/query_data_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import queryData from '~/boards/utils/query_data';
-
-describe('queryData', () => {
- it('parses path for label with trailing +', () => {
- expect(
- queryData('label_name[]=label%2B', {}),
- ).toEqual({
- label_name: ['label+'],
- });
- });
-
- it('parses path for milestone with trailing +', () => {
- expect(
- queryData('milestone_title=A%2B', {}),
- ).toEqual({
- milestone_title: 'A+',
- });
- });
-
- it('parses path for search terms with spaces', () => {
- expect(
- queryData('search=two+words', {}),
- ).toEqual({
- search: 'two words',
- });
- });
-});
diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js
index 44a38f7ca82..845fef23db6 100644
--- a/spec/javascripts/diffs/components/diff_file_spec.js
+++ b/spec/javascripts/diffs/components/diff_file_spec.js
@@ -51,7 +51,9 @@ describe('DiffFile', () => {
});
it('should have collapsed text and link', done => {
- vm.file.collapsed = true;
+ vm.file.renderIt = true;
+ vm.file.collapsed = false;
+ vm.file.highlightedDiffLines = null;
vm.$nextTick(() => {
expect(vm.$el.innerText).toContain('This diff is collapsed');
diff --git a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
index a1a37b342b7..663c0680845 100644
--- a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
+++ b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
@@ -6,61 +6,61 @@ import discussionsMockData from '../mock_data/diff_discussions';
import diffFileMockData from '../mock_data/diff_file';
describe('DiffLineGutterContent', () => {
- const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
const getDiffFileMock = () => Object.assign({}, diffFileMockData);
const createComponent = (options = {}) => {
const cmp = Vue.extend(DiffLineGutterContent);
const props = Object.assign({}, options);
+ props.line = {
+ lineCode: 'LC_42',
+ type: 'new',
+ oldLine: null,
+ newLine: 1,
+ discussions: [],
+ text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ metaData: null,
+ };
props.fileHash = getDiffFileMock().fileHash;
props.contextLinesPath = '/context/lines/path';
return createComponentWithStore(cmp, store, props).$mount();
};
- const setDiscussions = component => {
- component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
- };
-
- const resetDiscussions = component => {
- component.$store.dispatch('setInitialNotes', []);
- };
describe('computed', () => {
describe('lineHref', () => {
it('should prepend # to lineCode', () => {
const lineCode = 'LC_42';
- const component = createComponent({ lineCode });
+ const component = createComponent();
expect(component.lineHref).toEqual(`#${lineCode}`);
});
it('should return # if there is no lineCode', () => {
- const component = createComponent({ lineCode: null });
+ const component = createComponent();
+ component.line.lineCode = '';
expect(component.lineHref).toEqual('#');
});
});
describe('discussions, hasDiscussions, shouldShowAvatarsOnGutter', () => {
it('should return empty array when there is no discussion', () => {
- const component = createComponent({ lineCode: 'LC_42' });
- expect(component.discussions).toEqual([]);
+ const component = createComponent();
expect(component.hasDiscussions).toEqual(false);
expect(component.shouldShowAvatarsOnGutter).toEqual(false);
});
it('should return discussions for the given lineCode', () => {
- const { lineCode } = getDiffFileMock().highlightedDiffLines[1];
- const component = createComponent({
- lineCode,
+ const cmp = Vue.extend(DiffLineGutterContent);
+ const props = {
+ line: getDiffFileMock().highlightedDiffLines[1],
+ fileHash: getDiffFileMock().fileHash,
showCommentButton: true,
- discussions: getDiscussionsMockData(),
- });
+ contextLinesPath: '/context/lines/path',
+ };
+ props.line.discussions = [Object.assign({}, discussionsMockData)];
+ const component = createComponentWithStore(cmp, store, props).$mount();
- setDiscussions(component);
-
- expect(component.discussions).toEqual(getDiscussionsMockData());
expect(component.hasDiscussions).toEqual(true);
expect(component.shouldShowAvatarsOnGutter).toEqual(true);
-
- resetDiscussions(component);
});
});
});
@@ -104,9 +104,7 @@ describe('DiffLineGutterContent', () => {
lineCode: getDiffFileMock().highlightedDiffLines[1].lineCode,
});
- setDiscussions(component);
expect(component.$el.querySelector('.diff-comment-avatar-holders')).toBeDefined();
- resetDiscussions(component);
});
});
});
diff --git a/spec/javascripts/diffs/components/parallel_diff_view_spec.js b/spec/javascripts/diffs/components/parallel_diff_view_spec.js
index 165e4b69b6c..091e01868d3 100644
--- a/spec/javascripts/diffs/components/parallel_diff_view_spec.js
+++ b/spec/javascripts/diffs/components/parallel_diff_view_spec.js
@@ -18,11 +18,11 @@ describe('ParallelDiffView', () => {
}).$mount();
});
- describe('computed', () => {
- describe('parallelDiffLines', () => {
+ describe('assigned', () => {
+ describe('diffLines', () => {
it('should normalize lines for empty cells', () => {
- expect(component.parallelDiffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE);
- expect(component.parallelDiffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE);
+ expect(component.diffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE);
+ expect(component.diffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE);
});
});
});
diff --git a/spec/javascripts/diffs/mock_data/diff_discussions.js b/spec/javascripts/diffs/mock_data/diff_discussions.js
index 41d0dfd8939..b29a22da7c2 100644
--- a/spec/javascripts/diffs/mock_data/diff_discussions.js
+++ b/spec/javascripts/diffs/mock_data/diff_discussions.js
@@ -16,7 +16,7 @@ export default {
expanded: true,
notes: [
{
- id: 1749,
+ id: '1749',
type: 'DiffNote',
attachment: null,
author: {
@@ -68,7 +68,7 @@ export default {
'/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
},
{
- id: 1753,
+ id: '1753',
type: 'DiffNote',
attachment: null,
author: {
@@ -120,7 +120,7 @@ export default {
'/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
},
{
- id: 1754,
+ id: '1754',
type: 'DiffNote',
attachment: null,
author: {
@@ -162,7 +162,7 @@ export default {
'/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
},
{
- id: 1755,
+ id: '1755',
type: 'DiffNote',
attachment: null,
author: {
@@ -204,7 +204,7 @@ export default {
'/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
},
{
- id: 1756,
+ id: '1756',
type: 'DiffNote',
attachment: null,
author: {
diff --git a/spec/javascripts/diffs/mock_data/diff_file.js b/spec/javascripts/diffs/mock_data/diff_file.js
index cce36ecc91f..372b8f066cf 100644
--- a/spec/javascripts/diffs/mock_data/diff_file.js
+++ b/spec/javascripts/diffs/mock_data/diff_file.js
@@ -49,6 +49,7 @@ export default {
type: 'new',
oldLine: null,
newLine: 1,
+ discussions: [],
text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
metaData: null,
@@ -58,6 +59,7 @@ export default {
type: 'new',
oldLine: null,
newLine: 2,
+ discussions: [],
text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
richText: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
metaData: null,
@@ -67,6 +69,7 @@ export default {
type: null,
oldLine: 1,
newLine: 3,
+ discussions: [],
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
richText: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
metaData: null,
@@ -76,6 +79,7 @@ export default {
type: null,
oldLine: 2,
newLine: 4,
+ discussions: [],
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
richText: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
metaData: null,
@@ -85,6 +89,7 @@ export default {
type: null,
oldLine: 3,
newLine: 5,
+ discussions: [],
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
richText: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
metaData: null,
@@ -94,6 +99,7 @@ export default {
type: 'match',
oldLine: null,
newLine: null,
+ discussions: [],
text: '',
richText: '',
metaData: {
@@ -112,6 +118,7 @@ export default {
type: 'new',
oldLine: null,
newLine: 1,
+ discussions: [],
text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
richText: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
metaData: null,
@@ -126,6 +133,7 @@ export default {
type: 'new',
oldLine: null,
newLine: 2,
+ discussions: [],
text: '+<span id="LC2" class="line" lang="plaintext"></span>\n',
richText: '<span id="LC2" class="line" lang="plaintext"></span>\n',
metaData: null,
@@ -137,6 +145,7 @@ export default {
type: null,
oldLine: 1,
newLine: 3,
+ discussions: [],
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
metaData: null,
@@ -146,6 +155,7 @@ export default {
type: null,
oldLine: 1,
newLine: 3,
+ discussions: [],
text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
metaData: null,
@@ -157,6 +167,7 @@ export default {
type: null,
oldLine: 2,
newLine: 4,
+ discussions: [],
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
richText: '<span id="LC4" class="line" lang="plaintext"></span>\n',
metaData: null,
@@ -166,6 +177,7 @@ export default {
type: null,
oldLine: 2,
newLine: 4,
+ discussions: [],
text: ' <span id="LC4" class="line" lang="plaintext"></span>\n',
richText: '<span id="LC4" class="line" lang="plaintext"></span>\n',
metaData: null,
@@ -177,6 +189,7 @@ export default {
type: null,
oldLine: 3,
newLine: 5,
+ discussions: [],
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
metaData: null,
@@ -186,6 +199,7 @@ export default {
type: null,
oldLine: 3,
newLine: 5,
+ discussions: [],
text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
metaData: null,
@@ -197,6 +211,7 @@ export default {
type: 'match',
oldLine: null,
newLine: null,
+ discussions: [],
text: '',
richText: '',
metaData: {
@@ -209,6 +224,7 @@ export default {
type: 'match',
oldLine: null,
newLine: null,
+ discussions: [],
text: '',
richText: '',
metaData: {
diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js
index c1560dac1a0..cfb8f862598 100644
--- a/spec/javascripts/diffs/store/actions_spec.js
+++ b/spec/javascripts/diffs/store/actions_spec.js
@@ -7,10 +7,30 @@ import {
} from '~/diffs/constants';
import * as actions from '~/diffs/store/actions';
import * as types from '~/diffs/store/mutation_types';
+import { reduceDiscussionsToLineCodes } from '~/notes/stores/utils';
import axios from '~/lib/utils/axios_utils';
import testAction from '../../helpers/vuex_action_helper';
describe('DiffsStoreActions', () => {
+ const originalMethods = {
+ requestAnimationFrame: global.requestAnimationFrame,
+ requestIdleCallback: global.requestIdleCallback,
+ };
+
+ beforeEach(() => {
+ ['requestAnimationFrame', 'requestIdleCallback'].forEach(method => {
+ global[method] = cb => {
+ cb();
+ };
+ });
+ });
+
+ afterEach(() => {
+ ['requestAnimationFrame', 'requestIdleCallback'].forEach(method => {
+ global[method] = originalMethods[method];
+ });
+ });
+
describe('setBaseConfig', () => {
it('should set given endpoint and project path', done => {
const endpoint = '/diffs/set/endpoint';
@@ -53,6 +73,198 @@ describe('DiffsStoreActions', () => {
});
});
+ describe('assignDiscussionsToDiff', () => {
+ it('should merge discussions into diffs', done => {
+ const state = {
+ diffFiles: [
+ {
+ fileHash: 'ABC',
+ parallelDiffLines: [
+ {
+ left: {
+ lineCode: 'ABC_1_1',
+ discussions: [],
+ },
+ right: {
+ lineCode: 'ABC_1_1',
+ discussions: [],
+ },
+ },
+ ],
+ highlightedDiffLines: [
+ {
+ lineCode: 'ABC_1_1',
+ discussions: [],
+ oldLine: 5,
+ newLine: null,
+ },
+ ],
+ diffRefs: {
+ baseSha: 'abc',
+ headSha: 'def',
+ startSha: 'ghi',
+ },
+ newPath: 'file1',
+ oldPath: 'file2',
+ },
+ ],
+ };
+
+ const diffPosition = {
+ baseSha: 'abc',
+ headSha: 'def',
+ startSha: 'ghi',
+ newLine: null,
+ newPath: 'file1',
+ oldLine: 5,
+ oldPath: 'file2',
+ };
+
+ const singleDiscussion = {
+ line_code: 'ABC_1_1',
+ diff_discussion: {},
+ diff_file: {
+ file_hash: 'ABC',
+ },
+ fileHash: 'ABC',
+ resolvable: true,
+ position: {
+ formatter: diffPosition,
+ },
+ original_position: {
+ formatter: diffPosition,
+ },
+ };
+
+ const discussions = reduceDiscussionsToLineCodes([singleDiscussion]);
+
+ testAction(
+ actions.assignDiscussionsToDiff,
+ discussions,
+ state,
+ [
+ {
+ type: types.SET_LINE_DISCUSSIONS_FOR_FILE,
+ payload: {
+ fileHash: 'ABC',
+ discussions: [singleDiscussion],
+ diffPositionByLineCode: {
+ ABC_1_1: {
+ baseSha: 'abc',
+ headSha: 'def',
+ startSha: 'ghi',
+ newLine: null,
+ newPath: 'file1',
+ oldLine: 5,
+ oldPath: 'file2',
+ },
+ },
+ },
+ },
+ ],
+ [],
+ () => {
+ done();
+ },
+ );
+ });
+ });
+
+ describe('removeDiscussionsFromDiff', () => {
+ it('should remove discussions from diffs', done => {
+ const state = {
+ diffFiles: [
+ {
+ fileHash: 'ABC',
+ parallelDiffLines: [
+ {
+ left: {
+ lineCode: 'ABC_1_1',
+ discussions: [
+ {
+ id: 1,
+ },
+ ],
+ },
+ right: {
+ lineCode: 'ABC_1_1',
+ discussions: [],
+ },
+ },
+ ],
+ highlightedDiffLines: [
+ {
+ lineCode: 'ABC_1_1',
+ discussions: [],
+ },
+ ],
+ },
+ ],
+ };
+ const singleDiscussion = {
+ fileHash: 'ABC',
+ line_code: 'ABC_1_1',
+ };
+
+ testAction(
+ actions.removeDiscussionsFromDiff,
+ singleDiscussion,
+ state,
+ [
+ {
+ type: types.REMOVE_LINE_DISCUSSIONS_FOR_FILE,
+ payload: {
+ fileHash: 'ABC',
+ lineCode: 'ABC_1_1',
+ },
+ },
+ ],
+ [],
+ () => {
+ done();
+ },
+ );
+ });
+ });
+
+ describe('startRenderDiffsQueue', () => {
+ it('should set all files to RENDER_FILE', done => {
+ const state = {
+ diffFiles: [
+ {
+ id: 1,
+ renderIt: false,
+ collapsed: false,
+ },
+ {
+ id: 2,
+ renderIt: false,
+ collapsed: false,
+ },
+ ],
+ };
+
+ const pseudoCommit = (commitType, file) => {
+ expect(commitType).toBe(types.RENDER_FILE);
+ Object.assign(file, {
+ renderIt: true,
+ });
+ };
+
+ actions
+ .startRenderDiffsQueue({ state, commit: pseudoCommit })
+ .then(() => {
+ expect(state.diffFiles[0].renderIt).toBeTruthy();
+ expect(state.diffFiles[1].renderIt).toBeTruthy();
+
+ done();
+ })
+ .catch(() => {
+ done.fail();
+ });
+ });
+ });
+
describe('setInlineDiffViewType', () => {
it('should set diff view type to inline and also set the cookie properly', done => {
testAction(
@@ -204,7 +416,11 @@ describe('DiffsStoreActions', () => {
actions.toggleFileDiscussions({ getters, dispatch });
- expect(dispatch).toHaveBeenCalledWith('collapseDiscussion', { discussionId: 1 }, { root: true });
+ expect(dispatch).toHaveBeenCalledWith(
+ 'collapseDiscussion',
+ { discussionId: 1 },
+ { root: true },
+ );
});
it('should dispatch expandDiscussion when all discussions are collapsed', () => {
@@ -218,7 +434,11 @@ describe('DiffsStoreActions', () => {
actions.toggleFileDiscussions({ getters, dispatch });
- expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true });
+ expect(dispatch).toHaveBeenCalledWith(
+ 'expandDiscussion',
+ { discussionId: 1 },
+ { root: true },
+ );
});
it('should dispatch expandDiscussion when some discussions are collapsed and others are expanded for the collapsed discussion', () => {
@@ -232,7 +452,11 @@ describe('DiffsStoreActions', () => {
actions.toggleFileDiscussions({ getters, dispatch });
- expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true });
+ expect(dispatch).toHaveBeenCalledWith(
+ 'expandDiscussion',
+ { discussionId: 1 },
+ { root: true },
+ );
});
});
});
diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js
index a59b26b2634..4747e437c4e 100644
--- a/spec/javascripts/diffs/store/getters_spec.js
+++ b/spec/javascripts/diffs/store/getters_spec.js
@@ -184,101 +184,73 @@ describe('Diffs Module Getters', () => {
});
});
- describe('singleDiscussionByLineCode', () => {
- it('returns found discussion per line Code', () => {
- const discussionsMock = {};
- discussionsMock.ABC = discussionMock;
-
- expect(
- getters.singleDiscussionByLineCode(localState, {}, null, {
- discussionsByLineCode: () => discussionsMock,
- })('DEF'),
- ).toEqual([]);
- });
-
- it('returns empty array when no discussions match', () => {
- expect(
- getters.singleDiscussionByLineCode(localState, {}, null, {
- discussionsByLineCode: () => {},
- })('DEF'),
- ).toEqual([]);
- });
- });
-
describe('shouldRenderParallelCommentRow', () => {
let line;
beforeEach(() => {
line = {};
+ discussionMock.expanded = true;
+
line.left = {
lineCode: 'ABC',
+ discussions: [discussionMock],
};
line.right = {
lineCode: 'DEF',
+ discussions: [discussionMock1],
};
});
it('returns true when discussion is expanded', () => {
- discussionMock.expanded = true;
-
- expect(
- getters.shouldRenderParallelCommentRow(localState, {
- singleDiscussionByLineCode: () => [discussionMock],
- })(line),
- ).toEqual(true);
+ expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true);
});
it('returns false when no discussion was found', () => {
+ line.left.discussions = [];
+ line.right.discussions = [];
+
localState.diffLineCommentForms.ABC = false;
localState.diffLineCommentForms.DEF = false;
- expect(
- getters.shouldRenderParallelCommentRow(localState, {
- singleDiscussionByLineCode: () => [],
- })(line),
- ).toEqual(false);
+ expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(false);
});
it('returns true when discussionForm was found', () => {
localState.diffLineCommentForms.ABC = {};
- expect(
- getters.shouldRenderParallelCommentRow(localState, {
- singleDiscussionByLineCode: () => [discussionMock],
- })(line),
- ).toEqual(true);
+ expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true);
});
});
describe('shouldRenderInlineCommentRow', () => {
+ let line;
+
+ beforeEach(() => {
+ discussionMock.expanded = true;
+
+ line = {
+ lineCode: 'ABC',
+ discussions: [discussionMock],
+ };
+ });
+
it('returns true when diffLineCommentForms has form', () => {
localState.diffLineCommentForms.ABC = {};
- expect(
- getters.shouldRenderInlineCommentRow(localState)({
- lineCode: 'ABC',
- }),
- ).toEqual(true);
+ expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true);
});
it('returns false when no line discussions were found', () => {
- expect(
- getters.shouldRenderInlineCommentRow(localState, {
- singleDiscussionByLineCode: () => [],
- })('DEF'),
- ).toEqual(false);
+ line.discussions = [];
+ expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(false);
});
it('returns true if all found discussions are expanded', () => {
discussionMock.expanded = true;
- expect(
- getters.shouldRenderInlineCommentRow(localState, {
- singleDiscussionByLineCode: () => [discussionMock],
- })('ABC'),
- ).toEqual(true);
+ expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true);
});
});
diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js
index 8f89984c6e5..7eeca6712cc 100644
--- a/spec/javascripts/diffs/store/mutations_spec.js
+++ b/spec/javascripts/diffs/store/mutations_spec.js
@@ -138,10 +138,9 @@ describe('DiffsStoreMutations', () => {
const fileHash = 123;
const state = { diffFiles: [{}, { fileHash, existingField: 0 }] };
- const file = { fileHash };
const data = { diff_files: [{ file_hash: fileHash, extra_field: 1, existingField: 1 }] };
- mutations[types.ADD_COLLAPSED_DIFFS](state, { file, data });
+ mutations[types.ADD_COLLAPSED_DIFFS](state, { file: state.diffFiles[1], data });
expect(spy).toHaveBeenCalledWith(data, { deep: true });
expect(state.diffFiles[1].fileHash).toEqual(fileHash);
@@ -149,4 +148,141 @@ describe('DiffsStoreMutations', () => {
expect(state.diffFiles[1].extraField).toEqual(1);
});
});
+
+ describe('SET_LINE_DISCUSSIONS_FOR_FILE', () => {
+ it('should add discussions to the given line', () => {
+ const diffPosition = {
+ baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
+ newLine: null,
+ newPath: '500-lines-4.txt',
+ oldLine: 5,
+ oldPath: '500-lines-4.txt',
+ startSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ };
+
+ const state = {
+ diffFiles: [
+ {
+ fileHash: 'ABC',
+ parallelDiffLines: [
+ {
+ left: {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ right: {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ },
+ ],
+ highlightedDiffLines: [
+ {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ ],
+ },
+ ],
+ };
+ const discussions = [
+ {
+ id: 1,
+ line_code: 'ABC_1',
+ diff_discussion: true,
+ resolvable: true,
+ original_position: {
+ formatter: diffPosition,
+ },
+ position: {
+ formatter: diffPosition,
+ },
+ },
+ {
+ id: 2,
+ line_code: 'ABC_1',
+ diff_discussion: true,
+ resolvable: true,
+ original_position: {
+ formatter: diffPosition,
+ },
+ position: {
+ formatter: diffPosition,
+ },
+ },
+ ];
+
+ const diffPositionByLineCode = {
+ ABC_1: diffPosition,
+ };
+
+ mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
+ fileHash: 'ABC',
+ discussions,
+ diffPositionByLineCode,
+ });
+
+ expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2);
+ expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2);
+
+ expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
+ expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
+ });
+ });
+
+ describe('REMOVE_LINE_DISCUSSIONS', () => {
+ it('should remove the existing discussions on the given line', () => {
+ const state = {
+ diffFiles: [
+ {
+ fileHash: 'ABC',
+ parallelDiffLines: [
+ {
+ left: {
+ lineCode: 'ABC_1',
+ discussions: [
+ {
+ id: 1,
+ line_code: 'ABC_1',
+ },
+ {
+ id: 2,
+ line_code: 'ABC_1',
+ },
+ ],
+ },
+ right: {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ },
+ ],
+ highlightedDiffLines: [
+ {
+ lineCode: 'ABC_1',
+ discussions: [
+ {
+ id: 1,
+ line_code: 'ABC_1',
+ },
+ {
+ id: 2,
+ line_code: 'ABC_1',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ };
+
+ mutations[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, {
+ fileHash: 'ABC',
+ lineCode: 'ABC_1',
+ });
+ expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(0);
+ expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(0);
+ });
+ });
});
diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js
index 32136d9ebff..4b5cf450c68 100644
--- a/spec/javascripts/diffs/store/utils_spec.js
+++ b/spec/javascripts/diffs/store/utils_spec.js
@@ -179,32 +179,126 @@ describe('DiffsStoreUtils', () => {
describe('trimFirstCharOfLineContent', () => {
it('trims the line when it starts with a space', () => {
- expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({ richText: 'diff' });
+ expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({
+ discussions: [],
+ richText: 'diff',
+ });
});
it('trims the line when it starts with a +', () => {
- expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({ richText: 'diff' });
+ expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({
+ discussions: [],
+ richText: 'diff',
+ });
});
it('trims the line when it starts with a -', () => {
- expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({ richText: 'diff' });
+ expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({
+ discussions: [],
+ richText: 'diff',
+ });
});
it('does not trims the line when it starts with a letter', () => {
- expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({ richText: 'diff' });
+ expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({
+ discussions: [],
+ richText: 'diff',
+ });
});
it('does not modify the provided object', () => {
const lineObj = {
+ discussions: [],
richText: ' diff',
};
utils.trimFirstCharOfLineContent(lineObj);
- expect(lineObj).toEqual({ richText: ' diff' });
+ expect(lineObj).toEqual({ discussions: [], richText: ' diff' });
});
it('handles a undefined or null parameter', () => {
- expect(utils.trimFirstCharOfLineContent()).toEqual({});
+ expect(utils.trimFirstCharOfLineContent()).toEqual({ discussions: [] });
+ });
+ });
+
+ describe('prepareDiffData', () => {
+ it('sets the renderIt and collapsed attribute on files', () => {
+ const preparedDiff = { diffFiles: [getDiffFileMock()] };
+ utils.prepareDiffData(preparedDiff);
+
+ const firstParallelDiffLine = preparedDiff.diffFiles[0].parallelDiffLines[2];
+ expect(firstParallelDiffLine.left.discussions.length).toBe(0);
+ expect(firstParallelDiffLine.left).not.toHaveAttr('text');
+ expect(firstParallelDiffLine.right.discussions.length).toBe(0);
+ expect(firstParallelDiffLine.right).not.toHaveAttr('text');
+ const firstParallelChar = firstParallelDiffLine.right.richText.charAt(0);
+ expect(firstParallelChar).not.toBe(' ');
+ expect(firstParallelChar).not.toBe('+');
+ expect(firstParallelChar).not.toBe('-');
+
+ const checkLine = preparedDiff.diffFiles[0].highlightedDiffLines[0];
+ expect(checkLine.discussions.length).toBe(0);
+ expect(checkLine).not.toHaveAttr('text');
+ const firstChar = checkLine.richText.charAt(0);
+ expect(firstChar).not.toBe(' ');
+ expect(firstChar).not.toBe('+');
+ expect(firstChar).not.toBe('-');
+
+ expect(preparedDiff.diffFiles[0].renderIt).toBeTruthy();
+ expect(preparedDiff.diffFiles[0].collapsed).toBeFalsy();
+ });
+ });
+
+ describe('isDiscussionApplicableToLine', () => {
+ const diffPosition = {
+ baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
+ newLine: null,
+ newPath: '500-lines-4.txt',
+ oldLine: 5,
+ oldPath: '500-lines-4.txt',
+ startSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ };
+
+ const wrongDiffPosition = {
+ baseSha: 'wrong',
+ headSha: 'wrong',
+ newLine: null,
+ newPath: '500-lines-4.txt',
+ oldLine: 5,
+ oldPath: '500-lines-4.txt',
+ startSha: 'wrong',
+ };
+
+ const discussions = {
+ upToDateDiscussion1: {
+ original_position: {
+ formatter: diffPosition,
+ },
+ position: {
+ formatter: wrongDiffPosition,
+ },
+ },
+ outDatedDiscussion1: {
+ original_position: {
+ formatter: wrongDiffPosition,
+ },
+ position: {
+ formatter: wrongDiffPosition,
+ },
+ },
+ };
+
+ it('returns true when the discussion is up to date', () => {
+ expect(
+ utils.isDiscussionApplicableToLine(discussions.upToDateDiscussion1, diffPosition),
+ ).toBe(true);
+ });
+
+ it('returns false when the discussion is not up to date', () => {
+ expect(
+ utils.isDiscussionApplicableToLine(discussions.outDatedDiscussion1, diffPosition),
+ ).toBe(false);
});
});
});
diff --git a/spec/javascripts/dropzone_input_spec.js b/spec/javascripts/dropzone_input_spec.js
new file mode 100644
index 00000000000..0c6b1a8946d
--- /dev/null
+++ b/spec/javascripts/dropzone_input_spec.js
@@ -0,0 +1,68 @@
+import $ from 'jquery';
+import dropzoneInput from '~/dropzone_input';
+import { TEST_HOST } from 'spec/test_constants';
+
+const TEST_FILE = {
+ upload: {},
+};
+const TEST_UPLOAD_PATH = `${TEST_HOST}/upload/file`;
+const TEST_ERROR_MESSAGE = 'A big error occurred!';
+const TEMPLATE = (
+`<form class="gfm-form" data-uploads-path="${TEST_UPLOAD_PATH}">
+ <textarea class="js-gfm-input"></textarea>
+ <div class="uploading-error-message"></div>
+</form>`
+);
+
+describe('dropzone_input', () => {
+ let form;
+ let dropzone;
+ let xhr;
+ let oldXMLHttpRequest;
+
+ beforeEach(() => {
+ form = $(TEMPLATE);
+
+ dropzone = dropzoneInput(form);
+
+ xhr = jasmine.createSpyObj(Object.keys(XMLHttpRequest.prototype));
+ oldXMLHttpRequest = window.XMLHttpRequest;
+ window.XMLHttpRequest = () => xhr;
+ });
+
+ afterEach(() => {
+ window.XMLHttpRequest = oldXMLHttpRequest;
+ });
+
+ it('shows error message, when AJAX fails with json', () => {
+ xhr = {
+ ...xhr,
+ statusCode: 400,
+ readyState: 4,
+ responseText: JSON.stringify({ message: TEST_ERROR_MESSAGE }),
+ getResponseHeader: () => 'application/json',
+ };
+
+ dropzone.processFile(TEST_FILE);
+
+ xhr.onload();
+
+ expect(form.find('.uploading-error-message').text()).toEqual(TEST_ERROR_MESSAGE);
+ });
+
+ it('shows error message, when AJAX fails with text', () => {
+ xhr = {
+ ...xhr,
+ statusCode: 400,
+ readyState: 4,
+ responseText: TEST_ERROR_MESSAGE,
+ getResponseHeader: () => 'text/plain',
+ };
+
+ dropzone.processFile(TEST_FILE);
+
+ xhr.onload();
+
+ expect(form.find('.uploading-error-message').text()).toEqual(TEST_ERROR_MESSAGE);
+ });
+});
diff --git a/spec/javascripts/gfm_auto_complete_spec.js b/spec/javascripts/gfm_auto_complete_spec.js
index 1cb20a1e7ff..4f9cacf2724 100644
--- a/spec/javascripts/gfm_auto_complete_spec.js
+++ b/spec/javascripts/gfm_auto_complete_spec.js
@@ -146,7 +146,7 @@ describe('GfmAutoComplete', function () {
shouldNotBeFollowedBy.forEach((followedSymbol) => {
const seq = atSign + followedSymbol;
- it(`should not match "${seq}"`, () => {
+ it(`should not match ${JSON.stringify(seq)}`, () => {
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
});
});
diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js
index 03d4b472b87..89c07d1f06d 100644
--- a/spec/javascripts/groups/components/app_spec.js
+++ b/spec/javascripts/groups/components/app_spec.js
@@ -9,9 +9,14 @@ import GroupsStore from '~/groups/store/groups_store';
import GroupsService from '~/groups/service/groups_service';
import {
- mockEndpoint, mockGroups, mockSearchedGroups,
- mockRawPageInfo, mockParentGroupItem, mockRawChildren,
- mockChildren, mockPageInfo,
+ mockEndpoint,
+ mockGroups,
+ mockSearchedGroups,
+ mockRawPageInfo,
+ mockParentGroupItem,
+ mockRawChildren,
+ mockChildren,
+ mockPageInfo,
} from '../mock_data';
const createComponent = (hideProjects = false) => {
@@ -19,6 +24,8 @@ const createComponent = (hideProjects = false) => {
const store = new GroupsStore(false);
const service = new GroupsService(mockEndpoint);
+ store.state.pageInfo = mockPageInfo;
+
return new Component({
propsData: {
store,
@@ -28,22 +35,23 @@ const createComponent = (hideProjects = false) => {
});
};
-const returnServicePromise = (data, failed) => new Promise((resolve, reject) => {
- if (failed) {
- reject(data);
- } else {
- resolve({
- json() {
- return data;
- },
- });
- }
-});
+const returnServicePromise = (data, failed) =>
+ new Promise((resolve, reject) => {
+ if (failed) {
+ reject(data);
+ } else {
+ resolve({
+ json() {
+ return data;
+ },
+ });
+ }
+ });
describe('AppComponent', () => {
let vm;
- beforeEach((done) => {
+ beforeEach(done => {
Vue.component('group-folder', groupFolderComponent);
Vue.component('group-item', groupItemComponent);
@@ -94,7 +102,7 @@ describe('AppComponent', () => {
});
describe('fetchGroups', () => {
- it('should call `getGroups` with all the params provided', (done) => {
+ it('should call `getGroups` with all the params provided', done => {
spyOn(vm.service, 'getGroups').and.returnValue(returnServicePromise(mockGroups));
vm.fetchGroups({
@@ -110,8 +118,10 @@ describe('AppComponent', () => {
}, 0);
});
- it('should set headers to store for building pagination info when called with `updatePagination`', (done) => {
- spyOn(vm.service, 'getGroups').and.returnValue(returnServicePromise({ headers: mockRawPageInfo }));
+ it('should set headers to store for building pagination info when called with `updatePagination`', done => {
+ spyOn(vm.service, 'getGroups').and.returnValue(
+ returnServicePromise({ headers: mockRawPageInfo }),
+ );
spyOn(vm, 'updatePagination');
vm.fetchGroups({ updatePagination: true });
@@ -122,7 +132,7 @@ describe('AppComponent', () => {
}, 0);
});
- it('should show flash error when request fails', (done) => {
+ it('should show flash error when request fails', done => {
spyOn(vm.service, 'getGroups').and.returnValue(returnServicePromise(null, true));
spyOn($, 'scrollTo');
spyOn(window, 'Flash');
@@ -138,7 +148,7 @@ describe('AppComponent', () => {
});
describe('fetchAllGroups', () => {
- it('should fetch default set of groups', (done) => {
+ it('should fetch default set of groups', done => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise(mockGroups));
spyOn(vm, 'updatePagination').and.callThrough();
spyOn(vm, 'updateGroups').and.callThrough();
@@ -153,7 +163,7 @@ describe('AppComponent', () => {
}, 0);
});
- it('should fetch matching set of groups when app is loaded with search query', (done) => {
+ it('should fetch matching set of groups when app is loaded with search query', done => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise(mockSearchedGroups));
spyOn(vm, 'updateGroups').and.callThrough();
@@ -173,7 +183,7 @@ describe('AppComponent', () => {
});
describe('fetchPage', () => {
- it('should fetch groups for provided page details and update window state', (done) => {
+ it('should fetch groups for provided page details and update window state', done => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise(mockGroups));
spyOn(vm, 'updateGroups').and.callThrough();
const mergeUrlParams = spyOnDependency(appComponent, 'mergeUrlParams').and.callThrough();
@@ -193,9 +203,13 @@ describe('AppComponent', () => {
expect(vm.isLoading).toBe(false);
expect($.scrollTo).toHaveBeenCalledWith(0);
expect(mergeUrlParams).toHaveBeenCalledWith({ page: 2 }, jasmine.any(String));
- expect(window.history.replaceState).toHaveBeenCalledWith({
- page: jasmine.any(String),
- }, jasmine.any(String), jasmine.any(String));
+ expect(window.history.replaceState).toHaveBeenCalledWith(
+ {
+ page: jasmine.any(String),
+ },
+ jasmine.any(String),
+ jasmine.any(String),
+ );
expect(vm.updateGroups).toHaveBeenCalled();
done();
}, 0);
@@ -211,7 +225,7 @@ describe('AppComponent', () => {
groupItem.isChildrenLoading = false;
});
- it('should fetch children of given group and expand it if group is collapsed and children are not loaded', (done) => {
+ it('should fetch children of given group and expand it if group is collapsed and children are not loaded', done => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise(mockRawChildren));
spyOn(vm.store, 'setGroupChildren');
@@ -244,7 +258,7 @@ describe('AppComponent', () => {
expect(groupItem.isOpen).toBe(false);
});
- it('should set `isChildrenLoading` back to `false` if load request fails', (done) => {
+ it('should set `isChildrenLoading` back to `false` if load request fails', done => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise({}, true));
vm.toggleChildren(groupItem);
@@ -272,7 +286,9 @@ describe('AppComponent', () => {
expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.showModal).toBe(true);
- expect(vm.groupLeaveConfirmationMessage).toBe(`Are you sure you want to leave the "${group.fullName}" group?`);
+ expect(vm.groupLeaveConfirmationMessage).toBe(
+ `Are you sure you want to leave the "${group.fullName}" group?`,
+ );
});
});
@@ -299,7 +315,7 @@ describe('AppComponent', () => {
vm.targetParentGroup = groupItem;
});
- it('hides modal confirmation leave group and remove group item from tree', (done) => {
+ it('hides modal confirmation leave group and remove group item from tree', done => {
const notice = `You left the "${childGroupItem.fullName}" group.`;
spyOn(vm.service, 'leaveGroup').and.returnValue(returnServicePromise({ notice }));
spyOn(vm.store, 'removeGroup').and.callThrough();
@@ -318,9 +334,11 @@ describe('AppComponent', () => {
}, 0);
});
- it('should show error flash message if request failed to leave group', (done) => {
+ it('should show error flash message if request failed to leave group', done => {
const message = 'An error occurred. Please try again.';
- spyOn(vm.service, 'leaveGroup').and.returnValue(returnServicePromise({ status: 500 }, true));
+ spyOn(vm.service, 'leaveGroup').and.returnValue(
+ returnServicePromise({ status: 500 }, true),
+ );
spyOn(vm.store, 'removeGroup').and.callThrough();
spyOn(window, 'Flash');
@@ -335,9 +353,11 @@ describe('AppComponent', () => {
}, 0);
});
- it('should show appropriate error flash message if request forbids to leave group', (done) => {
+ it('should show appropriate error flash message if request forbids to leave group', done => {
const message = 'Failed to leave the group. Please make sure you are not the only owner.';
- spyOn(vm.service, 'leaveGroup').and.returnValue(returnServicePromise({ status: 403 }, true));
+ spyOn(vm.service, 'leaveGroup').and.returnValue(
+ returnServicePromise({ status: 403 }, true),
+ );
spyOn(vm.store, 'removeGroup').and.callThrough();
spyOn(window, 'Flash');
@@ -388,7 +408,7 @@ describe('AppComponent', () => {
});
describe('created', () => {
- it('should bind event listeners on eventHub', (done) => {
+ it('should bind event listeners on eventHub', done => {
spyOn(eventHub, '$on');
const newVm = createComponent();
@@ -405,21 +425,21 @@ describe('AppComponent', () => {
});
});
- it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `false`', (done) => {
+ it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `false`', done => {
const newVm = createComponent();
newVm.$mount();
Vue.nextTick(() => {
- expect(newVm.searchEmptyMessage).toBe('Sorry, no groups or projects matched your search');
+ expect(newVm.searchEmptyMessage).toBe('No groups or projects matched your search');
newVm.$destroy();
done();
});
});
- it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', (done) => {
+ it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', done => {
const newVm = createComponent(true);
newVm.$mount();
Vue.nextTick(() => {
- expect(newVm.searchEmptyMessage).toBe('Sorry, no groups matched your search');
+ expect(newVm.searchEmptyMessage).toBe('No groups matched your search');
newVm.$destroy();
done();
});
@@ -427,7 +447,7 @@ describe('AppComponent', () => {
});
describe('beforeDestroy', () => {
- it('should unbind event listeners on eventHub', (done) => {
+ it('should unbind event listeners on eventHub', done => {
spyOn(eventHub, '$off');
const newVm = createComponent();
@@ -454,7 +474,7 @@ describe('AppComponent', () => {
vm.$destroy();
});
- it('should render loading icon', (done) => {
+ it('should render loading icon', done => {
vm.isLoading = true;
Vue.nextTick(() => {
expect(vm.$el.querySelector('.loading-animation')).toBeDefined();
@@ -463,17 +483,16 @@ describe('AppComponent', () => {
});
});
- it('should render groups tree', (done) => {
+ it('should render groups tree', done => {
vm.store.state.groups = [mockParentGroupItem];
vm.isLoading = false;
- vm.store.state.pageInfo = mockPageInfo;
Vue.nextTick(() => {
expect(vm.$el.querySelector('.groups-list-tree-container')).toBeDefined();
done();
});
});
- it('renders modal confirmation dialog', (done) => {
+ it('renders modal confirmation dialog', done => {
vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?';
vm.showModal = true;
Vue.nextTick(() => {
diff --git a/spec/javascripts/helpers/vue_resource_helper.js b/spec/javascripts/helpers/vue_resource_helper.js
index 70b7ec4e574..0d1bf5e2e80 100644
--- a/spec/javascripts/helpers/vue_resource_helper.js
+++ b/spec/javascripts/helpers/vue_resource_helper.js
@@ -5,6 +5,7 @@ export const headersInterceptor = (request, next) => {
response.headers.forEach((value, key) => {
headers[key] = value;
});
+ // eslint-disable-next-line no-param-reassign
response.headers = headers;
});
};
diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
index 41d8bfff7e7..b45ae5bbb0f 100644
--- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
@@ -30,7 +30,7 @@ describe('Multi-file editor commit sidebar list item', () => {
});
it('renders file path', () => {
- expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent.trim()).toBe(f.path);
+ expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent).toContain(f.path);
});
it('renders actionn button', () => {
diff --git a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
index a5b906da8a1..e09ccbe2a63 100644
--- a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
@@ -29,7 +29,7 @@ describe('IDE stage file button', () => {
});
it('renders button to discard & stage', () => {
- expect(vm.$el.querySelectorAll('.btn').length).toBe(2);
+ expect(vm.$el.querySelectorAll('.btn-blank').length).toBe(2);
});
it('calls store with stage button', () => {
@@ -39,7 +39,7 @@ describe('IDE stage file button', () => {
});
it('calls store with discard button', () => {
- vm.$el.querySelector('.dropdown-menu button').click();
+ vm.$el.querySelector('.btn-danger').click();
expect(vm.discardFileChanges).toHaveBeenCalledWith(f.path);
});
diff --git a/spec/javascripts/ide/components/file_templates/bar_spec.js b/spec/javascripts/ide/components/file_templates/bar_spec.js
new file mode 100644
index 00000000000..a688f7f69a6
--- /dev/null
+++ b/spec/javascripts/ide/components/file_templates/bar_spec.js
@@ -0,0 +1,117 @@
+import Vue from 'vue';
+import { createStore } from '~/ide/stores';
+import Bar from '~/ide/components/file_templates/bar.vue';
+import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import { resetStore, file } from '../../helpers';
+
+describe('IDE file templates bar component', () => {
+ let Component;
+ let vm;
+
+ beforeAll(() => {
+ Component = Vue.extend(Bar);
+ });
+
+ beforeEach(() => {
+ const store = createStore();
+
+ store.state.openFiles.push({
+ ...file('file'),
+ opened: true,
+ active: true,
+ });
+
+ vm = mountComponentWithStore(Component, { store });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ resetStore(vm.$store);
+ });
+
+ describe('template type dropdown', () => {
+ it('renders dropdown component', () => {
+ expect(vm.$el.querySelector('.dropdown').textContent).toContain('Choose a type');
+ });
+
+ it('calls setSelectedTemplateType when clicking item', () => {
+ spyOn(vm, 'setSelectedTemplateType').and.stub();
+
+ vm.$el.querySelector('.dropdown-content button').click();
+
+ expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({
+ name: '.gitlab-ci.yml',
+ key: 'gitlab_ci_ymls',
+ });
+ });
+ });
+
+ describe('template dropdown', () => {
+ beforeEach(done => {
+ vm.$store.state.fileTemplates.templates = [
+ {
+ name: 'test',
+ },
+ ];
+ vm.$store.state.fileTemplates.selectedTemplateType = {
+ name: '.gitlab-ci.yml',
+ key: 'gitlab_ci_ymls',
+ };
+
+ vm.$nextTick(done);
+ });
+
+ it('renders dropdown component', () => {
+ expect(vm.$el.querySelectorAll('.dropdown')[1].textContent).toContain('Choose a template');
+ });
+
+ it('calls fetchTemplate on click', () => {
+ spyOn(vm, 'fetchTemplate').and.stub();
+
+ vm.$el
+ .querySelectorAll('.dropdown-content')[1]
+ .querySelector('button')
+ .click();
+
+ expect(vm.fetchTemplate).toHaveBeenCalledWith({
+ name: 'test',
+ });
+ });
+ });
+
+ it('shows undo button if updateSuccess is true', done => {
+ vm.$store.state.fileTemplates.updateSuccess = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.btn-default').style.display).not.toBe('none');
+
+ done();
+ });
+ });
+
+ it('calls undoFileTemplate when clicking undo button', () => {
+ spyOn(vm, 'undoFileTemplate').and.stub();
+
+ vm.$el.querySelector('.btn-default').click();
+
+ expect(vm.undoFileTemplate).toHaveBeenCalled();
+ });
+
+ it('calls setSelectedTemplateType if activeFile name matches a template', done => {
+ const fileName = '.gitlab-ci.yml';
+
+ spyOn(vm, 'setSelectedTemplateType');
+ vm.$store.state.openFiles[0].name = fileName;
+
+ vm.setInitialType();
+
+ vm.$nextTick(() => {
+ expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({
+ name: fileName,
+ key: 'gitlab_ci_ymls',
+ });
+
+ done();
+ });
+ });
+});
diff --git a/spec/javascripts/ide/components/file_templates/dropdown_spec.js b/spec/javascripts/ide/components/file_templates/dropdown_spec.js
new file mode 100644
index 00000000000..898796f4fa0
--- /dev/null
+++ b/spec/javascripts/ide/components/file_templates/dropdown_spec.js
@@ -0,0 +1,201 @@
+import $ from 'jquery';
+import Vue from 'vue';
+import { createStore } from '~/ide/stores';
+import Dropdown from '~/ide/components/file_templates/dropdown.vue';
+import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import { resetStore } from '../../helpers';
+
+describe('IDE file templates dropdown component', () => {
+ let Component;
+ let vm;
+
+ beforeAll(() => {
+ Component = Vue.extend(Dropdown);
+ });
+
+ beforeEach(() => {
+ const store = createStore();
+
+ vm = createComponentWithStore(Component, store, {
+ label: 'Test',
+ }).$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ resetStore(vm.$store);
+ });
+
+ describe('async', () => {
+ beforeEach(() => {
+ vm.isAsyncData = true;
+ });
+
+ it('calls async store method on Bootstrap dropdown event', () => {
+ spyOn(vm, 'fetchTemplateTypes').and.stub();
+
+ $(vm.$el).trigger('show.bs.dropdown');
+
+ expect(vm.fetchTemplateTypes).toHaveBeenCalled();
+ });
+
+ it('renders templates when async', done => {
+ vm.$store.state.fileTemplates.templates = [
+ {
+ name: 'test',
+ },
+ ];
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.dropdown-content').textContent).toContain('test');
+
+ done();
+ });
+ });
+
+ it('renders loading icon when isLoading is true', done => {
+ vm.$store.state.fileTemplates.isLoading = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('searches template data', () => {
+ vm.$store.state.fileTemplates.templates = [
+ {
+ name: 'test',
+ },
+ ];
+ vm.searchable = true;
+ vm.search = 'hello';
+
+ expect(vm.outputData).toEqual([]);
+ });
+
+ it('does not filter data is searchable is false', () => {
+ vm.$store.state.fileTemplates.templates = [
+ {
+ name: 'test',
+ },
+ ];
+ vm.search = 'hello';
+
+ expect(vm.outputData).toEqual([
+ {
+ name: 'test',
+ },
+ ]);
+ });
+
+ it('calls clickItem on click', done => {
+ spyOn(vm, 'clickItem').and.stub();
+
+ vm.$store.state.fileTemplates.templates = [
+ {
+ name: 'test',
+ },
+ ];
+
+ vm.$nextTick(() => {
+ vm.$el.querySelector('.dropdown-content button').click();
+
+ expect(vm.clickItem).toHaveBeenCalledWith({
+ name: 'test',
+ });
+
+ done();
+ });
+ });
+
+ it('renders input when searchable is true', done => {
+ vm.searchable = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.dropdown-input')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('does not render input when searchable is true & showLoading is true', done => {
+ vm.searchable = true;
+ vm.$store.state.fileTemplates.isLoading = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.dropdown-input')).toBe(null);
+
+ done();
+ });
+ });
+ });
+
+ describe('sync', () => {
+ beforeEach(done => {
+ vm.data = [
+ {
+ name: 'test sync',
+ },
+ ];
+
+ vm.$nextTick(done);
+ });
+
+ it('renders props data', () => {
+ expect(vm.$el.querySelector('.dropdown-content').textContent).toContain('test sync');
+ });
+
+ it('renders input when searchable is true', done => {
+ vm.searchable = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.dropdown-input')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('calls clickItem on click', done => {
+ spyOn(vm, 'clickItem').and.stub();
+
+ vm.$nextTick(() => {
+ vm.$el.querySelector('.dropdown-content button').click();
+
+ expect(vm.clickItem).toHaveBeenCalledWith({
+ name: 'test sync',
+ });
+
+ done();
+ });
+ });
+
+ it('searches template data', () => {
+ vm.searchable = true;
+ vm.search = 'hello';
+
+ expect(vm.outputData).toEqual([]);
+ });
+
+ it('does not filter data is searchable is false', () => {
+ vm.search = 'hello';
+
+ expect(vm.outputData).toEqual([
+ {
+ name: 'test sync',
+ },
+ ]);
+ });
+
+ it('renders dropdown title', done => {
+ vm.title = 'Test title';
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.dropdown-title').textContent).toContain('Test title');
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js
index 30cd92b2ca4..d09ccd7ac34 100644
--- a/spec/javascripts/ide/components/repo_commit_section_spec.js
+++ b/spec/javascripts/ide/components/repo_commit_section_spec.js
@@ -111,7 +111,7 @@ describe('RepoCommitSection', () => {
.then(vm.$nextTick)
.then(() => {
expect(vm.$el.querySelector('.ide-commit-list-container').textContent).toContain(
- 'No changes',
+ 'There are no unstaged changes',
);
})
.then(done)
@@ -133,7 +133,7 @@ describe('RepoCommitSection', () => {
});
it('discards a single file', done => {
- vm.$el.querySelector('.multi-file-discard-btn .dropdown-menu button').click();
+ vm.$el.querySelector('.multi-file-commit-list li:first-child .js-modal-primary-action').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1');
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
index c11c482fef8..3ce9c9fcda1 100644
--- a/spec/javascripts/ide/helpers.js
+++ b/spec/javascripts/ide/helpers.js
@@ -5,6 +5,7 @@ import commitState from '~/ide/stores/modules/commit/state';
import mergeRequestsState from '~/ide/stores/modules/merge_requests/state';
import pipelinesState from '~/ide/stores/modules/pipelines/state';
import branchesState from '~/ide/stores/modules/branches/state';
+import fileTemplatesState from '~/ide/stores/modules/file_templates/state';
export const resetStore = store => {
const newState = {
@@ -13,6 +14,7 @@ export const resetStore = store => {
mergeRequests: mergeRequestsState(),
pipelines: pipelinesState(),
branches: branchesState(),
+ fileTemplates: fileTemplatesState(),
};
store.replaceState(newState);
};
diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js
index bca2033ff97..1ca811e996b 100644
--- a/spec/javascripts/ide/stores/actions/file_spec.js
+++ b/spec/javascripts/ide/stores/actions/file_spec.js
@@ -692,21 +692,6 @@ describe('IDE store file actions', () => {
.then(done)
.catch(done.fail);
});
-
- it('calls scrollToTab', done => {
- const scrollToTabSpy = jasmine.createSpy('scrollToTab');
- const oldScrollToTab = store._actions.scrollToTab; // eslint-disable-line
- store._actions.scrollToTab = [scrollToTabSpy]; // eslint-disable-line
-
- store
- .dispatch('openPendingTab', { file: f, keyPrefix: 'pending' })
- .then(() => {
- expect(scrollToTabSpy).toHaveBeenCalled();
- store._actions.scrollToTab = oldScrollToTab; // eslint-disable-line
- })
- .then(done)
- .catch(done.fail);
- });
});
describe('removePendingTab', () => {
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
index d84f1717a61..c9a1158a14e 100644
--- a/spec/javascripts/ide/stores/actions_spec.js
+++ b/spec/javascripts/ide/stores/actions_spec.js
@@ -305,7 +305,11 @@ describe('Multi-file store actions', () => {
describe('stageAllChanges', () => {
it('adds all files from changedFiles to stagedFiles', done => {
- store.state.changedFiles.push(file(), file('new'));
+ const openFile = { ...file(), path: 'test' };
+
+ store.state.openFiles.push(openFile);
+ store.state.stagedFiles.push(openFile);
+ store.state.changedFiles.push(openFile, file('new'));
testAction(
stageAllChanges,
@@ -316,7 +320,12 @@ describe('Multi-file store actions', () => {
{ type: types.STAGE_CHANGE, payload: store.state.changedFiles[0].path },
{ type: types.STAGE_CHANGE, payload: store.state.changedFiles[1].path },
],
- [],
+ [
+ {
+ type: 'openPendingTab',
+ payload: { file: openFile, keyPrefix: 'staged' },
+ },
+ ],
done,
);
});
@@ -324,7 +333,11 @@ describe('Multi-file store actions', () => {
describe('unstageAllChanges', () => {
it('removes all files from stagedFiles after unstaging', done => {
- store.state.stagedFiles.push(file(), file('new'));
+ const openFile = { ...file(), path: 'test' };
+
+ store.state.openFiles.push(openFile);
+ store.state.changedFiles.push(openFile);
+ store.state.stagedFiles.push(openFile, file('new'));
testAction(
unstageAllChanges,
@@ -334,7 +347,12 @@ describe('Multi-file store actions', () => {
{ type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[0].path },
{ type: types.UNSTAGE_CHANGE, payload: store.state.stagedFiles[1].path },
],
- [],
+ [
+ {
+ type: 'openPendingTab',
+ payload: { file: openFile, keyPrefix: 'unstaged' },
+ },
+ ],
done,
);
});
diff --git a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
index f831a9f0a5d..c29dd9f0d06 100644
--- a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
@@ -148,14 +148,66 @@ describe('IDE file templates actions', () => {
});
describe('setSelectedTemplateType', () => {
- it('commits SET_SELECTED_TEMPLATE_TYPE', done => {
- testAction(
- actions.setSelectedTemplateType,
- 'test',
- state,
- [{ type: types.SET_SELECTED_TEMPLATE_TYPE, payload: 'test' }],
- [],
- done,
+ it('commits SET_SELECTED_TEMPLATE_TYPE', () => {
+ const commit = jasmine.createSpy('commit');
+ const options = {
+ commit,
+ dispatch() {},
+ rootGetters: {
+ activeFile: {
+ name: 'test',
+ prevPath: '',
+ },
+ },
+ };
+
+ actions.setSelectedTemplateType(options, { name: 'test' });
+
+ expect(commit).toHaveBeenCalledWith(types.SET_SELECTED_TEMPLATE_TYPE, { name: 'test' });
+ });
+
+ it('dispatches discardFileChanges if prevPath matches templates name', () => {
+ const dispatch = jasmine.createSpy('dispatch');
+ const options = {
+ commit() {},
+ dispatch,
+ rootGetters: {
+ activeFile: {
+ name: 'test',
+ path: 'test',
+ prevPath: 'test',
+ },
+ },
+ };
+
+ actions.setSelectedTemplateType(options, { name: 'test' });
+
+ expect(dispatch).toHaveBeenCalledWith('discardFileChanges', 'test', { root: true });
+ });
+
+ it('dispatches renameEntry if file name doesnt match', () => {
+ const dispatch = jasmine.createSpy('dispatch');
+ const options = {
+ commit() {},
+ dispatch,
+ rootGetters: {
+ activeFile: {
+ name: 'oldtest',
+ path: 'oldtest',
+ prevPath: '',
+ },
+ },
+ };
+
+ actions.setSelectedTemplateType(options, { name: 'test' });
+
+ expect(dispatch).toHaveBeenCalledWith(
+ 'renameEntry',
+ {
+ path: 'oldtest',
+ name: 'test',
+ },
+ { root: true },
);
});
});
@@ -332,5 +384,20 @@ describe('IDE file templates actions', () => {
expect(commit).toHaveBeenCalledWith('SET_UPDATE_SUCCESS', false);
});
+
+ it('dispatches discardFileChanges if file has prevPath', () => {
+ const dispatch = jasmine.createSpy('dispatch');
+ const rootGetters = {
+ activeFile: { path: 'test', prevPath: 'newtest', raw: 'raw content' },
+ };
+
+ actions.undoFileTemplate({ dispatch, commit() {}, rootGetters });
+
+ expect(dispatch.calls.mostRecent().args).toEqual([
+ 'discardFileChanges',
+ 'test',
+ { root: true },
+ ]);
+ });
});
});
diff --git a/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js b/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js
index e337c3f331b..17cb457881f 100644
--- a/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js
+++ b/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js
@@ -1,3 +1,5 @@
+import createState from '~/ide/stores/state';
+import { activityBarViews } from '~/ide/constants';
import * as getters from '~/ide/stores/modules/file_templates/getters';
describe('IDE file templates getters', () => {
@@ -8,22 +10,49 @@ describe('IDE file templates getters', () => {
});
describe('showFileTemplatesBar', () => {
- it('finds template type by name', () => {
+ let rootState;
+
+ beforeEach(() => {
+ rootState = createState();
+ });
+
+ it('returns true if template is found and currentActivityView is edit', () => {
+ rootState.currentActivityView = activityBarViews.edit;
+
+ expect(
+ getters.showFileTemplatesBar(
+ null,
+ {
+ templateTypes: getters.templateTypes(),
+ },
+ rootState,
+ )('LICENSE'),
+ ).toBe(true);
+ });
+
+ it('returns false if template is found and currentActivityView is not edit', () => {
+ rootState.currentActivityView = activityBarViews.commit;
+
expect(
- getters.showFileTemplatesBar(null, {
- templateTypes: getters.templateTypes(),
- })('LICENSE'),
- ).toEqual({
- name: 'LICENSE',
- key: 'licenses',
- });
+ getters.showFileTemplatesBar(
+ null,
+ {
+ templateTypes: getters.templateTypes(),
+ },
+ rootState,
+ )('LICENSE'),
+ ).toBe(false);
});
it('returns undefined if not found', () => {
expect(
- getters.showFileTemplatesBar(null, {
- templateTypes: getters.templateTypes(),
- })('test'),
+ getters.showFileTemplatesBar(
+ null,
+ {
+ templateTypes: getters.templateTypes(),
+ },
+ rootState,
+ )('test'),
).toBe(undefined);
});
});
diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js
index 6ce76aaa03b..41dd3d3c67f 100644
--- a/spec/javascripts/ide/stores/mutations_spec.js
+++ b/spec/javascripts/ide/stores/mutations_spec.js
@@ -339,5 +339,13 @@ describe('Multi-file store mutations', () => {
expect(localState.entries.parentPath.tree.length).toBe(1);
});
+
+ it('adds to openFiles if previously opened', () => {
+ localState.entries.oldPath.opened = true;
+
+ mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
+
+ expect(localState.openFiles).toEqual([localState.entries.newPath]);
+ });
});
});
diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js
index 1d81e4e2d1a..c177d79b9e0 100644
--- a/spec/javascripts/lazy_loader_spec.js
+++ b/spec/javascripts/lazy_loader_spec.js
@@ -2,10 +2,10 @@ import LazyLoader from '~/lazy_loader';
let lazyLoader = null;
-describe('LazyLoader', function () {
+describe('LazyLoader', function() {
preloadFixtures('issues/issue_with_comment.html.raw');
- beforeEach(function () {
+ beforeEach(function() {
loadFixtures('issues/issue_with_comment.html.raw');
lazyLoader = new LazyLoader({
observerNode: 'body',
@@ -13,8 +13,8 @@ describe('LazyLoader', function () {
// Doing everything that happens normally in onload
lazyLoader.loadCheck();
});
- describe('behavior', function () {
- it('should copy value from data-src to src for img 1', function (done) {
+ describe('behavior', function() {
+ it('should copy value from data-src to src for img 1', function(done) {
const img = document.querySelectorAll('img[data-src]')[0];
const originalDataSrc = img.getAttribute('data-src');
img.scrollIntoView();
@@ -26,7 +26,7 @@ describe('LazyLoader', function () {
}, 100);
});
- it('should lazy load dynamically added data-src images', function (done) {
+ it('should lazy load dynamically added data-src images', function(done) {
const newImg = document.createElement('img');
const testPath = '/img/testimg.png';
newImg.className = 'lazy';
@@ -41,7 +41,7 @@ describe('LazyLoader', function () {
}, 100);
});
- it('should not alter normal images', function (done) {
+ it('should not alter normal images', function(done) {
const newImg = document.createElement('img');
const testPath = '/img/testimg.png';
newImg.setAttribute('src', testPath);
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index babad296f09..28151c7e658 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -29,24 +29,46 @@ describe('common_utils', () => {
});
});
- describe('getUrlParamsArray', () => {
- it('should return params array', () => {
- expect(commonUtils.getUrlParamsArray() instanceof Array).toBe(true);
+ describe('urlParamsToArray', () => {
+ it('returns empty array for empty querystring', () => {
+ expect(commonUtils.urlParamsToArray('')).toEqual([]);
+ });
+
+ it('should decode params', () => {
+ expect(
+ commonUtils.urlParamsToArray('?label_name%5B%5D=test')[0],
+ ).toBe('label_name[]=test');
});
it('should remove the question mark from the search params', () => {
- const paramsArray = commonUtils.getUrlParamsArray();
+ const paramsArray = commonUtils.urlParamsToArray('?test=thing');
expect(paramsArray[0][0] !== '?').toBe(true);
});
+ });
- it('should decode params', () => {
- window.history.pushState('', '', '?label_name%5B%5D=test');
+ describe('urlParamsToObject', () => {
+ it('parses path for label with trailing +', () => {
+ expect(
+ commonUtils.urlParamsToObject('label_name[]=label%2B', {}),
+ ).toEqual({
+ label_name: ['label+'],
+ });
+ });
+ it('parses path for milestone with trailing +', () => {
expect(
- commonUtils.getUrlParamsArray()[0],
- ).toBe('label_name[]=test');
+ commonUtils.urlParamsToObject('milestone_title=A%2B', {}),
+ ).toEqual({
+ milestone_title: 'A+',
+ });
+ });
- window.history.pushState('', '', '?');
+ it('parses path for search terms with spaces', () => {
+ expect(
+ commonUtils.urlParamsToObject('search=two+words', {}),
+ ).toEqual({
+ search: 'two words',
+ });
});
});
diff --git a/spec/javascripts/lib/utils/mock_data.js b/spec/javascripts/lib/utils/mock_data.js
index fd0d62b751f..93d0d6259b9 100644
--- a/spec/javascripts/lib/utils/mock_data.js
+++ b/spec/javascripts/lib/utils/mock_data.js
@@ -2,4 +2,4 @@ export const faviconDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACA
export const overlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA85JREFUWAntVllIVGEUPv/9b46O41KplYN7PeRkti8TjQlhCUGh3MmeQugpIsGKAi2soIcIooiohxYKK2daqDAlIpIiWwxtQaJcaHE0d5tMrbn37z9XRqfR0TvVW56Hudf//uec72zfEWBCJjIwkYGJDPzvGSD/KgExN3Oi2Q+2DJgSDYQEMwItVGH1iZGmJw/Si1y+/PwVAMYYib22MYc/8hVQFgKDEfYoId0KYzagAQebsos/ewMZoeB9wdffcTYpQSaCTWHKoqSQaDk7zkIt0+aCUR8BelEHrf3dUNv9AcqbnsHtT5UKB/hTASh0SLYjnjb/CIDRJi0XiFAaJOpCD8zLpdb4NB66b1OfelthX815dtdRRfiti2aAXLvVLiMQ6olGyztGDkSo4JGGXk8/QFdGpYzpHG2GBQTDhtgVhPEaVbbVpvI6GJz22rv4TcAfrYI1x7Rj5MWWAppomKFVVb2302SFzUkZHAbkG+0b1+Gh77yNYjrmqnWTrLBLRxdvBWv8qlFujH/kYjJYyvLkj71t78zAUvzMAMnHhpN4zf9UREJhd8omyssxu1IgazQDwDnHUcNuH6vhPIE1fmuBzHt74Hn7W89jWGtcAjoaIDOFrdcMYJBkgOCoaRF0Lj0oglddDbCj6tRvKjphEpgjkzEQs2YAKsNxMzjn3nKurhzK+Ly7xe28ua8TwgMMcHJZnvvT0BPtEEKM4tDJ+C8GvIIk4ylINIXVZ0EUKJxYuh3mhCeokbudl6TtVc88dfBdLwbyaWB6zQCYQJpBYSrDGQxBQ/ZWRM2B+VNmQnVnHWx7elyNuL2/R336co7KyJR8CL9oLgEuFlREevWUkEl6uGwpVEG4FBm0OEf9N10NMgPlvWYAuNVwsWDKvcUNYsHUWTCZ13ysyFEXe6TO6aC8CUr9IiK+A05TQrc8yjwmxARHeeMAPlfQJw+AQRwu0YhL/GDXi9NwufG+S8dYkuYMqIb4SsWthotlNMOUCOM6r+G9cqXxPmd1dqrBav/o1zJy2l5/NUjJA/VORwYuFnOUaTQcPs9wMqwV++Xv8oADxKAcZ8nLPr8AoGW+xR6HSqYk3GodAz2QNj0V+Gr26dT9ASNH5239Pf0gktVNWZca8ZvfAFBprWS6hSu1pqt++Y0PD+WIwDAhIWQGtzvSHDbcodfFUFB9hg1Gjs5LXqIdFL+acFBl+FddqYwdxsWC3I70OvgfUaA65zhq2O2c8VxYcyIGFTVlXegYtvCXANCQZJMobjVcLMjtSK/IcEgyOOe8Ve5w7ryKDefp2P3+C/5ohv8HZmVLAAAAAElFTkSuQmCC';
-export const faviconWithOverlayDataUrl = 'data:image/png;base64,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';
+export const faviconWithOverlayDataUrl = 'data:image/png;base64,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';
diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js
index d60485b1308..ac3270baef5 100644
--- a/spec/javascripts/lib/utils/text_utility_spec.js
+++ b/spec/javascripts/lib/utils/text_utility_spec.js
@@ -63,6 +63,12 @@ describe('text_utility', () => {
});
});
+ describe('slugifyWithHyphens', () => {
+ it('should replaces whitespaces with hyphens and convert to lower case', () => {
+ expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string');
+ });
+ });
+
describe('stripHtml', () => {
it('replaces html tag with the default replacement', () => {
expect(textUtils.stripHtml('This is a text with <p>html</p>.')).toEqual(
diff --git a/spec/javascripts/monitoring/graph/flag_spec.js b/spec/javascripts/monitoring/graph/flag_spec.js
index 19278312b6d..a837b71db0b 100644
--- a/spec/javascripts/monitoring/graph/flag_spec.js
+++ b/spec/javascripts/monitoring/graph/flag_spec.js
@@ -35,7 +35,7 @@ const defaultValuesComponent = {
unitOfDisplay: 'ms',
currentDataIndex: 0,
legendTitle: 'Average',
- currentCoordinates: [],
+ currentCoordinates: {},
};
const deploymentFlagData = {
diff --git a/spec/javascripts/monitoring/graph_spec.js b/spec/javascripts/monitoring/graph_spec.js
index a46a387a534..990619b4109 100644
--- a/spec/javascripts/monitoring/graph_spec.js
+++ b/spec/javascripts/monitoring/graph_spec.js
@@ -113,6 +113,9 @@ describe('Graph', () => {
projectPath,
});
+ // simulate moving mouse over data series
+ component.seriesUnderMouse = component.timeSeries;
+
component.positionFlag();
expect(component.currentData).toBe(component.timeSeries[0].values[10]);
});
diff --git a/spec/javascripts/notes/components/note_actions_spec.js b/spec/javascripts/notes/components/note_actions_spec.js
index 52cc42cb53d..d7298cb3483 100644
--- a/spec/javascripts/notes/components/note_actions_spec.js
+++ b/spec/javascripts/notes/components/note_actions_spec.js
@@ -28,7 +28,7 @@ describe('issue_note_actions component', () => {
canEdit: true,
canAwardEmoji: true,
canReportAsAbuse: true,
- noteId: 539,
+ noteId: '539',
noteUrl: 'https://localhost:3000/group/project/merge_requests/1#note_1',
reportAbusePath:
'/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26',
@@ -59,6 +59,20 @@ describe('issue_note_actions component', () => {
expect(vm.$el.querySelector(`a[href="${props.reportAbusePath}"]`)).toBeDefined();
});
+ it('should be possible to copy link to a note', () => {
+ expect(vm.$el.querySelector('.js-btn-copy-note-link')).not.toBeNull();
+ });
+
+ it('should not show copy link action when `noteUrl` prop is empty', done => {
+ vm.noteUrl = '';
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.js-btn-copy-note-link')).toBeNull();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
it('should be possible to delete comment', () => {
expect(vm.$el.querySelector('.js-note-delete')).toBeDefined();
});
@@ -77,7 +91,7 @@ describe('issue_note_actions component', () => {
canEdit: false,
canAwardEmoji: false,
canReportAsAbuse: false,
- noteId: 539,
+ noteId: '539',
noteUrl: 'https://localhost:3000/group/project/merge_requests/1#note_1',
reportAbusePath:
'/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26',
diff --git a/spec/javascripts/notes/components/note_awards_list_spec.js b/spec/javascripts/notes/components/note_awards_list_spec.js
index 9d98ba219da..6a6a810acff 100644
--- a/spec/javascripts/notes/components/note_awards_list_spec.js
+++ b/spec/javascripts/notes/components/note_awards_list_spec.js
@@ -30,7 +30,7 @@ describe('note_awards_list component', () => {
propsData: {
awards: awardsMock,
noteAuthorId: 2,
- noteId: 545,
+ noteId: '545',
canAwardEmoji: true,
toggleAwardPath: '/gitlab-org/gitlab-ce/notes/545/toggle_award_emoji',
},
@@ -70,7 +70,7 @@ describe('note_awards_list component', () => {
propsData: {
awards: awardsMock,
noteAuthorId: 2,
- noteId: 545,
+ noteId: '545',
canAwardEmoji: false,
toggleAwardPath: '/gitlab-org/gitlab-ce/notes/545/toggle_award_emoji',
},
diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js
index 95d400ab3df..147ffcf1b81 100644
--- a/spec/javascripts/notes/components/note_form_spec.js
+++ b/spec/javascripts/notes/components/note_form_spec.js
@@ -19,7 +19,7 @@ describe('issue_note_form component', () => {
props = {
isEditing: false,
noteBody: 'Magni suscipit eius consectetur enim et ex et commodi.',
- noteId: 545,
+ noteId: '545',
};
vm = new Component({
@@ -32,6 +32,22 @@ describe('issue_note_form component', () => {
vm.$destroy();
});
+ describe('noteHash', () => {
+ it('returns note hash string based on `noteId`', () => {
+ expect(vm.noteHash).toBe(`#note_${props.noteId}`);
+ });
+
+ it('return note hash as `#` when `noteId` is empty', done => {
+ vm.noteId = '';
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.noteHash).toBe('#');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
describe('conflicts editing', () => {
it('should show conflict message if note changes outside the component', done => {
vm.isEditing = true;
diff --git a/spec/javascripts/notes/components/note_header_spec.js b/spec/javascripts/notes/components/note_header_spec.js
index a3c6bf78988..379780f43a0 100644
--- a/spec/javascripts/notes/components/note_header_spec.js
+++ b/spec/javascripts/notes/components/note_header_spec.js
@@ -33,7 +33,7 @@ describe('note_header component', () => {
},
createdAt: '2017-08-02T10:51:58.559Z',
includeToggle: false,
- noteId: 1394,
+ noteId: '1394',
expanded: true,
},
}).$mount();
@@ -47,6 +47,16 @@ describe('note_header component', () => {
it('should render timestamp link', () => {
expect(vm.$el.querySelector('a[href="#note_1394"]')).toBeDefined();
});
+
+ it('should not render user information when prop `author` is empty object', done => {
+ vm.author = {};
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.note-header-author-name')).toBeNull();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
});
describe('discussion', () => {
@@ -66,7 +76,7 @@ describe('note_header component', () => {
},
createdAt: '2017-08-02T10:51:58.559Z',
includeToggle: true,
- noteId: 1395,
+ noteId: '1395',
expanded: true,
},
}).$mount();
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index 0423fcb6ec4..1f030e5af28 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -66,7 +66,7 @@ export const individualNote = {
individual_note: true,
notes: [
{
- id: 1390,
+ id: '1390',
attachment: {
url: null,
filename: null,
@@ -111,7 +111,7 @@ export const individualNote = {
};
export const note = {
- id: 546,
+ id: '546',
attachment: {
url: null,
filename: null,
@@ -174,7 +174,7 @@ export const discussionMock = {
expanded: true,
notes: [
{
- id: 1395,
+ id: '1395',
attachment: {
url: null,
filename: null,
@@ -211,7 +211,7 @@ export const discussionMock = {
path: '/gitlab-org/gitlab-ce/notes/1395',
},
{
- id: 1396,
+ id: '1396',
attachment: {
url: null,
filename: null,
@@ -257,7 +257,7 @@ export const discussionMock = {
path: '/gitlab-org/gitlab-ce/notes/1396',
},
{
- id: 1437,
+ id: '1437',
attachment: {
url: null,
filename: null,
@@ -308,7 +308,7 @@ export const discussionMock = {
};
export const loggedOutnoteableData = {
- id: 98,
+ id: '98',
iid: 26,
author_id: 1,
description: '',
@@ -358,7 +358,7 @@ export const collapseNotesMock = [
individual_note: true,
notes: [
{
- id: 1390,
+ id: '1390',
attachment: null,
author: {
id: 1,
@@ -393,7 +393,7 @@ export const collapseNotesMock = [
individual_note: true,
notes: [
{
- id: 1391,
+ id: '1391',
attachment: null,
author: {
id: 1,
@@ -433,7 +433,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = {
expanded: true,
notes: [
{
- id: 1390,
+ id: '1390',
attachment: {
url: null,
filename: null,
@@ -495,7 +495,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = {
expanded: true,
notes: [
{
- id: 1391,
+ id: '1391',
attachment: {
url: null,
filename: null,
@@ -544,7 +544,7 @@ export const INDIVIDUAL_NOTE_RESPONSE_MAP = {
'/gitlab-org/gitlab-ce/notes/1471': {
commands_changes: null,
valid: true,
- id: 1471,
+ id: '1471',
attachment: null,
author: {
id: 1,
@@ -600,7 +600,7 @@ export const DISCUSSION_NOTE_RESPONSE_MAP = {
expanded: true,
notes: [
{
- id: 1471,
+ id: '1471',
attachment: {
url: null,
filename: null,
@@ -671,7 +671,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 901,
+ id: '901',
type: null,
attachment: null,
author: {
@@ -718,7 +718,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 902,
+ id: '902',
type: null,
attachment: null,
author: {
@@ -765,7 +765,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 903,
+ id: '903',
type: null,
attachment: null,
author: {
@@ -809,7 +809,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 904,
+ id: '904',
type: null,
attachment: null,
author: {
@@ -854,7 +854,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 905,
+ id: '905',
type: null,
attachment: null,
author: {
@@ -898,7 +898,7 @@ export const notesWithDescriptionChanges = [
expanded: true,
notes: [
{
- id: 906,
+ id: '906',
type: null,
attachment: null,
author: {
@@ -945,7 +945,7 @@ export const collapsedSystemNotes = [
expanded: true,
notes: [
{
- id: 901,
+ id: '901',
type: null,
attachment: null,
author: {
@@ -992,7 +992,7 @@ export const collapsedSystemNotes = [
expanded: true,
notes: [
{
- id: 902,
+ id: '902',
type: null,
attachment: null,
author: {
@@ -1039,7 +1039,7 @@ export const collapsedSystemNotes = [
expanded: true,
notes: [
{
- id: 904,
+ id: '904',
type: null,
attachment: null,
author: {
@@ -1084,7 +1084,7 @@ export const collapsedSystemNotes = [
expanded: true,
notes: [
{
- id: 905,
+ id: '905',
type: null,
attachment: null,
author: {
@@ -1129,7 +1129,7 @@ export const collapsedSystemNotes = [
expanded: true,
notes: [
{
- id: 906,
+ id: '906',
type: null,
attachment: null,
author: {
diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js
index 84515d2bf97..dace834a3c8 100644
--- a/spec/javascripts/projects/project_new_spec.js
+++ b/spec/javascripts/projects/project_new_spec.js
@@ -4,12 +4,14 @@ import projectNew from '~/projects/project_new';
describe('New Project', () => {
let $projectImportUrl;
let $projectPath;
+ let $projectName;
beforeEach(() => {
setFixtures(`
<div class='toggle-import-form'>
<div class='import-url-data'>
<input id="project_import_url" />
+ <input id="project_name" />
<input id="project_path" />
</div>
</div>
@@ -17,6 +19,7 @@ describe('New Project', () => {
$projectImportUrl = $('#project_import_url');
$projectPath = $('#project_path');
+ $projectName = $('#project_name');
});
describe('deriveProjectPathFromUrl', () => {
@@ -129,4 +132,31 @@ describe('New Project', () => {
});
});
});
+
+ describe('deriveSlugFromProjectName', () => {
+ beforeEach(() => {
+ projectNew.bindEvents();
+ $projectName.val('').keyup();
+ });
+
+ it('converts project name to lower case and dash-limited slug', () => {
+ const dummyProjectName = 'My Awesome Project';
+
+ $projectName.val(dummyProjectName);
+
+ projectNew.onProjectNameChange($projectName, $projectPath);
+
+ expect($projectPath.val()).toEqual('my-awesome-project');
+ });
+
+ it('does not add additional dashes in the slug if the project name already contains dashes', () => {
+ const dummyProjectName = 'My-Dash-Delimited Awesome Project';
+
+ $projectName.val(dummyProjectName);
+
+ projectNew.onProjectNameChange($projectName, $projectPath);
+
+ expect($projectPath.val()).toEqual('my-dash-delimited-awesome-project');
+ });
+ });
});
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 4452c470b82..b89d10cb993 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -1,6 +1,7 @@
/* eslint-disable
jasmine/no-global-setup, jasmine/no-unsafe-spy, no-underscore-dangle, no-console
*/
+/* global __karma__ */
import $ from 'jquery';
import 'vendor/jasmine-jquery';
@@ -41,8 +42,8 @@ jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH;
beforeAll(() => {
jasmine.addMatchers(
jasmineDiff(jasmine, {
- colors: true,
- inline: true,
+ colors: !__karma__.config.isCi,
+ inline: !__karma__.config.isCi,
}),
);
jasmine.addMatchers(customMatchers);
diff --git a/spec/javascripts/vue_shared/components/file_icon_spec.js b/spec/javascripts/vue_shared/components/file_icon_spec.js
index 1c666fc6c55..f2a09d08829 100644
--- a/spec/javascripts/vue_shared/components/file_icon_spec.js
+++ b/spec/javascripts/vue_shared/components/file_icon_spec.js
@@ -62,9 +62,11 @@ describe('File Icon component', () => {
loading: true,
});
- expect(
- vm.$el.querySelector('i').getAttribute('class'),
- ).toEqual('fa fa-spin fa-spinner fa-1x');
+ const { classList } = vm.$el.querySelector('i');
+ expect(classList.contains('fa')).toEqual(true);
+ expect(classList.contains('fa-spin')).toEqual(true);
+ expect(classList.contains('fa-spinner')).toEqual(true);
+ expect(classList.contains('fa-1x')).toEqual(true);
});
it('should add a special class and a size class', () => {
diff --git a/spec/javascripts/vue_shared/components/loading_icon_spec.js b/spec/javascripts/vue_shared/components/loading_icon_spec.js
deleted file mode 100644
index 5cd3466f501..00000000000
--- a/spec/javascripts/vue_shared/components/loading_icon_spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import Vue from 'vue';
-import loadingIcon from '~/vue_shared/components/loading_icon.vue';
-
-describe('Loading Icon Component', () => {
- let LoadingIconComponent;
-
- beforeEach(() => {
- LoadingIconComponent = Vue.extend(loadingIcon);
- });
-
- it('should render a spinner font awesome icon', () => {
- const component = new LoadingIconComponent().$mount();
-
- expect(
- component.$el.querySelector('i').getAttribute('class'),
- ).toEqual('fa fa-spin fa-spinner fa-1x');
-
- expect(component.$el.tagName).toEqual('DIV');
- expect(component.$el.classList).toContain('text-center');
- expect(component.$el.classList).toContain('loading-container');
- });
-
- it('should render accessibility attributes', () => {
- const component = new LoadingIconComponent().$mount();
-
- const icon = component.$el.querySelector('i');
- expect(icon.getAttribute('aria-hidden')).toEqual('true');
- expect(icon.getAttribute('aria-label')).toEqual('Loading');
- });
-
- it('should render the provided label', () => {
- const component = new LoadingIconComponent({
- propsData: {
- label: 'This is a loading icon',
- },
- }).$mount();
-
- expect(
- component.$el.querySelector('i').getAttribute('aria-label'),
- ).toEqual('This is a loading icon');
- });
-
- it('should render the provided size', () => {
- const component = new LoadingIconComponent({
- propsData: {
- size: '2',
- },
- }).$mount();
-
- expect(
- component.$el.querySelector('i').classList.contains('fa-2x'),
- ).toEqual(true);
- });
-});
diff --git a/spec/javascripts/vue_shared/components/notes/system_note_spec.js b/spec/javascripts/vue_shared/components/notes/system_note_spec.js
index 2a6015fe35f..adcb1c858aa 100644
--- a/spec/javascripts/vue_shared/components/notes/system_note_spec.js
+++ b/spec/javascripts/vue_shared/components/notes/system_note_spec.js
@@ -9,7 +9,7 @@ describe('system note component', () => {
beforeEach(() => {
props = {
note: {
- id: 1424,
+ id: '1424',
author: {
id: 1,
name: 'Root',
diff --git a/spec/javascripts/vue_shared/components/pagination_links_spec.js b/spec/javascripts/vue_shared/components/pagination_links_spec.js
new file mode 100644
index 00000000000..c9d183872b4
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/pagination_links_spec.js
@@ -0,0 +1,72 @@
+import Vue from 'vue';
+import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
+import { s__ } from '~/locale';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Pagination links component', () => {
+ const paginationLinksComponent = Vue.extend(PaginationLinks);
+ const change = page => page;
+ const pageInfo = {
+ page: 3,
+ perPage: 5,
+ total: 30,
+ };
+ const translations = {
+ firstText: s__('Pagination|« First'),
+ prevText: s__('Pagination|Prev'),
+ nextText: s__('Pagination|Next'),
+ lastText: s__('Pagination|Last »'),
+ };
+
+ let paginationLinks;
+ let glPagination;
+ let destinationComponent;
+
+ beforeEach(() => {
+ paginationLinks = mountComponent(
+ paginationLinksComponent,
+ {
+ change,
+ pageInfo,
+ },
+ );
+ [glPagination] = paginationLinks.$children;
+ [destinationComponent] = glPagination.$children;
+ });
+
+ afterEach(() => {
+ paginationLinks.$destroy();
+ });
+
+ it('should provide translated text to GitLab UI pagination', () => {
+ Object.entries(translations).forEach(entry =>
+ expect(
+ destinationComponent[entry[0]],
+ ).toBe(entry[1]),
+ );
+ });
+
+ it('should pass change to GitLab UI pagination', () => {
+ expect(
+ Object.is(glPagination.change, change),
+ ).toBe(true);
+ });
+
+ it('should pass page from pageInfo to GitLab UI pagination', () => {
+ expect(
+ destinationComponent.value,
+ ).toBe(pageInfo.page);
+ });
+
+ it('should pass per page from pageInfo to GitLab UI pagination', () => {
+ expect(
+ destinationComponent.perPage,
+ ).toBe(pageInfo.perPage);
+ });
+
+ it('should pass total items from pageInfo to GitLab UI pagination', () => {
+ expect(
+ destinationComponent.totalRows,
+ ).toBe(pageInfo.total);
+ });
+});