Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
6d706d5dc0
commit
a7ad649614
|
@ -277,6 +277,7 @@ export default {
|
|||
v-model="variable.key"
|
||||
:token-list="$options.tokenList"
|
||||
:label-text="__('Key')"
|
||||
data-testid="pipeline-form-ci-variable-key"
|
||||
data-qa-selector="ci_variable_key_field"
|
||||
/>
|
||||
|
||||
|
@ -293,6 +294,7 @@ export default {
|
|||
:state="variableValidationState"
|
||||
rows="3"
|
||||
max-rows="6"
|
||||
data-testid="pipeline-form-ci-variable-value"
|
||||
data-qa-selector="ci_variable_value_field"
|
||||
class="gl-font-monospace!"
|
||||
/>
|
||||
|
|
|
@ -255,6 +255,7 @@ export default {
|
|||
v-model="key"
|
||||
:token-list="$options.tokenList"
|
||||
:label-text="__('Key')"
|
||||
data-testid="pipeline-form-ci-variable-key"
|
||||
data-qa-selector="ci_variable_key_field"
|
||||
/>
|
||||
|
||||
|
@ -271,6 +272,7 @@ export default {
|
|||
:state="variableValidationState"
|
||||
rows="3"
|
||||
max-rows="6"
|
||||
data-testid="pipeline-form-ci-variable-value"
|
||||
data-qa-selector="ci_variable_value_field"
|
||||
class="gl-font-monospace!"
|
||||
/>
|
||||
|
|
|
@ -163,7 +163,6 @@ export default {
|
|||
v-gl-modal="'configure-feature-flags'"
|
||||
variant="confirm"
|
||||
category="secondary"
|
||||
data-qa-selector="configure_feature_flags_button"
|
||||
data-testid="ff-configure-button"
|
||||
class="gl-mb-3"
|
||||
>
|
||||
|
|
|
@ -142,9 +142,16 @@ export const dayInQuarter = (date, quarter) => {
|
|||
|
||||
export const millisecondsPerDay = 1000 * 60 * 60 * 24;
|
||||
|
||||
export const getDayDifference = (a, b) => {
|
||||
const date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
||||
const date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
||||
/**
|
||||
* Calculates the number of days between 2 specified dates, excluding the current date
|
||||
*
|
||||
* @param {Date} startDate the earlier date that we will substract from the end date
|
||||
* @param {Date} endDate the last date in the range
|
||||
* @return {Number} number of days in between
|
||||
*/
|
||||
export const getDayDifference = (startDate, endDate) => {
|
||||
const date1 = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
||||
const date2 = Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
||||
|
||||
return Math.floor((date2 - date1) / millisecondsPerDay);
|
||||
};
|
||||
|
|
|
@ -88,7 +88,8 @@ export default {
|
|||
:action-primary="actionPrimary"
|
||||
:title="actionText"
|
||||
:visible="removeMemberModalVisible"
|
||||
data-qa-selector="remove_member_modal_content"
|
||||
data-qa-selector="remove_member_modal"
|
||||
data-testid="remove-member-modal-content"
|
||||
@primary="submitForm"
|
||||
@hide="hideRemoveMemberModal"
|
||||
>
|
||||
|
|
|
@ -391,7 +391,11 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="prometheus-graphs" data-qa-selector="prometheus_graphs">
|
||||
<div
|
||||
class="prometheus-graphs"
|
||||
data-qa-selector="prometheus_graphs_content"
|
||||
data-testid="prometheus-graphs"
|
||||
>
|
||||
<div>
|
||||
<gl-alert
|
||||
v-if="!isDeprecationNoticeDismissed"
|
||||
|
|
|
@ -189,6 +189,7 @@ export default {
|
|||
ref="monitorEnvironmentsDropdown"
|
||||
class="flex-grow-1"
|
||||
data-qa-selector="environments_dropdown"
|
||||
data-testid="environments-dropdown"
|
||||
toggle-class="dropdown-menu-toggle"
|
||||
menu-class="monitor-environment-dropdown-menu"
|
||||
:text="environmentDropdownText"
|
||||
|
|
|
@ -59,6 +59,7 @@ export default {
|
|||
<resolve-discussion-button
|
||||
v-if="discussion.resolvable"
|
||||
data-qa-selector="resolve_discussion_button"
|
||||
data-testid="resolve-discussion-button"
|
||||
:is-resolving="isResolving"
|
||||
:button-title="resolveButtonTitle"
|
||||
@onClick="$emit('resolve')"
|
||||
|
|
|
@ -98,7 +98,7 @@ export default {
|
|||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div data-qa-selector="packages-table">
|
||||
<div data-testid="packages-table">
|
||||
<packages-list-row
|
||||
v-for="packageEntity in list"
|
||||
:key="packageEntity.id"
|
||||
|
|
|
@ -78,7 +78,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<list-item data-qa-selector="package_row" :disabled="disabledRow">
|
||||
<list-item data-testid="package-row" :disabled="disabledRow">
|
||||
<template #left-primary>
|
||||
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
|
||||
<gl-link
|
||||
|
|
|
@ -90,7 +90,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<list-item data-qa-selector="package_row">
|
||||
<list-item data-testid="package-row">
|
||||
<template #left-primary>
|
||||
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
|
||||
<router-link
|
||||
|
|
|
@ -151,7 +151,7 @@ export default {
|
|||
@primaryAction="showConfirmationModal"
|
||||
>{{ $options.i18n.errorMessageBodyAlert }}</gl-alert
|
||||
>
|
||||
<div data-qa-selector="packages-table">
|
||||
<div data-testid="packages-table">
|
||||
<packages-list-row
|
||||
v-for="packageEntity in list"
|
||||
:key="packageEntity.id"
|
||||
|
|
|
@ -87,7 +87,7 @@ export default {
|
|||
v-else-if="!loadingContentFailed && !isLoadingContent"
|
||||
ref="content"
|
||||
data-qa-selector="wiki_page_content"
|
||||
data-testid="wiki_page_content"
|
||||
data-testid="wiki-page-content"
|
||||
class="js-wiki-page-content md"
|
||||
v-html="content /* eslint-disable-line vue/no-v-html */"
|
||||
></div>
|
||||
|
|
|
@ -244,7 +244,7 @@ export default {
|
|||
/><span class="position-relative">{{ fullPath }}</span>
|
||||
</component>
|
||||
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
|
||||
<gl-badge v-if="lfsOid" variant="muted" size="sm" class="ml-1" data-qa-selector="label-lfs"
|
||||
<gl-badge v-if="lfsOid" variant="muted" size="sm" class="ml-1" data-testid="label-lfs"
|
||||
>LFS</gl-badge
|
||||
>
|
||||
<!-- eslint-enable @gitlab/vue-require-i18n-strings -->
|
||||
|
|
|
@ -32,17 +32,14 @@ export default {
|
|||
<div>
|
||||
<runner-status-badge
|
||||
:runner="runner"
|
||||
size="sm"
|
||||
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
|
||||
/>
|
||||
<runner-upgrade-status-badge
|
||||
:runner="runner"
|
||||
size="sm"
|
||||
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
|
||||
/>
|
||||
<runner-paused-badge
|
||||
v-if="paused"
|
||||
size="sm"
|
||||
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -57,7 +57,7 @@ export default {
|
|||
:title="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
name="lock"
|
||||
/>
|
||||
<runner-type-badge class="gl-ml-2" :type="runnerType" size="sm" />
|
||||
<runner-type-badge class="gl-ml-2 gl-vertical-align-middle" :type="runnerType" size="sm" />
|
||||
|
||||
<tooltip-on-truncate class="gl-display-block gl-text-truncate" :title="description">
|
||||
{{ description }}
|
||||
|
|
|
@ -38,31 +38,33 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
|
||||
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-gap-3 gl-flex-wrap gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
|
||||
>
|
||||
<div>
|
||||
<div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-flex-wrap">
|
||||
<runner-status-badge :runner="runner" />
|
||||
<runner-type-badge v-if="runner" :type="runner.runnerType" />
|
||||
<template v-if="runner.createdAt">
|
||||
<gl-sprintf :message="__('%{runner} created %{timeago}')">
|
||||
<template #runner>
|
||||
<strong>{{ heading }}</strong>
|
||||
<gl-icon
|
||||
v-if="runner.locked"
|
||||
v-gl-tooltip="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
name="lock"
|
||||
:aria-label="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
/>
|
||||
</template>
|
||||
<template #timeago>
|
||||
<time-ago :time="runner.createdAt" />
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<template v-else>
|
||||
<strong>{{ heading }}</strong>
|
||||
</template>
|
||||
<span>
|
||||
<template v-if="runner.createdAt">
|
||||
<gl-sprintf :message="__('%{runner} created %{timeago}')">
|
||||
<template #runner>
|
||||
<strong>{{ heading }}</strong>
|
||||
<gl-icon
|
||||
v-if="runner.locked"
|
||||
v-gl-tooltip="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
name="lock"
|
||||
:aria-label="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
|
||||
/>
|
||||
</template>
|
||||
<template #timeago>
|
||||
<time-ago :time="runner.createdAt" />
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<template v-else>
|
||||
<strong>{{ heading }}</strong>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="gl-ml-auto gl-flex-shrink-0"><slot name="actions"></slot></div>
|
||||
<div class="gl-display-flex gl-gap-3 gl-flex-wrap"><slot name="actions"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -14,7 +14,7 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<span class="gl-font-weight-bold"
|
||||
<span class="gl-font-weight-bold gl-vertical-align-middle"
|
||||
>#{{ getIdFromGraphQLId(runner.id) }} ({{ runner.shortSha }})</span
|
||||
>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { I18N_PAUSED_DESCRIPTION } from '../constants';
|
||||
import { I18N_PAUSED, I18N_PAUSED_DESCRIPTION } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -9,11 +9,17 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
I18N_PAUSED,
|
||||
I18N_PAUSED_DESCRIPTION,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION" variant="danger" v-bind="$attrs">
|
||||
{{ s__('Runners|paused') }}
|
||||
<gl-badge
|
||||
v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION"
|
||||
variant="warning"
|
||||
icon="status-paused"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
{{ $options.I18N_PAUSED }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
<script>
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { getTimeago } from '~/lib/utils/datetime_utility';
|
||||
import {
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_NEVER_CONTACTED,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
I18N_ONLINE_TIMEAGO_TOOLTIP,
|
||||
I18N_NEVER_CONTACTED_TOOLTIP,
|
||||
I18N_OFFLINE_TIMEAGO_TOOLTIP,
|
||||
|
@ -39,26 +43,30 @@ export default {
|
|||
switch (this.runner?.status) {
|
||||
case STATUS_ONLINE:
|
||||
return {
|
||||
icon: 'status-active',
|
||||
variant: 'success',
|
||||
label: s__('Runners|online'),
|
||||
label: I18N_STATUS_ONLINE,
|
||||
tooltip: this.timeAgoTooltip(I18N_ONLINE_TIMEAGO_TOOLTIP),
|
||||
};
|
||||
case STATUS_NEVER_CONTACTED:
|
||||
return {
|
||||
icon: 'time-out',
|
||||
variant: 'muted',
|
||||
label: s__('Runners|never contacted'),
|
||||
label: I18N_STATUS_NEVER_CONTACTED,
|
||||
tooltip: I18N_NEVER_CONTACTED_TOOLTIP,
|
||||
};
|
||||
case STATUS_OFFLINE:
|
||||
return {
|
||||
icon: 'time-out',
|
||||
variant: 'muted',
|
||||
label: s__('Runners|offline'),
|
||||
label: I18N_STATUS_OFFLINE,
|
||||
tooltip: this.timeAgoTooltip(I18N_OFFLINE_TIMEAGO_TOOLTIP),
|
||||
};
|
||||
case STATUS_STALE:
|
||||
return {
|
||||
icon: 'time-out',
|
||||
variant: 'warning',
|
||||
label: s__('Runners|stale'),
|
||||
label: I18N_STATUS_STALE,
|
||||
// runner may have contacted (or not) and be stale: consider both cases.
|
||||
tooltip: this.runner.contactedAt
|
||||
? this.timeAgoTooltip(I18N_STALE_TIMEAGO_TOOLTIP)
|
||||
|
@ -77,7 +85,13 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge v-if="badge" v-gl-tooltip="badge.tooltip" :variant="badge.variant" v-bind="$attrs">
|
||||
<gl-badge
|
||||
v-if="badge"
|
||||
v-gl-tooltip="badge.tooltip"
|
||||
:variant="badge.variant"
|
||||
:icon="badge.icon"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
{{ badge.label }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
<script>
|
||||
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import {
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PROJECT_TYPE,
|
||||
I18N_INSTANCE_TYPE,
|
||||
I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
I18N_GROUP_TYPE,
|
||||
I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
I18N_PROJECT_TYPE,
|
||||
I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
} from '../constants';
|
||||
|
||||
const BADGE_DATA = {
|
||||
[INSTANCE_TYPE]: {
|
||||
text: s__('Runners|shared'),
|
||||
icon: 'users',
|
||||
text: I18N_INSTANCE_TYPE,
|
||||
tooltip: I18N_INSTANCE_RUNNER_DESCRIPTION,
|
||||
},
|
||||
[GROUP_TYPE]: {
|
||||
text: s__('Runners|group'),
|
||||
icon: 'group',
|
||||
text: I18N_GROUP_TYPE,
|
||||
tooltip: I18N_GROUP_RUNNER_DESCRIPTION,
|
||||
},
|
||||
[PROJECT_TYPE]: {
|
||||
text: s__('Runners|specific'),
|
||||
icon: 'project',
|
||||
text: I18N_PROJECT_TYPE,
|
||||
tooltip: I18N_PROJECT_RUNNER_DESCRIPTION,
|
||||
},
|
||||
};
|
||||
|
@ -50,7 +55,13 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge v-if="badge" v-gl-tooltip="badge.tooltip" variant="info" v-bind="$attrs">
|
||||
<gl-badge
|
||||
v-if="badge"
|
||||
v-gl-tooltip="badge.tooltip"
|
||||
variant="muted"
|
||||
:icon="badge.icon"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
{{ badge.text }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
import { __ } from '~/locale';
|
||||
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
import { PARAM_KEY_PAUSED } from '../../constants';
|
||||
import { PARAM_KEY_PAUSED, I18N_PAUSED } from '../../constants';
|
||||
|
||||
const options = [
|
||||
{ value: 'true', title: __('Yes') },
|
||||
|
@ -10,7 +10,7 @@ const options = [
|
|||
|
||||
export const pausedTokenConfig = {
|
||||
icon: 'pause',
|
||||
title: s__('Runners|Paused'),
|
||||
title: I18N_PAUSED,
|
||||
type: PARAM_KEY_PAUSED,
|
||||
token: BaseToken,
|
||||
unique: true,
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
import { __ } from '~/locale';
|
||||
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
import {
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_NEVER_CONTACTED,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
STATUS_ONLINE,
|
||||
STATUS_OFFLINE,
|
||||
STATUS_NEVER_CONTACTED,
|
||||
|
@ -10,10 +14,10 @@ import {
|
|||
} from '../../constants';
|
||||
|
||||
const options = [
|
||||
{ value: STATUS_ONLINE, title: s__('Runners|Online') },
|
||||
{ value: STATUS_OFFLINE, title: s__('Runners|Offline') },
|
||||
{ value: STATUS_NEVER_CONTACTED, title: s__('Runners|Never contacted') },
|
||||
{ value: STATUS_STALE, title: s__('Runners|Stale') },
|
||||
{ value: STATUS_ONLINE, title: I18N_STATUS_ONLINE },
|
||||
{ value: STATUS_OFFLINE, title: I18N_STATUS_OFFLINE },
|
||||
{ value: STATUS_NEVER_CONTACTED, title: I18N_STATUS_NEVER_CONTACTED },
|
||||
{ value: STATUS_STALE, title: I18N_STATUS_STALE },
|
||||
];
|
||||
|
||||
export const statusTokenConfig = {
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<script>
|
||||
import { s__ } from '~/locale';
|
||||
import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
|
||||
import { STATUS_ONLINE, STATUS_OFFLINE, STATUS_STALE } from '../../constants';
|
||||
import {
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
STATUS_ONLINE,
|
||||
STATUS_OFFLINE,
|
||||
STATUS_STALE,
|
||||
} from '../../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -29,7 +35,7 @@ export default {
|
|||
skip: this.statusCountSkip(STATUS_ONLINE),
|
||||
variables: { ...this.variables, status: STATUS_ONLINE },
|
||||
variant: 'success',
|
||||
title: s__('Runners|Online'),
|
||||
title: I18N_STATUS_ONLINE,
|
||||
metaIcon: 'status-active',
|
||||
},
|
||||
},
|
||||
|
@ -39,7 +45,7 @@ export default {
|
|||
skip: this.statusCountSkip(STATUS_OFFLINE),
|
||||
variables: { ...this.variables, status: STATUS_OFFLINE },
|
||||
variant: 'muted',
|
||||
title: s__('Runners|Offline'),
|
||||
title: I18N_STATUS_OFFLINE,
|
||||
metaIcon: 'status-waiting',
|
||||
},
|
||||
},
|
||||
|
@ -49,7 +55,7 @@ export default {
|
|||
skip: this.statusCountSkip(STATUS_STALE),
|
||||
variables: { ...this.variables, status: STATUS_STALE },
|
||||
variant: 'warning',
|
||||
title: s__('Runners|Stale'),
|
||||
title: I18N_STATUS_STALE,
|
||||
metaIcon: 'time-out',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -23,6 +23,12 @@ export const I18N_GROUP_RUNNER_DESCRIPTION = s__(
|
|||
);
|
||||
export const I18N_PROJECT_RUNNER_DESCRIPTION = s__('Runners|Associated with one or more projects');
|
||||
|
||||
// Status
|
||||
export const I18N_STATUS_ONLINE = s__('Runners|Online');
|
||||
export const I18N_STATUS_NEVER_CONTACTED = s__('Runners|Never contacted');
|
||||
export const I18N_STATUS_OFFLINE = s__('Runners|Offline');
|
||||
export const I18N_STATUS_STALE = s__('Runners|Stale');
|
||||
|
||||
// Status help popover
|
||||
export const I18N_STATUS_POPOVER_TITLE = s__('Runners|Runner statuses');
|
||||
|
||||
|
@ -62,6 +68,7 @@ export const I18N_STALE_NEVER_CONTACTED_TOOLTIP = s__(
|
|||
export const I18N_EDIT = __('Edit');
|
||||
|
||||
export const I18N_PAUSE = __('Pause');
|
||||
export const I18N_PAUSED = s__('Runners|Paused');
|
||||
export const I18N_PAUSE_TOOLTIP = s__('Runners|Pause from accepting jobs');
|
||||
export const I18N_PAUSED_DESCRIPTION = s__('Runners|Not accepting jobs');
|
||||
|
||||
|
@ -94,7 +101,7 @@ export const I18N_NO_JOBS_FOUND = s__('Runners|This runner has not run any jobs.
|
|||
|
||||
// Styles
|
||||
|
||||
export const RUNNER_TAG_BADGE_VARIANT = 'neutral';
|
||||
export const RUNNER_TAG_BADGE_VARIANT = 'info';
|
||||
export const RUNNER_TAG_BG_CLASS = 'gl-bg-blue-100';
|
||||
|
||||
// Filtered search parameter names
|
||||
|
|
|
@ -16,7 +16,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<copyable-field
|
||||
data-qa-selector="copy-forward-email"
|
||||
data-testid="copy-forward-email"
|
||||
:name="s__('RightSidebar|Issue email')"
|
||||
:clipboard-tooltip-text="s__('RightSidebar|Copy email address')"
|
||||
:value="issueEmailAddress"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.js-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki_page_content', tracking_context: wiki_page_tracking_context(@page).to_json } }
|
||||
.js-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki-page-content', tracking_context: wiki_page_tracking_context(@page).to_json } }
|
||||
= render_wiki_content(@page)
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
.gl-mt-5.gl-mb-3
|
||||
.gl-display-flex.gl-justify-content-space-between
|
||||
%h2.gl-mt-0.gl-mb-5{ data: { qa_selector: 'wiki_page_title', testid: 'wiki_page_title' } }= @page ? @page.human_title : _('Failed to retrieve page')
|
||||
.js-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki_page_content' } }
|
||||
.js-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki-page-content' } }
|
||||
= _('The page could not be displayed because it timed out.')
|
||||
= html_escape(_('You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}')) % { linkStart: "<a href=\"#{git_access_url}\">".html_safe, linkEnd: '</a>'.html_safe, cloneIcon: sprite_icon('download', css_class: 'gl-mr-2').html_safe }
|
||||
|
|
|
@ -27,6 +27,6 @@
|
|||
- if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding
|
||||
= link_to sprite_icon('pencil', css_class: 'gl-icon'), wiki_page_path(@wiki, @page, action: :edit), title: 'Edit', role: "button", class: 'btn gl-button btn-icon btn-default js-wiki-edit', data: { qa_selector: 'edit_page_button', testid: 'wiki_edit_button' }
|
||||
|
||||
.js-async-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki_page_content', tracking_context: wiki_page_tracking_context(@page).to_json, get_wiki_content_url: wiki_page_render_api_endpoint(@page) } }
|
||||
.js-async-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki-page-content', tracking_context: wiki_page_tracking_context(@page).to_json, get_wiki_content_url: wiki_page_render_api_endpoint(@page) } }
|
||||
|
||||
= render 'shared/wikis/sidebar'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name: cache_issue_sums
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95048
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365940
|
||||
milestone: '15.3'
|
||||
milestone: '15.4'
|
||||
type: development
|
||||
group: group::product planning
|
||||
default_enabled: false
|
||||
|
|
|
@ -81,7 +81,6 @@ module Gitlab
|
|||
# @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
|
||||
# @return [Array<String>]
|
||||
def cached_collection(collection, presenter:, presenter_args:, context:, expires_in:)
|
||||
total_count = collection.size
|
||||
misses = 0
|
||||
|
||||
json = fetch_multi(presenter, collection, context: context, expires_in: expires_in) do |obj|
|
||||
|
@ -92,7 +91,7 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
increment_cache_metric(render_type: :collection, total_count: total_count, miss_count: misses)
|
||||
increment_cache_metric(render_type: :collection, total_count: collection.length, miss_count: misses)
|
||||
|
||||
json.values
|
||||
end
|
||||
|
|
|
@ -34251,15 +34251,6 @@ msgstr ""
|
|||
msgid "Runners|group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|never contacted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|offline"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|online"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|paused"
|
||||
msgstr ""
|
||||
|
||||
|
@ -34269,15 +34260,6 @@ msgstr ""
|
|||
msgid "Runners|specific"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|stale"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|upgrade available"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|upgrade recommended"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runner|Owner"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ module QA
|
|||
include Page::Component::MembersFilter
|
||||
|
||||
view 'app/assets/javascripts/members/components/modals/remove_member_modal.vue' do
|
||||
element :remove_member_modal_content
|
||||
element :remove_member_modal
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/pages/groups/group_members/index.js' do
|
||||
|
@ -45,7 +45,7 @@ module QA
|
|||
click_element :delete_member_button
|
||||
end
|
||||
|
||||
within_element(:remove_member_modal_content) do
|
||||
within_element(:remove_member_modal) do
|
||||
click_button("Remove member")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module QA
|
|||
LOADING_MESSAGE = 'Waiting for performance data'
|
||||
|
||||
view 'app/assets/javascripts/monitoring/components/dashboard.vue' do
|
||||
element :prometheus_graphs
|
||||
element :prometheus_graphs_content
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/monitoring/components/dashboard_header.vue' do
|
||||
|
@ -54,7 +54,7 @@ module QA
|
|||
end
|
||||
|
||||
def has_metrics?
|
||||
within_element :prometheus_graphs do
|
||||
within_element :prometheus_graphs_content do
|
||||
has_text?(EXPECTED_TITLE)
|
||||
end
|
||||
end
|
||||
|
@ -102,7 +102,7 @@ module QA
|
|||
end
|
||||
|
||||
def has_custom_metric?(metric)
|
||||
within_element :prometheus_graphs do
|
||||
within_element :prometheus_graphs_content do
|
||||
has_text?(metric)
|
||||
end
|
||||
end
|
||||
|
@ -114,7 +114,7 @@ module QA
|
|||
end
|
||||
|
||||
def has_template_metric?(metric)
|
||||
within_element :prometheus_graphs do
|
||||
within_element :prometheus_graphs_content do
|
||||
has_text?(metric)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,12 +6,10 @@ module QA
|
|||
module Packages
|
||||
class Index < QA::Page::Base
|
||||
view 'app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue' do
|
||||
element :package_row
|
||||
element :package_link
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/packages_and_registries/infrastructure_registry/shared/package_list_row.vue' do
|
||||
element :package_row
|
||||
element :package_link
|
||||
end
|
||||
|
||||
|
|
|
@ -263,22 +263,6 @@ module QA
|
|||
ENV['GITLAB_QA_PASSWORD_6']
|
||||
end
|
||||
|
||||
def gitlab_qa_1p_email
|
||||
ENV['GITLAB_QA_1P_EMAIL']
|
||||
end
|
||||
|
||||
def gitlab_qa_1p_password
|
||||
ENV['GITLAB_QA_1P_PASSWORD']
|
||||
end
|
||||
|
||||
def gitlab_qa_1p_secret
|
||||
ENV['GITLAB_QA_1P_SECRET']
|
||||
end
|
||||
|
||||
def gitlab_qa_1p_github_uuid
|
||||
ENV['GITLAB_QA_1P_GITHUB_UUID']
|
||||
end
|
||||
|
||||
def jira_admin_username
|
||||
ENV['JIRA_ADMIN_USERNAME']
|
||||
end
|
||||
|
|
|
@ -50,7 +50,7 @@ RSpec.describe "Admin Runners" do
|
|||
|
||||
it 'shows an instance badge' do
|
||||
within_runner_row(instance_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'shared'
|
||||
expect(page).to have_selector '.badge', text: 'Instance'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -66,9 +66,9 @@ RSpec.describe "Admin Runners" do
|
|||
|
||||
it 'has all necessary texts' do
|
||||
expect(page).to have_text "Register an instance runner"
|
||||
expect(page).to have_text "Online 1"
|
||||
expect(page).to have_text "Offline 2"
|
||||
expect(page).to have_text "Stale 1"
|
||||
expect(page).to have_text "#{s_('Runners|Online')} 1"
|
||||
expect(page).to have_text "#{s_('Runners|Offline')} 2"
|
||||
expect(page).to have_text "#{s_('Runners|Stale')} 1"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -145,7 +145,7 @@ RSpec.describe "Admin Runners" do
|
|||
end
|
||||
|
||||
it 'shows paused runners' do
|
||||
input_filtered_search_filter_is_only('Paused', 'Yes')
|
||||
input_filtered_search_filter_is_only(s_('Runners|Paused'), 'Yes')
|
||||
|
||||
expect(page).to have_link('All 1')
|
||||
|
||||
|
@ -154,7 +154,7 @@ RSpec.describe "Admin Runners" do
|
|||
end
|
||||
|
||||
it 'shows active runners' do
|
||||
input_filtered_search_filter_is_only('Paused', 'No')
|
||||
input_filtered_search_filter_is_only(s_('Runners|Paused'), 'No')
|
||||
|
||||
expect(page).to have_link('All 1')
|
||||
|
||||
|
@ -186,7 +186,7 @@ RSpec.describe "Admin Runners" do
|
|||
end
|
||||
|
||||
it 'shows correct runner when status matches' do
|
||||
input_filtered_search_filter_is_only('Status', 'Online')
|
||||
input_filtered_search_filter_is_only('Status', s_('Runners|Online'))
|
||||
|
||||
expect(page).to have_link('All 2')
|
||||
|
||||
|
@ -197,7 +197,7 @@ RSpec.describe "Admin Runners" do
|
|||
end
|
||||
|
||||
it 'shows correct runner when status is selected and search term is entered' do
|
||||
input_filtered_search_filter_is_only('Status', 'Online')
|
||||
input_filtered_search_filter_is_only('Status', s_('Runners|Online'))
|
||||
input_filtered_search_keys('runner-1')
|
||||
|
||||
expect(page).to have_link('All 1')
|
||||
|
@ -220,7 +220,7 @@ RSpec.describe "Admin Runners" do
|
|||
expect(page).to have_content 'runner-never-contacted'
|
||||
|
||||
within_runner_row(never_contacted.id) do
|
||||
expect(page).to have_selector '.badge', text: 'never contacted'
|
||||
expect(page).to have_selector '.badge', text: s_('Runners|Never contacted')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -308,7 +308,7 @@ RSpec.describe "Admin Runners" do
|
|||
|
||||
visit admin_runners_path
|
||||
|
||||
input_filtered_search_filter_is_only('Paused', 'No')
|
||||
input_filtered_search_filter_is_only(s_('Runners|Paused'), 'No')
|
||||
|
||||
expect(page).to have_content 'runner-project'
|
||||
expect(page).to have_content 'runner-group'
|
||||
|
@ -535,6 +535,36 @@ RSpec.describe "Admin Runners" do
|
|||
let(:runner_page_path) { admin_runner_path(project_runner) }
|
||||
end
|
||||
|
||||
describe 'breadcrumbs' do
|
||||
it 'contains the current runner id and token' do
|
||||
page.within '[data-testid="breadcrumb-links"]' do
|
||||
expect(page).to have_link("##{project_runner.id} (#{project_runner.short_sha})")
|
||||
expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_content("Edit")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'runner header', :js do
|
||||
it 'contains the runner status, type and id' do
|
||||
expect(page).to have_content("#{s_('Runners|Never contacted')} Project Runner ##{project_runner.id} created")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a runner is updated', :js do
|
||||
before do
|
||||
click_on _('Save changes')
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'show success alert' do
|
||||
expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
|
||||
end
|
||||
|
||||
it 'redirects to runner page' do
|
||||
expect(current_url).to match(admin_runner_path(project_runner))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'projects' do
|
||||
it 'contains project names' do
|
||||
expect(page).to have_content(project1.full_name)
|
||||
|
|
|
@ -3,14 +3,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Commit > User view commits' do
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
let_it_be(:user) { project.creator }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
|
||||
before do
|
||||
visit project_commits_path(project)
|
||||
end
|
||||
|
||||
describe 'Commits List' do
|
||||
shared_examples 'can view commits' do
|
||||
it 'displays the correct number of commits per day in the header' do
|
||||
expect(first('.js-commit-header').find('.commits-count').text).to eq('1 commit')
|
||||
end
|
||||
|
@ -19,4 +15,51 @@ RSpec.describe 'Commit > User view commits' do
|
|||
expect(page).to have_selector('#commits-list > li:nth-child(2) > ul', count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Commits List' do
|
||||
context 'when project is public' do
|
||||
let(:project) { create(:project, :public, :repository, group: group) }
|
||||
|
||||
before do
|
||||
visit project_commits_path(project)
|
||||
end
|
||||
|
||||
it_behaves_like 'can view commits'
|
||||
end
|
||||
|
||||
context 'when project is public with private repository' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
|
||||
|
||||
context 'and user is an inherited member from the group' do
|
||||
context 'and user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
sign_in(user)
|
||||
visit project_commits_path(project)
|
||||
end
|
||||
|
||||
it_behaves_like 'can view commits'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository, group: group) }
|
||||
|
||||
context 'and user is an inherited member from the group' do
|
||||
context 'and user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
sign_in(user)
|
||||
visit project_commits_path(project)
|
||||
end
|
||||
|
||||
it 'renders not found' do
|
||||
expect(page).to have_title('Not Found')
|
||||
expect(page).to have_content('Page Not Found')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,7 +61,7 @@ RSpec.describe "Group Runners" do
|
|||
|
||||
it 'shows a group badge' do
|
||||
within_runner_row(group_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'group'
|
||||
expect(page).to have_selector '.badge', text: s_('Runners|Group')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -101,9 +101,9 @@ RSpec.describe "Group Runners" do
|
|||
let(:runner) { project_runner }
|
||||
end
|
||||
|
||||
it 'shows a project (specific) badge' do
|
||||
it 'shows a project badge' do
|
||||
within_runner_row(project_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'specific'
|
||||
expect(page).to have_selector '.badge', text: s_('Runners|Project')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -137,7 +137,7 @@ RSpec.describe "Group Runners" do
|
|||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
expect(page).to have_link('Paused')
|
||||
expect(page).to have_link(s_('Runners|Paused'))
|
||||
expect(page).to have_content('Status')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
|
|||
|
||||
context 'resolving the thread' do
|
||||
before do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
it 'hides the link for creating a new issue' do
|
||||
|
|
|
@ -35,7 +35,7 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue',
|
|||
|
||||
context 'resolving the thread' do
|
||||
before do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
it 'hides the link for creating a new issue' do
|
||||
|
|
|
@ -302,7 +302,9 @@ RSpec.describe 'Issue Sidebar' do
|
|||
|
||||
context 'sidebar', :js do
|
||||
it 'finds issue copy forwarding email' do
|
||||
expect(find('[data-qa-selector="copy-forward-email"]').text).to eq "Issue email: #{issue.creatable_note_email_address(user)}" # rubocop:disable QA/SelectorUsage
|
||||
expect(
|
||||
find('[data-testid="copy-forward-email"]').text
|
||||
).to eq "Issue email: #{issue.creatable_note_email_address(user)}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -338,7 +340,7 @@ RSpec.describe 'Issue Sidebar' do
|
|||
end
|
||||
|
||||
it 'does not find issue email' do
|
||||
expect(page).not_to have_selector('[data-qa-selector="copy-forward-email"]') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).not_to have_selector('[data-testid="copy-forward-email"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,7 +66,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to mark thread as resolved' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.discussion-body', visible: false)
|
||||
|
@ -82,7 +82,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to unresolve thread' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
click_button 'Unresolve thread'
|
||||
end
|
||||
|
||||
|
@ -94,7 +94,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
describe 'resolved thread' do
|
||||
before do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
visit_merge_request
|
||||
|
@ -194,7 +194,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to resolve from reply form without a comment' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
page.within '.discussions-counter' do
|
||||
|
@ -229,7 +229,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'hides jump to next button when all resolved' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
expect(page).to have_selector('.discussion-next-btn', visible: false)
|
||||
|
@ -324,7 +324,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
it 'allows user to mark all threads as resolved' do
|
||||
page.all('.discussion-reply-holder', count: 2).each do |reply_holder|
|
||||
page.within reply_holder do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -335,7 +335,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to quickly scroll to next unresolved thread' do
|
||||
page.within('.discussion-reply-holder', match: :first) do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
page.within '.discussions-counter' do
|
||||
|
@ -406,7 +406,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to mark thread as resolved' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
end
|
||||
|
||||
page.within '.diff-content .note' do
|
||||
|
@ -420,7 +420,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to unresolve thread' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
click_button 'Unresolve thread'
|
||||
end
|
||||
|
||||
|
@ -447,7 +447,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do
|
|||
|
||||
it 'allows user to comment & unresolve thread' do
|
||||
page.within '.diff-content' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
|
||||
find_field('Reply…').click
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ RSpec.describe 'Environment > Metrics' do
|
|||
click_link 'Monitoring'
|
||||
|
||||
expect(page).to have_current_path(project_metrics_dashboard_path(project, environment: environment.id))
|
||||
expect(page).to have_css('[data-qa-selector="environments_dropdown"]') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).to have_css('[data-testid="environments-dropdown"]')
|
||||
|
||||
within('[data-qa-selector="environments_dropdown"]') do # rubocop:disable QA/SelectorUsage
|
||||
within('[data-testid="environments-dropdown"]') do
|
||||
# Click on the dropdown
|
||||
click_on(environment.name)
|
||||
|
||||
|
@ -59,7 +59,7 @@ RSpec.describe 'Environment > Metrics' do
|
|||
visit_environment(environment)
|
||||
click_link 'Monitoring'
|
||||
|
||||
expect(page).to have_css('[data-qa-selector="prometheus_graphs"]') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).to have_css('[data-testid="prometheus-graphs"]')
|
||||
end
|
||||
|
||||
it_behaves_like 'has environment selector'
|
||||
|
|
|
@ -90,7 +90,7 @@ RSpec.describe 'User sees feature flag list', :js do
|
|||
it 'shows the empty page' do
|
||||
expect(page).to have_text 'Get started with feature flags'
|
||||
expect(page).to have_selector('.btn-confirm', text: 'New feature flag')
|
||||
expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).to have_selector('[data-testid="ff-configure-button"]', text: 'Configure')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ RSpec.describe 'Projects tree', :js do
|
|||
expect(page).to have_selector('.tree-item')
|
||||
expect(page).to have_content('add tests for .gitattributes custom highlighting')
|
||||
expect(page).not_to have_selector('[data-testid="alert-danger"]')
|
||||
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).not_to have_selector('[data-testid="label-lfs"]', text: 'LFS')
|
||||
end
|
||||
|
||||
it 'renders tree table for a subtree without errors' do
|
||||
|
@ -35,7 +35,7 @@ RSpec.describe 'Projects tree', :js do
|
|||
|
||||
expect(page).to have_selector('.tree-item')
|
||||
expect(page).to have_content('add spaces in whitespace file')
|
||||
expect(page).not_to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).not_to have_selector('[data-testid="label-lfs"]', text: 'LFS')
|
||||
expect(page).not_to have_selector('[data-testid="alert-danger"]')
|
||||
end
|
||||
|
||||
|
@ -112,7 +112,7 @@ RSpec.describe 'Projects tree', :js do
|
|||
it 'renders LFS badge on blob item' do
|
||||
visit project_tree_path(project, File.join('master', 'files/lfs'))
|
||||
|
||||
expect(page).to have_selector('[data-qa-selector="label-lfs"]', text: 'LFS') # rubocop:disable QA/SelectorUsage
|
||||
expect(page).to have_selector('[data-testid="label-lfs"]', text: 'LFS')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
exports[`Dashboard template matches the default snapshot 1`] = `
|
||||
<div
|
||||
class="prometheus-graphs"
|
||||
data-qa-selector="prometheus_graphs"
|
||||
data-qa-selector="prometheus_graphs_content"
|
||||
data-testid="prometheus-graphs"
|
||||
environmentstate="available"
|
||||
metricsdashboardbasepath="/monitoring/monitor-project/-/metrics?environment=1"
|
||||
metricsendpoint="/monitoring/monitor-project/-/environments/1/additional_metrics.json"
|
||||
|
@ -60,6 +61,7 @@ exports[`Dashboard template matches the default snapshot 1`] = `
|
|||
clearalltext="Clear all"
|
||||
clearalltextclass="gl-px-5"
|
||||
data-qa-selector="environments_dropdown"
|
||||
data-testid="environments-dropdown"
|
||||
headertext=""
|
||||
hideheaderborder="true"
|
||||
highlighteditemstitle="Selected"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`packages_list_row renders 1`] = `
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
|
||||
data-qa-selector="package_row"
|
||||
data-testid="package-row"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-py-3"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`packages_list_row renders 1`] = `
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
|
||||
data-qa-selector="package_row"
|
||||
data-testid="package-row"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-py-3"
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('pages/shared/wikis/components/wiki_content', () => {
|
|||
|
||||
const findGlAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
|
||||
const findContent = () => wrapper.find('[data-testid="wiki_page_content"]');
|
||||
const findContent = () => wrapper.find('[data-testid="wiki-page-content"]');
|
||||
|
||||
describe('when loading content', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -33,6 +33,12 @@ import {
|
|||
CREATED_ASC,
|
||||
CREATED_DESC,
|
||||
DEFAULT_SORT,
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
I18N_INSTANCE_TYPE,
|
||||
I18N_GROUP_TYPE,
|
||||
I18N_PROJECT_TYPE,
|
||||
INSTANCE_TYPE,
|
||||
PARAM_KEY_PAUSED,
|
||||
PARAM_KEY_STATUS,
|
||||
|
@ -156,15 +162,16 @@ describe('AdminRunnersApp', () => {
|
|||
});
|
||||
|
||||
it('shows the runner tabs', () => {
|
||||
expect(findRunnerTypeTabs().text()).toMatchInterpolatedText(
|
||||
`All ${mockRunnersCount} Instance ${mockRunnersCount} Group ${mockRunnersCount} Project ${mockRunnersCount}`,
|
||||
const tabs = findRunnerTypeTabs().text();
|
||||
expect(tabs).toMatchInterpolatedText(
|
||||
`All ${mockRunnersCount} ${I18N_INSTANCE_TYPE} ${mockRunnersCount} ${I18N_GROUP_TYPE} ${mockRunnersCount} ${I18N_PROJECT_TYPE} ${mockRunnersCount}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the total', () => {
|
||||
expect(findRunnerStats().text()).toContain(`${s__('Runners|Online')} ${mockRunnersCount}`);
|
||||
expect(findRunnerStats().text()).toContain(`${s__('Runners|Offline')} ${mockRunnersCount}`);
|
||||
expect(findRunnerStats().text()).toContain(`${s__('Runners|Stale')} ${mockRunnersCount}`);
|
||||
expect(findRunnerStats().text()).toContain(`${I18N_STATUS_ONLINE} ${mockRunnersCount}`);
|
||||
expect(findRunnerStats().text()).toContain(`${I18N_STATUS_OFFLINE} ${mockRunnersCount}`);
|
||||
expect(findRunnerStats().text()).toContain(`${I18N_STATUS_STALE} ${mockRunnersCount}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import RunnerTags from '~/runner/components/runner_tags.vue';
|
|||
import RunnerSummaryField from '~/runner/components/cells/runner_summary_field.vue';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
|
||||
import { INSTANCE_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
import { INSTANCE_TYPE, I18N_INSTANCE_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
|
||||
import { allRunnersData } from '../../mock_data';
|
||||
|
||||
|
@ -69,7 +69,7 @@ describe('RunnerTypeCell', () => {
|
|||
locked: true,
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toContain('shared');
|
||||
expect(wrapper.text()).toContain(I18N_INSTANCE_TYPE);
|
||||
});
|
||||
|
||||
it('Displays the runner version', () => {
|
||||
|
|
|
@ -3,7 +3,14 @@ import RunnerStatusCell from '~/runner/components/cells/runner_status_cell.vue';
|
|||
|
||||
import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue';
|
||||
import RunnerPausedBadge from '~/runner/components/runner_paused_badge.vue';
|
||||
import { INSTANCE_TYPE, STATUS_ONLINE, STATUS_OFFLINE } from '~/runner/constants';
|
||||
import {
|
||||
I18N_PAUSED,
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_OFFLINE,
|
||||
INSTANCE_TYPE,
|
||||
STATUS_ONLINE,
|
||||
STATUS_OFFLINE,
|
||||
} from '~/runner/constants';
|
||||
|
||||
describe('RunnerStatusCell', () => {
|
||||
let wrapper;
|
||||
|
@ -31,8 +38,8 @@ describe('RunnerStatusCell', () => {
|
|||
it('Displays online status', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.text()).toMatchInterpolatedText('online');
|
||||
expect(findStatusBadge().text()).toBe('online');
|
||||
expect(wrapper.text()).toContain(I18N_STATUS_ONLINE);
|
||||
expect(findStatusBadge().text()).toBe(I18N_STATUS_ONLINE);
|
||||
});
|
||||
|
||||
it('Displays offline status', () => {
|
||||
|
@ -42,8 +49,8 @@ describe('RunnerStatusCell', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toMatchInterpolatedText('offline');
|
||||
expect(findStatusBadge().text()).toBe('offline');
|
||||
expect(wrapper.text()).toMatchInterpolatedText(I18N_STATUS_OFFLINE);
|
||||
expect(findStatusBadge().text()).toBe(I18N_STATUS_OFFLINE);
|
||||
});
|
||||
|
||||
it('Displays paused status', () => {
|
||||
|
@ -54,8 +61,8 @@ describe('RunnerStatusCell', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toMatchInterpolatedText('online paused');
|
||||
expect(findPausedBadge().text()).toBe('paused');
|
||||
expect(wrapper.text()).toMatchInterpolatedText(`${I18N_STATUS_ONLINE} ${I18N_PAUSED}`);
|
||||
expect(findPausedBadge().text()).toBe(I18N_PAUSED);
|
||||
});
|
||||
|
||||
it('Is empty when data is missing', () => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { __ } from '~/locale';
|
|||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import RunnerSummaryCell from '~/runner/components/cells/runner_summary_cell.vue';
|
||||
import RunnerTags from '~/runner/components/runner_tags.vue';
|
||||
import { INSTANCE_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
import { INSTANCE_TYPE, I18N_INSTANCE_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
|
||||
const mockId = '1';
|
||||
const mockShortSha = '2P6oDVDm';
|
||||
|
@ -46,7 +46,7 @@ describe('RunnerTypeCell', () => {
|
|||
});
|
||||
|
||||
it('Displays the runner type', () => {
|
||||
expect(wrapper.text()).toContain('shared');
|
||||
expect(wrapper.text()).toContain(I18N_INSTANCE_TYPE);
|
||||
});
|
||||
|
||||
it('Does not display the locked icon', () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { GROUP_TYPE, STATUS_ONLINE } from '~/runner/constants';
|
||||
import { I18N_STATUS_ONLINE, I18N_GROUP_TYPE, GROUP_TYPE, STATUS_ONLINE } from '~/runner/constants';
|
||||
import { TYPE_CI_RUNNER } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
|
@ -49,7 +49,7 @@ describe('RunnerHeader', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(findRunnerStatusBadge().text()).toContain('online');
|
||||
expect(findRunnerStatusBadge().text()).toContain(I18N_STATUS_ONLINE);
|
||||
});
|
||||
|
||||
it('displays the runner type', () => {
|
||||
|
@ -60,7 +60,7 @@ describe('RunnerHeader', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(findRunnerTypeBadge().text()).toContain('group');
|
||||
expect(findRunnerTypeBadge().text()).toContain(I18N_GROUP_TYPE);
|
||||
});
|
||||
|
||||
it('displays the runner id', () => {
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import RunnerList from '~/runner/components/runner_list.vue';
|
||||
import RunnerStatusPopover from '~/runner/components/runner_status_popover.vue';
|
||||
import { I18N_PROJECT_TYPE, I18N_STATUS_NEVER_CONTACTED } from '~/runner/constants';
|
||||
import { allRunnersData, onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data';
|
||||
|
||||
const mockRunners = allRunnersData.data.runners.nodes;
|
||||
|
@ -91,7 +92,7 @@ describe('RunnerList', () => {
|
|||
createComponent({}, mountExtended);
|
||||
|
||||
// Badges
|
||||
expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText('never contacted');
|
||||
expect(findCell({ fieldKey: 'status' }).text()).toBe(I18N_STATUS_NEVER_CONTACTED);
|
||||
|
||||
// Runner summary
|
||||
expect(findCell({ fieldKey: 'summary' }).text()).toContain(
|
||||
|
@ -262,13 +263,15 @@ describe('RunnerList', () => {
|
|||
const numericId = getIdFromGraphQLId(id);
|
||||
|
||||
// Badges
|
||||
expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText('never contacted');
|
||||
expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText(
|
||||
I18N_STATUS_NEVER_CONTACTED,
|
||||
);
|
||||
|
||||
// Runner summary
|
||||
const summary = findCell({ fieldKey: 'summary' }).text();
|
||||
|
||||
expect(summary).toContain(`#${numericId} (${shortSha})`);
|
||||
expect(summary).toContain('specific');
|
||||
expect(summary).toContain(I18N_PROJECT_TYPE);
|
||||
|
||||
expect(summary).toContain(version);
|
||||
expect(summary).toContain(description);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { GlBadge } from '@gitlab/ui';
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import RunnerStatePausedBadge from '~/runner/components/runner_paused_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { I18N_PAUSED } from '~/runner/constants';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
let wrapper;
|
||||
|
@ -29,8 +30,8 @@ describe('RunnerTypeBadge', () => {
|
|||
});
|
||||
|
||||
it('renders paused state', () => {
|
||||
expect(wrapper.text()).toBe('paused');
|
||||
expect(findBadge().props('variant')).toBe('danger');
|
||||
expect(wrapper.text()).toBe(I18N_PAUSED);
|
||||
expect(findBadge().props('variant')).toBe('warning');
|
||||
});
|
||||
|
||||
it('renders tooltip', () => {
|
||||
|
|
|
@ -3,12 +3,16 @@ import { shallowMount } from '@vue/test-utils';
|
|||
import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import {
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_NEVER_CONTACTED,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
I18N_NEVER_CONTACTED_TOOLTIP,
|
||||
I18N_STALE_NEVER_CONTACTED_TOOLTIP,
|
||||
STATUS_ONLINE,
|
||||
STATUS_OFFLINE,
|
||||
STATUS_STALE,
|
||||
STATUS_NEVER_CONTACTED,
|
||||
I18N_NEVER_CONTACTED_TOOLTIP,
|
||||
I18N_STALE_NEVER_CONTACTED_TOOLTIP,
|
||||
} from '~/runner/constants';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
|
@ -46,7 +50,7 @@ describe('RunnerTypeBadge', () => {
|
|||
it('renders online state', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.text()).toBe('online');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
|
||||
expect(findBadge().props('variant')).toBe('success');
|
||||
expect(getTooltip().value).toBe('Runner is online; last contact was 1 minute ago');
|
||||
});
|
||||
|
@ -59,7 +63,7 @@ describe('RunnerTypeBadge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toBe('never contacted');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_NEVER_CONTACTED);
|
||||
expect(findBadge().props('variant')).toBe('muted');
|
||||
expect(getTooltip().value).toBe(I18N_NEVER_CONTACTED_TOOLTIP);
|
||||
});
|
||||
|
@ -72,7 +76,7 @@ describe('RunnerTypeBadge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toBe('offline');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_OFFLINE);
|
||||
expect(findBadge().props('variant')).toBe('muted');
|
||||
expect(getTooltip().value).toBe('Runner is offline; last contact was 1 day ago');
|
||||
});
|
||||
|
@ -85,7 +89,7 @@ describe('RunnerTypeBadge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toBe('stale');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_STALE);
|
||||
expect(findBadge().props('variant')).toBe('warning');
|
||||
expect(getTooltip().value).toBe('Runner is stale; last contact was 1 year ago');
|
||||
});
|
||||
|
@ -98,7 +102,7 @@ describe('RunnerTypeBadge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toBe('stale');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_STALE);
|
||||
expect(findBadge().props('variant')).toBe('warning');
|
||||
expect(getTooltip().value).toBe(I18N_STALE_NEVER_CONTACTED_TOOLTIP);
|
||||
});
|
||||
|
@ -112,7 +116,7 @@ describe('RunnerTypeBadge', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(wrapper.text()).toBe('online');
|
||||
expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
|
||||
expect(getTooltip().value).toBe('Runner is online; last contact was never');
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { GlBadge } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
|
||||
import { RUNNER_TAG_BADGE_VARIANT } from '~/runner/constants';
|
||||
import RunnerTag from '~/runner/components/runner_tag.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
|
||||
|
@ -48,7 +50,7 @@ describe('RunnerTag', () => {
|
|||
it('Displays tags with correct style', () => {
|
||||
expect(findBadge().props()).toMatchObject({
|
||||
size: 'sm',
|
||||
variant: 'neutral',
|
||||
variant: RUNNER_TAG_BADGE_VARIANT,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ describe('RunnerTags', () => {
|
|||
|
||||
it('Displays tags with correct style', () => {
|
||||
expect(findBadge().props('size')).toBe('sm');
|
||||
expect(findBadge().props('variant')).toBe('neutral');
|
||||
});
|
||||
|
||||
it('Displays tags with md size', () => {
|
||||
|
|
|
@ -2,7 +2,14 @@ import { GlBadge } from '@gitlab/ui';
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import RunnerTypeBadge from '~/runner/components/runner_type_badge.vue';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
|
||||
import {
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PROJECT_TYPE,
|
||||
I18N_INSTANCE_TYPE,
|
||||
I18N_GROUP_TYPE,
|
||||
I18N_PROJECT_TYPE,
|
||||
} from '~/runner/constants';
|
||||
|
||||
describe('RunnerTypeBadge', () => {
|
||||
let wrapper;
|
||||
|
@ -27,9 +34,9 @@ describe('RunnerTypeBadge', () => {
|
|||
|
||||
describe.each`
|
||||
type | text
|
||||
${INSTANCE_TYPE} | ${'shared'}
|
||||
${GROUP_TYPE} | ${'group'}
|
||||
${PROJECT_TYPE} | ${'specific'}
|
||||
${INSTANCE_TYPE} | ${I18N_INSTANCE_TYPE}
|
||||
${GROUP_TYPE} | ${I18N_GROUP_TYPE}
|
||||
${PROJECT_TYPE} | ${I18N_PROJECT_TYPE}
|
||||
`('displays $type runner', ({ type, text }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ props: { type } });
|
||||
|
@ -37,7 +44,7 @@ describe('RunnerTypeBadge', () => {
|
|||
|
||||
it(`as "${text}" with an "info" variant`, () => {
|
||||
expect(findBadge().text()).toBe(text);
|
||||
expect(findBadge().props('variant')).toBe('info');
|
||||
expect(findBadge().props('variant')).toBe('muted');
|
||||
});
|
||||
|
||||
it('with a tooltip', () => {
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import { s__ } from '~/locale';
|
||||
import RunnerStats from '~/runner/components/stat/runner_stats.vue';
|
||||
import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
|
||||
import { INSTANCE_TYPE, STATUS_ONLINE, STATUS_OFFLINE, STATUS_STALE } from '~/runner/constants';
|
||||
import {
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
INSTANCE_TYPE,
|
||||
STATUS_ONLINE,
|
||||
STATUS_OFFLINE,
|
||||
STATUS_STALE,
|
||||
} from '~/runner/constants';
|
||||
|
||||
describe('RunnerStats', () => {
|
||||
let wrapper;
|
||||
|
@ -46,9 +53,9 @@ describe('RunnerStats', () => {
|
|||
});
|
||||
|
||||
const text = wrapper.text();
|
||||
expect(text).toContain(`${s__('Runners|Online')} 3`);
|
||||
expect(text).toContain(`${s__('Runners|Offline')} 2`);
|
||||
expect(text).toContain(`${s__('Runners|Stale')} 1`);
|
||||
expect(text).toContain(`${I18N_STATUS_ONLINE} 3`);
|
||||
expect(text).toContain(`${I18N_STATUS_OFFLINE} 2`);
|
||||
expect(text).toContain(`${I18N_STATUS_STALE} 1`);
|
||||
});
|
||||
|
||||
it('Skips query for other stats', () => {
|
||||
|
|
|
@ -28,6 +28,9 @@ import {
|
|||
CREATED_ASC,
|
||||
CREATED_DESC,
|
||||
DEFAULT_SORT,
|
||||
I18N_STATUS_ONLINE,
|
||||
I18N_STATUS_OFFLINE,
|
||||
I18N_STATUS_STALE,
|
||||
INSTANCE_TYPE,
|
||||
GROUP_TYPE,
|
||||
PARAM_KEY_PAUSED,
|
||||
|
@ -154,9 +157,9 @@ describe('GroupRunnersApp', () => {
|
|||
});
|
||||
|
||||
const text = findRunnerStats().text();
|
||||
expect(text).toContain(`${s__('Runners|Online')} ${mockGroupRunnersCount}`);
|
||||
expect(text).toContain(`${s__('Runners|Offline')} ${mockGroupRunnersCount}`);
|
||||
expect(text).toContain(`${s__('Runners|Stale')} ${mockGroupRunnersCount}`);
|
||||
expect(text).toContain(`${I18N_STATUS_ONLINE} ${mockGroupRunnersCount}`);
|
||||
expect(text).toContain(`${I18N_STATUS_OFFLINE} ${mockGroupRunnersCount}`);
|
||||
expect(text).toContain(`${I18N_STATUS_STALE} ${mockGroupRunnersCount}`);
|
||||
});
|
||||
|
||||
it('shows the runners list', async () => {
|
||||
|
|
|
@ -11,6 +11,7 @@ import RunnerUpdateForm from '~/runner/components/runner_update_form.vue';
|
|||
import runnerFormQuery from '~/runner/graphql/edit/runner_form.query.graphql';
|
||||
import RunnerEditApp from '~//runner/runner_edit/runner_edit_app.vue';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { I18N_STATUS_NEVER_CONTACTED, I18N_INSTANCE_TYPE } from '~/runner/constants';
|
||||
|
||||
import { runnerFormData } from '../mock_data';
|
||||
|
||||
|
@ -69,8 +70,8 @@ describe('RunnerEditApp', () => {
|
|||
it('displays the runner type and status', async () => {
|
||||
await createComponentWithApollo({ mountFn: mount });
|
||||
|
||||
expect(findRunnerHeader().text()).toContain(`never contacted`);
|
||||
expect(findRunnerHeader().text()).toContain(`shared`);
|
||||
expect(findRunnerHeader().text()).toContain(I18N_STATUS_NEVER_CONTACTED);
|
||||
expect(findRunnerHeader().text()).toContain(I18N_INSTANCE_TYPE);
|
||||
});
|
||||
|
||||
it('displays a loading runner form', () => {
|
||||
|
|
|
@ -9,6 +9,7 @@ RSpec.describe Mutations::Commits::Create do
|
|||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
|
||||
let(:context) do
|
||||
GraphQL::Query::Context.new(
|
||||
|
@ -39,20 +40,201 @@ RSpec.describe Mutations::Commits::Create do
|
|||
|
||||
let(:mutated_commit) { subject[:commit] }
|
||||
|
||||
it 'raises an error if the resource is not accessible to the user' do
|
||||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
|
||||
context 'when user does not have enough permissions' do
|
||||
before do
|
||||
project.add_guest(user)
|
||||
end
|
||||
|
||||
context 'when user is not a project member' do
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is a direct project member' do
|
||||
context 'and user is a guest' do
|
||||
before do
|
||||
project.add_guest(user)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and user is a developer' do
|
||||
let(:deltas) { mutated_commit.raw_deltas }
|
||||
|
||||
before_all do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
context 'when service successfully creates a new commit' do
|
||||
it "returns the ETag path for the commit's pipeline" do
|
||||
commit_pipeline_path = subject[:commit_pipeline_path]
|
||||
expect(commit_pipeline_path).to match(%r(pipelines/sha/\w+))
|
||||
end
|
||||
|
||||
it 'returns the content of the commit' do
|
||||
expect(subject[:content]).to eq(actions.pluck(:content))
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: file_path)
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when request has multiple actions' do
|
||||
let(:actions) do
|
||||
[
|
||||
{
|
||||
action: 'create',
|
||||
file_path: 'foo/foobar',
|
||||
content: 'some content'
|
||||
},
|
||||
{
|
||||
action: 'delete',
|
||||
file_path: 'README.md'
|
||||
},
|
||||
{
|
||||
action: 'move',
|
||||
file_path: "LICENSE.md",
|
||||
previous_path: "LICENSE",
|
||||
content: "some content"
|
||||
},
|
||||
{
|
||||
action: 'update',
|
||||
file_path: 'VERSION',
|
||||
content: 'new content'
|
||||
},
|
||||
{
|
||||
action: 'chmod',
|
||||
file_path: 'CHANGELOG',
|
||||
execute_filemode: true
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_path: 'foo/foobar'),
|
||||
a_hash_including(deleted_file: true, new_path: 'README.md'),
|
||||
a_hash_including(deleted_file: true, new_path: 'LICENSE'),
|
||||
a_hash_including(new_file: true, new_path: 'LICENSE.md'),
|
||||
a_hash_including(new_file: false, new_path: 'VERSION'),
|
||||
a_hash_including(a_mode: '100644', b_mode: '100755', new_path: 'CHANGELOG')
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when actions are not defined' do
|
||||
let(:actions) { [] }
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch does not exist' do
|
||||
let(:branch) { 'unknown' }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to match_array(['You can only create or edit files when you are on a branch'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch does not exist and a start branch is provided' do
|
||||
let(:branch) { 'my-branch' }
|
||||
let(:start_branch) { 'master' }
|
||||
let(:actions) do
|
||||
[
|
||||
{
|
||||
action: 'create',
|
||||
file_path: 'ANOTHER_FILE.md',
|
||||
content: 'Bye'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
expect(subject[:content]).to eq(actions.pluck(:content))
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: 'ANOTHER_FILE.md')
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when message is not set' do
|
||||
let(:message) { nil }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when actions are incorrect' do
|
||||
let(:actions) { [{ action: 'unknown', file_path: 'test.md', content: '' }] }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to match_array(['Unknown action \'unknown\''])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch is protected' do
|
||||
before do
|
||||
create(:protected_branch, project: project, name: branch)
|
||||
end
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to match_array(['You are not allowed to push into this branch'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an inherited member from the group' do
|
||||
context 'when project is public with private repository' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
|
||||
|
||||
context 'and user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository, group: group) }
|
||||
|
||||
context 'and user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is a maintainer of a different project' do
|
||||
before do
|
||||
create(:project_empty_repo).add_maintainer(user)
|
||||
|
@ -62,153 +244,6 @@ RSpec.describe Mutations::Commits::Create do
|
|||
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user can create a commit' do
|
||||
let(:deltas) { mutated_commit.raw_deltas }
|
||||
|
||||
before_all do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
context 'when service successfully creates a new commit' do
|
||||
it "returns the ETag path for the commit's pipeline" do
|
||||
commit_pipeline_path = subject[:commit_pipeline_path]
|
||||
expect(commit_pipeline_path).to match(%r(pipelines/sha/\w+))
|
||||
end
|
||||
|
||||
it 'returns the content of the commit' do
|
||||
expect(subject[:content]).to eq(actions.pluck(:content))
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: file_path)
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when request has multiple actions' do
|
||||
let(:actions) do
|
||||
[
|
||||
{
|
||||
action: 'create',
|
||||
file_path: 'foo/foobar',
|
||||
content: 'some content'
|
||||
},
|
||||
{
|
||||
action: 'delete',
|
||||
file_path: 'README.md'
|
||||
},
|
||||
{
|
||||
action: 'move',
|
||||
file_path: "LICENSE.md",
|
||||
previous_path: "LICENSE",
|
||||
content: "some content"
|
||||
},
|
||||
{
|
||||
action: 'update',
|
||||
file_path: 'VERSION',
|
||||
content: 'new content'
|
||||
},
|
||||
{
|
||||
action: 'chmod',
|
||||
file_path: 'CHANGELOG',
|
||||
execute_filemode: true
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_path: 'foo/foobar'),
|
||||
a_hash_including(deleted_file: true, new_path: 'README.md'),
|
||||
a_hash_including(deleted_file: true, new_path: 'LICENSE'),
|
||||
a_hash_including(new_file: true, new_path: 'LICENSE.md'),
|
||||
a_hash_including(new_file: false, new_path: 'VERSION'),
|
||||
a_hash_including(a_mode: '100644', b_mode: '100755', new_path: 'CHANGELOG')
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when actions are not defined' do
|
||||
let(:actions) { [] }
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
|
||||
expect_to_contain_deltas([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch does not exist' do
|
||||
let(:branch) { 'unknown' }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to eq(['You can only create or edit files when you are on a branch'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch does not exist and a start branch is provided' do
|
||||
let(:branch) { 'my-branch' }
|
||||
let(:start_branch) { 'master' }
|
||||
let(:actions) do
|
||||
[
|
||||
{
|
||||
action: 'create',
|
||||
file_path: 'ANOTHER_FILE.md',
|
||||
content: 'Bye'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns a new commit' do
|
||||
expect(mutated_commit).to have_attributes(message: message, project: project)
|
||||
expect(subject[:errors]).to be_empty
|
||||
expect(subject[:content]).to eq(actions.pluck(:content))
|
||||
|
||||
expect_to_contain_deltas([
|
||||
a_hash_including(a_mode: '0', b_mode: '100644', new_file: true, new_path: 'ANOTHER_FILE.md')
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when message is not set' do
|
||||
let(:message) { nil }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when actions are incorrect' do
|
||||
let(:actions) { [{ action: 'unknown', file_path: 'test.md', content: '' }] }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to eq(['Unknown action \'unknown\''])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when branch is protected' do
|
||||
before do
|
||||
create(:protected_branch, project: project, name: branch)
|
||||
end
|
||||
|
||||
it 'returns errors' do
|
||||
expect(mutated_commit).to be_nil
|
||||
expect(subject[:errors]).to eq(['You are not allowed to push into this branch'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expect_to_contain_deltas(expected_deltas)
|
||||
|
|
|
@ -10,11 +10,12 @@ RSpec.describe Gitlab::Metrics::Exporter::BaseExporter do
|
|||
describe 'when exporter is enabled' do
|
||||
before do
|
||||
allow(::WEBrick::HTTPServer).to receive(:new).with(
|
||||
Port: anything,
|
||||
BindAddress: anything,
|
||||
Logger: anything,
|
||||
AccessLog: anything
|
||||
).and_call_original
|
||||
{
|
||||
Port: anything,
|
||||
BindAddress: anything,
|
||||
Logger: anything,
|
||||
AccessLog: anything
|
||||
}).and_call_original
|
||||
|
||||
allow(settings).to receive(:enabled).and_return(true)
|
||||
allow(settings).to receive(:port).and_return(0)
|
||||
|
@ -45,11 +46,12 @@ RSpec.describe Gitlab::Metrics::Exporter::BaseExporter do
|
|||
|
||||
it 'starts server with port and address from settings' do
|
||||
expect(::WEBrick::HTTPServer).to receive(:new).with(
|
||||
Port: port,
|
||||
BindAddress: address,
|
||||
Logger: anything,
|
||||
AccessLog: anything
|
||||
).and_wrap_original do |m, *args|
|
||||
{
|
||||
Port: port,
|
||||
BindAddress: address,
|
||||
Logger: anything,
|
||||
AccessLog: anything
|
||||
}).and_wrap_original do |m, *args|
|
||||
m.call(DoNotListen: true, Logger: args.first[:Logger])
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe CommitPolicy do
|
||||
describe '#rules' do
|
||||
let(:group) { create(:group, :public) }
|
||||
let(:user) { create(:user) }
|
||||
let(:commit) { project.repository.head_commit }
|
||||
let(:policy) { described_class.new(user, commit) }
|
||||
|
@ -19,59 +20,119 @@ RSpec.describe CommitPolicy do
|
|||
end
|
||||
|
||||
shared_examples 'cannot read commit nor create a note' do
|
||||
it 'can not read commit' do
|
||||
it 'cannot read commit' do
|
||||
expect(policy).to be_disallowed(:read_commit)
|
||||
end
|
||||
|
||||
it 'can not create a note' do
|
||||
it 'cannot create a note' do
|
||||
expect(policy).to be_disallowed(:create_note)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is public' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:project) { create(:project, :public, :repository, group: group) }
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
context 'when the user is not a project member' do
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
|
||||
context 'when repository access level is private' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private) }
|
||||
let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
|
||||
|
||||
context 'when the user is not a project member' do
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
end
|
||||
|
||||
context 'when the user is a direct project member' do
|
||||
context 'and the user is a developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is an inherited member from the group' do
|
||||
context 'and the user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
|
||||
context 'and the user is a reporter' do
|
||||
before do
|
||||
group.add_reporter(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
|
||||
context 'and the user is a developer' do
|
||||
before do
|
||||
group.add_developer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository, group: group) }
|
||||
|
||||
context 'when the user is not a project member' do
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
end
|
||||
|
||||
context 'when the user is a project member' do
|
||||
context 'when the user is a direct project member' do
|
||||
context 'and the user is a developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository) }
|
||||
context 'and the user is a guest' do
|
||||
before do
|
||||
project.add_guest(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
|
||||
context 'when the user is a project member' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it 'can read commit and create a note' do
|
||||
expect(policy).to be_allowed(:read_commit)
|
||||
it 'cannot download code' do
|
||||
expect(policy).to be_disallowed(:download_code)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is a guest' do
|
||||
before do
|
||||
project.add_guest(user)
|
||||
context 'when the user is an inherited member from the group' do
|
||||
context 'and the user is a guest' do
|
||||
before do
|
||||
group.add_guest(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
end
|
||||
|
||||
it_behaves_like 'cannot read commit nor create a note'
|
||||
context 'and the user is a reporter' do
|
||||
before do
|
||||
group.add_reporter(user)
|
||||
end
|
||||
|
||||
it 'cannot download code' do
|
||||
expect(policy).to be_disallowed(:download_code)
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
|
||||
context 'and the user is a developer' do
|
||||
before do
|
||||
group.add_developer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'can read commit and create a note'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,8 @@ RSpec.describe API::Commits do
|
|||
let(:branch_with_slash) { project.repository.find_branch('improve/awesome') }
|
||||
let(:project_id) { project.id }
|
||||
let(:current_user) { nil }
|
||||
let(:group) { create(:group, :public) }
|
||||
let(:inherited_guest) { create(:user).tap { |u| group.add_guest(u) } }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
|
@ -56,311 +58,340 @@ RSpec.describe API::Commits do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when authenticated', 'as a maintainer' do
|
||||
let(:current_user) { user }
|
||||
context 'when authenticated' do
|
||||
context 'when user is a direct project member' do
|
||||
context 'and user is a maintainer' do
|
||||
let(:current_user) { user }
|
||||
|
||||
it_behaves_like 'project commits'
|
||||
it_behaves_like 'project commits'
|
||||
|
||||
context "since optional parameter" do
|
||||
it "returns project commits since provided parameter" do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
after = commits.second.created_at
|
||||
context "since optional parameter" do
|
||||
it "returns project commits since provided parameter" do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
after = commits.second.created_at
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
|
||||
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
|
||||
|
||||
expect(json_response.size).to eq 2
|
||||
expect(json_response.first["id"]).to eq(commits.first.id)
|
||||
expect(json_response.second["id"]).to eq(commits.second.id)
|
||||
end
|
||||
expect(json_response.size).to eq 2
|
||||
expect(json_response.first["id"]).to eq(commits.first.id)
|
||||
expect(json_response.second["id"]).to eq(commits.second.id)
|
||||
end
|
||||
|
||||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
after = commits.second.created_at
|
||||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
after = commits.second.created_at
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
|
||||
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "until optional parameter" do
|
||||
it "returns project commits until provided parameter" do
|
||||
commits = project.repository.commits("master", limit: 20)
|
||||
before = commits.second.created_at
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||
|
||||
if commits.size == 20
|
||||
expect(json_response.size).to eq(20)
|
||||
else
|
||||
expect(json_response.size).to eq(commits.size - 1)
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
expect(json_response.first["id"]).to eq(commits.second.id)
|
||||
expect(json_response.second["id"]).to eq(commits.third.id)
|
||||
end
|
||||
context "until optional parameter" do
|
||||
it "returns project commits until provided parameter" do
|
||||
commits = project.repository.commits("master", limit: 20)
|
||||
before = commits.second.created_at
|
||||
|
||||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
before = commits.second.created_at
|
||||
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||
if commits.size == 20
|
||||
expect(json_response.size).to eq(20)
|
||||
else
|
||||
expect(json_response.size).to eq(commits.size - 1)
|
||||
end
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
expect(json_response.first["id"]).to eq(commits.second.id)
|
||||
expect(json_response.second["id"]).to eq(commits.third.id)
|
||||
end
|
||||
|
||||
context "invalid xmlschema date parameters" do
|
||||
it "returns an invalid parameter error message" do
|
||||
get api("/projects/#{project_id}/repository/commits?since=invalid-date", user)
|
||||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
before = commits.second.created_at
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq('since is invalid')
|
||||
end
|
||||
end
|
||||
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||
|
||||
context "with empty ref_name parameter" do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?ref_name=" }
|
||||
|
||||
it_behaves_like 'project commits'
|
||||
end
|
||||
|
||||
context 'when repository does not exist' do
|
||||
let(:project) { create(:project, creator: user, path: 'my.project') }
|
||||
|
||||
it_behaves_like '404 response' do
|
||||
let(:request) { get api(route, current_user) }
|
||||
let(:message) { '404 Repository Not Found' }
|
||||
end
|
||||
end
|
||||
|
||||
context "path optional parameter" do
|
||||
it "returns project commits matching provided path parameter" do
|
||||
path = 'files/ruby/popen.rb'
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(json_response.size).to eq(3)
|
||||
expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
|
||||
expect(response).to include_limited_pagination_headers
|
||||
end
|
||||
|
||||
it 'include correct pagination headers' do
|
||||
path = 'files/ruby/popen.rb'
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'all optional parameter' do
|
||||
it 'returns all project commits' do
|
||||
expected_commit_ids = project.repository.commits(nil, all: true, limit: 50).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?all=true&per_page=50", user)
|
||||
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'first_parent optional parameter' do
|
||||
it 'returns all first_parent commits' do
|
||||
expected_commit_ids = project.repository.commits(SeedRepo::Commit::ID, limit: 50, first_parent: true).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?per_page=50", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
|
||||
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(expected_commit_ids.size).to eq(12)
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with_stats optional parameter' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
it_behaves_like 'project commits', schema: 'public_api/v4/commits_with_stats' do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?with_stats=true" }
|
||||
|
||||
it 'include commits details' do
|
||||
commit = project.repository.commit
|
||||
get api(route, current_user)
|
||||
|
||||
expect(json_response.first['stats']['additions']).to eq(commit.stats.additions)
|
||||
expect(json_response.first['stats']['deletions']).to eq(commit.stats.deletions)
|
||||
expect(json_response.first['stats']['total']).to eq(commit.stats.total)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with pagination params' do
|
||||
let(:page) { 1 }
|
||||
let(:per_page) { 5 }
|
||||
let(:ref_name) { 'master' }
|
||||
let(:request) do
|
||||
get api("/projects/#{project_id}/repository/commits?page=#{page}&per_page=#{per_page}&ref_name=#{ref_name}", user)
|
||||
end
|
||||
|
||||
it 'returns correct headers' do
|
||||
request
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['Link']).to match(/page=1&per_page=5/)
|
||||
expect(response.headers['Link']).to match(/page=2&per_page=5/)
|
||||
end
|
||||
|
||||
context 'viewing the first page' do
|
||||
it 'returns the first 5 commits' do
|
||||
request
|
||||
|
||||
commit = project.repository.commit
|
||||
|
||||
expect(json_response.size).to eq(per_page)
|
||||
expect(json_response.first['id']).to eq(commit.id)
|
||||
expect(response.headers['X-Page']).to eq('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'viewing the third page' do
|
||||
let(:page) { 3 }
|
||||
|
||||
it 'returns the third 5 commits' do
|
||||
request
|
||||
|
||||
commit = project.repository.commits('HEAD', limit: per_page, offset: (page - 1) * per_page).first
|
||||
|
||||
expect(json_response.size).to eq(per_page)
|
||||
expect(json_response.first['id']).to eq(commit.id)
|
||||
expect(response.headers['X-Page']).to eq('3')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pagination params are invalid' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:page, :per_page, :error_message) do
|
||||
0 | nil | 'page does not have a valid value'
|
||||
-1 | nil | 'page does not have a valid value'
|
||||
'a' | nil | 'page is invalid'
|
||||
nil | 0 | 'per_page does not have a valid value'
|
||||
nil | -1 | 'per_page does not have a valid value'
|
||||
nil | 'a' | 'per_page is invalid'
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns 400 response' do
|
||||
request
|
||||
context "invalid xmlschema date parameters" do
|
||||
it "returns an invalid parameter error message" do
|
||||
get api("/projects/#{project_id}/repository/commits?since=invalid-date", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq(error_message)
|
||||
expect(json_response['error']).to eq('since is invalid')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when FF is off' do
|
||||
before do
|
||||
stub_feature_flags(only_positive_pagination_values: false)
|
||||
context "with empty ref_name parameter" do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?ref_name=" }
|
||||
|
||||
it_behaves_like 'project commits'
|
||||
end
|
||||
|
||||
context 'when repository does not exist' do
|
||||
let(:project) { create(:project, creator: user, path: 'my.project') }
|
||||
|
||||
it_behaves_like '404 response' do
|
||||
let(:request) { get api(route, current_user) }
|
||||
let(:message) { '404 Repository Not Found' }
|
||||
end
|
||||
end
|
||||
|
||||
context "path optional parameter" do
|
||||
it "returns project commits matching provided path parameter" do
|
||||
path = 'files/ruby/popen.rb'
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(json_response.size).to eq(3)
|
||||
expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
|
||||
expect(response).to include_limited_pagination_headers
|
||||
end
|
||||
|
||||
where(:page, :per_page, :error_message, :status) do
|
||||
0 | nil | nil | :success
|
||||
-10 | nil | nil | :internal_server_error
|
||||
'a' | nil | 'page is invalid' | :bad_request
|
||||
nil | 0 | 'per_page has a value not allowed' | :bad_request
|
||||
nil | -1 | nil | :success
|
||||
nil | 'a' | 'per_page is invalid' | :bad_request
|
||||
it 'include correct pagination headers' do
|
||||
path = 'files/ruby/popen.rb'
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'all optional parameter' do
|
||||
it 'returns all project commits' do
|
||||
expected_commit_ids = project.repository.commits(nil, all: true, limit: 50).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?all=true&per_page=50", user)
|
||||
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'first_parent optional parameter' do
|
||||
it 'returns all first_parent commits' do
|
||||
expected_commit_ids = project.repository.commits(SeedRepo::Commit::ID, limit: 50, first_parent: true).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?per_page=50", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
|
||||
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(expected_commit_ids.size).to eq(12)
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with_stats optional parameter' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
it_behaves_like 'project commits', schema: 'public_api/v4/commits_with_stats' do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?with_stats=true" }
|
||||
|
||||
it 'include commits details' do
|
||||
commit = project.repository.commit
|
||||
get api(route, current_user)
|
||||
|
||||
expect(json_response.first['stats']['additions']).to eq(commit.stats.additions)
|
||||
expect(json_response.first['stats']['deletions']).to eq(commit.stats.deletions)
|
||||
expect(json_response.first['stats']['total']).to eq(commit.stats.total)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with pagination params' do
|
||||
let(:page) { 1 }
|
||||
let(:per_page) { 5 }
|
||||
let(:ref_name) { 'master' }
|
||||
let(:request) do
|
||||
get api("/projects/#{project_id}/repository/commits?page=#{page}&per_page=#{per_page}&ref_name=#{ref_name}", user)
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns a response' do
|
||||
it 'returns correct headers' do
|
||||
request
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['Link']).to match(/page=1&per_page=5/)
|
||||
expect(response.headers['Link']).to match(/page=2&per_page=5/)
|
||||
end
|
||||
|
||||
context 'viewing the first page' do
|
||||
it 'returns the first 5 commits' do
|
||||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(status)
|
||||
commit = project.repository.commit
|
||||
|
||||
if error_message
|
||||
expect(json_response.size).to eq(per_page)
|
||||
expect(json_response.first['id']).to eq(commit.id)
|
||||
expect(response.headers['X-Page']).to eq('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'viewing the third page' do
|
||||
let(:page) { 3 }
|
||||
|
||||
it 'returns the third 5 commits' do
|
||||
request
|
||||
|
||||
commit = project.repository.commits('HEAD', limit: per_page, offset: (page - 1) * per_page).first
|
||||
|
||||
expect(json_response.size).to eq(per_page)
|
||||
expect(json_response.first['id']).to eq(commit.id)
|
||||
expect(response.headers['X-Page']).to eq('3')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pagination params are invalid' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:page, :per_page, :error_message) do
|
||||
0 | nil | 'page does not have a valid value'
|
||||
-1 | nil | 'page does not have a valid value'
|
||||
'a' | nil | 'page is invalid'
|
||||
nil | 0 | 'per_page does not have a valid value'
|
||||
nil | -1 | 'per_page does not have a valid value'
|
||||
nil | 'a' | 'per_page is invalid'
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns 400 response' do
|
||||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq(error_message)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when FF is off' do
|
||||
before do
|
||||
stub_feature_flags(only_positive_pagination_values: false)
|
||||
end
|
||||
|
||||
where(:page, :per_page, :error_message, :status) do
|
||||
0 | nil | nil | :success
|
||||
-10 | nil | nil | :internal_server_error
|
||||
'a' | nil | 'page is invalid' | :bad_request
|
||||
nil | 0 | 'per_page has a value not allowed' | :bad_request
|
||||
nil | -1 | nil | :success
|
||||
nil | 'a' | 'per_page is invalid' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns a response' do
|
||||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(status)
|
||||
|
||||
if error_message
|
||||
expect(json_response['error']).to eq(error_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with order parameter' do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?ref_name=0031876&per_page=6&order=#{order}" }
|
||||
context 'with order parameter' do
|
||||
let(:route) { "/projects/#{project_id}/repository/commits?ref_name=0031876&per_page=6&order=#{order}" }
|
||||
|
||||
context 'set to topo' do
|
||||
let(:order) { 'topo' }
|
||||
context 'set to topo' do
|
||||
let(:order) { 'topo' }
|
||||
|
||||
# git log --graph -n 6 --pretty=format:"%h" --topo-order 0031876
|
||||
# * 0031876
|
||||
# |\
|
||||
# | * 48ca272
|
||||
# | * 335bc94
|
||||
# * | bf6e164
|
||||
# * | 9d526f8
|
||||
# |/
|
||||
# * 1039376
|
||||
it 'returns project commits ordered by topo order' do
|
||||
commits = project.repository.commits("0031876", limit: 6, order: 'topo')
|
||||
# git log --graph -n 6 --pretty=format:"%h" --topo-order 0031876
|
||||
# * 0031876
|
||||
# |\
|
||||
# | * 48ca272
|
||||
# | * 335bc94
|
||||
# * | bf6e164
|
||||
# * | 9d526f8
|
||||
# |/
|
||||
# * 1039376
|
||||
it 'returns project commits ordered by topo order' do
|
||||
commits = project.repository.commits("0031876", limit: 6, order: 'topo')
|
||||
|
||||
get api(route, current_user)
|
||||
get api(route, current_user)
|
||||
|
||||
expect(json_response.size).to eq(6)
|
||||
expect(json_response.map { |entry| entry["id"] }).to eq(commits.map(&:id))
|
||||
expect(json_response.size).to eq(6)
|
||||
expect(json_response.map { |entry| entry["id"] }).to eq(commits.map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to default' do
|
||||
let(:order) { 'default' }
|
||||
|
||||
# git log --graph -n 6 --pretty=format:"%h" --date-order 0031876
|
||||
# * 0031876
|
||||
# |\
|
||||
# * | bf6e164
|
||||
# | * 48ca272
|
||||
# * | 9d526f8
|
||||
# | * 335bc94
|
||||
# |/
|
||||
# * 1039376
|
||||
it 'returns project commits ordered by default order' do
|
||||
commits = project.repository.commits("0031876", limit: 6, order: 'default')
|
||||
|
||||
get api(route, current_user)
|
||||
|
||||
expect(json_response.size).to eq(6)
|
||||
expect(json_response.map { |entry| entry["id"] }).to eq(commits.map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to an invalid parameter' do
|
||||
let(:order) { 'invalid' }
|
||||
|
||||
it_behaves_like '400 response' do
|
||||
let(:request) { get api(route, current_user) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to default' do
|
||||
let(:order) { 'default' }
|
||||
context 'with the optional trailers parameter' do
|
||||
it 'includes the Git trailers' do
|
||||
get api("/projects/#{project_id}/repository/commits?ref_name=6d394385cf567f80a8fd85055db1ab4c5295806f&trailers=true", current_user)
|
||||
|
||||
# git log --graph -n 6 --pretty=format:"%h" --date-order 0031876
|
||||
# * 0031876
|
||||
# |\
|
||||
# * | bf6e164
|
||||
# | * 48ca272
|
||||
# * | 9d526f8
|
||||
# | * 335bc94
|
||||
# |/
|
||||
# * 1039376
|
||||
it 'returns project commits ordered by default order' do
|
||||
commits = project.repository.commits("0031876", limit: 6, order: 'default')
|
||||
commit = json_response[0]
|
||||
|
||||
get api(route, current_user)
|
||||
|
||||
expect(json_response.size).to eq(6)
|
||||
expect(json_response.map { |entry| entry["id"] }).to eq(commits.map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'set to an invalid parameter' do
|
||||
let(:order) { 'invalid' }
|
||||
|
||||
it_behaves_like '400 response' do
|
||||
let(:request) { get api(route, current_user) }
|
||||
expect(commit['trailers']).to eq(
|
||||
'Signed-off-by' => 'Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the optional trailers parameter' do
|
||||
it 'includes the Git trailers' do
|
||||
get api("/projects/#{project_id}/repository/commits?ref_name=6d394385cf567f80a8fd85055db1ab4c5295806f&trailers=true", current_user)
|
||||
context 'when user is an inherited member from the group' do
|
||||
context 'when project is public with private repository' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
|
||||
|
||||
commit = json_response[0]
|
||||
context 'and user is a guest' do
|
||||
let(:current_user) { inherited_guest }
|
||||
|
||||
expect(commit['trailers']).to eq(
|
||||
'Signed-off-by' => 'Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>'
|
||||
)
|
||||
it_behaves_like 'project commits'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository, group: group) }
|
||||
|
||||
context 'and user is a guest' do
|
||||
let(:current_user) { inherited_guest }
|
||||
|
||||
it_behaves_like '404 response' do
|
||||
let(:request) { get api(route) }
|
||||
let(:message) { '404 Project Not Found' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -466,11 +497,37 @@ RSpec.describe API::Commits do
|
|||
end
|
||||
|
||||
context 'a new file in project repo' do
|
||||
before do
|
||||
post api(url, user), params: valid_c_params
|
||||
context 'when user is a direct project member' do
|
||||
before do
|
||||
post api(url, user), params: valid_c_params
|
||||
end
|
||||
|
||||
it_behaves_like 'successfully creates the commit'
|
||||
end
|
||||
|
||||
it_behaves_like "successfully creates the commit"
|
||||
context 'when user is an inherited member from the group' do
|
||||
context 'when project is public with private repository' do
|
||||
let(:project) { create(:project, :public, :repository, :repository_private, group: group) }
|
||||
|
||||
context 'and user is a guest' do
|
||||
it_behaves_like '403 response' do
|
||||
let(:request) { post api(url, inherited_guest), params: valid_c_params }
|
||||
let(:message) { '403 Forbidden' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is private' do
|
||||
let(:project) { create(:project, :private, :repository, group: group) }
|
||||
|
||||
context 'and user is a guest' do
|
||||
it_behaves_like '403 response' do
|
||||
let(:request) { post api(url, inherited_guest), params: valid_c_params }
|
||||
let(:message) { '403 Forbidden' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'a new file with utf8 chars in project repo' do
|
||||
|
|
|
@ -304,7 +304,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
|
|||
let(:reply_id) { find("#{comments_selector} .note:last-of-type", match: :first)['data-note-id'] }
|
||||
|
||||
it 'can be replied to after resolving' do
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
wait_for_requests
|
||||
|
||||
refresh
|
||||
|
@ -316,7 +316,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re
|
|||
it 'shows resolved thread when toggled' do
|
||||
submit_reply('a')
|
||||
|
||||
find('button[data-qa-selector="resolve_discussion_button"]').click # rubocop:disable QA/SelectorUsage
|
||||
find('button[data-testid="resolve-discussion-button"]').click
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector(".note-row-#{note_id}", visible: true)
|
||||
|
|
|
@ -14,7 +14,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false|
|
|||
end
|
||||
|
||||
def package_table_row(index)
|
||||
page.all("#{packages_table_selector} > [data-qa-selector=\"package_row\"]")[index].text # rubocop:disable QA/SelectorUsage
|
||||
page.all("#{packages_table_selector} > [data-testid=\"package-row\"]")[index].text
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,7 +84,7 @@ RSpec.shared_examples 'shared package sorting' do
|
|||
end
|
||||
|
||||
def packages_table_selector
|
||||
'[data-qa-selector="packages-table"]' # rubocop:disable QA/SelectorUsage
|
||||
'[data-testid="packages-table"]'
|
||||
end
|
||||
|
||||
def click_sort_option(option, ascending)
|
||||
|
|
|
@ -64,9 +64,9 @@ end
|
|||
|
||||
RSpec.shared_examples 'shows no runners registered' do
|
||||
it 'shows counts with 0' do
|
||||
expect(page).to have_text "Online 0"
|
||||
expect(page).to have_text "Offline 0"
|
||||
expect(page).to have_text "Stale 0"
|
||||
expect(page).to have_text "#{s_('Runners|Online')} 0"
|
||||
expect(page).to have_text "#{s_('Runners|Offline')} 0"
|
||||
expect(page).to have_text "#{s_('Runners|Stale')} 0"
|
||||
end
|
||||
|
||||
it 'shows "no runners" message' do
|
||||
|
@ -101,7 +101,7 @@ RSpec.shared_examples 'pauses, resumes and deletes a runner' do
|
|||
within_runner_row(runner.id) do
|
||||
click_button "Pause"
|
||||
|
||||
expect(page).to have_text 'paused'
|
||||
expect(page).to have_text s_('Runners|Paused')
|
||||
expect(page).to have_button 'Resume'
|
||||
expect(page).not_to have_button 'Pause'
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ RSpec.shared_examples 'variable list' do |is_admin|
|
|||
end
|
||||
|
||||
page.within('#add-ci-variable') do
|
||||
find('[data-qa-selector="ci_variable_key_field"] input').set('new_key') # rubocop:disable QA/SelectorUsage
|
||||
find('[data-testid="pipeline-form-ci-variable-key"] input').set('new_key')
|
||||
|
||||
click_button('Update variable')
|
||||
end
|
||||
|
@ -173,7 +173,7 @@ RSpec.shared_examples 'variable list' do |is_admin|
|
|||
click_button('Add variable')
|
||||
|
||||
page.within('#add-ci-variable') do
|
||||
find('[data-qa-selector="ci_variable_key_field"] input').set('empty_mask_key') # rubocop:disable QA/SelectorUsage
|
||||
find('[data-testid="pipeline-form-ci-variable-key"] input').set('empty_mask_key')
|
||||
find('[data-testid="ci-variable-protected-checkbox"]').click
|
||||
find('[data-testid="ci-variable-masked-checkbox"]').click
|
||||
|
||||
|
@ -290,8 +290,8 @@ RSpec.shared_examples 'variable list' do |is_admin|
|
|||
wait_for_requests
|
||||
|
||||
page.within('#add-ci-variable') do
|
||||
find('[data-qa-selector="ci_variable_key_field"] input').set(key) # rubocop:disable QA/SelectorUsage
|
||||
find('[data-qa-selector="ci_variable_value_field"]').set(value) if value.present? # rubocop:disable QA/SelectorUsage
|
||||
find('[data-testid="pipeline-form-ci-variable-key"] input').set(key)
|
||||
find('[data-testid="pipeline-form-ci-variable-value"]').set(value) if value.present?
|
||||
find('[data-testid="ci-variable-protected-checkbox"]').click if protected
|
||||
find('[data-testid="ci-variable-masked-checkbox"]').click if masked
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ RSpec.shared_examples 'User previews wiki changes' do
|
|||
end
|
||||
|
||||
it_behaves_like 'relative links' do
|
||||
let(:element) { page.find('[data-testid="wiki_page_content"]') }
|
||||
let(:element) { page.find('[data-testid="wiki-page-content"]') }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'User views AsciiDoc page with includes' do
|
||||
let_it_be(:wiki_content_selector) { '[data-qa-selector=wiki_page_content]' } # rubocop:disable QA/SelectorUsage
|
||||
let_it_be(:wiki_content_selector) { '[data-testid=wiki-page-content]' }
|
||||
let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page') }
|
||||
let!(:wiki_page) { create_wiki_page('home', content: "Content from the main page.\ninclude::included_page.asciidoc[]") }
|
||||
|
||||
|
|
|
@ -185,6 +185,28 @@ RSpec.shared_examples_for 'collection cache helper' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when presentable has a group by clause' do
|
||||
let(:presentable) { MergeRequest.group(:id) }
|
||||
|
||||
it "returns the presentables" do
|
||||
expect(transaction)
|
||||
.to receive(:increment)
|
||||
.with(:cached_object_operations_total, 0, { caller_id: caller_id, render_type: :collection, cache_hit: true }).once
|
||||
|
||||
expect(transaction)
|
||||
.to receive(:increment)
|
||||
.with(:cached_object_operations_total, MergeRequest.count, { caller_id: caller_id, render_type: :collection, cache_hit: false }).once
|
||||
|
||||
parsed = Gitlab::Json.parse(subject.to_s)
|
||||
|
||||
expect(parsed).to be_an(Array)
|
||||
|
||||
presentable.each_with_index do |item, i|
|
||||
expect(parsed[i]["id"]).to eq(item.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the presentables all miss' do
|
||||
it 'increments the counters' do
|
||||
expect(transaction)
|
||||
|
|
Loading…
Reference in New Issue