Skip to content
Snippets Groups Projects
Commit c2367afb authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 51a95129
No related branches found
No related tags found
No related merge requests found
Showing
with 169 additions and 68 deletions
Loading
Loading
@@ -22,7 +22,7 @@ import {
} from '../mock_data';
 
const localVue = createLocalVue();
const expectedPanelCount = 2;
const expectedPanelCount = 3;
 
describe('Dashboard', () => {
let store;
Loading
Loading
Loading
Loading
@@ -513,6 +513,48 @@ export const metricsDashboardPayload = {
},
],
},
{
title: 'memories',
type: 'area-chart',
y_label: 'memories',
metrics: [
{
id: 'metric_of_ages_1000',
label: 'memory_1000',
unit: 'count',
prometheus_endpoint_path: '/root',
metric_id: 20,
},
{
id: 'metric_of_ages_1001',
label: 'memory_1000',
unit: 'count',
prometheus_endpoint_path: '/root',
metric_id: 21,
},
{
id: 'metric_of_ages_1002',
label: 'memory_1000',
unit: 'count',
prometheus_endpoint_path: '/root',
metric_id: 22,
},
{
id: 'metric_of_ages_1003',
label: 'memory_1000',
unit: 'count',
prometheus_endpoint_path: '/root',
metric_id: 23,
},
{
id: 'metric_of_ages_1004',
label: 'memory_1004',
unit: 'count',
prometheus_endpoint_path: '/root',
metric_id: 24,
},
],
},
],
},
],
Loading
Loading
Loading
Loading
@@ -50,9 +50,10 @@ describe('Monitoring mutations', () => {
expect(groups[0].panels).toHaveLength(1);
expect(groups[0].panels[0].metrics).toHaveLength(1);
 
expect(groups[1].panels).toHaveLength(2);
expect(groups[1].panels).toHaveLength(3);
expect(groups[1].panels[0].metrics).toHaveLength(1);
expect(groups[1].panels[1].metrics).toHaveLength(1);
expect(groups[1].panels[2].metrics).toHaveLength(5);
});
it('assigns metrics a metric id', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, payload);
Loading
Loading
Loading
Loading
@@ -13,7 +13,7 @@ describe('Release edit component', () => {
beforeEach(() => {
gon.api_version = 'v4';
 
releaseClone = JSON.parse(JSON.stringify(convertObjectPropsToCamelCase(release)));
releaseClone = convertObjectPropsToCamelCase(release, { deep: true });
 
state = {
release: releaseClone,
Loading
Loading
Loading
Loading
@@ -2,12 +2,14 @@ import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility';
import Icon from '~/vue_shared/components/icon.vue';
import { release } from '../mock_data';
import { release as originalRelease } from '../mock_data';
import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
 
describe('Evidence Block', () => {
let wrapper;
let release;
 
const factory = (options = {}) => {
wrapper = mount(EvidenceBlock, {
Loading
Loading
@@ -16,6 +18,8 @@ describe('Evidence Block', () => {
};
 
beforeEach(() => {
release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
factory({
propsData: {
release,
Loading
Loading
@@ -32,7 +36,7 @@ describe('Evidence Block', () => {
});
 
it('renders the title for the dowload link', () => {
expect(wrapper.find(GlLink).text()).toBe(`${release.tag_name}-evidence.json`);
expect(wrapper.find(GlLink).text()).toBe(`${release.tagName}-evidence.json`);
});
 
it('renders the correct hover text for the download', () => {
Loading
Loading
@@ -40,19 +44,19 @@ describe('Evidence Block', () => {
});
 
it('renders the correct file link for download', () => {
expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tag_name}-evidence.json`);
expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tagName}-evidence.json`);
});
 
describe('sha text', () => {
it('renders the short sha initially', () => {
expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidence_sha));
expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidenceSha));
});
 
it('renders the long sha after expansion', () => {
wrapper.find('.js-text-expander-prepend').trigger('click');
 
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find('.js-expanded').text()).toBe(release.evidence_sha);
expect(wrapper.find('.js-expanded').text()).toBe(release.evidenceSha);
});
});
});
Loading
Loading
@@ -68,7 +72,7 @@ describe('Evidence Block', () => {
 
it('copies the sha', () => {
expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe(
release.evidence_sha,
release.evidenceSha,
);
});
});
Loading
Loading
Loading
Loading
@@ -24,7 +24,7 @@ describe('Release block footer', () => {
const factory = (props = {}) => {
wrapper = mount(ReleaseBlockFooter, {
propsData: {
...convertObjectPropsToCamelCase(releaseClone),
...convertObjectPropsToCamelCase(releaseClone, { deep: true }),
...props,
},
});
Loading
Loading
import { shallowMount } from '@vue/test-utils';
import { cloneDeep, merge } from 'lodash';
import { merge } from 'lodash';
import { GlLink } from '@gitlab/ui';
import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
Loading
Loading
@@ -18,9 +18,7 @@ describe('Release block header', () => {
};
 
beforeEach(() => {
release = convertObjectPropsToCamelCase(cloneDeep(originalRelease), {
ignoreKeyNames: ['_links'],
});
release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
 
afterEach(() => {
Loading
Loading
@@ -39,13 +37,13 @@ describe('Release block header', () => {
const link = findHeaderLink();
 
expect(link.text()).toBe(release.name);
expect(link.attributes('href')).toBe(release._links.self);
expect(link.attributes('href')).toBe(release.Links.self);
});
});
 
describe('when _links.self is missing', () => {
beforeEach(() => {
factory({ _links: { self: null } });
factory({ Links: { self: null } });
});
 
it('renders the title as text', () => {
Loading
Loading
Loading
Loading
@@ -2,12 +2,13 @@ import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue';
import { milestones } from '../mock_data';
import { milestones as originalMilestones } from '../mock_data';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
 
describe('Release block milestone info', () => {
let wrapper;
let milestonesClone;
let milestones;
 
const factory = milestonesProp => {
wrapper = mount(ReleaseBlockMilestoneInfo, {
Loading
Loading
@@ -20,7 +21,7 @@ describe('Release block milestone info', () => {
};
 
beforeEach(() => {
milestonesClone = JSON.parse(JSON.stringify(milestones));
milestones = convertObjectPropsToCamelCase(originalMilestones, { deep: true });
});
 
afterEach(() => {
Loading
Loading
@@ -32,7 +33,7 @@ describe('Release block milestone info', () => {
const issuesContainer = () => wrapper.find('.js-issues-container');
 
describe('with default props', () => {
beforeEach(() => factory(milestonesClone));
beforeEach(() => factory(milestones));
 
it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete');
Loading
Loading
@@ -53,13 +54,13 @@ describe('Release block milestone info', () => {
it('renders a list of links to all associated milestones', () => {
expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
 
milestonesClone.forEach((m, i) => {
milestones.forEach((m, i) => {
const milestoneLink = milestoneListContainer()
.findAll(GlLink)
.at(i);
 
expect(milestoneLink.text()).toBe(m.title);
expect(milestoneLink.attributes('href')).toBe(m.web_url);
expect(milestoneLink.attributes('href')).toBe(m.webUrl);
expect(milestoneLink.attributes('title')).toBe(m.description);
});
});
Loading
Loading
@@ -84,7 +85,7 @@ describe('Release block milestone info', () => {
 
beforeEach(() => {
lotsOfMilestones = [];
const template = milestonesClone[0];
const template = milestones[0];
 
for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) {
lotsOfMilestones.push({
Loading
Loading
@@ -148,16 +149,16 @@ describe('Release block milestone info', () => {
/** Ensures we don't have any issues with dividing by zero when computing percentages */
describe('when all issue counts are zero', () => {
beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({
milestones = milestones.map(m => ({
...m,
issue_stats: {
...m.issue_stats,
issueStats: {
...m.issueStats,
opened: 0,
closed: 0,
},
}));
 
return factory(milestonesClone);
return factory(milestones);
});
 
expectAllZeros();
Loading
Loading
@@ -165,12 +166,12 @@ describe('Release block milestone info', () => {
 
describe('if the API response is missing the "issue_stats" property', () => {
beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({
milestones = milestones.map(m => ({
...m,
issue_stats: undefined,
issueStats: undefined,
}));
 
return factory(milestonesClone);
return factory(milestones);
});
 
expectAllZeros();
Loading
Loading
Loading
Loading
@@ -5,10 +5,12 @@ import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { release } from '../mock_data';
import { release as originalRelease } from '../mock_data';
import Icon from '~/vue_shared/components/icon.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
 
const { convertObjectPropsToCamelCase } = jest.requireActual('~/lib/utils/common_utils');
let mockLocationHash;
jest.mock('~/lib/utils/url_utility', () => ({
__esModule: true,
Loading
Loading
@@ -22,7 +24,7 @@ jest.mock('~/lib/utils/common_utils', () => ({
 
describe('Release block', () => {
let wrapper;
let releaseClone;
let release;
 
const factory = (releaseProp, featureFlags = {}) => {
wrapper = mount(ReleaseBlock, {
Loading
Loading
@@ -45,7 +47,7 @@ describe('Release block', () => {
 
beforeEach(() => {
jest.spyOn($.fn, 'renderGFM');
releaseClone = JSON.parse(JSON.stringify(release));
release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
 
afterEach(() => {
Loading
Loading
@@ -61,7 +63,7 @@ describe('Release block', () => {
 
it('renders an edit button that links to the "Edit release" page', () => {
expect(editButton().exists()).toBe(true);
expect(editButton().attributes('href')).toBe(release._links.edit_url);
expect(editButton().attributes('href')).toBe(release.Links.editUrl);
});
 
it('renders release name', () => {
Loading
Loading
@@ -74,7 +76,7 @@ describe('Release block', () => {
});
 
it('renders release date', () => {
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at));
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.releasedAt));
});
 
it('renders number of assets provided', () => {
Loading
Loading
@@ -129,72 +131,72 @@ describe('Release block', () => {
});
 
it('renders commit sha', () => {
releaseClone.commit_path = '/commit/example';
release.commitPath = '/commit/example';
 
return factory(releaseClone).then(() => {
expect(wrapper.text()).toContain(release.commit.short_id);
return factory(release).then(() => {
expect(wrapper.text()).toContain(release.commit.shortId);
 
expect(wrapper.find('a[href="/commit/example"]').exists()).toBe(true);
});
});
 
it('renders tag name', () => {
releaseClone.tag_path = '/tag/example';
release.tagPath = '/tag/example';
 
return factory(releaseClone).then(() => {
expect(wrapper.text()).toContain(release.tag_name);
return factory(release).then(() => {
expect(wrapper.text()).toContain(release.tagName);
 
expect(wrapper.find('a[href="/tag/example"]').exists()).toBe(true);
});
});
 
it("does not render an edit button if release._links.edit_url isn't a string", () => {
delete releaseClone._links;
it("does not render an edit button if release.Links.editUrl isn't a string", () => {
delete release.Links;
 
return factory(releaseClone).then(() => {
return factory(release).then(() => {
expect(editButton().exists()).toBe(false);
});
});
 
it('does not render the milestone list if no milestones are associated to the release', () => {
delete releaseClone.milestones;
delete release.milestones;
 
return factory(releaseClone).then(() => {
return factory(release).then(() => {
expect(milestoneListLabel().exists()).toBe(false);
});
});
 
it('renders upcoming release badge', () => {
releaseClone.upcoming_release = true;
release.upcomingRelease = true;
 
return factory(releaseClone).then(() => {
return factory(release).then(() => {
expect(wrapper.text()).toContain('Upcoming Release');
});
});
 
it('slugifies the tag_name before setting it as the elements ID', () => {
releaseClone.tag_name = 'a dangerous tag name <script>alert("hello")</script>';
it('slugifies the tagName before setting it as the elements ID', () => {
release.tagName = 'a dangerous tag name <script>alert("hello")</script>';
 
return factory(releaseClone).then(() => {
return factory(release).then(() => {
expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script');
});
});
 
describe('evidence block', () => {
it('renders the evidence block when the evidence is available and the feature flag is true', () =>
factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
));
 
it('does not render the evidence block when the evidence is available but the feature flag is false', () =>
factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
));
 
it('does not render the evidence block when there is no evidence', () => {
releaseClone.evidence_sha = null;
release.evidenceSha = null;
 
return factory(releaseClone).then(() => {
return factory(release).then(() => {
expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
});
});
Loading
Loading
@@ -222,7 +224,7 @@ describe('Release block', () => {
});
 
it("attempts to scroll itself into view if the anchor tag matches the release's tag name", () => {
mockLocationHash = release.tag_name;
mockLocationHash = release.tagName;
return factory(release).then(() => {
expect(scrollToElement).toHaveBeenCalledTimes(1);
 
Loading
Loading
@@ -231,7 +233,7 @@ describe('Release block', () => {
});
 
it('renders with a light blue background if it is the target of the anchor', () => {
mockLocationHash = release.tag_name;
mockLocationHash = release.tagName;
 
return factory(release).then(() => {
expect(hasTargetBlueBackground()).toBe(true);
Loading
Loading
@@ -275,16 +277,16 @@ describe('Release block', () => {
 
expect(milestoneLink.text()).toBe(milestone.title);
 
expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
expect(milestoneLink.attributes('href')).toBe(milestone.webUrl);
 
expect(milestoneLink.attributes('title')).toBe(milestone.description);
});
});
 
it('renders the label as "Milestone" if only a single milestone is passed in', () => {
releaseClone.milestones = releaseClone.milestones.slice(0, 1);
release.milestones = release.milestones.slice(0, 1);
 
return factory(releaseClone, { releaseIssueSummary: false }).then(() => {
return factory(release, { releaseIssueSummary: false }).then(() => {
expect(
milestoneListLabel()
.find('.js-label-text')
Loading
Loading
Loading
Loading
@@ -45,6 +45,21 @@ describe Resolvers::BoardsResolver do
expect(resolve_boards).to eq [board1]
end
end
context 'when querying for a single board' do
let(:board1) { create(:board, name: 'One', resource_parent: board_parent) }
it 'returns specified board' do
expect(resolve_boards(args: { id: global_id_of(board1) })).to eq [board1]
end
it 'returns nil if board not found' do
outside_parent = create(board_parent.class.underscore.to_sym)
outside_board = create(:board, name: 'outside board', resource_parent: outside_parent)
expect(resolve_boards(args: { id: global_id_of(outside_board) })).to eq Board.none
end
end
end
 
describe '#resolve' do
Loading
Loading
import _ from 'underscore';
import { escape as esc } from 'lodash';
import VisualTokenValue from '~/filtered_search/visual_token_value';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
Loading
Loading
@@ -121,7 +121,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokenValueElement.innerText.trim()).toBe(dummyUser.name);
tokenValueElement.querySelector('.avatar').remove();
 
expect(tokenValueElement.innerHTML.trim()).toBe(_.escape(dummyUser.name));
expect(tokenValueElement.innerHTML.trim()).toBe(esc(dummyUser.name));
})
.then(done)
.catch(done.fail);
Loading
Loading
Loading
Loading
@@ -12,6 +12,7 @@ import {
release,
releases,
} from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
 
describe('Releases App ', () => {
const Component = Vue.extend(app);
Loading
Loading
@@ -27,7 +28,10 @@ describe('Releases App ', () => {
 
beforeEach(() => {
store = createStore({ list: listModule });
releasesPagination = _.range(21).map(index => ({ ...release, tag_name: `${index}.00` }));
releasesPagination = _.range(21).map(index => ({
...convertObjectPropsToCamelCase(release, { deep: true }),
tagName: `${index}.00`,
}));
});
 
afterEach(() => {
Loading
Loading
Loading
Loading
@@ -8,16 +8,18 @@ import {
import state from '~/releases/stores/modules/list/state';
import * as types from '~/releases/stores/modules/list/mutation_types';
import api from '~/api';
import { parseIntPagination } from '~/lib/utils/common_utils';
import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data';
import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { pageInfoHeadersWithoutPagination, releases as originalReleases } from '../../../mock_data';
 
describe('Releases State actions', () => {
let mockedState;
let pageInfo;
let releases;
 
beforeEach(() => {
mockedState = state();
pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
});
 
describe('requestReleases', () => {
Loading
Loading
Loading
Loading
@@ -9,14 +9,12 @@ describe 'get list of boards' do
 
describe 'for a project' do
let(:board_parent) { create(:project, :repository, :private) }
let(:boards_data) { graphql_data['project']['boards']['edges'] }
 
it_behaves_like 'group and project boards query'
end
 
describe 'for a group' do
let(:board_parent) { create(:group, :private) }
let(:boards_data) { graphql_data['group']['boards']['edges'] }
 
before do
allow(board_parent).to receive(:multiple_issue_boards_available?).and_return(false)
Loading
Loading
Loading
Loading
@@ -5,6 +5,8 @@ RSpec.shared_context 'group and project boards query context' do
let(:current_user) { user }
let(:params) { '' }
let(:board_parent_type) { board_parent.class.to_s.downcase }
let(:boards_data) { graphql_data[board_parent_type]['boards']['edges'] }
let(:board_data) { graphql_data[board_parent_type]['board'] }
let(:start_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['startCursor'] }
let(:end_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['endCursor'] }
 
Loading
Loading
@@ -28,6 +30,18 @@ RSpec.shared_context 'group and project boards query context' do
)
end
 
def query_single_board(board_params = params)
graphql_query_for(
board_parent_type,
{ 'fullPath' => board_parent.full_path },
<<~BOARD
board(#{board_params}) {
#{all_graphql_fields_for('board'.classify)}
}
BOARD
)
end
def grab_names(data = boards_data)
data.map do |board|
board.dig('node', 'name')
Loading
Loading
Loading
Loading
@@ -89,4 +89,24 @@ RSpec.shared_examples 'group and project boards query' do
end
end
end
context 'when querying for a single board' do
before do
board_parent.add_reporter(current_user)
end
it_behaves_like 'a working graphql query' do
before do
post_graphql(query_single_board, current_user: current_user)
end
end
it 'finds the correct board' do
board = create(:board, resource_parent: board_parent, name: 'A')
post_graphql(query_single_board("id: \"#{global_id_of(board)}\""), current_user: current_user)
expect(board_data['name']).to eq board.name
end
end
end
Loading
Loading
@@ -56,7 +56,7 @@ describe 'profiles/preferences/show' do
expect(rendered).not_to have_sourcegraph_field
end
 
it 'does not display integrations settings' do
it 'does not display Integration Settings' do
expect(rendered).not_to have_integrations_section
end
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment