Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/avatar_helper_spec.js98
-rw-r--r--spec/javascripts/boards/issue_card_spec.js154
-rw-r--r--spec/javascripts/fixtures/search_autocomplete.html.haml6
-rw-r--r--spec/javascripts/ide/components/new_dropdown/index_spec.js6
-rw-r--r--spec/javascripts/ide/components/new_dropdown/modal_spec.js47
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js57
-rw-r--r--spec/javascripts/ide/stores/modules/commit/actions_spec.js6
-rw-r--r--spec/javascripts/ide/stores/mutations_spec.js100
-rw-r--r--spec/javascripts/ide/stores/utils_spec.js39
-rw-r--r--spec/javascripts/lib/utils/text_utility_spec.js17
-rw-r--r--spec/javascripts/pipelines/pipeline_url_spec.js26
-rw-r--r--spec/javascripts/reports/components/grouped_test_reports_app_spec.js163
-rw-r--r--spec/javascripts/reports/components/modal_spec.js45
-rw-r--r--spec/javascripts/reports/components/test_issue_body_spec.js71
-rw-r--r--spec/javascripts/reports/mock_data/mock_data.js8
-rw-r--r--spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json1
-rw-r--r--spec/javascripts/reports/mock_data/new_failures_report.json1
-rw-r--r--spec/javascripts/reports/mock_data/no_failures_report.json1
-rw-r--r--spec/javascripts/reports/store/actions_spec.js49
-rw-r--r--spec/javascripts/reports/store/mutations_spec.js31
-rw-r--r--spec/javascripts/reports/store/utils_spec.js138
-rw-r--r--spec/javascripts/test_bundle.js2
-rw-r--r--spec/javascripts/vue_shared/components/code_block_spec.js33
-rw-r--r--spec/javascripts/vue_shared/components/gl_modal_spec.js34
-rw-r--r--spec/javascripts/vue_shared/components/identicon_spec.js17
-rw-r--r--spec/javascripts/vue_shared/components/notes/placeholder_note_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js30
27 files changed, 1008 insertions, 174 deletions
diff --git a/spec/javascripts/avatar_helper_spec.js b/spec/javascripts/avatar_helper_spec.js
new file mode 100644
index 00000000000..b2f80678ae7
--- /dev/null
+++ b/spec/javascripts/avatar_helper_spec.js
@@ -0,0 +1,98 @@
+import { TEST_HOST } from 'spec/test_constants';
+import { getFirstCharacterCapitalized } from '~/lib/utils/text_utility';
+import {
+ DEFAULT_SIZE_CLASS,
+ IDENTICON_BG_COUNT,
+ renderAvatar,
+ renderIdenticon,
+ getIdenticonBackgroundClass,
+ getIdenticonTitle,
+} from '~/helpers/avatar_helper';
+
+function matchAll(str) {
+ return new RegExp(`^${str}$`);
+}
+
+describe('avatar_helper', () => {
+ describe('getIdenticonBackgroundClass', () => {
+ it('returns identicon bg class from id', () => {
+ expect(getIdenticonBackgroundClass(1)).toEqual('bg2');
+ });
+
+ it(`wraps around if id is bigger than ${IDENTICON_BG_COUNT}`, () => {
+ expect(getIdenticonBackgroundClass(IDENTICON_BG_COUNT + 4)).toEqual('bg5');
+ expect(getIdenticonBackgroundClass((IDENTICON_BG_COUNT * 5) + 6)).toEqual('bg7');
+ });
+ });
+
+ describe('getIdenticonTitle', () => {
+ it('returns identicon title from name', () => {
+ expect(getIdenticonTitle('Lorem')).toEqual('L');
+ expect(getIdenticonTitle('dolar-sit-amit')).toEqual('D');
+ expect(getIdenticonTitle('%-with-special-chars')).toEqual('%');
+ });
+
+ it('returns space if name is falsey', () => {
+ expect(getIdenticonTitle('')).toEqual(' ');
+ expect(getIdenticonTitle(null)).toEqual(' ');
+ });
+ });
+
+ describe('renderIdenticon', () => {
+ it('renders with the first letter as title and bg based on id', () => {
+ const entity = {
+ id: IDENTICON_BG_COUNT + 3,
+ name: 'Xavior',
+ };
+ const options = {
+ sizeClass: 's32',
+ };
+
+ const result = renderIdenticon(entity, options);
+
+ expect(result).toHaveClass(`identicon ${options.sizeClass} bg4`);
+ expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
+ });
+
+ it('renders with defaults, if no options are given', () => {
+ const entity = {
+ id: 1,
+ name: 'tanuki',
+ };
+
+ const result = renderIdenticon(entity);
+
+ expect(result).toHaveClass(`identicon ${DEFAULT_SIZE_CLASS} bg2`);
+ expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
+ });
+ });
+
+ describe('renderAvatar', () => {
+ it('renders an image with the avatarUrl', () => {
+ const avatarUrl = `${TEST_HOST}/not-real-assets/test.png`;
+
+ const result = renderAvatar({
+ avatar_url: avatarUrl,
+ });
+
+ expect(result).toBeMatchedBy('img');
+ expect(result).toHaveAttr('src', avatarUrl);
+ expect(result).toHaveClass(DEFAULT_SIZE_CLASS);
+ });
+
+ it('renders an identicon if no avatarUrl', () => {
+ const entity = {
+ id: 1,
+ name: 'walrus',
+ };
+ const options = {
+ sizeClass: 's16',
+ };
+
+ const result = renderAvatar(entity, options);
+
+ expect(result).toHaveClass(`identicon ${options.sizeClass} bg2`);
+ expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
+ });
+ });
+});
diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js
index 7a32e84bced..b6c61e7bad7 100644
--- a/spec/javascripts/boards/issue_card_spec.js
+++ b/spec/javascripts/boards/issue_card_spec.js
@@ -69,109 +69,100 @@ describe('Issue card component', () => {
});
it('renders issue title', () => {
- expect(
- component.$el.querySelector('.board-card-title').textContent,
- ).toContain(issue.title);
+ expect(component.$el.querySelector('.board-card-title').textContent).toContain(issue.title);
});
it('includes issue base in link', () => {
- expect(
- component.$el.querySelector('.board-card-title a').getAttribute('href'),
- ).toContain('/test');
+ expect(component.$el.querySelector('.board-card-title a').getAttribute('href')).toContain(
+ '/test',
+ );
});
it('includes issue title on link', () => {
- expect(
- component.$el.querySelector('.board-card-title a').getAttribute('title'),
- ).toBe(issue.title);
+ expect(component.$el.querySelector('.board-card-title a').getAttribute('title')).toBe(
+ issue.title,
+ );
});
it('does not render confidential icon', () => {
- expect(
- component.$el.querySelector('.fa-eye-flash'),
- ).toBeNull();
+ expect(component.$el.querySelector('.fa-eye-flash')).toBeNull();
});
- it('renders confidential icon', (done) => {
+ it('renders confidential icon', done => {
component.issue.confidential = true;
Vue.nextTick(() => {
- expect(
- component.$el.querySelector('.confidential-icon'),
- ).not.toBeNull();
+ expect(component.$el.querySelector('.confidential-icon')).not.toBeNull();
done();
});
});
it('renders issue ID with #', () => {
- expect(
- component.$el.querySelector('.board-card-number').textContent,
- ).toContain(`#${issue.id}`);
+ expect(component.$el.querySelector('.board-card-number').textContent).toContain(`#${issue.id}`);
});
describe('assignee', () => {
it('does not render assignee', () => {
- expect(
- component.$el.querySelector('.board-card-assignee .avatar'),
- ).toBeNull();
+ expect(component.$el.querySelector('.board-card-assignee .avatar')).toBeNull();
});
describe('exists', () => {
- beforeEach((done) => {
+ beforeEach(done => {
component.issue.assignees = [user];
Vue.nextTick(() => done());
});
it('renders assignee', () => {
- expect(
- component.$el.querySelector('.board-card-assignee .avatar'),
- ).not.toBeNull();
+ expect(component.$el.querySelector('.board-card-assignee .avatar')).not.toBeNull();
});
it('sets title', () => {
expect(
- component.$el.querySelector('.board-card-assignee img').getAttribute('data-original-title'),
+ component.$el
+ .querySelector('.board-card-assignee img')
+ .getAttribute('data-original-title'),
).toContain(`Assigned to ${user.name}`);
});
it('sets users path', () => {
- expect(
- component.$el.querySelector('.board-card-assignee a').getAttribute('href'),
- ).toBe('/test');
+ expect(component.$el.querySelector('.board-card-assignee a').getAttribute('href')).toBe(
+ '/test',
+ );
});
it('renders avatar', () => {
- expect(
- component.$el.querySelector('.board-card-assignee img'),
- ).not.toBeNull();
+ expect(component.$el.querySelector('.board-card-assignee img')).not.toBeNull();
});
});
describe('assignee default avatar', () => {
- beforeEach((done) => {
- component.issue.assignees = [new ListAssignee({
- id: 1,
- name: 'testing 123',
- username: 'test',
- }, 'default_avatar')];
+ beforeEach(done => {
+ component.issue.assignees = [
+ new ListAssignee(
+ {
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ },
+ 'default_avatar',
+ ),
+ ];
Vue.nextTick(done);
});
it('displays defaults avatar if users avatar is null', () => {
- expect(
- component.$el.querySelector('.board-card-assignee img'),
- ).not.toBeNull();
- expect(
- component.$el.querySelector('.board-card-assignee img').getAttribute('src'),
- ).toBe('default_avatar');
+ expect(component.$el.querySelector('.board-card-assignee img')).not.toBeNull();
+ expect(component.$el.querySelector('.board-card-assignee img').getAttribute('src')).toBe(
+ 'default_avatar?width=20',
+ );
});
});
});
describe('multiple assignees', () => {
- beforeEach((done) => {
+ beforeEach(done => {
component.issue.assignees = [
user,
new ListAssignee({
@@ -191,7 +182,8 @@ describe('Issue card component', () => {
name: 'user4',
username: 'user4',
avatar: 'test_image',
- })];
+ }),
+ ];
Vue.nextTick(() => done());
});
@@ -201,26 +193,30 @@ describe('Issue card component', () => {
});
describe('more than four assignees', () => {
- beforeEach((done) => {
- component.issue.assignees.push(new ListAssignee({
- id: 5,
- name: 'user5',
- username: 'user5',
- avatar: 'test_image',
- }));
+ beforeEach(done => {
+ component.issue.assignees.push(
+ new ListAssignee({
+ id: 5,
+ name: 'user5',
+ username: 'user5',
+ avatar: 'test_image',
+ }),
+ );
Vue.nextTick(() => done());
});
it('renders more avatar counter', () => {
- expect(component.$el.querySelector('.board-card-assignee .avatar-counter').innerText).toEqual('+2');
+ expect(
+ component.$el.querySelector('.board-card-assignee .avatar-counter').innerText,
+ ).toEqual('+2');
});
it('renders three assignees', () => {
expect(component.$el.querySelectorAll('.board-card-assignee .avatar').length).toEqual(3);
});
- it('renders 99+ avatar counter', (done) => {
+ it('renders 99+ avatar counter', done => {
for (let i = 5; i < 104; i += 1) {
const u = new ListAssignee({
id: i,
@@ -232,7 +228,9 @@ describe('Issue card component', () => {
}
Vue.nextTick(() => {
- expect(component.$el.querySelector('.board-card-assignee .avatar-counter').innerText).toEqual('99+');
+ expect(
+ component.$el.querySelector('.board-card-assignee .avatar-counter').innerText,
+ ).toEqual('99+');
done();
});
});
@@ -240,59 +238,51 @@ describe('Issue card component', () => {
});
describe('labels', () => {
- beforeEach((done) => {
+ beforeEach(done => {
component.issue.addLabel(label1);
Vue.nextTick(() => done());
});
it('renders list label', () => {
- expect(
- component.$el.querySelectorAll('.badge').length,
- ).toBe(2);
+ expect(component.$el.querySelectorAll('.badge').length).toBe(2);
});
it('renders label', () => {
const nodes = [];
- component.$el.querySelectorAll('.badge').forEach((label) => {
+ component.$el.querySelectorAll('.badge').forEach(label => {
nodes.push(label.getAttribute('data-original-title'));
});
- expect(
- nodes.includes(label1.description),
- ).toBe(true);
+ expect(nodes.includes(label1.description)).toBe(true);
});
it('sets label description as title', () => {
- expect(
- component.$el.querySelector('.badge').getAttribute('data-original-title'),
- ).toContain(label1.description);
+ expect(component.$el.querySelector('.badge').getAttribute('data-original-title')).toContain(
+ label1.description,
+ );
});
it('sets background color of button', () => {
const nodes = [];
- component.$el.querySelectorAll('.badge').forEach((label) => {
+ component.$el.querySelectorAll('.badge').forEach(label => {
nodes.push(label.style.backgroundColor);
});
- expect(
- nodes.includes(label1.color),
- ).toBe(true);
+ expect(nodes.includes(label1.color)).toBe(true);
});
- it('does not render label if label does not have an ID', (done) => {
- component.issue.addLabel(new ListLabel({
- title: 'closed',
- }));
+ it('does not render label if label does not have an ID', done => {
+ component.issue.addLabel(
+ new ListLabel({
+ title: 'closed',
+ }),
+ );
Vue.nextTick()
.then(() => {
- expect(
- component.$el.querySelectorAll('.badge').length,
- ).toBe(2);
- expect(
- component.$el.textContent,
- ).not.toContain('closed');
+ expect(component.$el.querySelectorAll('.badge').length).toBe(2);
+ expect(component.$el.textContent).not.toContain('closed');
done();
})
diff --git a/spec/javascripts/fixtures/search_autocomplete.html.haml b/spec/javascripts/fixtures/search_autocomplete.html.haml
index 0421ed2182f..4aa54da9411 100644
--- a/spec/javascripts/fixtures/search_autocomplete.html.haml
+++ b/spec/javascripts/fixtures/search_autocomplete.html.haml
@@ -1,8 +1,6 @@
-.search.search-form.has-location-badge
- %form.navbar-form
+.search.search-form
+ %form.form-inline
.search-input-container
- %div.location-badge
- This project
.search-input-wrap
.dropdown
%input#search.search-input.dropdown-menu-toggle
diff --git a/spec/javascripts/ide/components/new_dropdown/index_spec.js b/spec/javascripts/ide/components/new_dropdown/index_spec.js
index 092c405a70b..8a8cbd2cee4 100644
--- a/spec/javascripts/ide/components/new_dropdown/index_spec.js
+++ b/spec/javascripts/ide/components/new_dropdown/index_spec.js
@@ -62,7 +62,9 @@ describe('new dropdown component', () => {
vm.dropdownOpen = true;
setTimeout(() => {
- expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalled();
+ expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({
+ block: 'nearest',
+ });
done();
});
@@ -73,7 +75,7 @@ describe('new dropdown component', () => {
it('calls delete action', () => {
spyOn(vm, 'deleteEntry');
- vm.$el.querySelectorAll('.dropdown-menu button')[3].click();
+ vm.$el.querySelectorAll('.dropdown-menu button')[4].click();
expect(vm.deleteEntry).toHaveBeenCalledWith('');
});
diff --git a/spec/javascripts/ide/components/new_dropdown/modal_spec.js b/spec/javascripts/ide/components/new_dropdown/modal_spec.js
index 70651535e87..595a2f927e9 100644
--- a/spec/javascripts/ide/components/new_dropdown/modal_spec.js
+++ b/spec/javascripts/ide/components/new_dropdown/modal_spec.js
@@ -15,7 +15,7 @@ describe('new file modal component', () => {
describe(type, () => {
beforeEach(() => {
const store = createStore();
- store.state.newEntryModal = {
+ store.state.entryModal = {
type,
path: '',
};
@@ -45,7 +45,7 @@ describe('new file modal component', () => {
it('$emits create', () => {
spyOn(vm, 'createTempEntry');
- vm.createEntryInStore();
+ vm.submitForm();
expect(vm.createTempEntry).toHaveBeenCalledWith({
name: 'testing',
@@ -55,4 +55,47 @@ describe('new file modal component', () => {
});
});
});
+
+ describe('rename entry', () => {
+ beforeEach(() => {
+ const store = createStore();
+ store.state.entryModal = {
+ type: 'rename',
+ path: '',
+ entry: {
+ name: 'test',
+ type: 'blob',
+ },
+ };
+
+ vm = createComponentWithStore(Component, store).$mount();
+ });
+
+ ['tree', 'blob'].forEach(type => {
+ it(`renders title and button for renaming ${type}`, done => {
+ const text = type === 'tree' ? 'folder' : 'file';
+
+ vm.$store.state.entryModal.entry.type = type;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.modal-title').textContent.trim()).toBe(`Rename ${text}`);
+ expect(vm.$el.querySelector('.btn-success').textContent.trim()).toBe(`Rename ${text}`);
+
+ done();
+ });
+ });
+ });
+
+ describe('entryName', () => {
+ it('returns entries name', () => {
+ expect(vm.entryName).toBe('test');
+ });
+
+ it('updated name', () => {
+ vm.name = 'index.js';
+
+ expect(vm.entryName).toBe('index.js');
+ });
+ });
+ });
});
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
index 792a716565c..d84f1717a61 100644
--- a/spec/javascripts/ide/stores/actions_spec.js
+++ b/spec/javascripts/ide/stores/actions_spec.js
@@ -8,6 +8,7 @@ import actions, {
updateTempFlagForEntry,
setErrorMessage,
deleteEntry,
+ renameEntry,
} from '~/ide/stores/actions';
import store from '~/ide/stores';
import * as types from '~/ide/stores/mutation_types';
@@ -468,7 +469,61 @@ describe('Multi-file store actions', () => {
'path',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'path' }],
- [{ type: 'burstUnusedSeal' }, { type: 'closeFile', payload: store.state.entries.path }],
+ [{ type: 'burstUnusedSeal' }],
+ done,
+ );
+ });
+ });
+
+ describe('renameEntry', () => {
+ it('renames entry', done => {
+ store.state.entries.test = {
+ tree: [],
+ };
+
+ testAction(
+ renameEntry,
+ { path: 'test', name: 'new-name' },
+ store.state,
+ [
+ {
+ type: types.RENAME_ENTRY,
+ payload: { path: 'test', name: 'new-name', entryPath: null },
+ },
+ ],
+ [{ type: 'deleteEntry', payload: 'test' }],
+ done,
+ );
+ });
+
+ it('renames all entries in tree', done => {
+ store.state.entries.test = {
+ type: 'tree',
+ tree: [
+ {
+ path: 'tree-1',
+ },
+ {
+ path: 'tree-2',
+ },
+ ],
+ };
+
+ testAction(
+ renameEntry,
+ { path: 'test', name: 'new-name' },
+ store.state,
+ [
+ {
+ type: types.RENAME_ENTRY,
+ payload: { path: 'test', name: 'new-name', entryPath: null },
+ },
+ ],
+ [
+ { type: 'renameEntry', payload: { path: 'test', name: 'new-name', entryPath: 'tree-1' } },
+ { type: 'renameEntry', payload: { path: 'test', name: 'new-name', entryPath: 'tree-2' } },
+ { type: 'deleteEntry', payload: 'test' },
+ ],
done,
);
});
diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
index 133ad627f34..24a7d76f30b 100644
--- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
@@ -294,9 +294,10 @@ describe('IDE commit module actions', () => {
{
action: 'update',
file_path: jasmine.anything(),
- content: jasmine.anything(),
+ content: undefined,
encoding: jasmine.anything(),
last_commit_id: undefined,
+ previous_path: undefined,
},
],
start_branch: 'master',
@@ -320,9 +321,10 @@ describe('IDE commit module actions', () => {
{
action: 'update',
file_path: jasmine.anything(),
- content: jasmine.anything(),
+ content: undefined,
encoding: jasmine.anything(),
last_commit_id: '123456789',
+ previous_path: undefined,
},
],
start_branch: undefined,
diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js
index 8b5f2d0bdfa..1e836dbc3f9 100644
--- a/spec/javascripts/ide/stores/mutations_spec.js
+++ b/spec/javascripts/ide/stores/mutations_spec.js
@@ -206,6 +206,7 @@ describe('Multi-file store mutations', () => {
it('adds to changedFiles', () => {
localState.entries.filePath = {
deleted: false,
+ type: 'blob',
};
mutations.DELETE_ENTRY(localState, 'filePath');
@@ -213,4 +214,103 @@ describe('Multi-file store mutations', () => {
expect(localState.changedFiles).toEqual([localState.entries.filePath]);
});
});
+
+ describe('UPDATE_FILE_AFTER_COMMIT', () => {
+ it('updates URLs if prevPath is set', () => {
+ const f = {
+ ...file(),
+ path: 'test',
+ prevPath: 'testing-123',
+ rawPath: `${gl.TEST_HOST}/testing-123`,
+ permalink: `${gl.TEST_HOST}/testing-123`,
+ commitsPath: `${gl.TEST_HOST}/testing-123`,
+ blamePath: `${gl.TEST_HOST}/testing-123`,
+ };
+ localState.entries.test = f;
+ localState.changedFiles.push(f);
+
+ mutations.UPDATE_FILE_AFTER_COMMIT(localState, { file: f, lastCommit: { commit: {} } });
+
+ expect(f.rawPath).toBe(`${gl.TEST_HOST}/test`);
+ expect(f.permalink).toBe(`${gl.TEST_HOST}/test`);
+ expect(f.commitsPath).toBe(`${gl.TEST_HOST}/test`);
+ expect(f.blamePath).toBe(`${gl.TEST_HOST}/test`);
+ });
+ });
+
+ describe('OPEN_NEW_ENTRY_MODAL', () => {
+ it('sets entryModal', () => {
+ localState.entries.testPath = {
+ ...file(),
+ };
+
+ mutations.OPEN_NEW_ENTRY_MODAL(localState, { type: 'test', path: 'testPath' });
+
+ expect(localState.entryModal).toEqual({
+ type: 'test',
+ path: 'testPath',
+ entry: localState.entries.testPath,
+ });
+ });
+ });
+
+ describe('RENAME_ENTRY', () => {
+ beforeEach(() => {
+ localState.trees = {
+ 'gitlab-ce/master': { tree: [] },
+ };
+ localState.currentProjectId = 'gitlab-ce';
+ localState.currentBranchId = 'master';
+ localState.entries.oldPath = {
+ ...file(),
+ type: 'blob',
+ name: 'oldPath',
+ path: 'oldPath',
+ url: `${gl.TEST_HOST}/oldPath`,
+ };
+ });
+
+ it('creates new renamed entry', () => {
+ mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
+
+ expect(localState.entries.newPath).toEqual({
+ ...localState.entries.oldPath,
+ id: 'newPath',
+ name: 'newPath',
+ key: 'newPath-blob-name',
+ path: 'newPath',
+ tempFile: true,
+ prevPath: 'oldPath',
+ tree: [],
+ parentPath: '',
+ url: `${gl.TEST_HOST}/newPath`,
+ moved: jasmine.anything(),
+ movedPath: jasmine.anything(),
+ });
+ });
+
+ it('adds new entry to changedFiles', () => {
+ mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
+
+ expect(localState.changedFiles.length).toBe(1);
+ expect(localState.changedFiles[0].path).toBe('newPath');
+ });
+
+ it('sets oldEntry as moved', () => {
+ mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
+
+ expect(localState.entries.oldPath.moved).toBe(true);
+ });
+
+ it('adds to parents tree', () => {
+ localState.entries.oldPath.parentPath = 'parentPath';
+ localState.entries.parentPath = {
+ ...file(),
+ };
+
+ mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
+
+ expect(localState.entries.parentPath.tree.length).toBe(1);
+ });
+ });
});
diff --git a/spec/javascripts/ide/stores/utils_spec.js b/spec/javascripts/ide/stores/utils_spec.js
index 89db50b8874..9f18034f8a3 100644
--- a/spec/javascripts/ide/stores/utils_spec.js
+++ b/spec/javascripts/ide/stores/utils_spec.js
@@ -112,6 +112,7 @@ describe('Multi-file store utils', () => {
content: 'updated file content',
encoding: 'text',
last_commit_id: '123456789',
+ previous_path: undefined,
},
{
action: 'create',
@@ -119,13 +120,15 @@ describe('Multi-file store utils', () => {
content: 'new file content',
encoding: 'base64',
last_commit_id: '123456789',
+ previous_path: undefined,
},
{
action: 'delete',
file_path: 'deletedFile',
- content: '',
+ content: undefined,
encoding: 'text',
last_commit_id: undefined,
+ previous_path: undefined,
},
],
start_branch: undefined,
@@ -172,6 +175,7 @@ describe('Multi-file store utils', () => {
content: 'updated file content',
encoding: 'text',
last_commit_id: '123456789',
+ previous_path: undefined,
},
{
action: 'create',
@@ -179,6 +183,7 @@ describe('Multi-file store utils', () => {
content: 'new file content',
encoding: 'base64',
last_commit_id: '123456789',
+ previous_path: undefined,
},
],
start_branch: undefined,
@@ -195,13 +200,17 @@ describe('Multi-file store utils', () => {
expect(utils.commitActionForFile({ tempFile: true })).toBe('create');
});
+ it('returns move for moved file', () => {
+ expect(utils.commitActionForFile({ prevPath: 'test' })).toBe('move');
+ });
+
it('returns update by default', () => {
expect(utils.commitActionForFile({})).toBe('update');
});
});
describe('getCommitFiles', () => {
- it('returns flattened list of files and folders', () => {
+ it('returns list of files excluding moved files', () => {
const files = [
{
path: 'a',
@@ -209,19 +218,9 @@ describe('Multi-file store utils', () => {
deleted: true,
},
{
- path: 'b',
- type: 'tree',
- deleted: true,
- tree: [
- {
- path: 'c',
- type: 'blob',
- },
- {
- path: 'd',
- type: 'blob',
- },
- ],
+ path: 'c',
+ type: 'blob',
+ moved: true,
},
];
@@ -233,16 +232,6 @@ describe('Multi-file store utils', () => {
type: 'blob',
deleted: true,
},
- {
- path: 'c',
- type: 'blob',
- deleted: true,
- },
- {
- path: 'd',
- type: 'blob',
- deleted: true,
- },
]);
});
});
diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js
index 33987574f00..d60485b1308 100644
--- a/spec/javascripts/lib/utils/text_utility_spec.js
+++ b/spec/javascripts/lib/utils/text_utility_spec.js
@@ -112,4 +112,21 @@ describe('text_utility', () => {
expect(textUtils.splitCamelCase('HelloWorld')).toBe('Hello World');
});
});
+
+ describe('getFirstCharacterCapitalized', () => {
+ it('returns the first character captialized, if first character is alphabetic', () => {
+ expect(textUtils.getFirstCharacterCapitalized('loremIpsumDolar')).toEqual('L');
+ expect(textUtils.getFirstCharacterCapitalized('Sit amit !')).toEqual('S');
+ });
+
+ it('returns the first character, if first character is non-alphabetic', () => {
+ expect(textUtils.getFirstCharacterCapitalized(' lorem')).toEqual(' ');
+ expect(textUtils.getFirstCharacterCapitalized('%#!')).toEqual('%');
+ });
+
+ it('returns an empty string, if string is falsey', () => {
+ expect(textUtils.getFirstCharacterCapitalized('')).toEqual('');
+ expect(textUtils.getFirstCharacterCapitalized(null)).toEqual('');
+ });
+ });
});
diff --git a/spec/javascripts/pipelines/pipeline_url_spec.js b/spec/javascripts/pipelines/pipeline_url_spec.js
index 4a4f2259d23..ddd580ae8b7 100644
--- a/spec/javascripts/pipelines/pipeline_url_spec.js
+++ b/spec/javascripts/pipelines/pipeline_url_spec.js
@@ -35,7 +35,9 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(component.$el.querySelector('.js-pipeline-url-link').getAttribute('href')).toEqual('foo');
+ expect(component.$el.querySelector('.js-pipeline-url-link').getAttribute('href')).toEqual(
+ 'foo',
+ );
expect(component.$el.querySelector('.js-pipeline-url-link span').textContent).toEqual('#1');
});
@@ -61,11 +63,11 @@ describe('Pipeline Url Component', () => {
const image = component.$el.querySelector('.js-pipeline-url-user img');
- expect(
- component.$el.querySelector('.js-pipeline-url-user').getAttribute('href'),
- ).toEqual(mockData.pipeline.user.web_url);
+ expect(component.$el.querySelector('.js-pipeline-url-user').getAttribute('href')).toEqual(
+ mockData.pipeline.user.web_url,
+ );
expect(image.getAttribute('data-original-title')).toEqual(mockData.pipeline.user.name);
- expect(image.getAttribute('src')).toEqual(mockData.pipeline.user.avatar_url);
+ expect(image.getAttribute('src')).toEqual(`${mockData.pipeline.user.avatar_url}?width=20`);
});
it('should render "API" when no user is provided', () => {
@@ -100,7 +102,9 @@ describe('Pipeline Url Component', () => {
}).$mount();
expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest');
- expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain('yaml invalid');
+ expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain(
+ 'yaml invalid',
+ );
expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck');
});
@@ -121,9 +125,9 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(
- component.$el.querySelector('.js-pipeline-url-autodevops').textContent.trim(),
- ).toEqual('Auto DevOps');
+ expect(component.$el.querySelector('.js-pipeline-url-autodevops').textContent.trim()).toEqual(
+ 'Auto DevOps',
+ );
});
it('should render error badge when pipeline has a failure reason set', () => {
@@ -142,6 +146,8 @@ describe('Pipeline Url Component', () => {
}).$mount();
expect(component.$el.querySelector('.js-pipeline-url-failure').textContent).toContain('error');
- expect(component.$el.querySelector('.js-pipeline-url-failure').getAttribute('data-original-title')).toContain('some reason');
+ expect(
+ component.$el.querySelector('.js-pipeline-url-failure').getAttribute('data-original-title'),
+ ).toContain('some reason');
});
});
diff --git a/spec/javascripts/reports/components/grouped_test_reports_app_spec.js b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js
new file mode 100644
index 00000000000..d86e565036c
--- /dev/null
+++ b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js
@@ -0,0 +1,163 @@
+import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import state from '~/reports/store/state';
+import component from '~/reports/components/grouped_test_reports_app.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+import newFailedTestReports from '../mock_data/new_failures_report.json';
+import successTestReports from '../mock_data/no_failures_report.json';
+import mixedResultsTestReports from '../mock_data/new_and_fixed_failures_report.json';
+
+describe('Grouped Test Reports App', () => {
+ let vm;
+ let mock;
+ const Component = Vue.extend(component);
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ vm.$store.replaceState(state());
+ vm.$destroy();
+ mock.restore();
+ });
+
+ describe('with success result', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(200, successTestReports, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders success summary text', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.fa-spinner')).toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary contained no changed test results out of 11 total tests',
+ );
+
+ expect(vm.$el.textContent).toContain(
+ 'rspec:pg found no changed test results out of 8 total tests',
+ );
+ expect(vm.$el.textContent).toContain(
+ 'java ant found no changed test results out of 3 total tests',
+ );
+ done();
+ }, 0);
+ });
+ });
+
+ describe('with 204 result', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(204, {}, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders success summary text', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.fa-spinner')).not.toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary results are being parsed',
+ );
+
+ done();
+ }, 0);
+ });
+ });
+
+ describe('with new failed result', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(200, newFailedTestReports, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders failed summary text + new badge', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.fa-spinner')).toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary contained 2 failed test results out of 11 total tests',
+ );
+
+ expect(vm.$el.textContent).toContain(
+ 'rspec:pg found 2 failed test results out of 8 total tests',
+ );
+ expect(vm.$el.textContent).toContain('New');
+ expect(vm.$el.textContent).toContain(
+ 'java ant found no changed test results out of 3 total tests',
+ );
+ done();
+ }, 0);
+ });
+ });
+
+ describe('with mixed results', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(200, mixedResultsTestReports, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders summary text', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.fa-spinner')).toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary contained 2 failed test results and 2 fixed test results out of 11 total tests',
+ );
+
+ expect(vm.$el.textContent).toContain(
+ 'rspec:pg found 1 failed test result and 2 fixed test results out of 8 total tests',
+ );
+ expect(vm.$el.textContent).toContain('New');
+ expect(vm.$el.textContent).toContain(
+ ' java ant found 1 failed test result out of 3 total tests',
+ );
+ done();
+ }, 0);
+ });
+ });
+
+ describe('with error', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(500, {}, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders loading summary text with loading icon', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary failed loading results',
+ );
+ done();
+ }, 0);
+ });
+ });
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ mock.onGet('test_results.json').reply(200, {}, {});
+ vm = mountComponent(Component, {
+ endpoint: 'test_results.json',
+ });
+ });
+
+ it('renders loading summary text with loading icon', done => {
+ expect(vm.$el.querySelector('.fa-spinner')).not.toBeNull();
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Test summary results are being parsed',
+ );
+
+ setTimeout(() => {
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/spec/javascripts/reports/components/modal_spec.js b/spec/javascripts/reports/components/modal_spec.js
new file mode 100644
index 00000000000..3a567c40eca
--- /dev/null
+++ b/spec/javascripts/reports/components/modal_spec.js
@@ -0,0 +1,45 @@
+import Vue from 'vue';
+import component from '~/reports/components/modal.vue';
+import state from '~/reports/store/state';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+import { trimText } from '../../helpers/vue_component_helper';
+
+describe('Grouped Test Reports Modal', () => {
+ const Component = Vue.extend(component);
+ const modalDataStructure = state().modal.data;
+
+ // populate data
+ modalDataStructure.execution_time.value = 0.009411;
+ modalDataStructure.system_output.value = 'Failure/Error: is_expected.to eq(3)\n\n';
+ modalDataStructure.class.value = 'link';
+
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ title: 'Test#sum when a is 1 and b is 2 returns summary',
+ modalData: modalDataStructure,
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders code block', () => {
+ expect(vm.$el.querySelector('code').textContent).toEqual(modalDataStructure.system_output.value);
+ });
+
+ it('renders link', () => {
+ expect(vm.$el.querySelector('.js-modal-link').getAttribute('href')).toEqual(modalDataStructure.class.value);
+ expect(trimText(vm.$el.querySelector('.js-modal-link').textContent)).toEqual(modalDataStructure.class.value);
+ });
+
+ it('renders miliseconds', () => {
+ expect(vm.$el.textContent).toContain(`${modalDataStructure.execution_time.value} ms`);
+ });
+
+ it('render title', () => {
+ expect(trimText(vm.$el.querySelector('.modal-title').textContent)).toEqual('Test#sum when a is 1 and b is 2 returns summary');
+ });
+});
diff --git a/spec/javascripts/reports/components/test_issue_body_spec.js b/spec/javascripts/reports/components/test_issue_body_spec.js
new file mode 100644
index 00000000000..0ea81f714e7
--- /dev/null
+++ b/spec/javascripts/reports/components/test_issue_body_spec.js
@@ -0,0 +1,71 @@
+import Vue from 'vue';
+import component from '~/reports/components/test_issue_body.vue';
+import createStore from '~/reports/store';
+import { mountComponentWithStore } from '../../helpers/vue_mount_component_helper';
+import { trimText } from '../../helpers/vue_component_helper';
+import { issue } from '../mock_data/mock_data';
+
+describe('Test Issue body', () => {
+ let vm;
+ const Component = Vue.extend(component);
+ const store = createStore();
+
+ const commonProps = {
+ issue,
+ status: 'failed',
+ };
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('on click', () => {
+ it('calls openModal action', () => {
+ vm = mountComponentWithStore(Component, {
+ store,
+ props: commonProps,
+ });
+
+ spyOn(vm, 'openModal');
+
+ vm.$el.querySelector('button').click();
+ expect(vm.openModal).toHaveBeenCalledWith({
+ issue: commonProps.issue,
+ });
+ });
+ });
+
+ describe('is new', () => {
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ store,
+ props: Object.assign({}, commonProps, { isNew: true }),
+ });
+ });
+
+ it('renders issue name', () => {
+ expect(vm.$el.textContent).toContain(commonProps.issue.name);
+ });
+
+ it('renders new badge', () => {
+ expect(trimText(vm.$el.querySelector('.badge').textContent)).toEqual('New');
+ });
+ });
+
+ describe('not new', () => {
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ store,
+ props: commonProps,
+ });
+ });
+
+ it('renders issue name', () => {
+ expect(vm.$el.textContent).toContain(commonProps.issue.name);
+ });
+
+ it('does not renders new badge', () => {
+ expect(vm.$el.querySelector('.badge')).toEqual(null);
+ });
+ });
+});
diff --git a/spec/javascripts/reports/mock_data/mock_data.js b/spec/javascripts/reports/mock_data/mock_data.js
new file mode 100644
index 00000000000..0d90253bad2
--- /dev/null
+++ b/spec/javascripts/reports/mock_data/mock_data.js
@@ -0,0 +1,8 @@
+// eslint-disable-next-line import/prefer-default-export
+export const issue = {
+ result: 'failure',
+ name: 'Test#sum when a is 1 and b is 2 returns summary',
+ execution_time: 0.009411,
+ system_output:
+ "Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in \u003ctop (required)\u003e'",
+};
diff --git a/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json b/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json
new file mode 100644
index 00000000000..ceaf894375a
--- /dev/null
+++ b/spec/javascripts/reports/mock_data/new_and_fixed_failures_report.json
@@ -0,0 +1 @@
+{"status":"failed","summary":{"total":11,"resolved":2,"failed":2},"suites":[{"name":"rspec:pg","status":"failed","summary":{"total":8,"resolved":2,"failed":1},"new_failures":[{"status":"failed","name":"Test#subtract when a is 2 and b is 1 returns correct result","execution_time":0.00908,"system_output":"Failure/Error: is_expected.to eq(1)\n\n expected: 1\n got: 3\n\n (compared using ==)\n./spec/test_spec.rb:43:in `block (4 levels) in <top (required)>'"}],"resolved_failures":[{"status":"success","name":"Test#sum when a is 1 and b is 2 returns summary","execution_time":0.000318,"system_output":null},{"status":"success","name":"Test#sum when a is 100 and b is 200 returns summary","execution_time":0.000074,"system_output":null}],"existing_failures":[]},{"name":"java ant","status":"failed","summary":{"total":3,"resolved":0,"failed":1},"new_failures":[],"resolved_failures":[],"existing_failures":[{"status":"failed","name":"sumTest","execution_time":0.004,"system_output":"junit.framework.AssertionFailedError: expected:<3> but was:<-1>\n\tat CalculatorTest.sumTest(Unknown Source)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"}]}]} \ No newline at end of file
diff --git a/spec/javascripts/reports/mock_data/new_failures_report.json b/spec/javascripts/reports/mock_data/new_failures_report.json
new file mode 100644
index 00000000000..930efe16f65
--- /dev/null
+++ b/spec/javascripts/reports/mock_data/new_failures_report.json
@@ -0,0 +1 @@
+{"summary":{"total":11,"resolved":0,"failed":2},"suites":[{"name":"rspec:pg","summary":{"total":8,"resolved":0,"failed":2},"new_failures":[{"result":"failure","name":"Test#sum when a is 1 and b is 2 returns summary","execution_time":0.009411,"system_output":"Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in <top (required)>'"},{"result":"failure","name":"Test#sum when a is 100 and b is 200 returns summary","execution_time":0.000162,"system_output":"Failure/Error: is_expected.to eq(300)\n\n expected: 300\n got: -100\n\n (compared using ==)\n./spec/test_spec.rb:21:in `block (4 levels) in <top (required)>'"}],"resolved_failures":[],"existing_failures":[]},{"name":"java ant","summary":{"total":3,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]}]} \ No newline at end of file
diff --git a/spec/javascripts/reports/mock_data/no_failures_report.json b/spec/javascripts/reports/mock_data/no_failures_report.json
new file mode 100644
index 00000000000..6c0675ff7dc
--- /dev/null
+++ b/spec/javascripts/reports/mock_data/no_failures_report.json
@@ -0,0 +1 @@
+{"status":"success","summary":{"total":11,"resolved":0,"failed":0},"suites":[{"name":"rspec:pg","status":"success","summary":{"total":8,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]},{"name":"java ant","status":"success","summary":{"total":3,"resolved":0,"failed":0},"new_failures":[],"resolved_failures":[],"existing_failures":[]}]} \ No newline at end of file
diff --git a/spec/javascripts/reports/store/actions_spec.js b/spec/javascripts/reports/store/actions_spec.js
index c714c5af156..41137b50847 100644
--- a/spec/javascripts/reports/store/actions_spec.js
+++ b/spec/javascripts/reports/store/actions_spec.js
@@ -8,6 +8,8 @@ import {
clearEtagPoll,
receiveReportsSuccess,
receiveReportsError,
+ openModal,
+ setModalData,
} from '~/reports/store/actions';
import state from '~/reports/store/state';
import * as types from '~/reports/store/mutation_types';
@@ -56,7 +58,9 @@ describe('Reports Store Actions', () => {
describe('success', () => {
it('dispatches requestReports and receiveReportsSuccess ', done => {
- mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, { summary: {}, suites: [{ name: 'rspec' }] });
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`)
+ .replyOnce(200, { summary: {}, suites: [{ name: 'rspec' }] });
testAction(
fetchReports,
@@ -68,7 +72,7 @@ describe('Reports Store Actions', () => {
type: 'requestReports',
},
{
- payload: { summary: {}, suites: [{ name: 'rspec' }] },
+ payload: { data: { summary: {}, suites: [{ name: 'rspec' }] }, status: 200 },
type: 'receiveReportsSuccess',
},
],
@@ -103,16 +107,27 @@ describe('Reports Store Actions', () => {
});
describe('receiveReportsSuccess', () => {
- it('should commit RECEIVE_REPORTS_SUCCESS mutation', done => {
+ it('should commit RECEIVE_REPORTS_SUCCESS mutation with 200', done => {
testAction(
receiveReportsSuccess,
- { summary: {} },
+ { data: { summary: {} }, status: 200 },
mockedState,
[{ type: types.RECEIVE_REPORTS_SUCCESS, payload: { summary: {} } }],
[],
done,
);
});
+
+ it('should not commit RECEIVE_REPORTS_SUCCESS mutation with 204', done => {
+ testAction(
+ receiveReportsSuccess,
+ { data: { summary: {} }, status: 204 },
+ mockedState,
+ [],
+ [],
+ done,
+ );
+ });
});
describe('receiveReportsError', () => {
@@ -127,4 +142,30 @@ describe('Reports Store Actions', () => {
);
});
});
+
+ describe('openModal', () => {
+ it('should dispatch setModalData', done => {
+ testAction(
+ openModal,
+ { name: 'foo' },
+ mockedState,
+ [],
+ [{ type: 'setModalData', payload: { name: 'foo' } }],
+ done,
+ );
+ });
+ });
+
+ describe('setModalData', () => {
+ it('should commit SET_ISSUE_MODAL_DATA', done => {
+ testAction(
+ setModalData,
+ { name: 'foo' },
+ mockedState,
+ [{ type: types.SET_ISSUE_MODAL_DATA, payload: { name: 'foo' } }],
+ [],
+ done,
+ );
+ });
+ });
});
diff --git a/spec/javascripts/reports/store/mutations_spec.js b/spec/javascripts/reports/store/mutations_spec.js
index 3e0b15438c3..8f99d2675a5 100644
--- a/spec/javascripts/reports/store/mutations_spec.js
+++ b/spec/javascripts/reports/store/mutations_spec.js
@@ -1,6 +1,7 @@
import state from '~/reports/store/state';
import mutations from '~/reports/store/mutations';
import * as types from '~/reports/store/mutation_types';
+import { issue } from '../mock_data/mock_data';
describe('Reports Store Mutations', () => {
let stateCopy;
@@ -42,24 +43,21 @@ describe('Reports Store Mutations', () => {
{
name: 'StringHelper#concatenate when a is git and b is lab returns summary',
execution_time: 0.0092435,
- system_output:
- 'Failure/Error: is_expected.to eq(\'gitlab\')',
+ system_output: "Failure/Error: is_expected.to eq('gitlab')",
},
],
resolved_failures: [
{
name: 'StringHelper#concatenate when a is git and b is lab returns summary',
execution_time: 0.009235,
- system_output:
- 'Failure/Error: is_expected.to eq(\'gitlab\')',
+ system_output: "Failure/Error: is_expected.to eq('gitlab')",
},
],
existing_failures: [
{
name: 'StringHelper#concatenate when a is git and b is lab returns summary',
execution_time: 1232.08,
- system_output:
- 'Failure/Error: is_expected.to eq(\'gitlab\')',
+ system_output: "Failure/Error: is_expected.to eq('gitlab')",
},
],
},
@@ -89,6 +87,7 @@ describe('Reports Store Mutations', () => {
beforeEach(() => {
mutations[types.RECEIVE_REPORTS_ERROR](stateCopy);
});
+
it('should reset isLoading', () => {
expect(stateCopy.isLoading).toEqual(false);
});
@@ -97,5 +96,25 @@ describe('Reports Store Mutations', () => {
expect(stateCopy.hasError).toEqual(true);
});
+ it('should reset reports', () => {
+ expect(stateCopy.reports).toEqual([]);
+ });
+ });
+
+ describe('SET_ISSUE_MODAL_DATA', () => {
+ beforeEach(() => {
+ mutations[types.SET_ISSUE_MODAL_DATA](stateCopy, {
+ issue,
+ });
+ });
+
+ it('should set modal title', () => {
+ expect(stateCopy.modal.title).toEqual(issue.name);
+ });
+
+ it('should set modal data', () => {
+ expect(stateCopy.modal.data.execution_time.value).toEqual(issue.execution_time);
+ expect(stateCopy.modal.data.system_output.value).toEqual(issue.system_output);
+ });
});
});
diff --git a/spec/javascripts/reports/store/utils_spec.js b/spec/javascripts/reports/store/utils_spec.js
new file mode 100644
index 00000000000..1679d120db2
--- /dev/null
+++ b/spec/javascripts/reports/store/utils_spec.js
@@ -0,0 +1,138 @@
+import * as utils from '~/reports/store/utils';
+import {
+ STATUS_FAILED,
+ STATUS_SUCCESS,
+ ICON_WARNING,
+ ICON_SUCCESS,
+ ICON_NOTFOUND,
+} from '~/reports/constants';
+
+describe('Reports store utils', () => {
+ describe('summaryTextbuilder', () => {
+ it('should render text for no changed results in multiple tests', () => {
+ const name = 'Test summary';
+ const data = { total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe('Test summary contained no changed test results out of 10 total tests');
+ });
+
+ it('should render text for no changed results in one test', () => {
+ const name = 'Test summary';
+ const data = { total: 1 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe('Test summary contained no changed test results out of 1 total test');
+ });
+
+ it('should render text for multiple failed results', () => {
+ const name = 'Test summary';
+ const data = { failed: 3, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe('Test summary contained 3 failed test results out of 10 total tests');
+ });
+
+ it('should render text for multiple fixed results', () => {
+ const name = 'Test summary';
+ const data = { resolved: 4, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe('Test summary contained 4 fixed test results out of 10 total tests');
+ });
+
+ it('should render text for multiple fixed, and multiple failed results', () => {
+ const name = 'Test summary';
+ const data = { failed: 3, resolved: 4, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Test summary contained 3 failed test results and 4 fixed test results out of 10 total tests',
+ );
+ });
+
+ it('should render text for a singular fixed, and a singular failed result', () => {
+ const name = 'Test summary';
+ const data = { failed: 1, resolved: 1, total: 10 };
+ const result = utils.summaryTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Test summary contained 1 failed test result and 1 fixed test result out of 10 total tests',
+ );
+ });
+ });
+
+ describe('reportTextBuilder', () => {
+ it('should render text for no changed results in multiple tests', () => {
+ const name = 'Rspec';
+ const data = { total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe('Rspec found no changed test results out of 10 total tests');
+ });
+
+ it('should render text for no changed results in one test', () => {
+ const name = 'Rspec';
+ const data = { total: 1 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe('Rspec found no changed test results out of 1 total test');
+ });
+
+ it('should render text for multiple failed results', () => {
+ const name = 'Rspec';
+ const data = { failed: 3, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe('Rspec found 3 failed test results out of 10 total tests');
+ });
+
+ it('should render text for multiple fixed results', () => {
+ const name = 'Rspec';
+ const data = { resolved: 4, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe('Rspec found 4 fixed test results out of 10 total tests');
+ });
+
+ it('should render text for multiple fixed, and multiple failed results', () => {
+ const name = 'Rspec';
+ const data = { failed: 3, resolved: 4, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Rspec found 3 failed test results and 4 fixed test results out of 10 total tests',
+ );
+ });
+
+ it('should render text for a singular fixed, and a singular failed result', () => {
+ const name = 'Rspec';
+ const data = { failed: 1, resolved: 1, total: 10 };
+ const result = utils.reportTextBuilder(name, data);
+
+ expect(result).toBe(
+ 'Rspec found 1 failed test result and 1 fixed test result out of 10 total tests',
+ );
+ });
+ });
+
+ describe('statusIcon', () => {
+ describe('with failed status', () => {
+ it('returns ICON_WARNING', () => {
+ expect(utils.statusIcon(STATUS_FAILED)).toEqual(ICON_WARNING);
+ });
+ });
+
+ describe('with success status', () => {
+ it('returns ICON_SUCCESS', () => {
+ expect(utils.statusIcon(STATUS_SUCCESS)).toEqual(ICON_SUCCESS);
+ });
+ });
+
+ describe('without a status', () => {
+ it('returns ICON_NOTFOUND', () => {
+ expect(utils.statusIcon()).toEqual(ICON_NOTFOUND);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index e77236c40ef..5f4f4c26d74 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -98,7 +98,7 @@ let longRunningTestTimeoutHandle;
beforeEach((done) => {
longRunningTestTimeoutHandle = setTimeout(() => {
done.fail('Test is running too long!');
- }, 1000);
+ }, 2000);
done();
});
diff --git a/spec/javascripts/vue_shared/components/code_block_spec.js b/spec/javascripts/vue_shared/components/code_block_spec.js
new file mode 100644
index 00000000000..6b91a20ff76
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/code_block_spec.js
@@ -0,0 +1,33 @@
+import Vue from 'vue';
+import component from '~/vue_shared/components/code_block.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Code Block', () => {
+ const Component = Vue.extend(component);
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders a code block with the provided code', () => {
+ const code =
+ "Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in \u003ctop (required)\u003e'";
+
+ vm = mountComponent(Component, {
+ code,
+ });
+
+ expect(vm.$el.querySelector('code').textContent).toEqual(code);
+ });
+
+ it('escapes XSS injections', () => {
+ const code = 'CCC&lt;img src=x onerror=alert(document.domain)&gt;';
+
+ vm = mountComponent(Component, {
+ code,
+ });
+
+ expect(vm.$el.querySelector('code').textContent).toEqual(code);
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js
index e4737714312..263824a102a 100644
--- a/spec/javascripts/vue_shared/components/gl_modal_spec.js
+++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js
@@ -29,7 +29,7 @@ describe('GlModal', () => {
describe('without id', () => {
beforeEach(() => {
- vm = mountComponent(modalComponent, { });
+ vm = mountComponent(modalComponent, {});
});
it('does not add an id attribute to the modal', () => {
@@ -83,7 +83,7 @@ describe('GlModal', () => {
});
});
- it('works with data-toggle="modal"', (done) => {
+ it('works with data-toggle="modal"', done => {
setFixtures(`
<button id="modal-button" data-toggle="modal" data-target="#my-modal"></button>
<div id="modal-container"></div>
@@ -91,9 +91,13 @@ describe('GlModal', () => {
const modalContainer = document.getElementById('modal-container');
const modalButton = document.getElementById('modal-button');
- vm = mountComponent(modalComponent, {
- id: 'my-modal',
- }, modalContainer);
+ vm = mountComponent(
+ modalComponent,
+ {
+ id: 'my-modal',
+ },
+ modalContainer,
+ );
$(vm.$el).on('shown.bs.modal', () => done());
modalButton.click();
@@ -103,7 +107,7 @@ describe('GlModal', () => {
const dummyEvent = 'not really an event';
beforeEach(() => {
- vm = mountComponent(modalComponent, { });
+ vm = mountComponent(modalComponent, {});
spyOn(vm, '$emit');
});
@@ -122,11 +126,27 @@ describe('GlModal', () => {
expect(vm.$emit).toHaveBeenCalledWith('submit', dummyEvent);
});
});
+
+ describe('opened', () => {
+ it('emits a open event', () => {
+ vm.opened();
+
+ expect(vm.$emit).toHaveBeenCalledWith('open');
+ });
+ });
+
+ describe('closed', () => {
+ it('emits a closed event', () => {
+ vm.closed();
+
+ expect(vm.$emit).toHaveBeenCalledWith('closed');
+ });
+ });
});
describe('slots', () => {
const slotContent = 'this should go into the slot';
- const modalWithSlot = (slotName) => {
+ const modalWithSlot = slotName => {
let template;
if (slotName) {
template = `
diff --git a/spec/javascripts/vue_shared/components/identicon_spec.js b/spec/javascripts/vue_shared/components/identicon_spec.js
index 647680f00f7..0719800c682 100644
--- a/spec/javascripts/vue_shared/components/identicon_spec.js
+++ b/spec/javascripts/vue_shared/components/identicon_spec.js
@@ -25,19 +25,12 @@ describe('IdenticonComponent', () => {
vm.$destroy();
});
- describe('identiconStyles', () => {
- it('should return styles attribute value with `background-color` property', () => {
+ describe('identiconBackgroundClass', () => {
+ it('should return bg class based on entityId', () => {
vm.entityId = 4;
- expect(vm.identiconStyles).toBeDefined();
- expect(vm.identiconStyles.indexOf('background-color: #E0F2F1;') > -1).toBeTruthy();
- });
-
- it('should return styles attribute value with `color` property', () => {
- vm.entityId = 4;
-
- expect(vm.identiconStyles).toBeDefined();
- expect(vm.identiconStyles.indexOf('color: #555;') > -1).toBeTruthy();
+ expect(vm.identiconBackgroundClass).toBeDefined();
+ expect(vm.identiconBackgroundClass).toBe('bg5');
});
});
@@ -58,7 +51,7 @@ describe('IdenticonComponent', () => {
expect(vm.$el.nodeName).toBe('DIV');
expect(vm.$el.classList.contains('identicon')).toBeTruthy();
expect(vm.$el.classList.contains('s40')).toBeTruthy();
- expect(vm.$el.getAttribute('style').indexOf('background-color') > -1).toBeTruthy();
+ expect(vm.$el.classList.contains('bg2')).toBeTruthy();
vm.$destroy();
});
diff --git a/spec/javascripts/vue_shared/components/notes/placeholder_note_spec.js b/spec/javascripts/vue_shared/components/notes/placeholder_note_spec.js
index 7e57c51bf29..db665fdaad3 100644
--- a/spec/javascripts/vue_shared/components/notes/placeholder_note_spec.js
+++ b/spec/javascripts/vue_shared/components/notes/placeholder_note_spec.js
@@ -27,7 +27,7 @@ describe('issue placeholder system note component', () => {
userDataMock.path,
);
expect(vm.$el.querySelector('.user-avatar-link img').getAttribute('src')).toEqual(
- userDataMock.avatar_url,
+ `${userDataMock.avatar_url}?width=40`,
);
});
});
diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js
index 656b57d764e..dc7652c77f7 100644
--- a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js
+++ b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_image_spec.js
@@ -12,7 +12,7 @@ const DEFAULT_PROPS = {
tooltipPlacement: 'bottom',
};
-describe('User Avatar Image Component', function () {
+describe('User Avatar Image Component', function() {
let vm;
let UserAvatarImage;
@@ -20,37 +20,37 @@ describe('User Avatar Image Component', function () {
UserAvatarImage = Vue.extend(userAvatarImage);
});
- describe('Initialization', function () {
- beforeEach(function () {
+ describe('Initialization', function() {
+ beforeEach(function() {
vm = mountComponent(UserAvatarImage, {
...DEFAULT_PROPS,
}).$mount();
});
- it('should return a defined Vue component', function () {
+ it('should return a defined Vue component', function() {
expect(vm).toBeDefined();
});
- it('should have <img> as a child element', function () {
+ it('should have <img> as a child element', function() {
expect(vm.$el.tagName).toBe('IMG');
- expect(vm.$el.getAttribute('src')).toBe(DEFAULT_PROPS.imgSrc);
- expect(vm.$el.getAttribute('data-src')).toBe(DEFAULT_PROPS.imgSrc);
+ expect(vm.$el.getAttribute('src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
+ expect(vm.$el.getAttribute('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
expect(vm.$el.getAttribute('alt')).toBe(DEFAULT_PROPS.imgAlt);
});
- it('should properly compute tooltipContainer', function () {
+ it('should properly compute tooltipContainer', function() {
expect(vm.tooltipContainer).toBe('body');
});
- it('should properly render tooltipContainer', function () {
+ it('should properly render tooltipContainer', function() {
expect(vm.$el.getAttribute('data-container')).toBe('body');
});
- it('should properly compute avatarSizeClass', function () {
+ it('should properly compute avatarSizeClass', function() {
expect(vm.avatarSizeClass).toBe('s99');
});
- it('should properly render img css', function () {
+ it('should properly render img css', function() {
const { classList } = vm.$el;
const containsAvatar = classList.contains('avatar');
const containsSizeClass = classList.contains('s99');
@@ -64,21 +64,21 @@ describe('User Avatar Image Component', function () {
});
});
- describe('Initialization when lazy', function () {
- beforeEach(function () {
+ describe('Initialization when lazy', function() {
+ beforeEach(function() {
vm = mountComponent(UserAvatarImage, {
...DEFAULT_PROPS,
lazy: true,
}).$mount();
});
- it('should add lazy attributes', function () {
+ it('should add lazy attributes', function() {
const { classList } = vm.$el;
const lazyClass = classList.contains('lazy');
expect(lazyClass).toBe(true);
expect(vm.$el.getAttribute('src')).toBe(placeholderImage);
- expect(vm.$el.getAttribute('data-src')).toBe(DEFAULT_PROPS.imgSrc);
+ expect(vm.$el.getAttribute('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`);
});
});
});