Commit c46476c0 authored by Igor Drozdov's avatar Igor Drozdov

Merge branch 'ph/235715/autoMergeToGraphql' into 'master'

Moves the auto merge state to GraphQL

See merge request gitlab-org/gitlab!50980
parents ff1e3889 44926ce2
<script> <script>
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge'; import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge';
import autoMergeEnabledQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/auto_merge_enabled.query.graphql';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { deprecatedCreateFlash as Flash } from '../../../flash'; import { deprecatedCreateFlash as Flash } from '../../../flash';
import statusIcon from '../mr_widget_status_icon.vue'; import statusIcon from '../mr_widget_status_icon.vue';
import MrWidgetAuthor from '../mr_widget_author.vue'; import MrWidgetAuthor from '../mr_widget_author.vue';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import { AUTO_MERGE_STRATEGIES } from '../../constants'; import { AUTO_MERGE_STRATEGIES } from '../../constants';
import { __ } from '~/locale'; import { __ } from '~/locale';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
export default { export default {
name: 'MRWidgetAutoMergeEnabled', name: 'MRWidgetAutoMergeEnabled',
apollo: {
state: {
query: autoMergeEnabledQuery,
skip() {
return !this.glFeatures.mergeRequestWidgetGraphql;
},
variables() {
return this.mergeRequestQueryVariables;
},
update: (data) => data.project?.mergeRequest,
},
},
components: { components: {
MrWidgetAuthor, MrWidgetAuthor,
statusIcon, statusIcon,
GlLoadingIcon, GlLoadingIcon,
GlSkeletonLoader,
}, },
mixins: [autoMergeMixin], mixins: [autoMergeMixin, glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
props: { props: {
mr: { mr: {
type: Object, type: Object,
...@@ -30,20 +46,47 @@ export default { ...@@ -30,20 +46,47 @@ export default {
}, },
data() { data() {
return { return {
state: {},
isCancellingAutoMerge: false, isCancellingAutoMerge: false,
isRemovingSourceBranch: false, isRemovingSourceBranch: false,
}; };
}, },
computed: { computed: {
loading() {
return this.glFeatures.mergeRequestWidgetGraphql && this.$apollo.queries.state.loading;
},
mergeUser() {
if (this.glFeatures.mergeRequestWidgetGraphql) {
return this.state.mergeUser;
}
return this.mr.setToAutoMergeBy;
},
targetBranch() {
return (this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr).targetBranch;
},
shouldRemoveSourceBranch() {
if (this.glFeatures.mergeRequestWidgetGraphql) {
return this.state.shouldRemoveSourceBranch || this.state.forceRemoveSourceBranch;
}
return this.mr.shouldRemoveSourceBranch;
},
autoMergeStrategy() {
return (this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr).autoMergeStrategy;
},
canRemoveSourceBranch() { canRemoveSourceBranch() {
const { const { currentUserId } = this.mr;
shouldRemoveSourceBranch, const mergeUserId = this.glFeatures.mergeRequestWidgetGraphql
canRemoveSourceBranch, ? this.state.mergeUser?.id
mergeUserId, : this.mr.mergeUserId;
currentUserId, const canRemoveSourceBranch = this.glFeatures.mergeRequestWidgetGraphql
} = this.mr; ? this.state.userPermissions.removeSourceBranch
: this.mr.canRemoveSourceBranch;
return !shouldRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId; return (
!this.shouldRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId
);
}, },
}, },
methods: { methods: {
...@@ -63,7 +106,7 @@ export default { ...@@ -63,7 +106,7 @@ export default {
removeSourceBranch() { removeSourceBranch() {
const options = { const options = {
sha: this.mr.sha, sha: this.mr.sha,
auto_merge_strategy: this.mr.autoMergeStrategy, auto_merge_strategy: this.autoMergeStrategy,
should_remove_source_branch: true, should_remove_source_branch: true,
}; };
...@@ -86,49 +129,64 @@ export default { ...@@ -86,49 +129,64 @@ export default {
</script> </script>
<template> <template>
<div class="mr-widget-body media"> <div class="mr-widget-body media">
<status-icon status="success" /> <div v-if="loading" class="gl-w-full mr-conflict-loader">
<div class="media-body"> <gl-skeleton-loader :width="334" :height="30">
<h4 class="d-flex align-items-start"> <rect x="0" y="3" width="24" height="24" rx="4" />
<span class="gl-mr-3"> <rect x="32" y="7" width="150" height="16" rx="4" />
<span class="js-status-text-before-author">{{ statusTextBeforeAuthor }}</span> <rect x="190" y="7" width="144" height="16" rx="4" />
<mr-widget-author :author="mr.setToAutoMergeBy" /> </gl-skeleton-loader>
<span class="js-status-text-after-author">{{ statusTextAfterAuthor }}</span> </div>
</span> <template v-else>
<a <status-icon status="success" />
v-if="mr.canCancelAutomaticMerge" <div class="media-body">
:disabled="isCancellingAutoMerge" <h4 class="gl-display-flex">
role="button" <span class="gl-mr-3">
href="#" <span class="js-status-text-before-author" data-testid="beforeStatusText">{{
class="btn btn-sm btn-default js-cancel-auto-merge" statusTextBeforeAuthor
@click.prevent="cancelAutomaticMerge" }}</span>
> <mr-widget-author :author="mergeUser" />
<gl-loading-icon v-if="isCancellingAutoMerge" inline class="gl-mr-1" /> <span class="js-status-text-after-author" data-testid="afterStatusText">{{
{{ cancelButtonText }} statusTextAfterAuthor
</a> }}</span>
</h4> </span>
<section class="mr-info-list">
<p>
{{ s__('mrWidget|The changes will be merged into') }}
<a :href="mr.targetBranchPath" class="label-branch">{{ mr.targetBranch }}</a>
</p>
<p v-if="mr.shouldRemoveSourceBranch">
{{ s__('mrWidget|The source branch will be deleted') }}
</p>
<p v-else class="d-flex align-items-start">
<span class="gl-mr-3">{{ s__('mrWidget|The source branch will not be deleted') }}</span>
<a <a
v-if="canRemoveSourceBranch" v-if="mr.canCancelAutomaticMerge"
:disabled="isRemovingSourceBranch" :disabled="isCancellingAutoMerge"
role="button" role="button"
class="btn btn-sm btn-default js-remove-source-branch"
href="#" href="#"
@click.prevent="removeSourceBranch" class="btn btn-sm btn-default js-cancel-auto-merge"
data-testid="cancelAutomaticMergeButton"
@click.prevent="cancelAutomaticMerge"
> >
<gl-loading-icon v-if="isRemovingSourceBranch" inline class="gl-mr-1" /> <gl-loading-icon v-if="isCancellingAutoMerge" inline class="gl-mr-1" />
{{ s__('mrWidget|Delete source branch') }} {{ cancelButtonText }}
</a> </a>
</p> </h4>
</section> <section class="mr-info-list">
</div> <p>
{{ s__('mrWidget|The changes will be merged into') }}
<a :href="mr.targetBranchPath" class="label-branch">{{ targetBranch }}</a>
</p>
<p v-if="shouldRemoveSourceBranch">
{{ s__('mrWidget|The source branch will be deleted') }}
</p>
<p v-else class="gl-display-flex">
<span class="gl-mr-3">{{ s__('mrWidget|The source branch will not be deleted') }}</span>
<a
v-if="canRemoveSourceBranch"
:disabled="isRemovingSourceBranch"
role="button"
class="btn btn-sm btn-default js-remove-source-branch"
href="#"
data-testid="removeSourceBranchButton"
@click.prevent="removeSourceBranch"
>
<gl-loading-icon v-if="isRemovingSourceBranch" inline class="gl-mr-1" />
{{ s__('mrWidget|Delete source branch') }}
</a>
</p>
</section>
</div>
</template>
</div> </div>
</template> </template>
<script> <script>
import { GlLoadingIcon, GlButton } from '@gitlab/ui'; import { GlLoadingIcon, GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import statusIcon from '../mr_widget_status_icon.vue'; import statusIcon from '../mr_widget_status_icon.vue';
import autoMergeFailedQuery from '../../queries/states/auto_merge_failed.query.graphql';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
export default { export default {
name: 'MRWidgetAutoMergeFailed', name: 'MRWidgetAutoMergeFailed',
...@@ -10,6 +13,19 @@ export default { ...@@ -10,6 +13,19 @@ export default {
GlLoadingIcon, GlLoadingIcon,
GlButton, GlButton,
}, },
mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
apollo: {
mergeError: {
query: autoMergeFailedQuery,
skip() {
return !this.glFeatures.mergeRequestWidgetGraphql;
},
variables() {
return this.mergeRequestQueryVariables;
},
update: (data) => data.project?.mergeRequest?.mergeError,
},
},
props: { props: {
mr: { mr: {
type: Object, type: Object,
...@@ -18,6 +34,7 @@ export default { ...@@ -18,6 +34,7 @@ export default {
}, },
data() { data() {
return { return {
mergeError: this.glFeatures.mergeRequestWidgetGraphql ? null : this.mr.mergeError,
isRefreshing: false, isRefreshing: false,
}; };
}, },
...@@ -36,7 +53,7 @@ export default { ...@@ -36,7 +53,7 @@ export default {
<status-icon status="warning" /> <status-icon status="warning" />
<div class="media-body space-children gl-display-flex gl-flex-wrap gl-align-items-center"> <div class="media-body space-children gl-display-flex gl-flex-wrap gl-align-items-center">
<span class="bold"> <span class="bold">
<template v-if="mr.mergeError">{{ mr.mergeError }}</template> <template v-if="mergeError">{{ mergeError }}</template>
{{ s__('mrWidget|This merge request failed to be merged automatically') }} {{ s__('mrWidget|This merge request failed to be merged automatically') }}
</span> </span>
<gl-button <gl-button
......
fragment autoMergeEnabled on MergeRequest {
autoMergeStrategy
mergeUser {
name
username
webUrl
avatarUrl
}
targetBranch
shouldRemoveSourceBranch
forceRemoveSourceBranch
userPermissions {
removeSourceBranch
}
}
#import "./auto_merge_enabled.fragment.graphql"
query autoMergeEnabledQuery($projectPath: ID!, $iid: String!) {
project(fullPath: $projectPath) {
mergeRequest(iid: $iid) {
...autoMergeEnabled
mergeTrainsCount
}
}
}
query autoMergeFailedQuery($projectPath: ID!, $iid: String!) {
project(fullPath: $projectPath) {
mergeRequest(iid: $iid) {
mergeError
}
}
}
...@@ -175,6 +175,10 @@ module Types ...@@ -175,6 +175,10 @@ module Types
calls_gitaly: true, description: 'Merge request commits excluding merge commits' calls_gitaly: true, description: 'Merge request commits excluding merge commits'
field :security_auto_fix, GraphQL::BOOLEAN_TYPE, null: true, field :security_auto_fix, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' description: 'Indicates if the merge request is created by @GitLab-Security-Bot.'
field :auto_merge_strategy, GraphQL::STRING_TYPE, null: true,
description: 'Selected auto merge strategy'
field :merge_user, Types::UserType, null: true,
description: 'User who merged this merge request'
def approved_by def approved_by
object.approved_by_users object.approved_by_users
......
...@@ -13836,6 +13836,11 @@ type MergeRequest implements CurrentUserTodos & Noteable { ...@@ -13836,6 +13836,11 @@ type MergeRequest implements CurrentUserTodos & Noteable {
""" """
autoMergeEnabled: Boolean! autoMergeEnabled: Boolean!
"""
Selected auto merge strategy
"""
autoMergeStrategy: String
""" """
Array of available auto merge strategies Array of available auto merge strategies
""" """
...@@ -14075,6 +14080,11 @@ type MergeRequest implements CurrentUserTodos & Noteable { ...@@ -14075,6 +14080,11 @@ type MergeRequest implements CurrentUserTodos & Noteable {
""" """
mergeTrainsCount: Int mergeTrainsCount: Int
"""
User who merged this merge request
"""
mergeUser: User
""" """
Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS) Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)
""" """
......
...@@ -37994,6 +37994,20 @@ ...@@ -37994,6 +37994,20 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "autoMergeStrategy",
"description": "Selected auto merge strategy",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "availableAutoMergeStrategies", "name": "availableAutoMergeStrategies",
"description": "Array of available auto merge strategies", "description": "Array of available auto merge strategies",
...@@ -38645,6 +38659,20 @@ ...@@ -38645,6 +38659,20 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "mergeUser",
"description": "User who merged this merge request",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "User",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "mergeWhenPipelineSucceeds", "name": "mergeWhenPipelineSucceeds",
"description": "Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)", "description": "Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)",
...@@ -2095,6 +2095,7 @@ Autogenerated return type of MarkAsSpamSnippet. ...@@ -2095,6 +2095,7 @@ Autogenerated return type of MarkAsSpamSnippet.
| `assignees` | UserConnection | Assignees of the merge request | | `assignees` | UserConnection | Assignees of the merge request |
| `author` | User | User who created this merge request | | `author` | User | User who created this merge request |
| `autoMergeEnabled` | Boolean! | Indicates if auto merge is enabled for the merge request | | `autoMergeEnabled` | Boolean! | Indicates if auto merge is enabled for the merge request |
| `autoMergeStrategy` | String | Selected auto merge strategy |
| `availableAutoMergeStrategies` | String! => Array | Array of available auto merge strategies | | `availableAutoMergeStrategies` | String! => Array | Array of available auto merge strategies |
| `commitCount` | Int | Number of commits in the merge request | | `commitCount` | Int | Number of commits in the merge request |
| `commitsWithoutMergeCommits` | CommitConnection | Merge request commits excluding merge commits | | `commitsWithoutMergeCommits` | CommitConnection | Merge request commits excluding merge commits |
...@@ -2125,6 +2126,7 @@ Autogenerated return type of MarkAsSpamSnippet. ...@@ -2125,6 +2126,7 @@ Autogenerated return type of MarkAsSpamSnippet.
| `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring | | `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring |
| `mergeStatus` | String | Status of the merge request | | `mergeStatus` | String | Status of the merge request |
| `mergeTrainsCount` | Int | | | `mergeTrainsCount` | Int | |
| `mergeUser` | User | User who merged this merge request |
| `mergeWhenPipelineSucceeds` | Boolean | Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS) | | `mergeWhenPipelineSucceeds` | Boolean | Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS) |
| `mergeable` | Boolean! | Indicates if the merge request is mergeable | | `mergeable` | Boolean! | Indicates if the merge request is mergeable |
| `mergeableDiscussionsState` | Boolean | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged | | `mergeableDiscussionsState` | Boolean | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged |
......
...@@ -8,28 +8,27 @@ import { s__ } from '~/locale'; ...@@ -8,28 +8,27 @@ import { s__ } from '~/locale';
export default { export default {
computed: { computed: {
statusTextBeforeAuthor() { statusTextBeforeAuthor() {
if (this.mr.autoMergeStrategy === MT_MERGE_STRATEGY) { if (this.autoMergeStrategy === MT_MERGE_STRATEGY) {
return s__('mrWidget|Added to the merge train by'); return s__('mrWidget|Added to the merge train by');
} }
return s__('mrWidget|Set by'); return s__('mrWidget|Set by');
}, },
statusTextAfterAuthor() { statusTextAfterAuthor() {
if (this.mr.autoMergeStrategy === MTWPS_MERGE_STRATEGY && this.mr.mergeTrainsCount === 0) { const { mergeTrainsCount } = this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr;
if (this.autoMergeStrategy === MTWPS_MERGE_STRATEGY && mergeTrainsCount === 0) {
return s__('mrWidget|to start a merge train when the pipeline succeeds'); return s__('mrWidget|to start a merge train when the pipeline succeeds');
} else if ( } else if (this.autoMergeStrategy === MTWPS_MERGE_STRATEGY && mergeTrainsCount !== 0) {
this.mr.autoMergeStrategy === MTWPS_MERGE_STRATEGY &&
this.mr.mergeTrainsCount !== 0
) {
return s__('mrWidget|to be added to the merge train when the pipeline succeeds'); return s__('mrWidget|to be added to the merge train when the pipeline succeeds');
} else if (this.mr.autoMergeStrategy === MWPS_MERGE_STRATEGY) { } else if (this.autoMergeStrategy === MWPS_MERGE_STRATEGY) {
return s__('mrWidget|to be merged automatically when the pipeline succeeds'); return s__('mrWidget|to be merged automatically when the pipeline succeeds');
} }
return ''; return '';
}, },
cancelButtonText() { cancelButtonText() {
if (this.mr.autoMergeStrategy === MT_MERGE_STRATEGY) { if (this.autoMergeStrategy === MT_MERGE_STRATEGY) {
return s__('mrWidget|Remove from merge train'); return s__('mrWidget|Remove from merge train');
} }
......
#import "~/vue_merge_request_widget/queries/states/auto_merge_enabled.fragment.graphql"
query autoMergeEnabledQuery($projectPath: ID!, $iid: String!) {
project(fullPath: $projectPath) {
mergeRequest(iid: $iid) {
...autoMergeEnabled
}
}
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have correct elements 1`] = `
<div
class="mr-widget-body media"
>
<status-icon-stub
status="success"
/>
<div
class="media-body"
>
<h4
class="gl-display-flex"
>
<span
class="gl-mr-3"
>
<span
class="js-status-text-before-author"
data-testid="beforeStatusText"
>
Set by
</span>
<mr-widget-author-stub
author="[object Object]"
showauthorname="true"
/>
<span
class="js-status-text-after-author"
data-testid="afterStatusText"
>
to be merged automatically when the pipeline succeeds
</span>
</span>
<a
class="btn btn-sm btn-default js-cancel-auto-merge"
data-testid="cancelAutomaticMergeButton"
href="#"
role="button"
>
<!---->
Cancel automatic merge
</a>
</h4>
<section
class="mr-info-list"
>
<p>
The changes will be merged into
<a
class="label-branch"
href="/foo/bar"
>
foo
</a>
</p>
<p
class="gl-display-flex"
>
<span
class="gl-mr-3"
>
The source branch will not be deleted
</span>
<a
class="btn btn-sm btn-default js-remove-source-branch"
data-testid="removeSourceBranchButton"
href="#"
role="button"
>
<!---->
Delete source branch
</a>
</p>
</section>
</div>
</div>
`;
exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have correct elements 1`] = `
<div
class="mr-widget-body media"
>
<status-icon-stub
status="success"
/>
<div
class="media-body"
>
<h4
class="gl-display-flex"
>
<span
class="gl-mr-3"
>
<span
class="js-status-text-before-author"
data-testid="beforeStatusText"
>
Set by
</span>
<mr-widget-author-stub
author="[object Object]"
showauthorname="true"
/>
<span
class="js-status-text-after-author"
data-testid="afterStatusText"
>
to be merged automatically when the pipeline succeeds
</span>
</span>
<a
class="btn btn-sm btn-default js-cancel-auto-merge"
data-testid="cancelAutomaticMergeButton"
href="#"
role="button"
>
<!---->
Cancel automatic merge
</a>
</h4>
<section
class="mr-info-list"
>
<p>
The changes will be merged into
<a
class="label-branch"
href="/foo/bar"
>
foo
</a>
</p>
<p
class="gl-display-flex"
>
<span
class="gl-mr-3"
>
The source branch will not be deleted
</span>
<a
class="btn btn-sm btn-default js-remove-source-branch"
data-testid="removeSourceBranchButton"
href="#"
role="button"
>
<!---->
Delete source branch
</a>
</p>
</section>
</div>
</div>
`;
import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlLoadingIcon, GlButton } from '@gitlab/ui'; import { GlLoadingIcon, GlButton } from '@gitlab/ui';
import AutoMergeFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue'; import AutoMergeFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue';
...@@ -8,43 +9,60 @@ describe('MRWidgetAutoMergeFailed', () => { ...@@ -8,43 +9,60 @@ describe('MRWidgetAutoMergeFailed', () => {
const mergeError = 'This is the merge error'; const mergeError = 'This is the merge error';
const findButton = () => wrapper.find(GlButton); const findButton = () => wrapper.find(GlButton);
const createComponent = (props = {}) => { const createComponent = (props = {}, mergeRequestWidgetGraphql = false) => {
wrapper = shallowMount(AutoMergeFailedComponent, { wrapper = shallowMount(AutoMergeFailedComponent, {
propsData: { ...props }, propsData: { ...props },
}); data() {
}; if (mergeRequestWidgetGraphql) {
return { mergeError: props.mr?.mergeError };
}
beforeEach(() => { return {};
createComponent({ },
mr: { mergeError }, provide: {
glFeatures: { mergeRequestWidgetGraphql },
},
}); });
}); };
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders failed message', () => { [true, false].forEach((mergeRequestWidgetGraphql) => {
expect(wrapper.text()).toContain('This merge request failed to be merged automatically'); describe(`when graphql is ${mergeRequestWidgetGraphql ? 'enabled' : 'dislabed'}`, () => {
}); beforeEach(() => {
createComponent(
{
mr: { mergeError },
},
mergeRequestWidgetGraphql,
);
});
it('renders merge error provided', () => { it('renders failed message', () => {
expect(wrapper.text()).toContain(mergeError); expect(wrapper.text()).toContain('This merge request failed to be merged automatically');
}); });
it('render refresh button', () => { it('renders merge error provided', () => {
expect(findButton().text()).toEqual('Refresh'); expect(wrapper.text()).toContain(mergeError);
}); });
it('render refresh button', () => {
expect(findButton().text()).toBe('Refresh');
});
it('emits event and shows loading icon when button is clicked', async () => {
jest.spyOn(eventHub, '$emit');
findButton().vm.$emit('click');
it('emits event and shows loading icon when button is clicked', () => { expect(eventHub.$emit.mock.calls[0][0]).toBe('MRWidgetUpdateRequested');
jest.spyOn(eventHub, '$emit');
findButton().vm.$emit('click');
expect(eventHub.$emit.mock.calls[0][0]).toBe('MRWidgetUpdateRequested'); await nextTick();
return wrapper.vm.$nextTick(() => { expect(findButton().attributes('disabled')).toBe('true');
expect(findButton().attributes('disabled')).toBe('true'); expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); });
}); });
}); });
}); });
...@@ -30,6 +30,7 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do ...@@ -30,6 +30,7 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do
conflicts auto_merge_enabled approved_by source_branch_protected conflicts auto_merge_enabled approved_by source_branch_protected
default_merge_commit_message_with_description squash_on_merge available_auto_merge_strategies default_merge_commit_message_with_description squash_on_merge available_auto_merge_strategies
has_ci mergeable commits_without_merge_commits squash security_auto_fix default_squash_commit_message has_ci mergeable commits_without_merge_commits squash security_auto_fix default_squash_commit_message
auto_merge_strategy merge_user
] ]
expect(described_class).to have_graphql_fields(*expected_fields).at_least expect(described_class).to have_graphql_fields(*expected_fields).at_least
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment