提交 0c27b33a 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 ff83f24e
43e8389d447f471e889dd4521a13037f36d8a230
00c7c2a5a1820397e65fbcff67cdd05bb961a40b
import axios from '~/lib/utils/axios_utils';
import statusCodes from '~/lib/utils/http_status';
import { backOff } from '~/lib/utils/common_utils';
import { PROMETHEUS_TIMEOUT } from '../constants';
const backOffRequest = makeRequestCallback =>
backOff((next, stop) => {
makeRequestCallback()
.then(resp => {
if (resp.status === statusCodes.NO_CONTENT) {
next();
} else {
stop(resp);
}
})
.catch(stop);
}, PROMETHEUS_TIMEOUT);
export const getDashboard = (dashboardEndpoint, params) =>
backOffRequest(() => axios.get(dashboardEndpoint, { params })).then(
axiosResponse => axiosResponse.data,
);
export const getPrometheusQueryData = (prometheusEndpoint, params) =>
backOffRequest(() => axios.get(prometheusEndpoint, { params }))
.then(axiosResponse => axiosResponse.data)
.then(prometheusResponse => prometheusResponse.data)
.catch(error => {
// Prometheus returns errors in specific cases
// https://prometheus.io/docs/prometheus/latest/querying/api/#format-overview
const { response = {} } = error;
if (
response.status === statusCodes.BAD_REQUEST ||
response.status === statusCodes.UNPROCESSABLE_ENTITY ||
response.status === statusCodes.SERVICE_UNAVAILABLE
) {
const { data } = response;
if (data?.status === 'error' && data?.error) {
throw new Error(data.error);
}
}
throw error;
});
......@@ -13,16 +13,11 @@ import trackDashboardLoad from '../monitoring_tracking_helper';
import getEnvironments from '../queries/getEnvironments.query.graphql';
import getAnnotations from '../queries/getAnnotations.query.graphql';
import getDashboardValidationWarnings from '../queries/getDashboardValidationWarnings.query.graphql';
import statusCodes from '../../lib/utils/http_status';
import { backOff, convertObjectPropsToCamelCase } from '../../lib/utils/common_utils';
import { convertObjectPropsToCamelCase } from '../../lib/utils/common_utils';
import { s__, sprintf } from '../../locale';
import { getDashboard, getPrometheusQueryData } from '../requests';
import {
PROMETHEUS_TIMEOUT,
ENVIRONMENT_AVAILABLE_STATE,
DEFAULT_DASHBOARD_PATH,
VARIABLE_TYPES,
} from '../constants';
import { ENVIRONMENT_AVAILABLE_STATE, DEFAULT_DASHBOARD_PATH, VARIABLE_TYPES } from '../constants';
function prometheusMetricQueryParams(timeRange) {
const { start, end } = convertToFixedRange(timeRange);
......@@ -38,31 +33,6 @@ function prometheusMetricQueryParams(timeRange) {
};
}
function backOffRequest(makeRequestCallback) {
return backOff((next, stop) => {
makeRequestCallback()
.then(resp => {
if (resp.status === statusCodes.NO_CONTENT) {
next();
} else {
stop(resp);
}
})
.catch(stop);
}, PROMETHEUS_TIMEOUT);
}
function getPrometheusQueryData(prometheusEndpoint, params) {
return backOffRequest(() => axios.get(prometheusEndpoint, { params }))
.then(res => res.data)
.then(response => {
if (response.status === 'error') {
throw new Error(response.error);
}
return response.data;
});
}
// Setup
export const setGettingStartedEmptyState = ({ commit }) => {
......@@ -126,8 +96,7 @@ export const fetchDashboard = ({ state, commit, dispatch, getters }) => {
params.dashboard = getters.fullDashboardPath;
}
return backOffRequest(() => axios.get(state.dashboardEndpoint, { params }))
.then(resp => resp.data)
return getDashboard(state.dashboardEndpoint, params)
.then(response => {
dispatch('receiveMetricsDashboardSuccess', { response });
/**
......@@ -484,12 +453,10 @@ export const fetchVariableMetricLabelValues = ({ state, commit }, { defaultQuery
if (variable.type === VARIABLE_TYPES.metric_label_values) {
const { prometheusEndpointPath, label } = variable.options;
const optionsRequest = backOffRequest(() =>
axios.get(prometheusEndpointPath, {
params: { start_time, end_time },
}),
)
.then(({ data }) => data.data)
const optionsRequest = getPrometheusQueryData(prometheusEndpointPath, {
start_time,
end_time,
})
.then(data => {
commit(types.UPDATE_VARIABLE_METRIC_LABEL_VALUES, { variable, label, data });
})
......
......@@ -3,6 +3,7 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import SnippetHeader from './snippet_header.vue';
import SnippetTitle from './snippet_title.vue';
import SnippetBlob from './snippet_blob_view.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import { getSnippetMixin } from '../mixins/snippets';
......@@ -15,12 +16,16 @@ export default {
SnippetTitle,
GlLoadingIcon,
SnippetBlob,
CloneDropdownButton,
},
mixins: [getSnippetMixin],
computed: {
embeddable() {
return this.snippet.visibilityLevel === SNIPPET_VISIBILITY_PUBLIC;
},
canBeCloned() {
return Boolean(this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo);
},
},
};
</script>
......@@ -35,7 +40,16 @@ export default {
<template v-else>
<snippet-header :snippet="snippet" />
<snippet-title :snippet="snippet" />
<blob-embeddable v-if="embeddable" class="gl-mb-5" :url="snippet.webUrl" />
<div class="gl-display-flex gl-justify-content-end gl-mb-5">
<blob-embeddable v-if="embeddable" class="gl-flex-fill-1" :url="snippet.webUrl" />
<clone-dropdown-button
v-if="canBeCloned"
class="gl-ml-3"
:ssh-link="snippet.sshUrlToRepo"
:http-link="snippet.httpUrlToRepo"
data-qa-selector="clone_button"
/>
</div>
<div v-for="blob in blobs" :key="blob.path">
<snippet-blob :snippet="snippet" :blob="blob" />
</div>
......
<script>
import BlobHeader from '~/blob/components/blob_header.vue';
import BlobContent from '~/blob/components/blob_content.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import GetBlobContent from '../queries/snippet.blob.content.query.graphql';
......@@ -16,7 +15,6 @@ export default {
components: {
BlobHeader,
BlobContent,
CloneDropdownButton,
},
apollo: {
blobContent: {
......@@ -66,9 +64,6 @@ export default {
const { richViewer, simpleViewer } = this.blob;
return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer;
},
canBeCloned() {
return this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo;
},
hasRenderError() {
return Boolean(this.viewer.renderError);
},
......@@ -93,17 +88,7 @@ export default {
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
@viewer-changed="switchViewer"
>
<template #actions>
<clone-dropdown-button
v-if="canBeCloned"
class="gl-mr-3"
:ssh-link="snippet.sshUrlToRepo"
:http-link="snippet.httpUrlToRepo"
data-qa-selector="clone_button"
/>
</template>
</blob-header>
/>
<blob-content
:loading="isContentLoading"
:content="blobContent"
......
......@@ -42,6 +42,7 @@ class PipelineSerializer < BaseSerializer
[
:cancelable_statuses,
:latest_statuses_ordered_by_stage,
:latest_builds_report_results,
:manual_actions,
:retryable_builds,
:scheduled_actions,
......
- if Gitlab::CurrentSettings.email_author_in_body
%div
#{link_to @note.author_name, user_url(@note.author)} wrote:
= _("%{author_link} wrote:").html_safe % { author_link: link_to(@note.author_name, user_url(@note.author)) }
%div
= markdown(@note.note, pipeline: :email, author: @note.author)
New response for issue #<%= @issue.iid %>:
<%= _("New response for issue #%{issue_iid}:") % { issue_iid: @issue.iid } %>
Author: <%= sanitize_name(@note.author_name) %>
<%= _("Author: %{author_name}") % { author_name: sanitize_name(@note.author_name) } %>
<%= @note.note %>
<%# EE-specific start %><%= render_if_exists 'layouts/mailer/additional_text'%><%# EE-specific end %>
%p
Thank you for your support request! We are tracking your request as ticket ##{@issue.iid}, and will respond as soon as we can.
= _("Thank you for your support request! We are tracking your request as ticket #%{issue_iid}, and will respond as soon as we can.") % { issue_iid: @issue.iid }
Thank you for your support request! We are tracking your request as ticket #<%= @issue.iid %>, and will respond as soon as we can.
<%= _("Thank you for your support request! We are tracking your request as ticket #%{issue_iid}, and will respond as soon as we can.") % { issue_iid: @issue.iid } %>
To unsubscribe from this issue, please paste the following link into your browser:
<%= _("To unsubscribe from this issue, please paste the following link into your browser:") %>
<%= @unsubscribe_url %>
<%# EE-specific start %><%= render_if_exists 'layouts/mailer/additional_text' %><%# EE-specific end %>
......@@ -5,9 +5,9 @@
.svg-container
= custom_icon('icon_service_desk')
.user-callout-copy
-# haml-lint:disable NoPlainNodes
%h4
Improve customer support with GitLab Service Desk.
= _("Improve customer support with GitLab Service Desk.")
%p
GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email.
= link_to 'Read more', help_page_path('user/project/service_desk.md'), target: '_blank'
= _("GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email.")
= link_to _('Read more'), help_page_path('user/project/service_desk.md'), target: '_blank'
---
title: Move clone button out of blob header
merge_request: 37696
author:
type: changed
---
title: Preload build report results for pipeline builds
merge_request: 37582
author:
type: performance
......@@ -4006,7 +4006,7 @@ input EpicAddIssueInput {
issueIid: String!
"""
The project the issue belongs to
The full path of the project the issue belongs to
"""
projectPath: ID!
}
......
......@@ -11161,7 +11161,7 @@
},
{
"name": "projectPath",
"description": "The project the issue belongs to",
"description": "The full path of the project the issue belongs to",
"type": {
"kind": "NON_NULL",
"name": null,
......@@ -292,6 +292,9 @@ msgstr[1] ""
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
msgid "%{author_link} wrote:"
msgstr ""
msgid "%{authorsName}'s thread"
msgstr ""
......@@ -3432,6 +3435,9 @@ msgstr ""
msgid "Author"
msgstr ""
msgid "Author: %{author_name}"
msgstr ""
msgid "Authored %{timeago} by %{author}"
msgstr ""
......@@ -11203,6 +11209,9 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
......@@ -12650,6 +12659,9 @@ msgstr ""
msgid "Improve Merge Requests and customer support with GitLab Enterprise Edition."
msgstr ""
msgid "Improve customer support with GitLab Service Desk."
msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
......@@ -15773,6 +15785,9 @@ msgstr ""
msgid "New requirement"
msgstr ""
msgid "New response for issue #%{issue_iid}:"
msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
......@@ -23464,6 +23479,9 @@ msgstr ""
msgid "Thank you for your report. A GitLab administrator will look into it shortly."
msgstr ""
msgid "Thank you for your support request! We are tracking your request as ticket #%{issue_iid}, and will respond as soon as we can."
msgstr ""
msgid "Thanks for your purchase!"
msgstr ""
......@@ -25011,6 +25029,9 @@ msgstr ""
msgid "To start serving your jobs you can either add specific Runners to your project or use shared Runners"
msgstr ""
msgid "To unsubscribe from this issue, please paste the following link into your browser:"
msgstr ""
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
......
......@@ -38,7 +38,7 @@ module QA
element :delete_snippet_button
end
base.view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do
base.view 'app/assets/javascripts/snippets/components/show.vue' do
element :clone_button
end
......
/**
* A mock version of a commonUtils `backOff` to test multiple
* retries.
*
* Usage:
*
* ```
* import * as commonUtils from '~/lib/utils/common_utils';
* import { backoffMockImplementation } from '../../helpers/backoff_helper';
*
* beforeEach(() => {
* // ...
* jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
* });
* ```
*
* @param {Function} callback
*/
export const backoffMockImplementation = callback => {
const q = new Promise((resolve, reject) => {
const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg));
const next = () => callback(next, stop);
// Define a timeout based on a mock timer
setTimeout(() => {
callback(next, stop);
});
});
// Run all resolved promises in chain
jest.runOnlyPendingTimers();
return q;
};
export default { backoffMockImplementation };
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import statusCodes from '~/lib/utils/http_status';
import * as commonUtils from '~/lib/utils/common_utils';
import { backoffMockImplementation } from 'jest/helpers/backoff_helper';
import { metricsDashboardResponse } from '../fixture_data';
import { getDashboard, getPrometheusQueryData } from '~/monitoring/requests';
describe('monitoring metrics_requests', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
});
afterEach(() => {
mock.reset();
commonUtils.backOff.mockReset();
});
describe('getDashboard', () => {
const response = metricsDashboardResponse;
const dashboardEndpoint = '/dashboard';
const params = {
start_time: 'start_time',
end_time: 'end_time',
};
it('returns a dashboard response', () => {
mock.onGet(dashboardEndpoint).reply(statusCodes.OK, response);
return getDashboard(dashboardEndpoint, params).then(data => {
expect(data).toEqual(metricsDashboardResponse);
});
});
it('returns a dashboard response after retrying twice', () => {
mock.onGet(dashboardEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(dashboardEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(dashboardEndpoint).reply(statusCodes.OK, response);
return getDashboard(dashboardEndpoint, params).then(data => {
expect(data).toEqual(metricsDashboardResponse);
expect(mock.history.get).toHaveLength(3);
});
});
it('rejects after getting an error', () => {
mock.onGet(dashboardEndpoint).reply(500);
return getDashboard(dashboardEndpoint, params).catch(error => {
expect(error).toEqual(expect.any(Error));
expect(mock.history.get).toHaveLength(1);
});
});
});
describe('getPrometheusQueryData', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [],
},
};
const prometheusEndpoint = '/query_range';
const params = {
start_time: 'start_time',
end_time: 'end_time',
};
it('returns a dashboard response', () => {
mock.onGet(prometheusEndpoint).reply(statusCodes.OK, response);
return getPrometheusQueryData(prometheusEndpoint, params).then(data => {
expect(data).toEqual(response.data);
});
});
it('returns a dashboard response after retrying twice', () => {
// Mock multiple attempts while the cache is filling up
mock.onGet(prometheusEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpoint).reply(statusCodes.OK, response); // 3rd attempt
return getPrometheusQueryData(prometheusEndpoint, params).then(data => {
expect(data).toEqual(response.data);
expect(mock.history.get).toHaveLength(3);
});
});
it('rejects after getting an HTTP 500 error', () => {
mock.onGet(prometheusEndpoint).reply(500, {
status: 'error',
error: 'An error ocurred',
});
return getPrometheusQueryData(prometheusEndpoint, params).catch(error => {
expect(error).toEqual(new Error('Request failed with status code 500'));
});
});
it('rejects after retrying twice and getting an HTTP 401 error', () => {
// Mock multiple attempts while the cache is filling up and fails
mock.onGet(prometheusEndpoint).reply(statusCodes.UNAUTHORIZED, {
status: 'error',
error: 'An error ocurred',
});
return getPrometheusQueryData(prometheusEndpoint, params).catch(error => {
expect(error).toEqual(new Error('Request failed with status code 401'));
});
});
it('rejects after retrying twice and getting an HTTP 500 error', () => {
// Mock multiple attempts while the cache is filling up and fails
mock.onGet(prometheusEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpoint).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpoint).reply(500, {
status: 'error',
error: 'An error ocurred',
}); // 3rd attempt
return getPrometheusQueryData(prometheusEndpoint, params).catch(error => {
expect(error).toEqual(new Error('Request failed with status code 500'));
expect(mock.history.get).toHaveLength(3);
});
});
test.each`
code | reason
${statusCodes.BAD_REQUEST} | ${'Parameters are missing or incorrect'}
${statusCodes.UNPROCESSABLE_ENTITY} | ${"Expression can't be executed"}
${statusCodes.SERVICE_UNAVAILABLE} | ${'Query timed out or aborted'}
`('rejects with details: "$reason" after getting an HTTP $code error', ({ code, reason }) => {
mock.onGet(prometheusEndpoint).reply(code, {
status: 'error',
error: reason,
});
return getPrometheusQueryData(prometheusEndpoint, params).catch(error => {
expect(error).toEqual(new Error(reason));
expect(mock.history.get).toHaveLength(1);
});
});
});
});
......@@ -8,6 +8,7 @@ import createFlash from '~/flash';
import { defaultTimeRange } from '~/vue_shared/constants';
import * as getters from '~/monitoring/stores/getters';
import { ENVIRONMENT_AVAILABLE_STATE } from '~/monitoring/constants';
import { backoffMockImplementation } from 'jest/helpers/backoff_helper';
import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types';
......@@ -73,19 +74,7 @@ describe('Monitoring store actions', () => {
commit = jest.fn();
dispatch = jest.fn();
jest.spyOn(commonUtils, 'backOff').mockImplementation(callback => {
const q = new Promise((resolve, reject) => {
const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg));
const next = () => callback(next, stop);
// Define a timeout based on a mock timer
setTimeout(() => {
callback(next, stop);
});
});
// Run all resolved promises in chain
jest.runOnlyPendingTimers();
return q;
});
jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
});
afterEach(() => {
......@@ -483,7 +472,6 @@ describe('Monitoring store actions', () => {
],
[],
() => {
expect(mock.history.get).toHaveLength(1);
done();
},
).catch(done.fail);
......@@ -569,46 +557,8 @@ describe('Monitoring store actions', () => {
});
});
it('commits result, when waiting for results', done => {
// Mock multiple attempts while the cache is filling up
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).reply(200, { data }); // 4th attempt
testAction(
fetchPrometheusMetric,
{ metric, defaultQueryParams },
state,
[
{
type: types.REQUEST_METRIC_RESULT,
payload: {
metricId: metric.metricId,
},
},
{
type: types.RECEIVE_METRIC_RESULT_SUCCESS,
payload: {
metricId: metric.metricId,
data,
},
},
],
[],
() => {
expect(mock.history.get).toHaveLength(4);
done();
},
).catch(done.fail);
});
it('commits failure, when waiting for results and getting a server error', done => {
// Mock multiple attempts while the cache is filling up and fails
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).reply(500); // 4th attempt
mock.onGet(prometheusEndpointPath).reply(500);
const error = new Error('Request failed with status code 500');
......@@ -633,7 +583,6 @@ describe('Monitoring store actions', () => {
],
[],
).catch(e => {
expect(mock.history.get).toHaveLength(4);
expect(e).toEqual(error);
done();
});
......
......@@ -3,17 +3,25 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import SnippetHeader from '~/snippets/components/snippet_header.vue';
import SnippetTitle from '~/snippets/components/snippet_title.vue';
import SnippetBlob from '~/snippets/components/snippet_blob_view.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import { shallowMount } from '@vue/test-utils';
import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants';
import {
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_PUBLIC,
} from '~/snippets/constants';
describe('Snippet view app', () => {
let wrapper;
const defaultProps = {
snippetGid: 'gid://gitlab/PersonalSnippet/42',
};
const webUrl = 'http://foo.bar';
const dummyHTTPUrl = webUrl;
const dummySSHUrl = 'ssh://foo.bar';
function createComponent({ props = defaultProps, data = {}, loading = false } = {}) {
const $apollo = {
......@@ -72,4 +80,47 @@ describe('Snippet view app', () => {
expect(blobs.at(0).props('blob')).toEqual(Blob);
expect(blobs.at(1).props('blob')).toEqual(BinaryBlob);
});
describe('Embed dropdown rendering', () => {
it.each`
visibilityLevel | condition | isRendered
${SNIPPET_VISIBILITY_INTERNAL} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PRIVATE} | ${'not render'} | ${false}
${'foo'} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PUBLIC} | ${'render'} | ${true}
`('does $condition blob-embeddable by default', ({ visibilityLevel, isRendered }) => {
createComponent({
data: {
snippet: {
visibilityLevel,
webUrl,
},
},
});
expect(wrapper.contains(BlobEmbeddable)).toBe(isRendered);
});
});
describe('Clone button rendering', () => {
it.each`
httpUrlToRepo | sshUrlToRepo | shouldRender | isRendered
${null} | ${null} | ${'Should not'} | ${false}
${null} | ${dummySSHUrl} | ${'Should'} | ${true}
${dummyHTTPUrl} | ${null} | ${'Should'} | ${true}
${dummyHTTPUrl} | ${dummySSHUrl} | ${'Should'} | ${true}
`(
'$shouldRender render "Clone" button when `httpUrlToRepo` is $httpUrlToRepo and `sshUrlToRepo` is $sshUrlToRepo',
({ httpUrlToRepo, sshUrlToRepo, isRendered }) => {
createComponent({
data: {
snippet: {
sshUrlToRepo,
httpUrlToRepo,
},
},
});
expect(wrapper.contains(CloneDropdownButton)).toBe(isRendered);
},
);
});
});
import { mount } from '@vue/test-utils';
import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue';
import BlobHeader from '~/blob/components/blob_header.vue';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import BlobContent from '~/blob/components/blob_content.vue';
import {
BLOB_RENDER_EVENT_LOAD,
......@@ -9,11 +8,7 @@ import {
BLOB_RENDER_ERRORS,
} from '~/blob/components/constants';
import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers';
import {
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PUBLIC,
} from '~/snippets/constants';
import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants';
import { Blob as BlobMock, SimpleViewerMock, RichViewerMock } from 'jest/blob/components/mock_data';
......@@ -72,18 +67,6 @@ describe('Blob Embeddable', () => {
expect(wrapper.find(BlobContent).exists()).toBe(true);
});
it.each([SNIPPET_VISIBILITY_INTERNAL, SNIPPET_VISIBILITY_PRIVATE, 'foo'])(
'does not render blob-embeddable by default',
visibilityLevel => {
createComponent({
snippetProps: {
visibilityLevel,
},
});
expect(wrapper.find(BlobEmbeddable).exists()).toBe(false);
},
);
it('sets simple viewer correctly', () => {
createComponent();
expect(wrapper.find(SimpleViewer).exists()).toBe(true);
......
......@@ -231,7 +231,7 @@ RSpec.describe PipelineSerializer do
# :source_pipeline and :source_job
# Existing numbers are high and require performance optimization
# https://gitlab.com/gitlab-org/gitlab/-/issues/225156
expected_queries = Gitlab.ee? ? 101 : 92
expected_queries = Gitlab.ee? ? 95 : 86
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册