Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
cc77bdd6f5
commit
a0e1fa9aad
|
|
@ -225,7 +225,7 @@ export default {
|
|||
v-model="searchText"
|
||||
role="searchbox"
|
||||
class="gl-z-index-1"
|
||||
data-testid="global_search_input"
|
||||
data-testid="global-search-input"
|
||||
autocomplete="off"
|
||||
:placeholder="$options.i18n.SEARCH_GITLAB"
|
||||
:aria-activedescendant="currentFocusedId"
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ export default {
|
|||
<gl-dropdown-item
|
||||
v-gl-modal="$options.deleteModalId"
|
||||
variant="danger"
|
||||
data-testid="delete_issue_button"
|
||||
data-testid="delete-issue-button"
|
||||
@click="track('click_dropdown')"
|
||||
>
|
||||
{{ deleteButtonText }}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
<script>
|
||||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import ImageListRow from './image_list_row.vue';
|
||||
|
||||
export default {
|
||||
name: 'ImageList',
|
||||
components: {
|
||||
GlKeysetPagination,
|
||||
ImageListRow,
|
||||
},
|
||||
props: {
|
||||
|
|
@ -18,10 +16,6 @@ export default {
|
|||
default: false,
|
||||
required: false,
|
||||
},
|
||||
pageInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
expirationPolicy: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
|
|
@ -41,13 +35,5 @@ export default {
|
|||
:expiration-policy="expirationPolicy"
|
||||
@delete="$emit('delete', $event)"
|
||||
/>
|
||||
<div class="gl-display-flex gl-justify-content-center">
|
||||
<gl-keyset-pagination
|
||||
v-bind="pageInfo"
|
||||
class="gl-mt-3"
|
||||
@prev="$emit('prev-page')"
|
||||
@next="$emit('next-page')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { createAlert } from '~/alert';
|
|||
import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import Tracking from '~/tracking';
|
||||
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
|
||||
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
|
||||
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import DeleteImage from '../components/delete_image.vue';
|
||||
|
|
@ -33,6 +34,7 @@ import {
|
|||
SETTINGS_TEXT,
|
||||
} from '../constants/index';
|
||||
import getContainerRepositoriesDetails from '../graphql/queries/get_container_repositories_details.query.graphql';
|
||||
import { getPageParams, getNextPageParams, getPreviousPageParams } from '../utils';
|
||||
|
||||
export default {
|
||||
name: 'RegistryListPage',
|
||||
|
|
@ -62,6 +64,7 @@ export default {
|
|||
GlSkeletonLoader,
|
||||
RegistryHeader,
|
||||
DeleteImage,
|
||||
PersistedPagination,
|
||||
PersistedSearch,
|
||||
},
|
||||
directives: {
|
||||
|
|
@ -198,25 +201,18 @@ export default {
|
|||
this.deleteAlertType = null;
|
||||
this.itemToDelete = {};
|
||||
},
|
||||
async fetchNextPage() {
|
||||
this.pageParams = {
|
||||
after: this.pageInfo?.endCursor,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
};
|
||||
fetchNextPage() {
|
||||
this.pageParams = getNextPageParams(this.pageInfo?.endCursor);
|
||||
},
|
||||
async fetchPreviousPage() {
|
||||
this.pageParams = {
|
||||
first: null,
|
||||
before: this.pageInfo?.startCursor,
|
||||
last: GRAPHQL_PAGE_SIZE,
|
||||
};
|
||||
fetchPreviousPage() {
|
||||
this.pageParams = getPreviousPageParams(this.pageInfo?.startCursor);
|
||||
},
|
||||
startDelete() {
|
||||
this.track('confirm_delete');
|
||||
this.mutationLoading = true;
|
||||
},
|
||||
handleSearchUpdate({ sort, filters }) {
|
||||
this.pageParams = {};
|
||||
handleSearchUpdate({ sort, filters, pageInfo }) {
|
||||
this.pageParams = getPageParams(pageInfo);
|
||||
this.sorting = sort;
|
||||
|
||||
const search = filters.find((i) => i.type === FILTERED_SEARCH_TERM);
|
||||
|
|
@ -322,11 +318,8 @@ export default {
|
|||
v-if="images.length"
|
||||
:images="images"
|
||||
:metadata-loading="$apollo.queries.additionalDetails.loading"
|
||||
:page-info="pageInfo"
|
||||
:expiration-policy="config.expirationPolicy"
|
||||
@delete="deleteImage"
|
||||
@prev-page="fetchPreviousPage"
|
||||
@next-page="fetchNextPage"
|
||||
/>
|
||||
|
||||
<gl-empty-state
|
||||
|
|
@ -346,6 +339,15 @@ export default {
|
|||
</template>
|
||||
</template>
|
||||
|
||||
<div class="gl-display-flex gl-justify-content-center">
|
||||
<persisted-pagination
|
||||
class="gl-mt-3"
|
||||
:pagination="pageInfo"
|
||||
@prev="fetchPreviousPage"
|
||||
@next="fetchNextPage"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<delete-image
|
||||
:id="itemToDelete.id"
|
||||
@start="startDelete"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { approximateDuration, calculateRemainingMilliseconds } from '~/lib/utils/datetime_utility';
|
||||
import { GRAPHQL_PAGE_SIZE } from './constants/index';
|
||||
|
||||
export const getImageName = (image = {}) => {
|
||||
return image.name || image.project?.path;
|
||||
|
|
@ -10,3 +11,26 @@ export const timeTilRun = (time) => {
|
|||
const difference = calculateRemainingMilliseconds(time);
|
||||
return approximateDuration(difference / 1000);
|
||||
};
|
||||
|
||||
export const getNextPageParams = (cursor) => ({
|
||||
after: cursor,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
});
|
||||
|
||||
export const getPreviousPageParams = (cursor) => ({
|
||||
first: null,
|
||||
before: cursor,
|
||||
last: GRAPHQL_PAGE_SIZE,
|
||||
});
|
||||
|
||||
export const getPageParams = (pageInfo = {}) => {
|
||||
if (pageInfo.before) {
|
||||
return getPreviousPageParams(pageInfo.before);
|
||||
}
|
||||
|
||||
if (pageInfo.after) {
|
||||
return getNextPageParams(pageInfo.after);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import UrlSync from '~/vue_shared/components/url_sync.vue';
|
||||
|
||||
export default {
|
||||
name: 'PersistedPagination',
|
||||
components: {
|
||||
GlKeysetPagination,
|
||||
UrlSync,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
pagination: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
attrs() {
|
||||
return {
|
||||
...this.pagination,
|
||||
...this.$attrs,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onPrev(updateQuery) {
|
||||
updateQuery({
|
||||
before: this.pagination?.startCursor,
|
||||
after: null,
|
||||
});
|
||||
this.$emit('prev');
|
||||
},
|
||||
onNext(updateQuery) {
|
||||
updateQuery({
|
||||
after: this.pagination?.endCursor,
|
||||
before: null,
|
||||
});
|
||||
this.$emit('next');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<url-sync>
|
||||
<template #default="{ updateQuery }">
|
||||
<gl-keyset-pagination
|
||||
v-bind="attrs"
|
||||
@prev="onPrev(updateQuery)"
|
||||
@next="onNext(updateQuery)"
|
||||
/>
|
||||
</template>
|
||||
</url-sync>
|
||||
</template>
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
<script>
|
||||
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
|
||||
import UrlSync from '~/vue_shared/components/url_sync.vue';
|
||||
import { extractFilterAndSorting, getQueryParams } from '~/packages_and_registries/shared/utils';
|
||||
import {
|
||||
extractFilterAndSorting,
|
||||
extractPageInfo,
|
||||
getQueryParams,
|
||||
} from '~/packages_and_registries/shared/utils';
|
||||
|
||||
export default {
|
||||
components: { RegistrySearch, UrlSync },
|
||||
|
|
@ -31,6 +35,7 @@ export default {
|
|||
orderBy: this.defaultOrder,
|
||||
sort: this.defaultSort,
|
||||
},
|
||||
pageInfo: {},
|
||||
mountRegistrySearch: false,
|
||||
};
|
||||
},
|
||||
|
|
@ -40,27 +45,49 @@ export default {
|
|||
return `${cleanOrderBy}_${this.sorting?.sort}`.toUpperCase();
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route(newValue, oldValue) {
|
||||
if (newValue.fullPath !== oldValue.fullPath) {
|
||||
this.updateDataFromUrl();
|
||||
this.emitUpdate();
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const queryParams = getQueryParams(window.document.location.search);
|
||||
const { sorting, filters } = extractFilterAndSorting(queryParams);
|
||||
this.updateSorting(sorting);
|
||||
this.updateFilters(filters);
|
||||
this.updateDataFromUrl();
|
||||
this.mountRegistrySearch = true;
|
||||
this.emitUpdate();
|
||||
},
|
||||
methods: {
|
||||
updateDataFromUrl() {
|
||||
const queryParams = getQueryParams(window.location.search);
|
||||
const { sorting, filters } = extractFilterAndSorting(queryParams);
|
||||
const pageInfo = extractPageInfo(queryParams);
|
||||
this.updateSorting(sorting);
|
||||
this.updateFilters(filters);
|
||||
this.updatePageInfo(pageInfo);
|
||||
},
|
||||
updateFilters(newValue) {
|
||||
this.updatePageInfo({});
|
||||
this.filters = newValue;
|
||||
},
|
||||
updateSorting(newValue) {
|
||||
this.updatePageInfo({});
|
||||
this.sorting = { ...this.sorting, ...newValue };
|
||||
},
|
||||
updatePageInfo(newValue) {
|
||||
this.pageInfo = newValue;
|
||||
},
|
||||
updateSortingAndEmitUpdate(newValue) {
|
||||
this.updateSorting(newValue);
|
||||
this.emitUpdate();
|
||||
},
|
||||
emitUpdate() {
|
||||
this.$emit('update', { sort: this.parsedSorting, filters: this.filters });
|
||||
this.$emit('update', {
|
||||
sort: this.parsedSorting,
|
||||
filters: this.filters,
|
||||
pageInfo: this.pageInfo,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ export const extractFilterAndSorting = (queryObject) => {
|
|||
return { filters, sorting };
|
||||
};
|
||||
|
||||
export const extractPageInfo = (queryObject) => {
|
||||
const { before, after } = queryObject;
|
||||
return {
|
||||
before,
|
||||
after,
|
||||
};
|
||||
};
|
||||
|
||||
export const beautifyPath = (path) => (path ? path.split('/').join(' / ') : '');
|
||||
|
||||
export const getCommitLink = ({ project_path: projectPath, pipeline = {} }, isGroup = false) => {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,13 @@ export default {
|
|||
methods: {
|
||||
generateQueryData({ sorting = {}, filter = [] } = {}) {
|
||||
// Ensure that we clean up the query when we remove a token from the search
|
||||
const result = { ...this.baselineQueryStringFilters, ...sorting, search: [] };
|
||||
const result = {
|
||||
...this.baselineQueryStringFilters,
|
||||
...sorting,
|
||||
search: [],
|
||||
after: null,
|
||||
before: null,
|
||||
};
|
||||
|
||||
filter.forEach((f) => {
|
||||
if (f.type === FILTERED_SEARCH_TERM) {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@
|
|||
- if header_link?(:todos)
|
||||
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
|
||||
= link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos js-prefetch-document',
|
||||
data: { testid: 'todos_shortcut_button', toggle: 'tooltip', placement: 'bottom',
|
||||
data: { testid: 'todos-shortcut-button', toggle: 'tooltip', placement: 'bottom',
|
||||
track_label: 'main_navigation',
|
||||
track_action: 'click_to_do_link',
|
||||
track_property: 'navigation_top',
|
||||
|
|
|
|||
|
|
@ -483,8 +483,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
#
|
||||
# Service Desk
|
||||
#
|
||||
get '/service_desk' => 'service_desk#show', as: :service_desk # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
put '/service_desk' => 'service_desk#update', as: :service_desk_refresh # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
get '/service_desk' => 'service_desk#show' # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
put '/service_desk' => 'service_desk#update' # rubocop:todo Cop/PutProjectRoutesUnderScope
|
||||
|
||||
#
|
||||
# Templates
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ architecture.
|
|||
|
||||
| OS Version | First supported GitLab version | Arch | Install Documentation | OS EOL | Details |
|
||||
| ------------------------------------------------------------ | ------------------------------ | --------------- | :----------------------------------------------------------: | ---------- | ------------------------------------------------------------ |
|
||||
| AlmaLinux 8 | GitLab CE / GitLab EE 14.5.0 | x86_64, aarch64 | [AlmaLinux Install Documentation](https://about.gitlab.com/install/#almalinux-8) | 2029 | <https://almalinux.org/> |
|
||||
| AlmaLinux 8 | GitLab CE / GitLab EE 14.5.0 | x86_64, aarch64 | [AlmaLinux Install Documentation](https://about.gitlab.com/install/#almalinux) | 2029 | <https://almalinux.org/> |
|
||||
| AlmaLinux 9 | GitLab CE / GitLab EE 16.0.0 | x86_64, aarch64 | [AlmaLinux Install Documentation](https://about.gitlab.com/install/#almalinux) | 2032 | <https://almalinux.org/> |
|
||||
| CentOS 7 | GitLab CE / GitLab EE 7.10.0 | x86_64 | [CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | June 2024 | <https://wiki.centos.org/About/Product> |
|
||||
| Debian 10 | GitLab CE / GitLab EE 12.2.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2024 | <https://wiki.debian.org/LTS> |
|
||||
| Debian 11 | GitLab CE / GitLab EE 14.6.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2026 | <https://wiki.debian.org/LTS> |
|
||||
|
|
|
|||
|
|
@ -105,7 +105,14 @@ Gather data on the state of the Sidekiq workers with the following Ruby script.
|
|||
|
||||
If the performance issue is intermittent:
|
||||
|
||||
- Run this in a cron job every five minutes. Write the files to a location with enough space: allow for 500 KB per file.
|
||||
- Run this in a cron job every five minutes. Write the files to a location with enough space: allow for at least 500 KB per file.
|
||||
|
||||
```shell
|
||||
cat > /etc/cron.d/sidekiqcheck <<EOF
|
||||
*/5 * * * * root /opt/gitlab/bin/gitlab-rails runner /var/opt/gitlab/sidekiqcheck.rb > /tmp/sidekiqcheck_$(date '+\%Y\%m\%d-\%H:\%M').out
|
||||
EOF
|
||||
```
|
||||
|
||||
- Refer back to the data to see what went wrong.
|
||||
|
||||
1. Analyze the output. The following commands assume that you have a directory of output files.
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ as it can cause the pipeline to behave unexpectedly.
|
|||
| `CI_PIPELINE_TRIGGERED` | all | all | `true` if the job was [triggered](../triggers/index.md). |
|
||||
| `CI_PIPELINE_URL` | 11.1 | 0.5 | The URL for the pipeline details. |
|
||||
| `CI_PIPELINE_CREATED_AT` | 13.10 | all | The UTC datetime when the pipeline was created, in [ISO 8601](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) format. |
|
||||
| `CI_PIPELINE_NAME` | 16.3 | all | The pipeline name defined in [`workflow:name`](../yaml/index.md#workflowname) |
|
||||
| `CI_PROJECT_DIR` | all | all | The full path the repository is cloned to, and where the job runs from. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see the [Advanced GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_PROJECT_ID` | all | all | The ID of the current project. This ID is unique across all projects on the GitLab instance. |
|
||||
| `CI_PROJECT_NAME` | 8.10 | 0.5 | The name of the directory for the project. For example if the project URL is `gitlab.example.com/group-name/project-1`, `CI_PROJECT_NAME` is `project-1`. |
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ To upgrade GitLab that was [installed using Docker Engine](#install-gitlab-using
|
|||
On the first run, GitLab will reconfigure and upgrade itself.
|
||||
|
||||
Refer to the GitLab [Upgrade recommendations](../policy/maintenance.md#upgrade-recommendations)
|
||||
when upgrading between major versions.
|
||||
when upgrading between versions.
|
||||
|
||||
### Upgrade GitLab using Docker compose
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module Gitlab
|
|||
variables.append(key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s)
|
||||
variables.append(key: 'CI_PIPELINE_SOURCE', value: pipeline.source.to_s)
|
||||
variables.append(key: 'CI_PIPELINE_CREATED_AT', value: pipeline.created_at&.iso8601)
|
||||
variables.append(key: 'CI_PIPELINE_NAME', value: pipeline.name)
|
||||
|
||||
variables.concat(predefined_commit_variables) if pipeline.sha.present?
|
||||
variables.concat(predefined_commit_tag_variables) if pipeline.tag?
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/admin/users/components/users_table.vue' do
|
||||
element :user_row_content
|
||||
element 'user-row-content'
|
||||
end
|
||||
|
||||
def search_user(username)
|
||||
|
|
@ -24,13 +24,13 @@ module QA
|
|||
end
|
||||
|
||||
def click_user(username)
|
||||
within_element(:user_row_content, text: username) do
|
||||
within_element('user-row-content', text: username) do
|
||||
click_link(username)
|
||||
end
|
||||
end
|
||||
|
||||
def has_username?(username)
|
||||
has_element?(:user_row_content, text: username, wait: 1)
|
||||
has_element?('user-row-content', text: username, wait: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ module QA
|
|||
super
|
||||
|
||||
base.view 'app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue' do
|
||||
element :confirm_ok_button
|
||||
element :confirmation_modal
|
||||
element 'confirm-ok-button'
|
||||
element 'confirmation-modal'
|
||||
end
|
||||
|
||||
base.view 'app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue' do
|
||||
|
|
@ -36,7 +36,7 @@ module QA
|
|||
end
|
||||
|
||||
def click_confirmation_ok_button
|
||||
click_element(:confirm_ok_button)
|
||||
click_element('confirm-ok-button')
|
||||
end
|
||||
|
||||
# Click the confirmation button if the confirmation modal is present
|
||||
|
|
@ -48,9 +48,9 @@ module QA
|
|||
# to skip the loading check otherwise it will time out.
|
||||
#
|
||||
# [1]: https://gitlab.com/gitlab-org/gitlab/-/blob/4a99af809b86047ce3c8985e6582748bbd23fc84/qa/qa/page/component/members/members_table.rb#L54
|
||||
return unless has_element?(:confirmation_modal, skip_finished_loading_check: true)
|
||||
return unless has_element?('confirmation-modal', skip_finished_loading_check: true)
|
||||
|
||||
click_element(:confirm_ok_button, skip_finished_loading_check: true)
|
||||
click_element('confirm-ok-button', skip_finished_loading_check: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module QA
|
|||
super
|
||||
|
||||
base.view 'app/assets/javascripts/issues/show/components/title.vue' do
|
||||
element :issue_title, required: true
|
||||
element 'issue-title', required: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ module QA
|
|||
end
|
||||
|
||||
base.view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue' do
|
||||
element :labels_select_dropdown_contents
|
||||
element 'labels-select-dropdown-contents'
|
||||
end
|
||||
|
||||
base.view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_value.vue' do
|
||||
|
|
@ -49,7 +49,7 @@ module QA
|
|||
end
|
||||
|
||||
base.view 'app/assets/javascripts/sidebar/components/sidebar_editable_item.vue' do
|
||||
element :edit_button
|
||||
element 'edit-button'
|
||||
end
|
||||
|
||||
base.view 'app/helpers/dropdowns_helper.rb' do
|
||||
|
|
@ -59,7 +59,7 @@ module QA
|
|||
|
||||
def assign_milestone(milestone)
|
||||
wait_milestone_block_finish_loading do
|
||||
click_element(:edit_button)
|
||||
click_element('edit-button')
|
||||
click_on(milestone.title)
|
||||
end
|
||||
|
||||
|
|
@ -134,17 +134,17 @@ module QA
|
|||
|
||||
def select_labels(labels)
|
||||
within_element(:labels_block) do
|
||||
click_element(:edit_button)
|
||||
click_element('edit-button')
|
||||
|
||||
labels.each do |label|
|
||||
within_element(:labels_select_dropdown_contents) do
|
||||
within_element('labels-select-dropdown-contents') do
|
||||
fill_element(:dropdown_input_field, label)
|
||||
click_button(text: label)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
click_element(:issue_title) # to blur dropdown
|
||||
click_element('issue-title') # to blur dropdown
|
||||
end
|
||||
|
||||
def toggle_more_assignees_link
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ module QA
|
|||
|
||||
def select_filter_with_text(text)
|
||||
retry_on_exception do
|
||||
click_element(:issue_title)
|
||||
click_element('issue-title')
|
||||
click_element :discussion_preferences_dropdown
|
||||
find_element(:filter_menu_item, text: text).click
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module QA
|
|||
super
|
||||
|
||||
base.view 'app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue' do
|
||||
element :rich_text_promo_popover
|
||||
element 'rich-text-promo-popover'
|
||||
end
|
||||
|
||||
base.view 'app/views/shared/_broadcast_message.html.haml' do
|
||||
|
|
@ -19,12 +19,12 @@ module QA
|
|||
end
|
||||
|
||||
def close_rich_text_promo_popover_if_present
|
||||
return unless has_element?(:rich_text_promo_popover, wait: 0)
|
||||
return unless has_element?('rich-text-promo-popover', wait: 0)
|
||||
|
||||
within_element(:rich_text_promo_popover) do
|
||||
click_element(:close_button)
|
||||
within_element('rich-text-promo-popover') do
|
||||
click_element('close-button')
|
||||
end
|
||||
has_no_element?(:rich_text_promo_popover)
|
||||
has_no_element?('rich-text-promo-popover')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,19 +40,14 @@ module QA
|
|||
end
|
||||
|
||||
def matches?(line)
|
||||
!!(line =~ /["']#{name}['"]|["']#{convert_to_kebabcase(name)}['"]|#{expression}/)
|
||||
!!(line =~ /["']#{name}['"]|#{expression}/)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def convert_to_kebabcase(text)
|
||||
text.to_s.tr('_', '-')
|
||||
end
|
||||
|
||||
def qa_selector
|
||||
[
|
||||
%([data-testid="#{name}"]#{additional_selectors}),
|
||||
%([data-testid="#{convert_to_kebabcase(name)}"]#{additional_selectors}),
|
||||
%([data-qa-selector="#{name}"]#{additional_selectors})
|
||||
].join(',')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module QA
|
|||
element :import_table
|
||||
element :import_item
|
||||
element :import_status_indicator
|
||||
element :filter_groups
|
||||
element 'filter-groups'
|
||||
end
|
||||
|
||||
view "app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue" do
|
||||
|
|
@ -20,7 +20,7 @@ module QA
|
|||
end
|
||||
|
||||
view "app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue" do
|
||||
element :import_group_button
|
||||
element 'import-group-button'
|
||||
end
|
||||
|
||||
def filter_group(source_group_name)
|
||||
|
|
@ -44,7 +44,7 @@ module QA
|
|||
click_element(:target_group_dropdown_item, group_name: target_group_name)
|
||||
|
||||
retry_until(message: "Triggering import") do
|
||||
click_element(:import_group_button)
|
||||
click_element('import-group-button')
|
||||
# Make sure import started before waiting for completion
|
||||
has_no_element?(:import_status_indicator, text: "Not started", wait: 1)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ module QA
|
|||
module Group
|
||||
class DependencyProxy < QA::Page::Base
|
||||
view 'app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue' do
|
||||
element :proxy_count
|
||||
element 'proxy-count'
|
||||
end
|
||||
|
||||
def has_blob_count?(blob_text)
|
||||
has_element?(:proxy_count, text: blob_text)
|
||||
has_element?('proxy-count', text: blob_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue' do
|
||||
element :labels_select_dropdown_contents
|
||||
element 'labels-select-dropdown-contents'
|
||||
end
|
||||
|
||||
view 'app/views/shared/issuable/form/_metadata_issuable_assignee.html.haml' do
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
|
||||
element :user_dropdown, required: !Runtime::Env.phone_layout?
|
||||
element 'user-dropdown', required: !Runtime::Env.phone_layout?
|
||||
element :user_avatar_content, required: !Runtime::Env.phone_layout?
|
||||
element :sign_out_link
|
||||
element :edit_profile_link
|
||||
|
|
@ -31,26 +31,26 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do
|
||||
element :super_sidebar_search_button
|
||||
element :stop_impersonation_btn
|
||||
element :issues_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element :merge_requests_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element :todos_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element 'super-sidebar-search-button'
|
||||
element 'stop-impersonation-btn'
|
||||
element 'issues-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
element 'todos-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do
|
||||
element :global_search_input
|
||||
element 'global-search-input'
|
||||
end
|
||||
else
|
||||
view 'app/views/layouts/header/_default.html.haml' do
|
||||
element :navbar, required: true
|
||||
element :canary_badge_link
|
||||
element :user_avatar_content, required: !Runtime::Env.phone_layout?
|
||||
element :user_dropdown, required: !Runtime::Env.phone_layout?
|
||||
element :stop_impersonation_btn
|
||||
element :issues_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element :merge_requests_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element :todos_shortcut_button, required: !Runtime::Env.phone_layout?
|
||||
element 'user-dropdown', required: !Runtime::Env.phone_layout?
|
||||
element 'stop-impersonation-btn'
|
||||
element 'issues-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
element 'todos-shortcut-button', required: !Runtime::Env.phone_layout?
|
||||
end
|
||||
|
||||
view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
|
||||
|
|
@ -65,7 +65,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/nav/components/top_nav_dropdown_menu.vue' do
|
||||
element :menu_subview
|
||||
element 'menu-subview'
|
||||
end
|
||||
|
||||
view 'lib/gitlab/nav/top_nav_menu_item.rb' do
|
||||
|
|
@ -84,11 +84,11 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/header_search/components/app.vue' do
|
||||
element :global_search_input
|
||||
element 'global-search-input'
|
||||
end
|
||||
|
||||
view 'app/views/layouts/header/_new_dropdown.html.haml' do
|
||||
element :new_menu_toggle
|
||||
element 'new-menu-toggle'
|
||||
end
|
||||
|
||||
view 'app/helpers/nav/new_dropdown_helper.rb' do
|
||||
|
|
@ -140,17 +140,17 @@ module QA
|
|||
end
|
||||
|
||||
def go_to_create_project
|
||||
click_element(:new_menu_toggle)
|
||||
click_element('new-menu-toggle')
|
||||
click_element(:global_new_project_link)
|
||||
end
|
||||
|
||||
def go_to_create_group
|
||||
click_element(:new_menu_toggle)
|
||||
click_element('new-menu-toggle')
|
||||
click_element(:global_new_group_link)
|
||||
end
|
||||
|
||||
def go_to_create_snippet
|
||||
click_element(:new_menu_toggle)
|
||||
click_element('new-menu-toggle')
|
||||
click_element(:global_new_snippet_link)
|
||||
end
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ module QA
|
|||
# @param [Symbol] the name of the element (e.g: `:issues_shortcut button`)
|
||||
# @example:
|
||||
# Menu.perform do |menu|
|
||||
# menu.go_to_page_by_shortcut(:issues_shortcut_button) #=> Go to Issues page using shortcut button
|
||||
# menu.go_to_page_by_shortcut('issues-shortcut-button') #=> Go to Issues page using shortcut button
|
||||
# end
|
||||
def go_to_page_by_shortcut(button)
|
||||
within_top_menu do
|
||||
|
|
@ -243,8 +243,8 @@ module QA
|
|||
end
|
||||
|
||||
def search_for(term)
|
||||
click_element(Runtime::Env.super_sidebar_enabled? ? :super_sidebar_search_button : :search_box)
|
||||
fill_element(:global_search_input, "#{term}\n")
|
||||
click_element(Runtime::Env.super_sidebar_enabled? ? 'super-sidebar-search-button' : :search_box)
|
||||
fill_element('global-search-input', "#{term}\n")
|
||||
end
|
||||
|
||||
def has_personal_area?(wait: Capybara.default_max_wait_time)
|
||||
|
|
@ -265,7 +265,7 @@ module QA
|
|||
end
|
||||
|
||||
def click_stop_impersonation_link
|
||||
click_element(:stop_impersonation_btn)
|
||||
click_element('stop-impersonation-btn')
|
||||
end
|
||||
|
||||
# To verify whether the user has been directed to a canary web node
|
||||
|
|
@ -308,20 +308,20 @@ module QA
|
|||
within_top_menu do
|
||||
click_element :user_avatar_content unless has_element?(:user_profile_link, wait: 1)
|
||||
|
||||
within_element(:user_dropdown, &block)
|
||||
within_element('user-dropdown', &block)
|
||||
end
|
||||
end
|
||||
|
||||
def within_groups_menu(&block)
|
||||
go_to_menu_dropdown_option(:groups_dropdown)
|
||||
|
||||
within_element(:menu_subview, &block)
|
||||
within_element('menu-subview', &block)
|
||||
end
|
||||
|
||||
def within_projects_menu(&block)
|
||||
go_to_menu_dropdown_option(:projects_dropdown)
|
||||
|
||||
within_element(:menu_subview, &block)
|
||||
within_element('menu-subview', &block)
|
||||
end
|
||||
|
||||
def click_admin_area
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ module QA
|
|||
view 'app/assets/javascripts/issues/show/components/header_actions.vue' do
|
||||
element 'toggle-issue-state-button'
|
||||
element 'desktop-dropdown'
|
||||
element :delete_issue_button
|
||||
element 'delete-issue-button'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/related_issues/components/add_issuable_form.vue' do
|
||||
|
|
@ -33,7 +33,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/related_issues/components/related_issues_block.vue' do
|
||||
element :related_issues_plus_button
|
||||
element 'related-issues-plus-button'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/related_issues/components/related_issues_list.vue' do
|
||||
|
|
@ -42,7 +42,7 @@ module QA
|
|||
end
|
||||
|
||||
def relate_issue(issue)
|
||||
click_element(:related_issues_plus_button)
|
||||
click_element('related-issues-plus-button')
|
||||
fill_element(:add_issue_field, issue.web_url)
|
||||
send_keys_to_element(:add_issue_field, :enter)
|
||||
end
|
||||
|
|
@ -74,14 +74,14 @@ module QA
|
|||
|
||||
def has_delete_issue_button?
|
||||
open_actions_dropdown
|
||||
has_element?(:delete_issue_button)
|
||||
has_element?('delete-issue-button')
|
||||
end
|
||||
|
||||
def delete_issue
|
||||
has_delete_issue_button?
|
||||
|
||||
click_element(
|
||||
:delete_issue_button,
|
||||
'delete-issue-button',
|
||||
Page::Modal::DeleteIssue,
|
||||
wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,27 +6,27 @@ 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 :details_link
|
||||
element 'details-link'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/packages_and_registries/infrastructure_registry/shared/package_list_row.vue' do
|
||||
element :details_link
|
||||
element 'details-link'
|
||||
end
|
||||
|
||||
def click_package(name)
|
||||
click_element(:details_link, text: name)
|
||||
click_element('details-link', text: name)
|
||||
end
|
||||
|
||||
def has_package?(name)
|
||||
has_element?(:details_link, text: name, wait: 20)
|
||||
has_element?('details-link', text: name, wait: 20)
|
||||
end
|
||||
|
||||
def has_module?(name)
|
||||
has_element?(:details_link, text: name, wait: 20)
|
||||
has_element?('details-link', text: name, wait: 20)
|
||||
end
|
||||
|
||||
def has_no_package?(name)
|
||||
has_no_element?(:details_link, text: name)
|
||||
has_no_element?('details-link', text: name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@ module QA
|
|||
module Packages
|
||||
class Show < QA::Page::Base
|
||||
view 'app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue' do
|
||||
element :delete_package
|
||||
element :delete_modal_button
|
||||
element :package_information_content
|
||||
element 'delete-package'
|
||||
element 'delete-modal-button'
|
||||
element 'package-information-content'
|
||||
end
|
||||
|
||||
def has_package_info?(name, version)
|
||||
has_element?(:package_information_content, text: /#{name}.*#{version}/)
|
||||
has_element?('package-information-content', text: /#{name}.*#{version}/)
|
||||
end
|
||||
|
||||
def click_delete
|
||||
click_element(:delete_package)
|
||||
wait_for_animated_element(:delete_modal_button)
|
||||
click_element(:delete_modal_button)
|
||||
click_element('delete-package')
|
||||
wait_for_animated_element('delete-modal-button')
|
||||
click_element('delete-modal-button')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,21 +6,21 @@ module QA
|
|||
module Registry
|
||||
class Show < QA::Page::Base
|
||||
view 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue' do
|
||||
element :details_link
|
||||
element 'details-link'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue' do
|
||||
element :additional_actions
|
||||
element :single_delete_button
|
||||
element 'additional-actions'
|
||||
element 'single-delete-button'
|
||||
element :name
|
||||
end
|
||||
|
||||
def has_registry_repository?(name)
|
||||
find_element(:details_link, text: name)
|
||||
find_element('details-link', text: name)
|
||||
end
|
||||
|
||||
def click_on_image(name)
|
||||
click_element(:details_link, text: name)
|
||||
click_element('details-link', text: name)
|
||||
end
|
||||
|
||||
def has_tag?(tag_name)
|
||||
|
|
@ -32,8 +32,8 @@ module QA
|
|||
end
|
||||
|
||||
def click_delete
|
||||
click_element(:additional_actions)
|
||||
click_element(:single_delete_button)
|
||||
click_element('additional-actions')
|
||||
click_element('single-delete-button')
|
||||
find_button('Delete').click
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,30 +8,30 @@ module QA
|
|||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/assets/javascripts/security_configuration/components/app.vue' do
|
||||
element :security_configuration_container
|
||||
element :security_view_history_link
|
||||
element 'security-configuration-container'
|
||||
element 'security-view-history-link'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/security_configuration/components/feature_card.vue' do
|
||||
element :feature_status
|
||||
element 'feature-status'
|
||||
element :sast_enable_button, "`${feature.type}_enable_button`" # rubocop:disable QA/ElementWithPattern
|
||||
element :dependency_scanning_mr_button, "`${feature.type}_mr_button`" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue' do
|
||||
element :autodevops_container
|
||||
element 'autodevops-container'
|
||||
end
|
||||
|
||||
def has_security_configuration_history_link?
|
||||
has_element?(:security_view_history_link)
|
||||
has_element?('security-view-history-link')
|
||||
end
|
||||
|
||||
def has_no_security_configuration_history_link?
|
||||
has_no_element?(:security_view_history_link)
|
||||
has_no_element?('security-view-history-link')
|
||||
end
|
||||
|
||||
def click_security_configuration_history_link
|
||||
click_element(:security_view_history_link)
|
||||
click_element('security-view-history-link')
|
||||
end
|
||||
|
||||
def click_sast_enable_button
|
||||
|
|
@ -43,31 +43,31 @@ module QA
|
|||
end
|
||||
|
||||
def has_true_sast_status?
|
||||
has_element?(:feature_status, feature: 'sast_true_status')
|
||||
has_element?('feature-status', feature: 'sast_true_status')
|
||||
end
|
||||
|
||||
def has_false_sast_status?
|
||||
has_element?(:feature_status, feature: 'sast_false_status')
|
||||
has_element?('feature-status', feature: 'sast_false_status')
|
||||
end
|
||||
|
||||
def has_true_dependency_scanning_status?
|
||||
has_element?(:feature_status, feature: 'dependency_scanning_true_status')
|
||||
has_element?('feature-status', feature: 'dependency_scanning_true_status')
|
||||
end
|
||||
|
||||
def has_false_dependency_scanning_status?
|
||||
has_element?(:feature_status, feature: 'dependency_scanning_false_status')
|
||||
has_element?('feature-status', feature: 'dependency_scanning_false_status')
|
||||
end
|
||||
|
||||
def has_auto_devops_container?
|
||||
has_element?(:autodevops_container)
|
||||
has_element?('autodevops-container')
|
||||
end
|
||||
|
||||
def has_no_auto_devops_container?
|
||||
has_no_element?(:autodevops_container)
|
||||
has_no_element?('autodevops-container')
|
||||
end
|
||||
|
||||
def has_auto_devops_container_description?
|
||||
within_element(:autodevops_container) do
|
||||
within_element('autodevops-container') do
|
||||
has_text?('Quickly enable all continuous testing and compliance tools by enabling Auto DevOps')
|
||||
end
|
||||
end
|
||||
|
|
@ -79,7 +79,7 @@ module QA
|
|||
private
|
||||
|
||||
def go_to_tab(name)
|
||||
within_element(:security_configuration_container) do
|
||||
within_element('security-configuration-container') do
|
||||
find('.nav-item', text: name).click
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ module QA
|
|||
click_ci_variable_save_button
|
||||
|
||||
wait_until(reload: false) do
|
||||
# Using data-testid="ci-variable-table"
|
||||
within_element(:ci_variable_table) { has_element?(:edit_ci_variable_button) }
|
||||
within_element('ci-variable-table') { has_element?(:edit_ci_variable_button) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -29,8 +28,7 @@ module QA
|
|||
end
|
||||
|
||||
def click_edit_ci_variable
|
||||
# Using data-testid="ci-variable-table"
|
||||
within_element(:ci_variable_table) do
|
||||
within_element('ci-variable-table') do
|
||||
click_element :edit_ci_variable_button
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,65 +6,65 @@ module QA
|
|||
module Settings
|
||||
class DeployKeys < Page::Base
|
||||
view 'app/views/shared/deploy_keys/_form.html.haml' do
|
||||
element :deploy_key_title_field
|
||||
element :deploy_key_field
|
||||
element 'deploy-key-title-field'
|
||||
element 'deploy-key-field'
|
||||
end
|
||||
|
||||
view 'app/views/shared/deploy_keys/_project_group_form.html.haml' do
|
||||
element :deploy_key_title_field
|
||||
element :deploy_key_field
|
||||
element :deploy_key_expires_at_field
|
||||
element :add_deploy_key_button
|
||||
element 'deploy-key-title-field'
|
||||
element 'deploy-key-field'
|
||||
element 'deploy-key-expires-at-field'
|
||||
element 'add-deploy-key-button'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/deploy_keys/components/app.vue' do
|
||||
element :project_deploy_keys_container
|
||||
element 'project-deploy-keys-container'
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/deploy_keys/components/key.vue' do
|
||||
element :key_container
|
||||
element :key_title_content
|
||||
element :key_sha256_fingerprint_content
|
||||
element 'key-container'
|
||||
element 'key-title-content'
|
||||
element 'key-sha256-fingerprint-content'
|
||||
end
|
||||
|
||||
def add_key
|
||||
click_element(:add_deploy_key_button)
|
||||
click_element('add-deploy-key-button')
|
||||
end
|
||||
|
||||
def fill_key_title(title)
|
||||
fill_element(:deploy_key_title_field, title)
|
||||
fill_element('deploy-key-title-field', title)
|
||||
end
|
||||
|
||||
def fill_key_value(key)
|
||||
fill_element(:deploy_key_field, key)
|
||||
fill_element('deploy-key-field', key)
|
||||
end
|
||||
|
||||
def find_sha256_fingerprint(title)
|
||||
within_project_deploy_keys do
|
||||
find_element(:key_container, text: title)
|
||||
.find(element_selector_css(:key_sha256_fingerprint_content)).text
|
||||
find_element('key-container', text: title)
|
||||
.find(element_selector_css('key-sha256-fingerprint-content')).text
|
||||
end
|
||||
end
|
||||
|
||||
def has_key?(title, sha256_fingerprint)
|
||||
within_project_deploy_keys do
|
||||
find_element(:key_container, text: title)
|
||||
.has_css?(element_selector_css(:key_sha256_fingerprint_content), text: sha256_fingerprint)
|
||||
find_element('key-container', text: title)
|
||||
.has_css?(element_selector_css('key-sha256-fingerprint-content'), text: sha256_fingerprint)
|
||||
end
|
||||
end
|
||||
|
||||
def key_title
|
||||
within_project_deploy_keys do
|
||||
find_element(:key_title_content).text
|
||||
find_element('key-title-content').text
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def within_project_deploy_keys
|
||||
has_element?(:project_deploy_keys_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
|
||||
has_element?('project-deploy-keys-container', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
|
||||
|
||||
within_element(:project_deploy_keys_container) do
|
||||
within_element('project-deploy-keys-container') do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/views/shared/deploy_keys/_index.html.haml' do
|
||||
element :deploy_keys_settings_content
|
||||
element 'deploy-keys-settings-content'
|
||||
end
|
||||
|
||||
view 'app/views/projects/protected_tags/shared/_index.html.haml' do
|
||||
|
|
@ -38,7 +38,7 @@ module QA
|
|||
end
|
||||
|
||||
def expand_deploy_keys(&block)
|
||||
expand_content(:deploy_keys_settings_content) do
|
||||
expand_content('deploy-keys-settings-content') do
|
||||
Settings::DeployKeys.perform(&block)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/views/layouts/header/_new_dropdown.html.haml' do
|
||||
element :new_menu_toggle
|
||||
element 'new-menu-toggle'
|
||||
end
|
||||
|
||||
view 'app/views/projects/_last_push.html.haml' do
|
||||
|
|
@ -50,7 +50,7 @@ module QA
|
|||
end
|
||||
|
||||
view 'app/assets/javascripts/forks/components/forks_button.vue' do
|
||||
element :fork_button
|
||||
element 'fork-button'
|
||||
end
|
||||
|
||||
view 'app/views/projects/empty.html.haml' do
|
||||
|
|
@ -93,7 +93,7 @@ module QA
|
|||
# Change back to regular click_element when vscode_web_ide FF is removed
|
||||
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/371084
|
||||
def fork_project
|
||||
fork_button = find_element(:fork_button)
|
||||
fork_button = find_element('fork-button')
|
||||
click_by_javascript(fork_button)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ module QA
|
|||
#
|
||||
# @return [void]
|
||||
def within_new_item_menu
|
||||
click_element(:new_menu_toggle)
|
||||
click_element('new-menu-toggle')
|
||||
|
||||
yield
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module QA
|
|||
Flow::Login.sign_in_as_admin
|
||||
|
||||
Page::Main::Menu.perform do |menu|
|
||||
menu.go_to_page_by_shortcut(:todos_shortcut_button)
|
||||
menu.go_to_page_by_shortcut('todos-shortcut-button')
|
||||
end
|
||||
|
||||
Page::Dashboard::Todos.perform do |todos|
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ RSpec.describe 'Container Registry', :js, feature_category: :groups_and_projects
|
|||
visit_next_page
|
||||
expect(page).to have_content 'my/image'
|
||||
end
|
||||
|
||||
it 'pagination is preserved after navigating back from details' do
|
||||
visit_next_page
|
||||
click_link 'my/image'
|
||||
page.go_back
|
||||
expect(page).to have_content 'my/image'
|
||||
end
|
||||
end
|
||||
|
||||
def visit_container_registry
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Component from '~/packages_and_registries/container_registry/explorer/components/list_page/image_list.vue';
|
||||
import ImageListRow from '~/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue';
|
||||
|
||||
import { imagesListResponse, pageInfo } from '../../mock_data';
|
||||
import { imagesListResponse } from '../../mock_data';
|
||||
|
||||
describe('Image List', () => {
|
||||
let wrapper;
|
||||
|
||||
const findRow = () => wrapper.findAllComponents(ImageListRow);
|
||||
const findPagination = () => wrapper.findComponent(GlKeysetPagination);
|
||||
|
||||
const { __typename, ...defaultPageInfo } = pageInfo;
|
||||
|
||||
const mountComponent = (props) => {
|
||||
wrapper = shallowMount(Component, {
|
||||
propsData: {
|
||||
images: imagesListResponse,
|
||||
pageInfo: defaultPageInfo,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
|
|
@ -42,28 +37,4 @@ describe('Image List', () => {
|
|||
expect(findRow().at(0).props('metadataLoading')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
it('exists', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findPagination().props()).toMatchObject({ ...defaultPageInfo });
|
||||
});
|
||||
|
||||
it('emits "prev-page" when the user clicks the back page button', () => {
|
||||
mountComponent();
|
||||
|
||||
findPagination().vm.$emit('prev');
|
||||
|
||||
expect(wrapper.emitted('prev-page')).toEqual([[]]);
|
||||
});
|
||||
|
||||
it('emits "next-page" when the user clicks the forward page button', () => {
|
||||
mountComponent();
|
||||
|
||||
findPagination().vm.$emit('next');
|
||||
|
||||
expect(wrapper.emitted('next-page')).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import deleteContainerRepositoryMutation from '~/packages_and_registries/contain
|
|||
import getContainerRepositoriesDetails from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql';
|
||||
import component from '~/packages_and_registries/container_registry/explorer/pages/list.vue';
|
||||
import Tracking from '~/tracking';
|
||||
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
|
||||
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
|
||||
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
|
||||
|
|
@ -61,8 +62,10 @@ describe('List Page', () => {
|
|||
const findEmptySearchMessage = () => wrapper.find('[data-testid="emptySearch"]');
|
||||
const findDeleteImage = () => wrapper.findComponent(DeleteImage);
|
||||
|
||||
const findPersistedPagination = () => wrapper.findComponent(PersistedPagination);
|
||||
|
||||
const fireFirstSortUpdate = () => {
|
||||
findPersistedSearch().vm.$emit('update', { sort: 'UPDATED_DESC', filters: [] });
|
||||
findPersistedSearch().vm.$emit('update', { sort: 'UPDATED_DESC', filters: [], pageInfo: {} });
|
||||
};
|
||||
|
||||
const waitForApolloRequestRender = async () => {
|
||||
|
|
@ -219,6 +222,12 @@ describe('List Page', () => {
|
|||
expect(findImageList().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('pagination is set to empty object', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findPersistedPagination().props('pagination')).toEqual({});
|
||||
});
|
||||
|
||||
it('cli commands is not visible', () => {
|
||||
mountComponent();
|
||||
|
||||
|
|
@ -462,7 +471,15 @@ describe('List Page', () => {
|
|||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
it('prev-page event triggers a fetchMore request', async () => {
|
||||
it('exists', async () => {
|
||||
mountComponent();
|
||||
fireFirstSortUpdate();
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
expect(findPersistedPagination().props('pagination')).toEqual(pageInfo);
|
||||
});
|
||||
|
||||
it('prev event triggers a previous page request', async () => {
|
||||
const resolver = jest.fn().mockResolvedValue(graphQLImageListMock);
|
||||
const detailsResolver = jest
|
||||
.fn()
|
||||
|
|
@ -471,7 +488,7 @@ describe('List Page', () => {
|
|||
fireFirstSortUpdate();
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
findImageList().vm.$emit('prev-page');
|
||||
findPersistedPagination().vm.$emit('prev');
|
||||
await waitForPromises();
|
||||
|
||||
expect(resolver).toHaveBeenCalledWith(
|
||||
|
|
@ -490,7 +507,39 @@ describe('List Page', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('next-page event triggers a fetchMore request', async () => {
|
||||
it('calls resolver with pagination params when persisted search returns before', async () => {
|
||||
const resolver = jest.fn().mockResolvedValue(graphQLImageListMock);
|
||||
const detailsResolver = jest
|
||||
.fn()
|
||||
.mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock);
|
||||
mountComponent({ resolver, detailsResolver });
|
||||
|
||||
findPersistedSearch().vm.$emit('update', {
|
||||
sort: 'UPDATED_DESC',
|
||||
filters: [],
|
||||
pageInfo: { before: pageInfo.startCursor },
|
||||
});
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
expect(resolver).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sort: 'UPDATED_DESC',
|
||||
before: pageInfo.startCursor,
|
||||
first: null,
|
||||
last: GRAPHQL_PAGE_SIZE,
|
||||
}),
|
||||
);
|
||||
expect(detailsResolver).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sort: 'UPDATED_DESC',
|
||||
before: pageInfo.startCursor,
|
||||
first: null,
|
||||
last: GRAPHQL_PAGE_SIZE,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('next event triggers a next page request', async () => {
|
||||
const resolver = jest.fn().mockResolvedValue(graphQLImageListMock);
|
||||
const detailsResolver = jest
|
||||
.fn()
|
||||
|
|
@ -499,7 +548,7 @@ describe('List Page', () => {
|
|||
fireFirstSortUpdate();
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
findImageList().vm.$emit('next-page');
|
||||
findPersistedPagination().vm.$emit('next');
|
||||
await waitForPromises();
|
||||
|
||||
expect(resolver).toHaveBeenCalledWith(
|
||||
|
|
@ -515,6 +564,36 @@ describe('List Page', () => {
|
|||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('calls resolver with pagination params when persisted search returns after', async () => {
|
||||
const resolver = jest.fn().mockResolvedValue(graphQLImageListMock);
|
||||
const detailsResolver = jest
|
||||
.fn()
|
||||
.mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock);
|
||||
mountComponent({ resolver, detailsResolver });
|
||||
|
||||
findPersistedSearch().vm.$emit('update', {
|
||||
sort: 'UPDATED_DESC',
|
||||
filters: [],
|
||||
pageInfo: { after: pageInfo.endCursor },
|
||||
});
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
expect(resolver).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sort: 'UPDATED_DESC',
|
||||
after: pageInfo.endCursor,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
}),
|
||||
);
|
||||
expect(detailsResolver).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sort: 'UPDATED_DESC',
|
||||
after: pageInfo.endCursor,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import {
|
||||
getImageName,
|
||||
timeTilRun,
|
||||
getNextPageParams,
|
||||
getPreviousPageParams,
|
||||
getPageParams,
|
||||
} from '~/packages_and_registries/container_registry/explorer/utils';
|
||||
|
||||
describe('Container registry utilities', () => {
|
||||
|
|
@ -35,4 +38,49 @@ describe('Container registry utilities', () => {
|
|||
expect(result).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNextPageParams', () => {
|
||||
it('should return the next page params with the provided cursor', () => {
|
||||
const cursor = 'abc123';
|
||||
expect(getNextPageParams(cursor)).toEqual({
|
||||
after: cursor,
|
||||
first: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPreviousPageParams', () => {
|
||||
it('should return the previous page params with the provided cursor', () => {
|
||||
const cursor = 'abc123';
|
||||
expect(getPreviousPageParams(cursor)).toEqual({
|
||||
first: null,
|
||||
before: cursor,
|
||||
last: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPageParams', () => {
|
||||
it('should return the previous page params if before cursor is available', () => {
|
||||
const pageInfo = { before: 'abc123' };
|
||||
expect(getPageParams(pageInfo)).toEqual({
|
||||
first: null,
|
||||
before: pageInfo.before,
|
||||
last: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the next page params if after cursor is available', () => {
|
||||
const pageInfo = { after: 'abc123' };
|
||||
expect(getPageParams(pageInfo)).toEqual({
|
||||
after: pageInfo.after,
|
||||
first: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty object if both before and after cursors are not available', () => {
|
||||
const pageInfo = {};
|
||||
expect(getPageParams(pageInfo)).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
|
||||
import UrlSync from '~/vue_shared/components/url_sync.vue';
|
||||
|
||||
describe('Persisted Search', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
pagination: {
|
||||
hasNextPage: true,
|
||||
hasPreviousPage: true,
|
||||
startCursor: 'eyJpZCI6IjI2In0',
|
||||
endCursor: 'eyJpZCI6IjgifQ',
|
||||
},
|
||||
};
|
||||
|
||||
const findPagination = () => wrapper.findComponent(GlKeysetPagination);
|
||||
const findUrlSync = () => wrapper.findComponent(UrlSync);
|
||||
|
||||
const mountComponent = ({ propsData = defaultProps, stubs = {} } = {}) => {
|
||||
wrapper = shallowMountExtended(PersistedPagination, {
|
||||
propsData,
|
||||
stubs: {
|
||||
UrlSync,
|
||||
...stubs,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it('has pagination component', () => {
|
||||
mountComponent();
|
||||
|
||||
const { hasNextPage, hasPreviousPage, startCursor, endCursor } = defaultProps.pagination;
|
||||
expect(findPagination().props('hasNextPage')).toBe(hasNextPage);
|
||||
expect(findPagination().props('hasPreviousPage')).toBe(hasPreviousPage);
|
||||
expect(findPagination().props('startCursor')).toBe(startCursor);
|
||||
expect(findPagination().props('endCursor')).toBe(endCursor);
|
||||
});
|
||||
|
||||
it('has a UrlSync component', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findUrlSync().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('pagination events', () => {
|
||||
const updateQueryMock = jest.fn();
|
||||
const mockUrlSync = {
|
||||
methods: {
|
||||
updateQuery: updateQueryMock,
|
||||
},
|
||||
render() {
|
||||
return this.$scopedSlots.default?.({ updateQuery: this.updateQuery });
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent({ stubs: { UrlSync: mockUrlSync } });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
updateQueryMock.mockReset();
|
||||
});
|
||||
|
||||
describe('prev event', () => {
|
||||
beforeEach(() => {
|
||||
findPagination().vm.$emit('prev');
|
||||
});
|
||||
|
||||
it('calls updateQuery mock with right params', () => {
|
||||
expect(updateQueryMock).toHaveBeenCalledWith({
|
||||
before: defaultProps.pagination?.startCursor,
|
||||
after: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('re-emits prev event', () => {
|
||||
expect(wrapper.emitted('prev')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('next event', () => {
|
||||
beforeEach(() => {
|
||||
findPagination().vm.$emit('next');
|
||||
});
|
||||
|
||||
it('calls updateQuery mock with right params', () => {
|
||||
expect(updateQueryMock).toHaveBeenCalledWith({
|
||||
after: defaultProps.pagination.endCursor,
|
||||
before: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('re-emits next event', () => {
|
||||
expect(wrapper.emitted('next')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,16 +1,21 @@
|
|||
import { nextTick } from 'vue';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
|
||||
import component from '~/packages_and_registries/shared/components/persisted_search.vue';
|
||||
import UrlSync from '~/vue_shared/components/url_sync.vue';
|
||||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils';
|
||||
import {
|
||||
getQueryParams,
|
||||
extractFilterAndSorting,
|
||||
extractPageInfo,
|
||||
} from '~/packages_and_registries/shared/utils';
|
||||
|
||||
jest.mock('~/packages_and_registries/shared/utils');
|
||||
|
||||
useMockLocationHelper();
|
||||
Vue.use(VueRouter);
|
||||
|
||||
describe('Persisted Search', () => {
|
||||
let router;
|
||||
let wrapper;
|
||||
|
||||
const defaultQueryParamsMock = {
|
||||
|
|
@ -31,8 +36,11 @@ describe('Persisted Search', () => {
|
|||
const findUrlSync = () => wrapper.findComponent(UrlSync);
|
||||
|
||||
const mountComponent = (propsData = defaultProps) => {
|
||||
router = new VueRouter({ mode: 'history' });
|
||||
|
||||
wrapper = shallowMountExtended(component, {
|
||||
propsData,
|
||||
router,
|
||||
stubs: {
|
||||
UrlSync,
|
||||
},
|
||||
|
|
@ -41,6 +49,10 @@ describe('Persisted Search', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
extractFilterAndSorting.mockReturnValue(defaultQueryParamsMock);
|
||||
extractPageInfo.mockReturnValue({
|
||||
after: '123',
|
||||
before: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('has a registry search component', async () => {
|
||||
|
|
@ -63,6 +75,48 @@ describe('Persisted Search', () => {
|
|||
expect(findUrlSync().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('emits update event on mount', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(wrapper.emitted('update')[0]).toEqual([
|
||||
{
|
||||
filters: ['foo'],
|
||||
sort: 'TEST_DESC',
|
||||
pageInfo: {
|
||||
after: '123',
|
||||
before: null,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('re-emits update event when route changes', async () => {
|
||||
mountComponent();
|
||||
|
||||
extractFilterAndSorting.mockReturnValue({
|
||||
filters: [],
|
||||
sorting: {},
|
||||
});
|
||||
extractPageInfo.mockReturnValue({
|
||||
after: null,
|
||||
before: '456',
|
||||
});
|
||||
|
||||
await router.push({ query: { before: '456' } });
|
||||
|
||||
// there is always a first call on mounted that emits up default values
|
||||
expect(wrapper.emitted('update')[1]).toEqual([
|
||||
{
|
||||
filters: [],
|
||||
sort: 'TEST_DESC',
|
||||
pageInfo: {
|
||||
before: '456',
|
||||
after: null,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('on sorting:changed emits update event and update internal sort', async () => {
|
||||
const payload = { sort: 'desc', orderBy: 'test' };
|
||||
|
||||
|
|
@ -81,6 +135,7 @@ describe('Persisted Search', () => {
|
|||
{
|
||||
filters: ['foo'],
|
||||
sort: 'TEST_DESC',
|
||||
pageInfo: {},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
@ -110,6 +165,10 @@ describe('Persisted Search', () => {
|
|||
{
|
||||
filters: ['foo'],
|
||||
sort: 'TEST_DESC',
|
||||
pageInfo: {
|
||||
after: '123',
|
||||
before: null,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
@ -126,7 +185,7 @@ describe('Persisted Search', () => {
|
|||
expect(UrlSync.methods.updateQuery).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sets the component sorting and filtering based on the querystring', async () => {
|
||||
it('sets the component sorting, filtering and page info based on the querystring', async () => {
|
||||
mountComponent();
|
||||
|
||||
await nextTick();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
keyValueToFilterToken,
|
||||
searchArrayToFilterTokens,
|
||||
extractFilterAndSorting,
|
||||
extractPageInfo,
|
||||
beautifyPath,
|
||||
getCommitLink,
|
||||
} from '~/packages_and_registries/shared/utils';
|
||||
|
|
@ -61,6 +62,21 @@ describe('Packages And Registries shared utils', () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe('extractPageInfo', () => {
|
||||
it.each`
|
||||
after | before | result
|
||||
${null} | ${null} | ${{ after: null, before: null }}
|
||||
${'123'} | ${null} | ${{ after: '123', before: null }}
|
||||
${null} | ${'123'} | ${{ after: null, before: '123' }}
|
||||
`('returns pagination objects', ({ after, before, result }) => {
|
||||
const queryObject = {
|
||||
after,
|
||||
before,
|
||||
};
|
||||
expect(extractPageInfo(queryObject)).toStrictEqual(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe('beautifyPath', () => {
|
||||
it('returns a string with spaces around /', () => {
|
||||
expect(beautifyPath('foo/bar')).toBe('foo / bar');
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ describe('Registry Search', () => {
|
|||
orderBy: 'name',
|
||||
search: [],
|
||||
sort: 'asc',
|
||||
after: null,
|
||||
before: null,
|
||||
};
|
||||
|
||||
const mountComponent = (propsData = defaultProps) => {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
|
|||
CI_PIPELINE_IID
|
||||
CI_PIPELINE_SOURCE
|
||||
CI_PIPELINE_CREATED_AT
|
||||
CI_PIPELINE_NAME
|
||||
CI_COMMIT_SHA
|
||||
CI_COMMIT_SHORT_SHA
|
||||
CI_COMMIT_BEFORE_SHA
|
||||
|
|
@ -43,6 +44,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
|
|||
CI_PIPELINE_IID
|
||||
CI_PIPELINE_SOURCE
|
||||
CI_PIPELINE_CREATED_AT
|
||||
CI_PIPELINE_NAME
|
||||
CI_COMMIT_SHA
|
||||
CI_COMMIT_SHORT_SHA
|
||||
CI_COMMIT_BEFORE_SHA
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
|
|||
value: pipeline.source },
|
||||
{ key: 'CI_PIPELINE_CREATED_AT',
|
||||
value: pipeline.created_at.iso8601 },
|
||||
{ key: 'CI_PIPELINE_NAME',
|
||||
value: pipeline.name },
|
||||
{ key: 'CI_COMMIT_SHA',
|
||||
value: job.sha },
|
||||
{ key: 'CI_COMMIT_SHORT_SHA',
|
||||
|
|
|
|||
|
|
@ -2400,6 +2400,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
|
|||
{ key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s, public: true, masked: false },
|
||||
{ key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true, masked: false },
|
||||
{ key: 'CI_PIPELINE_CREATED_AT', value: pipeline.created_at.iso8601, public: true, masked: false },
|
||||
{ key: 'CI_PIPELINE_NAME', value: pipeline.name, public: true, masked: false },
|
||||
{ key: 'CI_COMMIT_SHA', value: build.sha, public: true, masked: false },
|
||||
{ key: 'CI_COMMIT_SHORT_SHA', value: build.short_sha, public: true, masked: false },
|
||||
{ key: 'CI_COMMIT_BEFORE_SHA', value: build.before_sha, public: true, masked: false },
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ RSpec.describe Projects::ServiceDeskController, feature_category: :service_desk
|
|||
it 'toggles services desk incoming email' do
|
||||
project.update!(service_desk_enabled: false)
|
||||
|
||||
put project_service_desk_refresh_path(project, format: :json), params: { service_desk_enabled: true }
|
||||
put project_service_desk_path(project, format: :json), params: { service_desk_enabled: true }
|
||||
|
||||
expect(json_response["service_desk_address"]).to be_present
|
||||
expect(json_response["service_desk_enabled"]).to be_truthy
|
||||
|
|
@ -79,7 +79,7 @@ RSpec.describe Projects::ServiceDeskController, feature_category: :service_desk
|
|||
end
|
||||
|
||||
it 'sets issue_template_key' do
|
||||
put project_service_desk_refresh_path(project, format: :json), params: { issue_template_key: 'service_desk' }
|
||||
put project_service_desk_path(project, format: :json), params: { issue_template_key: 'service_desk' }
|
||||
|
||||
settings = project.service_desk_setting
|
||||
expect(settings).to be_present
|
||||
|
|
@ -89,7 +89,7 @@ RSpec.describe Projects::ServiceDeskController, feature_category: :service_desk
|
|||
end
|
||||
|
||||
it 'returns an error when update of service desk settings fails' do
|
||||
put project_service_desk_refresh_path(project, format: :json), params: { issue_template_key: 'invalid key' }
|
||||
put project_service_desk_path(project, format: :json), params: { issue_template_key: 'invalid key' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
||||
expect(json_response['message']).to eq('Issue template key is empty or does not exist')
|
||||
|
|
@ -100,7 +100,7 @@ RSpec.describe Projects::ServiceDeskController, feature_category: :service_desk
|
|||
|
||||
it 'renders 404' do
|
||||
sign_in(other_user)
|
||||
put project_service_desk_refresh_path(project, format: :json), params: { service_desk_enabled: true }
|
||||
put project_service_desk_path(project, format: :json), params: { service_desk_enabled: true }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue