Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d15cc2684c
commit
2f47b6d8e1
|
@ -112,9 +112,10 @@
|
|||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "config.ru"
|
||||
# List explicitly all the app/ dirs that aren't backend (i.e. all except app/assets).
|
||||
# List explicitly all the app/ dirs that are backend (i.e. all except app/assets).
|
||||
- "{,ee/}{app/channels,app/controllers,app/finders,app/graphql,app/helpers,app/mailers,app/models,app/policies,app/presenters,app/serializers,app/services,app/uploaders,app/validators,app/views,app/workers}/**/*"
|
||||
- "{,ee/}{bin,cable,config,db,lib}/**/*"
|
||||
- "{,ee/}spec/**/*.rb"
|
||||
|
||||
.db-patterns: &db-patterns
|
||||
- "{,ee/}{db}/**/*"
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import TagsListRow from './tags_list_row.vue';
|
||||
import { REMOVE_TAGS_BUTTON_TITLE, TAGS_LIST_TITLE } from '../../constants/index';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
TagsListRow,
|
||||
},
|
||||
props: {
|
||||
tags: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
isDesktop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
REMOVE_TAGS_BUTTON_TITLE,
|
||||
TAGS_LIST_TITLE,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedItems: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasSelectedItems() {
|
||||
return this.tags.some(tag => this.selectedItems[tag.name]);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateSelectedItems(name) {
|
||||
this.$set(this.selectedItems, name, !this.selectedItems[name]);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="gl-display-flex gl-justify-content-space-between gl-mb-3">
|
||||
<h5 data-testid="list-title">
|
||||
{{ $options.i18n.TAGS_LIST_TITLE }}
|
||||
</h5>
|
||||
|
||||
<gl-button
|
||||
v-if="isDesktop"
|
||||
:disabled="!hasSelectedItems"
|
||||
category="secondary"
|
||||
variant="danger"
|
||||
@click="$emit('delete', selectedItems)"
|
||||
>
|
||||
{{ $options.i18n.REMOVE_TAGS_BUTTON_TITLE }}
|
||||
</gl-button>
|
||||
</div>
|
||||
<tags-list-row
|
||||
v-for="(tag, index) in tags"
|
||||
:key="tag.path"
|
||||
:tag="tag"
|
||||
:index="index"
|
||||
:selected="selectedItems[tag.name]"
|
||||
:is-desktop="isDesktop"
|
||||
@select="updateSelectedItems(tag.name)"
|
||||
@delete="$emit('delete', { [tag.name]: true })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,129 @@
|
|||
<script>
|
||||
import { GlFormCheckbox, GlTooltipDirective, GlSprintf } from '@gitlab/ui';
|
||||
import { n__ } from '~/locale';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import DeleteButton from '../delete_button.vue';
|
||||
import ListItem from '../list_item.vue';
|
||||
import {
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
SHORT_REVISION_LABEL,
|
||||
CREATED_AT_LABEL,
|
||||
REMOVE_TAG_BUTTON_DISABLE_TOOLTIP,
|
||||
} from '../../constants/index';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlSprintf,
|
||||
GlFormCheckbox,
|
||||
DeleteButton,
|
||||
ListItem,
|
||||
ClipboardButton,
|
||||
TimeAgoTooltip,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
tag: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
isDesktop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
SHORT_REVISION_LABEL,
|
||||
CREATED_AT_LABEL,
|
||||
REMOVE_TAG_BUTTON_DISABLE_TOOLTIP,
|
||||
},
|
||||
computed: {
|
||||
formattedSize() {
|
||||
return this.tag.total_size ? numberToHumanSize(this.tag.total_size) : '';
|
||||
},
|
||||
layers() {
|
||||
return this.tag.layers ? n__('%d layer', '%d layers', this.tag.layers) : '';
|
||||
},
|
||||
mobileClasses() {
|
||||
return this.isDesktop ? '' : 'mw-s';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<list-item :index="index" :selected="selected">
|
||||
<template #left-action>
|
||||
<gl-form-checkbox class="gl-m-0" :checked="selected" @change="$emit('select')" />
|
||||
</template>
|
||||
<template #left-primary>
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<div
|
||||
v-gl-tooltip="{ title: tag.name }"
|
||||
data-testid="name"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap"
|
||||
:class="mobileClasses"
|
||||
>
|
||||
{{ tag.name }}
|
||||
</div>
|
||||
|
||||
<clipboard-button
|
||||
v-if="tag.location"
|
||||
:title="tag.location"
|
||||
:text="tag.location"
|
||||
css-class="btn-default btn-transparent btn-clipboard"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #left-secondary>
|
||||
<span data-testid="size">
|
||||
{{ formattedSize }}
|
||||
<template v-if="formattedSize && layers"
|
||||
>·</template
|
||||
>
|
||||
{{ layers }}
|
||||
</span>
|
||||
</template>
|
||||
<template #right-primary>
|
||||
<span data-testid="time">
|
||||
<gl-sprintf :message="$options.i18n.CREATED_AT_LABEL">
|
||||
<template #timeInfo>
|
||||
<time-ago-tooltip :time="tag.created_at" />
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
</template>
|
||||
<template #right-secondary>
|
||||
<span data-testid="short-revision">
|
||||
<gl-sprintf :message="$options.i18n.SHORT_REVISION_LABEL">
|
||||
<template #imageId>{{ tag.short_revision }}</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
</template>
|
||||
<template #right-action>
|
||||
<delete-button
|
||||
:disabled="!tag.destroy_path"
|
||||
:title="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
|
||||
:tooltip-title="$options.i18n.REMOVE_TAG_BUTTON_DISABLE_TOOLTIP"
|
||||
:tooltip-disabled="Boolean(tag.destroy_path)"
|
||||
data-testid="single-delete-button"
|
||||
@delete="$emit('delete')"
|
||||
/>
|
||||
</template>
|
||||
</list-item>
|
||||
</template>
|
|
@ -1,210 +0,0 @@
|
|||
<script>
|
||||
import { GlTable, GlFormCheckbox, GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { n__ } from '~/locale';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
import {
|
||||
LIST_KEY_TAG,
|
||||
LIST_KEY_IMAGE_ID,
|
||||
LIST_KEY_SIZE,
|
||||
LIST_KEY_LAST_UPDATED,
|
||||
LIST_KEY_ACTIONS,
|
||||
LIST_KEY_CHECKBOX,
|
||||
LIST_LABEL_TAG,
|
||||
LIST_LABEL_IMAGE_ID,
|
||||
LIST_LABEL_SIZE,
|
||||
LIST_LABEL_LAST_UPDATED,
|
||||
REMOVE_TAGS_BUTTON_TITLE,
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
} from '../../constants/index';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlTable,
|
||||
GlFormCheckbox,
|
||||
GlButton,
|
||||
ClipboardButton,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [timeagoMixin],
|
||||
props: {
|
||||
tags: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
isDesktop: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
REMOVE_TAGS_BUTTON_TITLE,
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedItems: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
fields() {
|
||||
const tagClass = this.isDesktop ? 'w-25' : '';
|
||||
const tagInnerClass = this.isDesktop ? 'mw-m' : 'gl-justify-content-end';
|
||||
return [
|
||||
{ key: LIST_KEY_CHECKBOX, label: '', class: 'gl-w-16' },
|
||||
{
|
||||
key: LIST_KEY_TAG,
|
||||
label: LIST_LABEL_TAG,
|
||||
class: `${tagClass} js-tag-column`,
|
||||
innerClass: tagInnerClass,
|
||||
},
|
||||
{ key: LIST_KEY_IMAGE_ID, label: LIST_LABEL_IMAGE_ID },
|
||||
{ key: LIST_KEY_SIZE, label: LIST_LABEL_SIZE },
|
||||
{ key: LIST_KEY_LAST_UPDATED, label: LIST_LABEL_LAST_UPDATED },
|
||||
{ key: LIST_KEY_ACTIONS, label: '' },
|
||||
].filter(f => f.key !== LIST_KEY_CHECKBOX || this.isDesktop);
|
||||
},
|
||||
tagsNames() {
|
||||
return this.tags.map(t => t.name);
|
||||
},
|
||||
selectAllChecked() {
|
||||
return this.selectedItems.length === this.tags.length && this.tags.length > 0;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
tagsNames: {
|
||||
immediate: false,
|
||||
handler(tagsNames) {
|
||||
this.selectedItems = this.selectedItems.filter(t => tagsNames.includes(t));
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatSize(size) {
|
||||
return numberToHumanSize(size);
|
||||
},
|
||||
layers(layers) {
|
||||
return layers ? n__('%d layer', '%d layers', layers) : '';
|
||||
},
|
||||
onSelectAllChange() {
|
||||
if (this.selectAllChecked) {
|
||||
this.selectedItems = [];
|
||||
} else {
|
||||
this.selectedItems = this.tags.map(x => x.name);
|
||||
}
|
||||
},
|
||||
updateSelectedItems(name) {
|
||||
const delIndex = this.selectedItems.findIndex(x => x === name);
|
||||
|
||||
if (delIndex > -1) {
|
||||
this.selectedItems.splice(delIndex, 1);
|
||||
} else {
|
||||
this.selectedItems.push(name);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-table :items="tags" :fields="fields" :stacked="!isDesktop" show-empty :busy="isLoading">
|
||||
<template v-if="isDesktop" #head(checkbox)>
|
||||
<gl-form-checkbox
|
||||
data-testid="mainCheckbox"
|
||||
:checked="selectAllChecked"
|
||||
@change="onSelectAllChange"
|
||||
/>
|
||||
</template>
|
||||
<template #head(actions)>
|
||||
<span class="gl-display-flex gl-justify-content-end">
|
||||
<gl-button
|
||||
v-gl-tooltip
|
||||
data-testid="bulkDeleteButton"
|
||||
:disabled="!selectedItems || selectedItems.length === 0"
|
||||
icon="remove"
|
||||
variant="danger"
|
||||
:title="$options.i18n.REMOVE_TAGS_BUTTON_TITLE"
|
||||
:aria-label="$options.i18n.REMOVE_TAGS_BUTTON_TITLE"
|
||||
@click="$emit('delete', selectedItems)"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell(checkbox)="{item}">
|
||||
<gl-form-checkbox
|
||||
data-testid="rowCheckbox"
|
||||
:checked="selectedItems.includes(item.name)"
|
||||
@change="updateSelectedItems(item.name)"
|
||||
/>
|
||||
</template>
|
||||
<template #cell(name)="{item, field}">
|
||||
<div data-testid="rowName" :class="[field.innerClass, 'gl-display-flex']">
|
||||
<span
|
||||
v-gl-tooltip
|
||||
data-testid="rowNameText"
|
||||
:title="item.name"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap"
|
||||
>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<clipboard-button
|
||||
v-if="item.location"
|
||||
data-testid="rowClipboardButton"
|
||||
:title="item.location"
|
||||
:text="item.location"
|
||||
css-class="btn-default btn-transparent btn-clipboard"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell(short_revision)="{value}">
|
||||
<span data-testid="rowShortRevision">
|
||||
{{ value }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(total_size)="{item}">
|
||||
<span data-testid="rowSize">
|
||||
{{ formatSize(item.total_size) }}
|
||||
<template v-if="item.total_size && item.layers">
|
||||
·
|
||||
</template>
|
||||
{{ layers(item.layers) }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(created_at)="{value}">
|
||||
<span v-gl-tooltip data-testid="rowTime" :title="tooltipTitle(value)">
|
||||
{{ timeFormatted(value) }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell(actions)="{item}">
|
||||
<span class="gl-display-flex gl-justify-content-end">
|
||||
<gl-button
|
||||
data-testid="singleDeleteButton"
|
||||
:title="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
|
||||
:aria-label="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
|
||||
:disabled="!item.destroy_path"
|
||||
variant="danger"
|
||||
icon="remove"
|
||||
category="secondary"
|
||||
@click="$emit('delete', [item.name])"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #empty>
|
||||
<slot name="empty"></slot>
|
||||
</template>
|
||||
<template #table-busy>
|
||||
<slot name="loader"></slot>
|
||||
</template>
|
||||
</gl-table>
|
||||
</template>
|
|
@ -12,12 +12,19 @@ export default {
|
|||
default: false,
|
||||
required: false,
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
optionalClasses() {
|
||||
return {
|
||||
'gl-border-t-solid gl-border-t-1': this.index === 0,
|
||||
'disabled-content': this.disabled,
|
||||
'gl-border-gray-200': !this.selected,
|
||||
'gl-bg-blue-50 gl-border-blue-200': this.selected,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -26,22 +33,36 @@ export default {
|
|||
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'gl-display-flex gl-justify-content-space-between gl-align-items-center gl-py-2 gl-px-1 gl-border-gray-200 gl-border-b-solid gl-border-b-1 gl-py-4',
|
||||
optionalClasses,
|
||||
]"
|
||||
class="gl-display-flex gl-align-items-center gl-border-b-solid gl-border-b-1 gl-py-4 gl-px-2"
|
||||
:class="optionalClasses"
|
||||
>
|
||||
<div class="gl-display-flex gl-flex-direction-column">
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<slot name="left-primary"></slot>
|
||||
<div v-if="$slots['left-action']" class="gl-mr-5 gl-display-none gl-display-sm-block">
|
||||
<slot name="left-action"></slot>
|
||||
</div>
|
||||
<div class="gl-display-flex gl-flex-direction-column gl-flex-fill-1">
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-text-black-normal gl-font-weight-bold"
|
||||
>
|
||||
<div>
|
||||
<slot name="left-primary"></slot>
|
||||
</div>
|
||||
<div>
|
||||
<slot name="right-primary"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gl-font-sm gl-text-gray-500">
|
||||
<slot name="left-secondary"></slot>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-font-sm gl-text-gray-500"
|
||||
>
|
||||
<div>
|
||||
<slot name="left-secondary"></slot>
|
||||
</div>
|
||||
<div>
|
||||
<slot name="right-secondary"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<slot name="right"></slot>
|
||||
<div v-if="$slots['right-action']" class="gl-ml-5 gl-display-none gl-display-sm-block">
|
||||
<slot name="right-action"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -106,9 +106,8 @@ export default {
|
|||
</gl-sprintf>
|
||||
</span>
|
||||
</template>
|
||||
<template #right>
|
||||
<template #right-action>
|
||||
<delete-button
|
||||
class="gl-display-none d-sm-block"
|
||||
:title="$options.i18n.REMOVE_REPOSITORY_LABEL"
|
||||
:disabled="disabledDelete"
|
||||
:tooltip-disabled="Boolean(item.destroy_path)"
|
||||
|
|
|
@ -14,12 +14,13 @@ export const DELETE_TAGS_ERROR_MESSAGE = s__(
|
|||
export const DELETE_TAGS_SUCCESS_MESSAGE = s__(
|
||||
'ContainerRegistry|Tags successfully marked for deletion.',
|
||||
);
|
||||
export const LIST_LABEL_TAG = s__('ContainerRegistry|Tag');
|
||||
export const LIST_LABEL_IMAGE_ID = s__('ContainerRegistry|Image ID');
|
||||
export const LIST_LABEL_SIZE = s__('ContainerRegistry|Compressed Size');
|
||||
export const LIST_LABEL_LAST_UPDATED = s__('ContainerRegistry|Last Updated');
|
||||
|
||||
export const TAGS_LIST_TITLE = s__('ContainerRegistry|Image tags');
|
||||
export const SHORT_REVISION_LABEL = s__('ContainerRegistry|Image ID: %{imageId}');
|
||||
export const CREATED_AT_LABEL = s__('ContainerRegistry|Published %{timeInfo}');
|
||||
|
||||
export const REMOVE_TAG_BUTTON_TITLE = s__('ContainerRegistry|Remove tag');
|
||||
export const REMOVE_TAGS_BUTTON_TITLE = s__('ContainerRegistry|Remove selected tags');
|
||||
export const REMOVE_TAGS_BUTTON_TITLE = s__('ContainerRegistry|Delete selected');
|
||||
export const REMOVE_TAG_CONFIRMATION_TEXT = s__(
|
||||
`ContainerRegistry|You are about to remove %{item}. Are you sure?`,
|
||||
);
|
||||
|
@ -36,17 +37,15 @@ export const ADMIN_GARBAGE_COLLECTION_TIP = s__(
|
|||
'ContainerRegistry|Remember to run %{docLinkStart}garbage collection%{docLinkEnd} to remove the stale data from storage.',
|
||||
);
|
||||
|
||||
export const REMOVE_TAG_BUTTON_DISABLE_TOOLTIP = s__(
|
||||
'ContainerRegistry|Missing or insufficient permission, delete button disabled',
|
||||
);
|
||||
|
||||
// Parameters
|
||||
|
||||
export const DEFAULT_PAGE = 1;
|
||||
export const DEFAULT_PAGE_SIZE = 10;
|
||||
export const GROUP_PAGE_TYPE = 'groups';
|
||||
export const LIST_KEY_TAG = 'name';
|
||||
export const LIST_KEY_IMAGE_ID = 'short_revision';
|
||||
export const LIST_KEY_SIZE = 'total_size';
|
||||
export const LIST_KEY_LAST_UPDATED = 'created_at';
|
||||
export const LIST_KEY_ACTIONS = 'actions';
|
||||
export const LIST_KEY_CHECKBOX = 'checkbox';
|
||||
export const ALERT_SUCCESS_TAG = 'success_tag';
|
||||
export const ALERT_DANGER_TAG = 'danger_tag';
|
||||
export const ALERT_SUCCESS_TAGS = 'success_tags';
|
||||
|
|
|
@ -6,7 +6,7 @@ import Tracking from '~/tracking';
|
|||
import DeleteAlert from '../components/details_page/delete_alert.vue';
|
||||
import DeleteModal from '../components/details_page/delete_modal.vue';
|
||||
import DetailsHeader from '../components/details_page/details_header.vue';
|
||||
import TagsTable from '../components/details_page/tags_table.vue';
|
||||
import TagsList from '../components/details_page/tags_list.vue';
|
||||
import TagsLoader from '../components/details_page/tags_loader.vue';
|
||||
import EmptyTagsState from '../components/details_page/empty_tags_state.vue';
|
||||
|
||||
|
@ -24,7 +24,7 @@ export default {
|
|||
DetailsHeader,
|
||||
GlPagination,
|
||||
DeleteModal,
|
||||
TagsTable,
|
||||
TagsList,
|
||||
TagsLoader,
|
||||
EmptyTagsState,
|
||||
},
|
||||
|
@ -65,10 +65,8 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions(['requestTagsList', 'requestDeleteTag', 'requestDeleteTags']),
|
||||
deleteTags(toBeDeletedList) {
|
||||
this.itemsToBeDeleted = toBeDeletedList.map(name => ({
|
||||
...this.tags.find(t => t.name === name),
|
||||
}));
|
||||
deleteTags(toBeDeleted) {
|
||||
this.itemsToBeDeleted = this.tags.filter(tag => toBeDeleted[tag.name]);
|
||||
this.track('click_button');
|
||||
this.$refs.deleteModal.show();
|
||||
},
|
||||
|
@ -114,24 +112,21 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-gl-resize-observer="handleResize" class="my-3 w-100 slide-enter-to-element">
|
||||
<div v-gl-resize-observer="handleResize" class="gl-my-3 gl-w-full slide-enter-to-element">
|
||||
<delete-alert
|
||||
v-model="deleteAlertType"
|
||||
:garbage-collection-help-page-path="config.garbageCollectionHelpPagePath"
|
||||
:is-admin="config.isAdmin"
|
||||
class="my-2"
|
||||
class="gl-my-2"
|
||||
/>
|
||||
|
||||
<details-header :image-name="imageName" />
|
||||
|
||||
<tags-table :tags="tags" :is-loading="isLoading" :is-desktop="isDesktop" @delete="deleteTags">
|
||||
<template #empty>
|
||||
<empty-tags-state :no-containers-image="config.noContainersImage" />
|
||||
</template>
|
||||
<template #loader>
|
||||
<tags-loader v-once />
|
||||
</template>
|
||||
</tags-table>
|
||||
<tags-loader v-if="isLoading" />
|
||||
<template v-else>
|
||||
<empty-tags-state v-if="tags.length === 0" :no-containers-image="config.noContainersImage" />
|
||||
<tags-list v-else :tags="tags" :is-desktop="isDesktop" @delete="deleteTags" />
|
||||
</template>
|
||||
|
||||
<gl-pagination
|
||||
v-if="!isLoading"
|
||||
|
@ -140,7 +135,7 @@ export default {
|
|||
:per-page="tagsPagination.perPage"
|
||||
:total-items="tagsPagination.total"
|
||||
align="center"
|
||||
class="w-100"
|
||||
class="gl-w-full gl-mt-3"
|
||||
/>
|
||||
|
||||
<delete-modal
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Convert the Image tag UI from a table to a list view
|
||||
merge_request: 35138
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix approval rule type when project rule has users/groups
|
||||
merge_request: 34026
|
||||
author:
|
||||
type: fixed
|
|
@ -66,7 +66,7 @@ one major version. For example, it is safe to:
|
|||
- `9.5.5` -> `9.5.9`
|
||||
- `8.9.2` -> `8.9.6`
|
||||
|
||||
NOTE **Note** Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/update/README.html#version-specific-changes).
|
||||
NOTE: **Note** Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/update/README.html#version-specific-changes).
|
||||
|
||||
NOTE: **Note:**
|
||||
Instructions are available for downloading an Omnibus GitLab Linux package locally and [manually installing](https://docs.gitlab.com/omnibus/manual_install.html) it.
|
||||
|
@ -107,7 +107,7 @@ Please see the table below for some examples:
|
|||
|
||||
| Target version | Your version | Recommended upgrade path | Note |
|
||||
| --------------------- | ------------ | ------------------------ | ---- |
|
||||
| `13.2.0` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.6` -> `13.0.0` -> `13.2.0` | Four intermediate versions are required: the final 11.11, 12.0, and 12.10 releases, plus 13.0. |
|
||||
| `13.2.0` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.6` -> `13.0.0` -> `13.2.0` | Four intermediate versions are required: the final `11.11`, `12.0`, and `12.10` releases, plus `13.0`. |
|
||||
| `13.0.1` | `11.10.8` | `11.10.5` -> `11.11.8` -> `12.0.12` -> `12.10.6` -> `13.0.1` | Three intermediate versions are required: `11.11`, `12.0`, and `12.10`. |
|
||||
| `12.10.6` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.10.6` | Two intermediate versions are required: `11.11` and `12.0` |
|
||||
| `12.9.5.` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.9.5` | Three intermediate versions are required: `10.8`, `11.11`, and `12.0`, then `12.9.5` |
|
||||
|
|
|
@ -6082,9 +6082,6 @@ msgstr ""
|
|||
msgid "ContainerRegistry|CLI Commands"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Compressed Size"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Container Registry"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6100,6 +6097,9 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Copy push command"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Delete selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Docker connection error"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6133,16 +6133,16 @@ msgstr ""
|
|||
msgid "ContainerRegistry|If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a %{personalAccessTokensDocLinkStart}Personal Access Token%{personalAccessTokensDocLinkEnd} instead of a password."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Image ID"
|
||||
msgid "ContainerRegistry|Image ID: %{imageId}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Image Repositories"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Keep and protect the images that matter most."
|
||||
msgid "ContainerRegistry|Image tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Last Updated"
|
||||
msgid "ContainerRegistry|Keep and protect the images that matter most."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Login"
|
||||
|
@ -6157,6 +6157,9 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Please contact your administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Published %{timeInfo}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Push an image"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6172,9 +6175,6 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Remove repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Remove selected tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Remove tag"
|
||||
msgid_plural "ContainerRegistry|Remove tags"
|
||||
msgstr[0] ""
|
||||
|
@ -6204,9 +6204,6 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Sorry, your filter produced no results."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Tag expiration policy"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Groups::ImportsController do
|
||||
RSpec.describe Groups::ImportsController do
|
||||
describe 'GET #show' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group, :private) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Projects::Pipelines::TestsController do
|
||||
RSpec.describe Projects::Pipelines::TestsController do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Registrations::ExperienceLevelsController do
|
||||
RSpec.describe Registrations::ExperienceLevelsController do
|
||||
let_it_be(:namespace) { create(:group, path: 'group-path' ) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ RSpec.describe 'Container Registry', :js do
|
|||
expect(service).to receive(:execute).with(container_repository) { { status: :success } }
|
||||
expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['latest']) { service }
|
||||
|
||||
first('[data-testid="singleDeleteButton"]').click
|
||||
first('[data-testid="single-delete-button"]').click
|
||||
expect(find('.modal .modal-title')).to have_content _('Remove tag')
|
||||
find('.modal .modal-footer .btn-danger').click
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Import/Export - Group Import', :js do
|
||||
RSpec.describe 'Import/Export - Group Import', :js do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:import_path) { "#{Dir.tmpdir}/group_import_spec" }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Projects > Activity > User sees design Activity', :js do
|
||||
RSpec.describe 'Projects > Activity > User sees design Activity', :js do
|
||||
include DesignManagementTestHelpers
|
||||
|
||||
let_it_be(:uploader) { create(:user) }
|
||||
|
|
|
@ -84,7 +84,7 @@ RSpec.describe 'Container Registry', :js do
|
|||
expect(service).to receive(:execute).with(container_repository) { { status: :success } }
|
||||
expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['1']) { service }
|
||||
|
||||
first('[data-testid="singleDeleteButton"]').click
|
||||
first('[data-testid="single-delete-button"]').click
|
||||
expect(find('.modal .modal-title')).to have_content _('Remove tag')
|
||||
find('.modal .modal-footer .btn-danger').click
|
||||
end
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlFormCheckbox, GlSprintf } from '@gitlab/ui';
|
||||
|
||||
import component from '~/registry/explorer/components/details_page/tags_list_row.vue';
|
||||
import ListItem from '~/registry/explorer/components/list_item.vue';
|
||||
import DeleteButton from '~/registry/explorer/components/delete_button.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import {
|
||||
REMOVE_TAG_BUTTON_TITLE,
|
||||
REMOVE_TAG_BUTTON_DISABLE_TOOLTIP,
|
||||
} from '~/registry/explorer/constants/index';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
|
||||
import { tagsListResponse } from '../../mock_data';
|
||||
|
||||
describe('tags list row', () => {
|
||||
let wrapper;
|
||||
const [tag] = [...tagsListResponse.data];
|
||||
|
||||
const defaultProps = { tag, isDesktop: true, index: 0 };
|
||||
|
||||
const findCheckbox = () => wrapper.find(GlFormCheckbox);
|
||||
const findName = () => wrapper.find('[data-testid="name"]');
|
||||
const findSize = () => wrapper.find('[data-testid="size"]');
|
||||
const findTime = () => wrapper.find('[data-testid="time"]');
|
||||
const findShortRevision = () => wrapper.find('[data-testid="short-revision"]');
|
||||
const findClipboardButton = () => wrapper.find(ClipboardButton);
|
||||
const findDeleteButton = () => wrapper.find(DeleteButton);
|
||||
const findTimeAgoTooltip = () => wrapper.find(TimeAgoTooltip);
|
||||
|
||||
const mountComponent = (propsData = defaultProps) => {
|
||||
wrapper = shallowMount(component, {
|
||||
stubs: {
|
||||
GlSprintf,
|
||||
ListItem,
|
||||
},
|
||||
propsData,
|
||||
directives: {
|
||||
GlTooltip: createMockDirective(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('checkbox', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findCheckbox().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('is wired to the selected prop', () => {
|
||||
mountComponent({ ...defaultProps, selected: true });
|
||||
|
||||
expect(findCheckbox().attributes('checked')).toBe('true');
|
||||
});
|
||||
|
||||
it('when changed emit a select event', () => {
|
||||
mountComponent();
|
||||
|
||||
findCheckbox().vm.$emit('change');
|
||||
|
||||
expect(wrapper.emitted('select')).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tag name', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findName().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct text', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findName().text()).toBe(tag.name);
|
||||
});
|
||||
|
||||
it('has a tooltip', () => {
|
||||
mountComponent();
|
||||
|
||||
const tooltip = getBinding(findName().element, 'gl-tooltip');
|
||||
|
||||
expect(tooltip.value.title).toBe(tag.name);
|
||||
});
|
||||
|
||||
it('on mobile has mw-s class', () => {
|
||||
mountComponent({ ...defaultProps, isDesktop: false });
|
||||
|
||||
expect(findName().classes('mw-s')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clipboard button', () => {
|
||||
it('exist if tag.location exist', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findClipboardButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('is hidden if tag does not have a location', () => {
|
||||
mountComponent({ ...defaultProps, tag: { ...tag, location: null } });
|
||||
expect(findClipboardButton().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('has the correct props/attributes', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findClipboardButton().attributes()).toMatchObject({
|
||||
text: 'location',
|
||||
title: 'location',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('size', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findSize().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('contains the total_size and layers', () => {
|
||||
mountComponent({ ...defaultProps, tag: { ...tag, total_size: 1024 } });
|
||||
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB · 10 layers');
|
||||
});
|
||||
|
||||
it('when total_size is missing', () => {
|
||||
mountComponent();
|
||||
expect(findSize().text()).toMatchInterpolatedText('10 layers');
|
||||
});
|
||||
|
||||
it('when layers are missing', () => {
|
||||
mountComponent({ ...defaultProps, tag: { ...tag, total_size: 1024, layers: null } });
|
||||
expect(findSize().text()).toMatchInterpolatedText('1.00 KiB');
|
||||
});
|
||||
|
||||
it('when there is 1 layer', () => {
|
||||
mountComponent({ ...defaultProps, tag: { ...tag, layers: 1 } });
|
||||
expect(findSize().text()).toMatchInterpolatedText('1 layer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('time', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTime().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct text', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTime().text()).toBe('Published');
|
||||
});
|
||||
|
||||
it('contains time_ago_tooltip component', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTimeAgoTooltip().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('pass the correct props to time ago tooltip', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTimeAgoTooltip().attributes()).toMatchObject({ time: tag.created_at });
|
||||
});
|
||||
});
|
||||
|
||||
describe('shortRevision', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findShortRevision().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct text', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findShortRevision().text()).toMatchInterpolatedText('Image ID: b118ab5b0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete button', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct props/attributes', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().attributes()).toMatchObject({
|
||||
title: REMOVE_TAG_BUTTON_TITLE,
|
||||
tooltiptitle: REMOVE_TAG_BUTTON_DISABLE_TOOLTIP,
|
||||
tooltipdisabled: 'true',
|
||||
});
|
||||
});
|
||||
|
||||
it('is disabled when tag has no destroy path', () => {
|
||||
mountComponent({ ...defaultProps, tag: { ...tag, destroy_path: null } });
|
||||
|
||||
expect(findDeleteButton().attributes('disabled')).toBe('true');
|
||||
});
|
||||
|
||||
it('delete event emits delete', () => {
|
||||
mountComponent();
|
||||
|
||||
findDeleteButton().vm.$emit('delete');
|
||||
|
||||
expect(wrapper.emitted('delete')).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,138 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import component from '~/registry/explorer/components/details_page/tags_list.vue';
|
||||
import TagsListRow from '~/registry/explorer/components/details_page/tags_list_row.vue';
|
||||
import { TAGS_LIST_TITLE, REMOVE_TAGS_BUTTON_TITLE } from '~/registry/explorer/constants/index';
|
||||
import { tagsListResponse } from '../../mock_data';
|
||||
|
||||
describe('Tags List', () => {
|
||||
let wrapper;
|
||||
const tags = [...tagsListResponse.data];
|
||||
|
||||
const findTagsListRow = () => wrapper.findAll(TagsListRow);
|
||||
const findDeleteButton = () => wrapper.find(GlButton);
|
||||
const findListTitle = () => wrapper.find('[data-testid="list-title"]');
|
||||
|
||||
const mountComponent = (propsData = { tags, isDesktop: true }) => {
|
||||
wrapper = shallowMount(component, {
|
||||
propsData,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('List title', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findListTitle().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct text', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findListTitle().text()).toBe(TAGS_LIST_TITLE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete button', () => {
|
||||
it('is not shown on mobile view', () => {
|
||||
mountComponent({ tags, isDesktop: false });
|
||||
|
||||
expect(findDeleteButton().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('is shown on desktop view', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct text', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().text()).toBe(REMOVE_TAGS_BUTTON_TITLE);
|
||||
});
|
||||
|
||||
it('has the correct props', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().attributes()).toMatchObject({
|
||||
category: 'secondary',
|
||||
variant: 'danger',
|
||||
});
|
||||
});
|
||||
|
||||
it('is disabled when no item is selected', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDeleteButton().attributes('disabled')).toBe('true');
|
||||
});
|
||||
|
||||
it('is enabled when at least one item is selected', async () => {
|
||||
mountComponent();
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.vm.$emit('select');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(findDeleteButton().attributes('disabled')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('click event emits a deleted event with selected items', () => {
|
||||
mountComponent();
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.vm.$emit('select');
|
||||
|
||||
findDeleteButton().vm.$emit('click');
|
||||
expect(wrapper.emitted('delete')).toEqual([[{ centos6: true }]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('list rows', () => {
|
||||
it('one row exist for each tag', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTagsListRow()).toHaveLength(tags.length);
|
||||
});
|
||||
|
||||
it('the correct props are bound to it', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.attributes(),
|
||||
).toMatchObject({
|
||||
index: '0',
|
||||
isdesktop: 'true',
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
it('select event update the selected items', async () => {
|
||||
mountComponent();
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.vm.$emit('select');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.attributes('selected'),
|
||||
).toBe('true');
|
||||
});
|
||||
|
||||
it('delete event emit a delete event', () => {
|
||||
mountComponent();
|
||||
findTagsListRow()
|
||||
.at(0)
|
||||
.vm.$emit('delete');
|
||||
expect(wrapper.emitted('delete')).toEqual([[{ centos6: true }]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,286 +0,0 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import stubChildren from 'helpers/stub_children';
|
||||
import component from '~/registry/explorer/components/details_page/tags_table.vue';
|
||||
import { tagsListResponse } from '../../mock_data';
|
||||
|
||||
describe('tags_table', () => {
|
||||
let wrapper;
|
||||
const tags = [...tagsListResponse.data];
|
||||
|
||||
const findMainCheckbox = () => wrapper.find('[data-testid="mainCheckbox"]');
|
||||
const findFirstRowItem = testid => wrapper.find(`[data-testid="${testid}"]`);
|
||||
const findBulkDeleteButton = () => wrapper.find('[data-testid="bulkDeleteButton"]');
|
||||
const findAllDeleteButtons = () => wrapper.findAll('[data-testid="singleDeleteButton"]');
|
||||
const findAllCheckboxes = () => wrapper.findAll('[data-testid="rowCheckbox"]');
|
||||
const findCheckedCheckboxes = () => findAllCheckboxes().filter(c => c.attributes('checked'));
|
||||
const findFirsTagColumn = () => wrapper.find('.js-tag-column');
|
||||
const findFirstTagNameText = () => wrapper.find('[data-testid="rowNameText"]');
|
||||
|
||||
const findLoaderSlot = () => wrapper.find('[data-testid="loaderSlot"]');
|
||||
const findEmptySlot = () => wrapper.find('[data-testid="emptySlot"]');
|
||||
|
||||
const mountComponent = (propsData = { tags, isDesktop: true }) => {
|
||||
wrapper = mount(component, {
|
||||
stubs: {
|
||||
...stubChildren(component),
|
||||
GlTable: false,
|
||||
},
|
||||
propsData,
|
||||
slots: {
|
||||
loader: '<div data-testid="loaderSlot"></div>',
|
||||
empty: '<div data-testid="emptySlot"></div>',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
it.each([
|
||||
'rowCheckbox',
|
||||
'rowName',
|
||||
'rowShortRevision',
|
||||
'rowSize',
|
||||
'rowTime',
|
||||
'singleDeleteButton',
|
||||
])('%s exist in the table', element => {
|
||||
mountComponent();
|
||||
|
||||
expect(findFirstRowItem(element).exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('header checkbox', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
expect(findMainCheckbox().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('if selected selects all the rows', () => {
|
||||
mountComponent();
|
||||
findMainCheckbox().vm.$emit('change');
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(findMainCheckbox().attributes('checked')).toBeTruthy();
|
||||
expect(findCheckedCheckboxes()).toHaveLength(tags.length);
|
||||
});
|
||||
});
|
||||
|
||||
it('if deselect deselects all the row', () => {
|
||||
mountComponent();
|
||||
findMainCheckbox().vm.$emit('change');
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(() => {
|
||||
expect(findMainCheckbox().attributes('checked')).toBeTruthy();
|
||||
findMainCheckbox().vm.$emit('change');
|
||||
return wrapper.vm.$nextTick();
|
||||
})
|
||||
.then(() => {
|
||||
expect(findMainCheckbox().attributes('checked')).toBe(undefined);
|
||||
expect(findCheckedCheckboxes()).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('row checkbox', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('selecting and deselecting the checkbox works as intended', () => {
|
||||
findFirstRowItem('rowCheckbox').vm.$emit('change');
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(() => {
|
||||
expect(wrapper.vm.selectedItems).toEqual([tags[0].name]);
|
||||
expect(findFirstRowItem('rowCheckbox').attributes('checked')).toBeTruthy();
|
||||
findFirstRowItem('rowCheckbox').vm.$emit('change');
|
||||
return wrapper.vm.$nextTick();
|
||||
})
|
||||
.then(() => {
|
||||
expect(wrapper.vm.selectedItems.length).toBe(0);
|
||||
expect(findFirstRowItem('rowCheckbox').attributes('checked')).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('header delete button', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('exists', () => {
|
||||
expect(findBulkDeleteButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('is disabled if no item is selected', () => {
|
||||
expect(findBulkDeleteButton().attributes('disabled')).toBe('true');
|
||||
});
|
||||
|
||||
it('is enabled if at least one item is selected', () => {
|
||||
expect(findBulkDeleteButton().attributes('disabled')).toBe('true');
|
||||
findFirstRowItem('rowCheckbox').vm.$emit('change');
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(findBulkDeleteButton().attributes('disabled')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('on click', () => {
|
||||
it('when one item is selected', () => {
|
||||
findFirstRowItem('rowCheckbox').vm.$emit('change');
|
||||
findBulkDeleteButton().vm.$emit('click');
|
||||
expect(wrapper.emitted('delete')).toEqual([[['centos6']]]);
|
||||
});
|
||||
|
||||
it('when multiple items are selected', () => {
|
||||
findMainCheckbox().vm.$emit('change');
|
||||
findBulkDeleteButton().vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('delete')).toEqual([[tags.map(t => t.name)]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('row delete button', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('exists', () => {
|
||||
expect(
|
||||
findAllDeleteButtons()
|
||||
.at(0)
|
||||
.exists(),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('is disabled if the item has no destroy_path', () => {
|
||||
expect(
|
||||
findAllDeleteButtons()
|
||||
.at(1)
|
||||
.attributes('disabled'),
|
||||
).toBe('true');
|
||||
});
|
||||
|
||||
it('on click', () => {
|
||||
findAllDeleteButtons()
|
||||
.at(0)
|
||||
.vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('delete')).toEqual([[['centos6']]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('name cell', () => {
|
||||
it('tag column has a tooltip with the tag name', () => {
|
||||
mountComponent();
|
||||
expect(findFirstTagNameText().attributes('title')).toBe(tagsListResponse.data[0].name);
|
||||
});
|
||||
|
||||
describe('on desktop viewport', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('table header has class w-25', () => {
|
||||
expect(findFirsTagColumn().classes()).toContain('w-25');
|
||||
});
|
||||
|
||||
it('tag column has the mw-m class', () => {
|
||||
expect(findFirstRowItem('rowName').classes()).toContain('mw-m');
|
||||
});
|
||||
});
|
||||
|
||||
describe('on mobile viewport', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ tags, isDesktop: false });
|
||||
});
|
||||
|
||||
it('table header does not have class w-25', () => {
|
||||
expect(findFirsTagColumn().classes()).not.toContain('w-25');
|
||||
});
|
||||
|
||||
it('tag column has the gl-justify-content-end class', () => {
|
||||
expect(findFirstRowItem('rowName').classes()).toContain('gl-justify-content-end');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('last updated cell', () => {
|
||||
let timeCell;
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
timeCell = findFirstRowItem('rowTime');
|
||||
});
|
||||
|
||||
it('displays the time in string format', () => {
|
||||
expect(timeCell.text()).toBe('2 years ago');
|
||||
});
|
||||
|
||||
it('has a tooltip timestamp', () => {
|
||||
expect(timeCell.attributes('title')).toBe('Sep 19, 2017 1:45pm GMT+0000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('empty state slot', () => {
|
||||
describe('when the table is empty', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ tags: [], isDesktop: true });
|
||||
});
|
||||
|
||||
it('does not show table rows', () => {
|
||||
expect(findFirstTagNameText().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('has the empty state slot', () => {
|
||||
expect(findEmptySlot().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the table is not empty', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ tags, isDesktop: true });
|
||||
});
|
||||
|
||||
it('does show table rows', () => {
|
||||
expect(findFirstTagNameText().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show the empty state', () => {
|
||||
expect(findEmptySlot().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('loader slot', () => {
|
||||
describe('when the data is loading', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ isLoading: true, tags });
|
||||
});
|
||||
|
||||
it('show the loader', () => {
|
||||
expect(findLoaderSlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show the table rows', () => {
|
||||
expect(findFirstTagNameText().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the data is not loading', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ isLoading: false, tags });
|
||||
});
|
||||
|
||||
it('does not show the loader', () => {
|
||||
expect(findLoaderSlot().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows the table rows', () => {
|
||||
expect(findFirstTagNameText().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -4,17 +4,23 @@ import component from '~/registry/explorer/components/list_item.vue';
|
|||
describe('list item', () => {
|
||||
let wrapper;
|
||||
|
||||
const findLeftActionSlot = () => wrapper.find('[data-testid="left-action"]');
|
||||
const findLeftPrimarySlot = () => wrapper.find('[data-testid="left-primary"]');
|
||||
const findLeftSecondarySlot = () => wrapper.find('[data-testid="left-secondary"]');
|
||||
const findRightSlot = () => wrapper.find('[data-testid="right"]');
|
||||
const findRightPrimarySlot = () => wrapper.find('[data-testid="right-primary"]');
|
||||
const findRightSecondarySlot = () => wrapper.find('[data-testid="right-secondary"]');
|
||||
const findRightActionSlot = () => wrapper.find('[data-testid="right-action"]');
|
||||
|
||||
const mountComponent = propsData => {
|
||||
wrapper = shallowMount(component, {
|
||||
propsData,
|
||||
slots: {
|
||||
'left-action': '<div data-testid="left-action" />',
|
||||
'left-primary': '<div data-testid="left-primary" />',
|
||||
'left-secondary': '<div data-testid="left-secondary" />',
|
||||
right: '<div data-testid="right" />',
|
||||
'right-primary': '<div data-testid="right-primary" />',
|
||||
'right-secondary': '<div data-testid="right-secondary" />',
|
||||
'right-action': '<div data-testid="right-action" />',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -24,29 +30,30 @@ describe('list item', () => {
|
|||
wrapper = null;
|
||||
});
|
||||
|
||||
it('has a left primary slot', () => {
|
||||
it.each`
|
||||
slotName | finderFunction
|
||||
${'left-primary'} | ${findLeftPrimarySlot}
|
||||
${'left-secondary'} | ${findLeftSecondarySlot}
|
||||
${'right-primary'} | ${findRightPrimarySlot}
|
||||
${'right-secondary'} | ${findRightSecondarySlot}
|
||||
${'left-action'} | ${findLeftActionSlot}
|
||||
${'right-action'} | ${findRightActionSlot}
|
||||
`('has a $slotName slot', ({ finderFunction }) => {
|
||||
mountComponent();
|
||||
expect(findLeftPrimarySlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has a left secondary slot', () => {
|
||||
mountComponent();
|
||||
expect(findLeftSecondarySlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has a right slot', () => {
|
||||
mountComponent();
|
||||
expect(findRightSlot().exists()).toBe(true);
|
||||
expect(finderFunction().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('disabled prop', () => {
|
||||
it('when true applies disabled-content class', () => {
|
||||
mountComponent({ disabled: true });
|
||||
|
||||
expect(wrapper.classes('disabled-content')).toBe(true);
|
||||
});
|
||||
|
||||
it('when false does not apply disabled-content class', () => {
|
||||
mountComponent({ disabled: false });
|
||||
|
||||
expect(wrapper.classes('disabled-content')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -54,15 +61,38 @@ describe('list item', () => {
|
|||
describe('index prop', () => {
|
||||
it('when index is 0 displays a top border', () => {
|
||||
mountComponent({ index: 0 });
|
||||
|
||||
expect(wrapper.classes()).toEqual(
|
||||
expect.arrayContaining(['gl-border-t-solid', 'gl-border-t-1']),
|
||||
);
|
||||
});
|
||||
|
||||
it('when index is not 0 hides top border', () => {
|
||||
it('when index is not 0 hides top border', () => {
|
||||
mountComponent({ index: 1 });
|
||||
expect(wrapper.classes('gl-border-t-solid')).toBe(false);
|
||||
expect(wrapper.classes('gl-border-t-1')).toBe(false);
|
||||
|
||||
expect(wrapper.classes()).toEqual(
|
||||
expect.not.arrayContaining(['gl-border-t-solid', 'gl-border-t-1']),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('selected prop', () => {
|
||||
it('when true applies the selected border and background', () => {
|
||||
mountComponent({ selected: true });
|
||||
|
||||
expect(wrapper.classes()).toEqual(
|
||||
expect.arrayContaining(['gl-bg-blue-50', 'gl-border-blue-200']),
|
||||
);
|
||||
expect(wrapper.classes()).toEqual(expect.not.arrayContaining(['gl-border-gray-200']));
|
||||
});
|
||||
|
||||
it('when false applies the default border', () => {
|
||||
mountComponent({ selected: false });
|
||||
|
||||
expect(wrapper.classes()).toEqual(
|
||||
expect.not.arrayContaining(['gl-bg-blue-50', 'gl-border-blue-200']),
|
||||
);
|
||||
expect(wrapper.classes()).toEqual(expect.arrayContaining(['gl-border-gray-200']));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -71,7 +71,7 @@ export const tagsListResponse = {
|
|||
layers: 10,
|
||||
location: 'location',
|
||||
path: 'bar',
|
||||
created_at: 1505828744434,
|
||||
created_at: '1505828744434',
|
||||
destroy_path: 'path',
|
||||
},
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ export const tagsListResponse = {
|
|||
layers: 10,
|
||||
path: 'foo',
|
||||
location: 'location-2',
|
||||
created_at: 1505828744434,
|
||||
created_at: '1505828744434',
|
||||
},
|
||||
],
|
||||
headers,
|
||||
|
|
|
@ -5,6 +5,7 @@ import component from '~/registry/explorer/pages/details.vue';
|
|||
import DeleteAlert from '~/registry/explorer/components/details_page/delete_alert.vue';
|
||||
import DetailsHeader from '~/registry/explorer/components/details_page/details_header.vue';
|
||||
import TagsLoader from '~/registry/explorer/components/details_page/tags_loader.vue';
|
||||
import TagsList from '~/registry/explorer/components/details_page/tags_list.vue';
|
||||
import EmptyTagsState from '~/registry/explorer/components/details_page/empty_tags_state.vue';
|
||||
import { createStore } from '~/registry/explorer/stores/';
|
||||
import {
|
||||
|
@ -15,7 +16,7 @@ import {
|
|||
} from '~/registry/explorer/stores/mutation_types/';
|
||||
|
||||
import { tagsListResponse } from '../mock_data';
|
||||
import { TagsTable, DeleteModal } from '../stubs';
|
||||
import { DeleteModal } from '../stubs';
|
||||
|
||||
describe('Details Page', () => {
|
||||
let wrapper;
|
||||
|
@ -25,18 +26,23 @@ describe('Details Page', () => {
|
|||
const findDeleteModal = () => wrapper.find(DeleteModal);
|
||||
const findPagination = () => wrapper.find(GlPagination);
|
||||
const findTagsLoader = () => wrapper.find(TagsLoader);
|
||||
const findTagsTable = () => wrapper.find(TagsTable);
|
||||
const findTagsList = () => wrapper.find(TagsList);
|
||||
const findDeleteAlert = () => wrapper.find(DeleteAlert);
|
||||
const findDetailsHeader = () => wrapper.find(DetailsHeader);
|
||||
const findEmptyTagsState = () => wrapper.find(EmptyTagsState);
|
||||
|
||||
const routeId = window.btoa(JSON.stringify({ name: 'foo', tags_path: 'bar' }));
|
||||
|
||||
const tagsArrayToSelectedTags = tags =>
|
||||
tags.reduce((acc, c) => {
|
||||
acc[c.name] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const mountComponent = options => {
|
||||
wrapper = shallowMount(component, {
|
||||
store,
|
||||
stubs: {
|
||||
TagsTable,
|
||||
DeleteModal,
|
||||
},
|
||||
mocks: {
|
||||
|
@ -66,15 +72,18 @@ describe('Details Page', () => {
|
|||
|
||||
describe('when isLoading is true', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
store.commit(SET_MAIN_LOADING, true);
|
||||
return wrapper.vm.$nextTick();
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
afterEach(() => store.commit(SET_MAIN_LOADING, false));
|
||||
|
||||
it('binds isLoading to tags-table', () => {
|
||||
expect(findTagsTable().props('isLoading')).toBe(true);
|
||||
it('shows the loader', () => {
|
||||
expect(findTagsLoader().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show the list', () => {
|
||||
expect(findTagsList().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not show pagination', () => {
|
||||
|
@ -82,8 +91,9 @@ describe('Details Page', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('table slots', () => {
|
||||
describe('when the list of tags is empty', () => {
|
||||
beforeEach(() => {
|
||||
store.commit(SET_TAGS_LIST_SUCCESS, []);
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
|
@ -91,32 +101,37 @@ describe('Details Page', () => {
|
|||
expect(findEmptyTagsState().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has a skeleton loader', () => {
|
||||
expect(findTagsLoader().exists()).toBe(true);
|
||||
it('does not show the loader', () => {
|
||||
expect(findTagsLoader().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not show the list', () => {
|
||||
expect(findTagsList().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('table', () => {
|
||||
describe('list', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('exists', () => {
|
||||
expect(findTagsTable().exists()).toBe(true);
|
||||
expect(findTagsList().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct props bound', () => {
|
||||
expect(findTagsTable().props()).toMatchObject({
|
||||
expect(findTagsList().props()).toMatchObject({
|
||||
isDesktop: true,
|
||||
isLoading: false,
|
||||
tags: store.state.tags,
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteEvent', () => {
|
||||
describe('single item', () => {
|
||||
let tagToBeDeleted;
|
||||
beforeEach(() => {
|
||||
findTagsTable().vm.$emit('delete', [store.state.tags[0].name]);
|
||||
[tagToBeDeleted] = store.state.tags;
|
||||
findTagsList().vm.$emit('delete', { [tagToBeDeleted.name]: true });
|
||||
});
|
||||
|
||||
it('open the modal', () => {
|
||||
|
@ -124,7 +139,7 @@ describe('Details Page', () => {
|
|||
});
|
||||
|
||||
it('maps the selection to itemToBeDeleted', () => {
|
||||
expect(wrapper.vm.itemsToBeDeleted).toEqual([store.state.tags[0]]);
|
||||
expect(wrapper.vm.itemsToBeDeleted).toEqual([tagToBeDeleted]);
|
||||
});
|
||||
|
||||
it('tracks a single delete event', () => {
|
||||
|
@ -136,7 +151,7 @@ describe('Details Page', () => {
|
|||
|
||||
describe('multiple items', () => {
|
||||
beforeEach(() => {
|
||||
findTagsTable().vm.$emit('delete', store.state.tags.map(t => t.name));
|
||||
findTagsList().vm.$emit('delete', tagsArrayToSelectedTags(store.state.tags));
|
||||
});
|
||||
|
||||
it('open the modal', () => {
|
||||
|
@ -202,7 +217,7 @@ describe('Details Page', () => {
|
|||
describe('when one item is selected to be deleted', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
findTagsTable().vm.$emit('delete', [store.state.tags[0].name]);
|
||||
findTagsList().vm.$emit('delete', { [store.state.tags[0].name]: true });
|
||||
});
|
||||
|
||||
it('dispatch requestDeleteTag with the right parameters', () => {
|
||||
|
@ -217,7 +232,7 @@ describe('Details Page', () => {
|
|||
describe('when more than one item is selected to be deleted', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
findTagsTable().vm.$emit('delete', store.state.tags.map(t => t.name));
|
||||
findTagsList().vm.$emit('delete', tagsArrayToSelectedTags(store.state.tags));
|
||||
});
|
||||
|
||||
it('dispatch requestDeleteTags with the right parameters', () => {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import RealTagsTable from '~/registry/explorer/components/details_page/tags_table.vue';
|
||||
import RealDeleteModal from '~/registry/explorer/components/details_page/delete_modal.vue';
|
||||
|
||||
export const GlModal = {
|
||||
|
@ -18,11 +17,6 @@ export const RouterLink = {
|
|||
props: ['to'],
|
||||
};
|
||||
|
||||
export const TagsTable = {
|
||||
props: RealTagsTable.props,
|
||||
template: `<div><slot name="empty"></slot><slot name="loader"></slot></div>`,
|
||||
};
|
||||
|
||||
export const DeleteModal = {
|
||||
template: '<div></div>',
|
||||
methods: {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutations::AlertManagement::Alerts::SetAssignees do
|
||||
RSpec.describe Mutations::AlertManagement::Alerts::SetAssignees do
|
||||
let_it_be(:starting_assignee) { create(:user) }
|
||||
let_it_be(:unassigned_user) { create(:user) }
|
||||
let_it_be(:alert) { create(:alert_management_alert, assignees: [starting_assignee]) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutations::ContainerExpirationPolicies::Update do
|
||||
RSpec.describe Mutations::ContainerExpirationPolicies::Update do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:project, reload: true) { create(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe LooksAhead do
|
||||
RSpec.describe LooksAhead do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:the_user) { create(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Resolvers::ProjectMembersResolver do
|
||||
RSpec.describe Resolvers::ProjectMembersResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
context "with a group" do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Resolvers::ProjectPipelineResolver do
|
||||
RSpec.describe Resolvers::ProjectPipelineResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Resolvers::UsersResolver do
|
||||
RSpec.describe Resolvers::UsersResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user1) { create(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['AccessLevelEnum'] do
|
||||
RSpec.describe GitlabSchema.types['AccessLevelEnum'] do
|
||||
specify { expect(described_class.graphql_name).to eq('AccessLevelEnum') }
|
||||
|
||||
it 'exposes all the existing access levels' do
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['AccessLevel'] do
|
||||
RSpec.describe GitlabSchema.types['AccessLevel'] do
|
||||
specify { expect(described_class.graphql_name).to eq('AccessLevel') }
|
||||
specify { expect(described_class).to require_graphql_authorizations(nil) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['ReleaseEvidence'] do
|
||||
RSpec.describe GitlabSchema.types['ReleaseEvidence'] do
|
||||
it { expect(described_class).to require_graphql_authorizations(:download_code) }
|
||||
|
||||
it 'has the expected fields' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::GroupMemberType do
|
||||
RSpec.describe Types::GroupMemberType do
|
||||
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Group) }
|
||||
|
||||
specify { expect(described_class.graphql_name).to eq('GroupMember') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['MilestoneStats'] do
|
||||
RSpec.describe GitlabSchema.types['MilestoneStats'] do
|
||||
it { expect(described_class).to require_graphql_authorizations(:read_milestone) }
|
||||
|
||||
it 'has the expected fields' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::ProjectMemberType do
|
||||
RSpec.describe Types::ProjectMemberType do
|
||||
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
|
||||
|
||||
specify { expect(described_class.graphql_name).to eq('ProjectMember') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['ReleaseAssetLink'] do
|
||||
RSpec.describe GitlabSchema.types['ReleaseAssetLink'] do
|
||||
it { expect(described_class).to require_graphql_authorizations(:read_release) }
|
||||
|
||||
it 'has the expected fields' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Snippets::FileInputActionEnum do
|
||||
RSpec.describe Types::Snippets::FileInputActionEnum do
|
||||
specify { expect(described_class.graphql_name).to eq('SnippetFileInputActionEnum') }
|
||||
|
||||
it 'exposes all file input action types' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Snippets::FileInputType do
|
||||
RSpec.describe Types::Snippets::FileInputType do
|
||||
specify { expect(described_class.graphql_name).to eq('SnippetFileInputType') }
|
||||
|
||||
it 'has the correct arguments' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['UntrustedRegexp'] do
|
||||
RSpec.describe GitlabSchema.types['UntrustedRegexp'] do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
specify { expect(described_class.graphql_name).to eq('UntrustedRegexp') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require "spec_helper"
|
||||
|
||||
describe Analytics::UniqueVisitsHelper do
|
||||
RSpec.describe Analytics::UniqueVisitsHelper do
|
||||
include Devise::Test::ControllerHelpers
|
||||
|
||||
describe '#track_visit' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe SubscribableBannerHelper do
|
||||
RSpec.describe SubscribableBannerHelper do
|
||||
describe '#display_subscription_banner!' do
|
||||
it 'is over-written in EE' do
|
||||
expect { helper.display_subscription_banner! }.not_to raise_error
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe API::Entities::DeployKey do
|
||||
RSpec.describe API::Entities::DeployKey do
|
||||
describe '#as_json' do
|
||||
subject { entity.as_json }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe API::Entities::DeployKeysProject do
|
||||
RSpec.describe API::Entities::DeployKeysProject do
|
||||
describe '#as_json' do
|
||||
subject { entity.as_json }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe API::Entities::SSHKey do
|
||||
RSpec.describe API::Entities::SSHKey do
|
||||
describe '#as_json' do
|
||||
subject { entity.as_json }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe API::Validations::Validators::UntrustedRegexp do
|
||||
RSpec.describe API::Validations::Validators::UntrustedRegexp do
|
||||
include ApiValidatorsHelpers
|
||||
|
||||
subject do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::JiraImport::AdfToCommonmarkFilter do
|
||||
RSpec.describe Banzai::Filter::JiraImport::AdfToCommonmarkFilter do
|
||||
include FilterSpecHelper
|
||||
|
||||
let_it_be(:fixtures_path) { 'lib/kramdown/atlassian_document_format' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Pipeline::JiraImport::AdfCommonmarkPipeline do
|
||||
RSpec.describe Banzai::Pipeline::JiraImport::AdfCommonmarkPipeline do
|
||||
let_it_be(:fixtures_path) { 'lib/kramdown/atlassian_document_format' }
|
||||
|
||||
it 'converts text in Atlassian Document Format ' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ExtractsRef do
|
||||
RSpec.describe ExtractsRef do
|
||||
include described_class
|
||||
include RepoHelpers
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state do
|
||||
RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state do
|
||||
let(:unique_visits) { Gitlab::Analytics::UniqueVisits.new }
|
||||
let(:target1_id) { 'g_analytics_contribution' }
|
||||
let(:target2_id) { 'g_analytics_insights' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Ci::Build::Releaser do
|
||||
RSpec.describe Gitlab::Ci::Build::Releaser do
|
||||
subject { described_class.new(config: config[:release]).script }
|
||||
|
||||
describe '#script' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Ci::Reports::TestReportSummary do
|
||||
RSpec.describe Gitlab::Ci::Reports::TestReportSummary do
|
||||
let(:build_report_result_1) { build(:ci_build_report_result) }
|
||||
let(:build_report_result_2) { build(:ci_build_report_result, :with_junit_success) }
|
||||
let(:test_report_summary) { described_class.new([build_report_result_1, build_report_result_2]) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Ci::Reports::TestSuiteSummary do
|
||||
RSpec.describe Gitlab::Ci::Reports::TestSuiteSummary do
|
||||
let(:build_report_result_1) { build(:ci_build_report_result) }
|
||||
let(:build_report_result_2) { build(:ci_build_report_result, :with_junit_success) }
|
||||
let(:test_suite_summary) { described_class.new([build_report_result_1, build_report_result_2]) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::DataBuilder::Alert do
|
||||
RSpec.describe Gitlab::DataBuilder::Alert do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:alert) { create(:alert_management_alert, project: project) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Database::CustomStructure do
|
||||
RSpec.describe Gitlab::Database::CustomStructure do
|
||||
let_it_be(:structure) { described_class.new }
|
||||
let_it_be(:filepath) { Rails.root.join(described_class::CUSTOM_DUMP_FILE) }
|
||||
let_it_be(:file_header) do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Database::DynamicModelHelpers do
|
||||
RSpec.describe Gitlab::Database::DynamicModelHelpers do
|
||||
describe '#define_batchable_model' do
|
||||
subject { including_class.new.define_batchable_model(table_name) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Database::Migrations::BackgroundMigrationHelpers do
|
||||
RSpec.describe Gitlab::Database::Migrations::BackgroundMigrationHelpers do
|
||||
let(:model) do
|
||||
ActiveRecord::Migration.new.extend(described_class)
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Database::PartitioningMigrationHelpers::BackfillPartitionedTable, '#perform' do
|
||||
RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::BackfillPartitionedTable, '#perform' do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:source_table) { '_test_partitioning_backfills' }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::DependencyLinker::GoModLinker do
|
||||
RSpec.describe Gitlab::DependencyLinker::GoModLinker do
|
||||
let(:file_name) { 'go.mod' }
|
||||
let(:file_content) do
|
||||
<<-CONTENT.strip_heredoc
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::DependencyLinker::GoSumLinker do
|
||||
RSpec.describe Gitlab::DependencyLinker::GoSumLinker do
|
||||
let(:file_name) { 'go.sum' }
|
||||
let(:file_content) do
|
||||
<<-CONTENT.strip_heredoc
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Diff::StatsCache, :use_clean_rails_memory_store_caching do
|
||||
RSpec.describe Gitlab::Diff::StatsCache, :use_clean_rails_memory_store_caching do
|
||||
subject(:stats_cache) { described_class.new(cachable_key: cachable_key) }
|
||||
|
||||
let(:key) { ['diff_stats', cachable_key, described_class::VERSION].join(":") }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Doctor::Secrets do
|
||||
RSpec.describe Gitlab::Doctor::Secrets do
|
||||
let!(:user) { create(:user, otp_secret: "test") }
|
||||
let!(:group) { create(:group, runners_token: "test") }
|
||||
let(:logger) { double(:logger).as_null_object }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Emoji do
|
||||
RSpec.describe Gitlab::Emoji do
|
||||
let_it_be(:emojis) { Gemojione.index.instance_variable_get(:@emoji_by_name) }
|
||||
let_it_be(:emojis_by_moji) { Gemojione.index.instance_variable_get(:@emoji_by_moji) }
|
||||
let_it_be(:emoji_unicode_versions_by_name) { Gitlab::Json.parse(File.read(Rails.root.join('fixtures', 'emojis', 'emoji-unicode-version-map.json'))) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitAccessProject do
|
||||
RSpec.describe Gitlab::GitAccessProject do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:actor) { user }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Graphql::MountMutation do
|
||||
RSpec.describe Gitlab::Graphql::MountMutation do
|
||||
let_it_be(:mutation) do
|
||||
Class.new(Mutations::BaseMutation) do
|
||||
graphql_name 'TestMutation'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Instrumentation::RedisBase, :request_store do
|
||||
RSpec.describe Gitlab::Instrumentation::RedisBase, :request_store do
|
||||
let(:instrumentation_class_a) do
|
||||
stub_const('InstanceA', Class.new(described_class))
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'fast_spec_helper'
|
|||
require 'support/helpers/rails_helpers'
|
||||
require 'rspec-parameterized'
|
||||
|
||||
describe Gitlab::Instrumentation::RedisClusterValidator do
|
||||
RSpec.describe Gitlab::Instrumentation::RedisClusterValidator do
|
||||
include RailsHelpers
|
||||
|
||||
describe '.validate!' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Metrics::Dashboard::Stages::UrlValidator do
|
||||
RSpec.describe Gitlab::Metrics::Dashboard::Stages::UrlValidator do
|
||||
let(:project) { build_stubbed(:project) }
|
||||
|
||||
describe '#transform!' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Metrics::Dashboard::Stages::VariableEndpointInserter do
|
||||
RSpec.describe Gitlab::Metrics::Dashboard::Stages::VariableEndpointInserter do
|
||||
include MetricsDashboardHelpers
|
||||
|
||||
let(:project) { build_stubbed(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Suggestions::CommitMessage do
|
||||
RSpec.describe Gitlab::Suggestions::CommitMessage do
|
||||
def create_suggestion(file_path, new_line, to_content)
|
||||
position = Gitlab::Diff::Position.new(old_path: file_path,
|
||||
new_path: file_path,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Suggestions::FileSuggestion do
|
||||
RSpec.describe Gitlab::Suggestions::FileSuggestion do
|
||||
def create_suggestion(new_line, to_content, lines_above = 0, lines_below = 0)
|
||||
position = Gitlab::Diff::Position.new(old_path: file_path,
|
||||
new_path: file_path,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Suggestions::SuggestionSet do
|
||||
RSpec.describe Gitlab::Suggestions::SuggestionSet do
|
||||
def create_suggestion(file_path, new_line, to_content)
|
||||
position = Gitlab::Diff::Position.new(old_path: file_path,
|
||||
new_path: file_path,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::UsageDataConcerns::Topology do
|
||||
RSpec.describe Gitlab::UsageDataConcerns::Topology do
|
||||
include UsageDataHelpers
|
||||
|
||||
describe '#topology_usage_data' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
context Kramdown::Parser::AtlassianDocumentFormat do
|
||||
RSpec.context Kramdown::Parser::AtlassianDocumentFormat do
|
||||
let_it_be(:options) { { input: 'AtlassianDocumentFormat', html_tables: true } }
|
||||
let_it_be(:fixtures_path) { 'lib/kramdown/atlassian_document_format' }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe LearnGitlab do
|
||||
RSpec.describe LearnGitlab do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:learn_gitlab_project) { create(:project, name: LearnGitlab::PROJECT_NAME) }
|
||||
let_it_be(:learn_gitlab_board) { create(:board, project: learn_gitlab_project, name: LearnGitlab::BOARD_NAME) }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'migrate', '20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb')
|
||||
|
||||
describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
|
||||
RSpec.describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
|
||||
let(:migration) { described_class.new }
|
||||
|
||||
let(:approval_rules) { table(:approval_merge_request_rules) }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'migrate', '20200609212701_add_incident_settings_to_all_existing_projects.rb')
|
||||
|
||||
describe AddIncidentSettingsToAllExistingProjects, :migration do
|
||||
RSpec.describe AddIncidentSettingsToAllExistingProjects, :migration do
|
||||
let(:project_incident_management_settings) { table(:project_incident_management_settings) }
|
||||
let(:labels) { table(:labels) }
|
||||
let(:label_links) { table(:label_links) }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'post_migrate', '20200608072931_backfill_imported_snippet_repositories.rb')
|
||||
|
||||
describe BackfillImportedSnippetRepositories do
|
||||
RSpec.describe BackfillImportedSnippetRepositories do
|
||||
let(:users) { table(:users) }
|
||||
let(:snippets) { table(:snippets) }
|
||||
let(:user) { users.create(id: 1, email: 'user@example.com', projects_limit: 10, username: 'test', name: 'Test', state: 'active') }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'post_migrate', '20200602013901_cap_designs_filename_length_to_new_limit')
|
||||
|
||||
describe CapDesignsFilenameLengthToNewLimit, :migration, schema: 20200528125905 do
|
||||
RSpec.describe CapDesignsFilenameLengthToNewLimit, :migration, schema: 20200528125905 do
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
let(:projects) { table(:projects) }
|
||||
let(:issues) { table(:issues) }
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
require Rails.root.join('db', 'post_migrate', '20200602143020_update_routes_for_lost_and_found_group_and_orphaned_projects.rb')
|
||||
|
||||
describe UpdateRoutesForLostAndFoundGroupAndOrphanedProjects, :migration do
|
||||
RSpec.describe UpdateRoutesForLostAndFoundGroupAndOrphanedProjects, :migration do
|
||||
let(:users) { table(:users) }
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
let(:members) { table(:members) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe AlertManagement::AlertUserMention do
|
||||
RSpec.describe AlertManagement::AlertUserMention do
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:alert_management_alert) }
|
||||
it { is_expected.to belong_to(:note) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe BlobViewer::GoMod do
|
||||
RSpec.describe BlobViewer::GoMod do
|
||||
include FakeBlobHelpers
|
||||
|
||||
let(:project) { build_stubbed(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GroupDeployKey do
|
||||
RSpec.describe GroupDeployKey do
|
||||
it { is_expected.to validate_presence_of(:user) }
|
||||
|
||||
it 'is of type DeployKey' do
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GroupImportState do
|
||||
RSpec.describe GroupImportState do
|
||||
describe 'validations' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ChatMessage::AlertMessage do
|
||||
RSpec.describe ChatMessage::AlertMessage do
|
||||
subject { described_class.new(args) }
|
||||
|
||||
let_it_be(:start_time) { Time.current }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe SnippetStatistics do
|
||||
RSpec.describe SnippetStatistics do
|
||||
let_it_be(:snippet_without_repo) { create(:snippet) }
|
||||
let_it_be(:snippet_with_repo) { create(:snippet, :repository) }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::BlamePresenter do
|
||||
RSpec.describe Gitlab::BlamePresenter do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:path) { 'files/ruby/popen.rb' }
|
||||
let(:commit) { project.commit('master') }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Setting assignees of an alert' do
|
||||
RSpec.describe 'Setting assignees of an alert' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Updating the container expiration policy' do
|
||||
RSpec.describe 'Updating the container expiration policy' do
|
||||
include GraphqlHelpers
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Importing Jira Users' do
|
||||
RSpec.describe 'Importing Jira Users' do
|
||||
include JiraServiceHelper
|
||||
include GraphqlHelpers
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutations::Metrics::Dashboard::Annotations::Delete do
|
||||
RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'getting Alert Management Alert Assignees' do
|
||||
RSpec.describe 'getting Alert Management Alert Assignees' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'getting Alert Management Alert Notes' do
|
||||
RSpec.describe 'getting Alert Management Alert Notes' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'getting pipeline information nested in a project' do
|
||||
RSpec.describe 'getting pipeline information nested in a project' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:project) { create(:project, :repository, :public) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Query.project(fullPath).releases()' do
|
||||
RSpec.describe 'Query.project(fullPath).releases()' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:stranger) { create(:user) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'GroupMember' do
|
||||
RSpec.describe 'GroupMember' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:member) { create(:group_member, :developer) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'ProjectMember' do
|
||||
RSpec.describe 'ProjectMember' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:member) { create(:project_member, :developer) }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Users' do
|
||||
RSpec.describe 'Users' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user, created_at: 1.day.ago) }
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue