Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
413a526be6
commit
6121eccf2b
13 changed files with 128 additions and 141 deletions
|
@ -1,10 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlAlert } from '@gitlab/ui';
|
import { GlAlert } from '@gitlab/ui';
|
||||||
import { mapState, mapActions } from 'vuex';
|
import { mapState, mapActions } from 'vuex';
|
||||||
import axios from '~/lib/utils/axios_utils';
|
|
||||||
import featureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
import featureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||||
import { NEW_VERSION_FLAG, ROLLOUT_STRATEGY_ALL_USERS } from '../constants';
|
import { ROLLOUT_STRATEGY_ALL_USERS } from '../constants';
|
||||||
import { createNewEnvironmentScope } from '../store/helpers';
|
|
||||||
import FeatureFlagForm from './form.vue';
|
import FeatureFlagForm from './form.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -13,48 +11,14 @@ export default {
|
||||||
GlAlert,
|
GlAlert,
|
||||||
},
|
},
|
||||||
mixins: [featureFlagsMixin()],
|
mixins: [featureFlagsMixin()],
|
||||||
inject: {
|
|
||||||
showUserCallout: {},
|
|
||||||
userCalloutId: {
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
userCalloutsPath: {
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
userShouldSeeNewFlagAlert: this.showUserCallout,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['error', 'path']),
|
...mapState(['error', 'path']),
|
||||||
scopes() {
|
|
||||||
return [
|
|
||||||
createNewEnvironmentScope(
|
|
||||||
{
|
|
||||||
environmentScope: '*',
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
this.glFeatures.featureFlagsPermissions,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
},
|
|
||||||
version() {
|
|
||||||
return NEW_VERSION_FLAG;
|
|
||||||
},
|
|
||||||
strategies() {
|
strategies() {
|
||||||
return [{ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] }];
|
return [{ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] }];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['createFeatureFlag']),
|
...mapActions(['createFeatureFlag']),
|
||||||
dismissNewVersionFlagAlert() {
|
|
||||||
this.userShouldSeeNewFlagAlert = false;
|
|
||||||
axios.post(this.userCalloutsPath, {
|
|
||||||
feature_name: this.userCalloutId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -69,9 +33,7 @@ export default {
|
||||||
<feature-flag-form
|
<feature-flag-form
|
||||||
:cancel-path="path"
|
:cancel-path="path"
|
||||||
:submit-text="s__('FeatureFlags|Create feature flag')"
|
:submit-text="s__('FeatureFlags|Create feature flag')"
|
||||||
:scopes="scopes"
|
|
||||||
:strategies="strategies"
|
:strategies="strategies"
|
||||||
:version="version"
|
|
||||||
@handleSubmit="(data) => createFeatureFlag(data)"
|
@handleSubmit="(data) => createFeatureFlag(data)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import axios from '~/lib/utils/axios_utils';
|
import axios from '~/lib/utils/axios_utils';
|
||||||
import { visitUrl } from '~/lib/utils/url_utility';
|
import { visitUrl } from '~/lib/utils/url_utility';
|
||||||
import { NEW_VERSION_FLAG } from '../../constants';
|
import { mapStrategiesToRails } from '../helpers';
|
||||||
import { mapFromScopesViewModel, mapStrategiesToRails } from '../helpers';
|
|
||||||
import * as types from './mutation_types';
|
import * as types from './mutation_types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,12 +16,7 @@ export const createFeatureFlag = ({ state, dispatch }, params) => {
|
||||||
dispatch('requestCreateFeatureFlag');
|
dispatch('requestCreateFeatureFlag');
|
||||||
|
|
||||||
return axios
|
return axios
|
||||||
.post(
|
.post(state.endpoint, mapStrategiesToRails(params))
|
||||||
state.endpoint,
|
|
||||||
params.version === NEW_VERSION_FLAG
|
|
||||||
? mapStrategiesToRails(params)
|
|
||||||
: mapFromScopesViewModel(params),
|
|
||||||
)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch('receiveCreateFeatureFlagSuccess');
|
dispatch('receiveCreateFeatureFlagSuccess');
|
||||||
visitUrl(state.path);
|
visitUrl(state.path);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlButton, GlModalDirective } from '@gitlab/ui';
|
import { GlButtonGroup, GlButton, GlModalDirective } from '@gitlab/ui';
|
||||||
import { uniqueId } from 'lodash';
|
import { uniqueId } from 'lodash';
|
||||||
import { sprintf, __ } from '~/locale';
|
import { sprintf, __ } from '~/locale';
|
||||||
import getRefMixin from '../mixins/get_ref';
|
import getRefMixin from '../mixins/get_ref';
|
||||||
|
@ -9,8 +9,10 @@ export default {
|
||||||
i18n: {
|
i18n: {
|
||||||
replace: __('Replace'),
|
replace: __('Replace'),
|
||||||
replacePrimaryBtnText: __('Replace file'),
|
replacePrimaryBtnText: __('Replace file'),
|
||||||
|
delete: __('Delete'),
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
GlButtonGroup,
|
||||||
GlButton,
|
GlButton,
|
||||||
UploadBlobModal,
|
UploadBlobModal,
|
||||||
},
|
},
|
||||||
|
@ -48,7 +50,7 @@ export default {
|
||||||
replaceModalId() {
|
replaceModalId() {
|
||||||
return uniqueId('replace-modal');
|
return uniqueId('replace-modal');
|
||||||
},
|
},
|
||||||
title() {
|
replaceModalTitle() {
|
||||||
return sprintf(__('Replace %{name}'), { name: this.name });
|
return sprintf(__('Replace %{name}'), { name: this.name });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -57,13 +59,16 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gl-mr-3">
|
<div class="gl-mr-3">
|
||||||
<gl-button v-gl-modal="replaceModalId">
|
<gl-button-group>
|
||||||
{{ $options.i18n.replace }}
|
<gl-button v-gl-modal="replaceModalId">
|
||||||
</gl-button>
|
{{ $options.i18n.replace }}
|
||||||
|
</gl-button>
|
||||||
|
<gl-button>{{ $options.i18n.delete }}</gl-button>
|
||||||
|
</gl-button-group>
|
||||||
<upload-blob-modal
|
<upload-blob-modal
|
||||||
:modal-id="replaceModalId"
|
:modal-id="replaceModalId"
|
||||||
:modal-title="title"
|
:modal-title="replaceModalTitle"
|
||||||
:commit-message="title"
|
:commit-message="replaceModalTitle"
|
||||||
:target-branch="targetBranch || ref"
|
:target-branch="targetBranch || ref"
|
||||||
:original-branch="originalBranch || ref"
|
:original-branch="originalBranch || ref"
|
||||||
:can-push-code="canPushCode"
|
:can-push-code="canPushCode"
|
|
@ -7,14 +7,14 @@ import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constant
|
||||||
import createFlash from '~/flash';
|
import createFlash from '~/flash';
|
||||||
import { __ } from '~/locale';
|
import { __ } from '~/locale';
|
||||||
import blobInfoQuery from '../queries/blob_info.query.graphql';
|
import blobInfoQuery from '../queries/blob_info.query.graphql';
|
||||||
|
import BlobButtonGroup from './blob_button_group.vue';
|
||||||
import BlobEdit from './blob_edit.vue';
|
import BlobEdit from './blob_edit.vue';
|
||||||
import BlobReplace from './blob_replace.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
BlobHeader,
|
BlobHeader,
|
||||||
BlobEdit,
|
BlobEdit,
|
||||||
BlobReplace,
|
BlobButtonGroup,
|
||||||
BlobContent,
|
BlobContent,
|
||||||
GlLoadingIcon,
|
GlLoadingIcon,
|
||||||
},
|
},
|
||||||
|
@ -132,7 +132,7 @@ export default {
|
||||||
>
|
>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<blob-edit :edit-path="blobInfo.editBlobPath" :web-ide-path="blobInfo.ideEditPath" />
|
<blob-edit :edit-path="blobInfo.editBlobPath" :web-ide-path="blobInfo.ideEditPath" />
|
||||||
<blob-replace
|
<blob-button-group
|
||||||
v-if="isLoggedIn"
|
v-if="isLoggedIn"
|
||||||
:path="path"
|
:path="path"
|
||||||
:name="blobInfo.name"
|
:name="blobInfo.name"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddForeignKeyForEnvironmentIdToEnvironments < ActiveRecord::Migration[6.0]
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
# `validate: false` option is passed here, because validating the existing rows fails by the orphaned deployments,
|
||||||
|
# which will be cleaned up in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64588.
|
||||||
|
# The validation runs for only new records or updates, so that we can at least
|
||||||
|
# stop creating orphaned rows.
|
||||||
|
add_concurrent_foreign_key :deployments, :environments, column: :environment_id, on_delete: :cascade, validate: false
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
with_lock_retries do
|
||||||
|
remove_foreign_key_if_exists :deployments, :environments
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
1
db/schema_migrations/20210622135221
Normal file
1
db/schema_migrations/20210622135221
Normal file
|
@ -0,0 +1 @@
|
||||||
|
e43889baa57ea2cd0b87ba98819408115955f6a6586b3275cf0a08bd79909c71
|
|
@ -25476,6 +25476,9 @@ CREATE TRIGGER trigger_has_external_wiki_on_update AFTER UPDATE ON services FOR
|
||||||
ALTER TABLE ONLY chat_names
|
ALTER TABLE ONLY chat_names
|
||||||
ADD CONSTRAINT fk_00797a2bf9 FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_00797a2bf9 FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE ONLY deployments
|
||||||
|
ADD CONSTRAINT fk_009fd21147 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE NOT VALID;
|
||||||
|
|
||||||
ALTER TABLE ONLY epics
|
ALTER TABLE ONLY epics
|
||||||
ADD CONSTRAINT fk_013c9f36ca FOREIGN KEY (due_date_sourcing_epic_id) REFERENCES epics(id) ON DELETE SET NULL;
|
ADD CONSTRAINT fk_013c9f36ca FOREIGN KEY (due_date_sourcing_epic_id) REFERENCES epics(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
|
|
@ -3591,6 +3591,27 @@ Input type: `RunnersRegistrationTokenResetInput`
|
||||||
| <a id="mutationrunnersregistrationtokenreseterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
| <a id="mutationrunnersregistrationtokenreseterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||||
| <a id="mutationrunnersregistrationtokenresettoken"></a>`token` | [`String`](#string) | The runner token after mutation. |
|
| <a id="mutationrunnersregistrationtokenresettoken"></a>`token` | [`String`](#string) | The runner token after mutation. |
|
||||||
|
|
||||||
|
### `Mutation.scanExecutionPolicyCommit`
|
||||||
|
|
||||||
|
Input type: `ScanExecutionPolicyCommitInput`
|
||||||
|
|
||||||
|
#### Arguments
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitoperationmode"></a>`operationMode` | [`MutationOperationMode!`](#mutationoperationmode) | Changes the operation mode. |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitpolicyyaml"></a>`policyYaml` | [`String!`](#string) | YAML snippet of the policy. |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitbranch"></a>`branch` | [`String`](#string) | Name of the branch to which the policy changes are committed. |
|
||||||
|
| <a id="mutationscanexecutionpolicycommitclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||||
|
| <a id="mutationscanexecutionpolicycommiterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||||
|
|
||||||
### `Mutation.terraformStateDelete`
|
### `Mutation.terraformStateDelete`
|
||||||
|
|
||||||
Input type: `TerraformStateDeleteInput`
|
Input type: `TerraformStateDeleteInput`
|
||||||
|
|
|
@ -34,7 +34,7 @@ RSpec.describe 'Database schema' do
|
||||||
compliance_management_frameworks: %w[group_id],
|
compliance_management_frameworks: %w[group_id],
|
||||||
commit_user_mentions: %w[commit_id],
|
commit_user_mentions: %w[commit_id],
|
||||||
deploy_keys_projects: %w[deploy_key_id],
|
deploy_keys_projects: %w[deploy_key_id],
|
||||||
deployments: %w[deployable_id environment_id user_id],
|
deployments: %w[deployable_id user_id],
|
||||||
draft_notes: %w[discussion_id commit_id],
|
draft_notes: %w[discussion_id commit_id],
|
||||||
epics: %w[updated_by_id last_edited_by_id state_id],
|
epics: %w[updated_by_id last_edited_by_id state_id],
|
||||||
events: %w[target_id],
|
events: %w[target_id],
|
||||||
|
|
|
@ -4,7 +4,6 @@ import Vuex from 'vuex';
|
||||||
import { TEST_HOST } from 'spec/test_constants';
|
import { TEST_HOST } from 'spec/test_constants';
|
||||||
import Form from '~/feature_flags/components/form.vue';
|
import Form from '~/feature_flags/components/form.vue';
|
||||||
import NewFeatureFlag from '~/feature_flags/components/new_feature_flag.vue';
|
import NewFeatureFlag from '~/feature_flags/components/new_feature_flag.vue';
|
||||||
import { ROLLOUT_STRATEGY_ALL_USERS, DEFAULT_PERCENT_ROLLOUT } from '~/feature_flags/constants';
|
|
||||||
import createStore from '~/feature_flags/store/new';
|
import createStore from '~/feature_flags/store/new';
|
||||||
import { allUsersStrategy } from '../mock_data';
|
import { allUsersStrategy } from '../mock_data';
|
||||||
|
|
||||||
|
@ -71,18 +70,6 @@ describe('New feature flag form', () => {
|
||||||
expect(wrapper.find(Form).exists()).toEqual(true);
|
expect(wrapper.find(Form).exists()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render default * row', () => {
|
|
||||||
const defaultScope = {
|
|
||||||
id: expect.any(String),
|
|
||||||
environmentScope: '*',
|
|
||||||
active: true,
|
|
||||||
rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
|
|
||||||
rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
|
|
||||||
rolloutUserIds: '',
|
|
||||||
};
|
|
||||||
expect(wrapper.vm.scopes).toEqual([defaultScope]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has an all users strategy by default', () => {
|
it('has an all users strategy by default', () => {
|
||||||
const strategies = wrapper.find(Form).props('strategies');
|
const strategies = wrapper.find(Form).props('strategies');
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
import testAction from 'helpers/vuex_action_helper';
|
import testAction from 'helpers/vuex_action_helper';
|
||||||
import { TEST_HOST } from 'spec/test_constants';
|
import { ROLLOUT_STRATEGY_ALL_USERS, NEW_VERSION_FLAG } from '~/feature_flags/constants';
|
||||||
import {
|
import { mapStrategiesToRails } from '~/feature_flags/store/helpers';
|
||||||
ROLLOUT_STRATEGY_ALL_USERS,
|
|
||||||
ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
|
|
||||||
LEGACY_FLAG,
|
|
||||||
NEW_VERSION_FLAG,
|
|
||||||
} from '~/feature_flags/constants';
|
|
||||||
import { mapFromScopesViewModel, mapStrategiesToRails } from '~/feature_flags/store/helpers';
|
|
||||||
import {
|
import {
|
||||||
createFeatureFlag,
|
createFeatureFlag,
|
||||||
requestCreateFeatureFlag,
|
requestCreateFeatureFlag,
|
||||||
|
@ -24,33 +19,13 @@ describe('Feature flags New Module Actions', () => {
|
||||||
let mockedState;
|
let mockedState;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedState = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
|
mockedState = state({ endpoint: '/feature_flags.json', path: '/feature_flags' });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createFeatureFlag', () => {
|
describe('createFeatureFlag', () => {
|
||||||
let mock;
|
let mock;
|
||||||
|
|
||||||
const actionParams = {
|
|
||||||
name: 'name',
|
|
||||||
description: 'description',
|
|
||||||
active: true,
|
|
||||||
version: LEGACY_FLAG,
|
|
||||||
scopes: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
environmentScope: 'environmentScope',
|
|
||||||
active: true,
|
|
||||||
canUpdate: true,
|
|
||||||
protected: true,
|
|
||||||
shouldBeDestroyed: false,
|
|
||||||
rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
|
|
||||||
rolloutPercentage: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
|
|
||||||
mock = new MockAdapter(axios);
|
mock = new MockAdapter(axios);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,9 +35,22 @@ describe('Feature flags New Module Actions', () => {
|
||||||
|
|
||||||
describe('success', () => {
|
describe('success', () => {
|
||||||
it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagSuccess ', (done) => {
|
it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagSuccess ', (done) => {
|
||||||
const convertedActionParams = mapFromScopesViewModel(actionParams);
|
const actionParams = {
|
||||||
|
name: 'name',
|
||||||
mock.onPost(`${TEST_HOST}/endpoint.json`, convertedActionParams).replyOnce(200);
|
description: 'description',
|
||||||
|
active: true,
|
||||||
|
version: NEW_VERSION_FLAG,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
name: ROLLOUT_STRATEGY_ALL_USERS,
|
||||||
|
parameters: {},
|
||||||
|
id: 1,
|
||||||
|
scopes: [{ id: 1, environmentScope: 'environmentScope', shouldBeDestroyed: false }],
|
||||||
|
shouldBeDestroyed: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
mock.onPost(mockedState.endpoint, mapStrategiesToRails(actionParams)).replyOnce(200);
|
||||||
|
|
||||||
testAction(
|
testAction(
|
||||||
createFeatureFlag,
|
createFeatureFlag,
|
||||||
|
@ -80,9 +68,11 @@ describe('Feature flags New Module Actions', () => {
|
||||||
done,
|
done,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('sends strategies for new style feature flags', (done) => {
|
describe('error', () => {
|
||||||
const newVersionFlagParams = {
|
it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagError ', (done) => {
|
||||||
|
const actionParams = {
|
||||||
name: 'name',
|
name: 'name',
|
||||||
description: 'description',
|
description: 'description',
|
||||||
active: true,
|
active: true,
|
||||||
|
@ -98,33 +88,7 @@ describe('Feature flags New Module Actions', () => {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
mock
|
mock
|
||||||
.onPost(`${TEST_HOST}/endpoint.json`, mapStrategiesToRails(newVersionFlagParams))
|
.onPost(mockedState.endpoint, mapStrategiesToRails(actionParams))
|
||||||
.replyOnce(200);
|
|
||||||
|
|
||||||
testAction(
|
|
||||||
createFeatureFlag,
|
|
||||||
newVersionFlagParams,
|
|
||||||
mockedState,
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
type: 'requestCreateFeatureFlag',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'receiveCreateFeatureFlagSuccess',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
done,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('error', () => {
|
|
||||||
it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagError ', (done) => {
|
|
||||||
const convertedActionParams = mapFromScopesViewModel(actionParams);
|
|
||||||
|
|
||||||
mock
|
|
||||||
.onPost(`${TEST_HOST}/endpoint.json`, convertedActionParams)
|
|
||||||
.replyOnce(500, { message: [] });
|
.replyOnce(500, { message: [] });
|
||||||
|
|
||||||
testAction(
|
testAction(
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import { GlButton } from '@gitlab/ui';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import BlobReplace from '~/repository/components/blob_replace.vue';
|
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||||
|
|
||||||
|
import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
|
||||||
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
|
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
|
||||||
|
|
||||||
const DEFAULT_PROPS = {
|
const DEFAULT_PROPS = {
|
||||||
|
@ -14,11 +17,11 @@ const DEFAULT_INJECT = {
|
||||||
originalBranch: 'master',
|
originalBranch: 'master',
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('BlobReplace component', () => {
|
describe('BlobButtonGroup component', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
const createComponent = (props = {}) => {
|
const createComponent = (props = {}) => {
|
||||||
wrapper = shallowMount(BlobReplace, {
|
wrapper = shallowMount(BlobButtonGroup, {
|
||||||
propsData: {
|
propsData: {
|
||||||
...DEFAULT_PROPS,
|
...DEFAULT_PROPS,
|
||||||
...props,
|
...props,
|
||||||
|
@ -26,6 +29,9 @@ describe('BlobReplace component', () => {
|
||||||
provide: {
|
provide: {
|
||||||
...DEFAULT_INJECT,
|
...DEFAULT_INJECT,
|
||||||
},
|
},
|
||||||
|
directives: {
|
||||||
|
GlModal: createMockDirective(),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,6 +40,7 @@ describe('BlobReplace component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
|
const findUploadBlobModal = () => wrapper.findComponent(UploadBlobModal);
|
||||||
|
const findReplaceButton = () => wrapper.findAll(GlButton).at(0);
|
||||||
|
|
||||||
it('renders component', () => {
|
it('renders component', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
@ -46,6 +53,28 @@ describe('BlobReplace component', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('buttons', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders both the replace and delete button', () => {
|
||||||
|
expect(wrapper.findAll(GlButton)).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the buttons in the correct order', () => {
|
||||||
|
expect(wrapper.findAll(GlButton).at(0).text()).toBe('Replace');
|
||||||
|
expect(wrapper.findAll(GlButton).at(1).text()).toBe('Delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('triggers the UploadBlobModal from the replace button', () => {
|
||||||
|
const { value } = getBinding(findReplaceButton().element, 'gl-modal');
|
||||||
|
const modalId = findUploadBlobModal().props('modalId');
|
||||||
|
|
||||||
|
expect(modalId).toEqual(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('renders UploadBlobModal', () => {
|
it('renders UploadBlobModal', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { shallowMount, mount } from '@vue/test-utils';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import BlobContent from '~/blob/components/blob_content.vue';
|
import BlobContent from '~/blob/components/blob_content.vue';
|
||||||
import BlobHeader from '~/blob/components/blob_header.vue';
|
import BlobHeader from '~/blob/components/blob_header.vue';
|
||||||
|
import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
|
||||||
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
|
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
|
||||||
import BlobEdit from '~/repository/components/blob_edit.vue';
|
import BlobEdit from '~/repository/components/blob_edit.vue';
|
||||||
import BlobReplace from '~/repository/components/blob_replace.vue';
|
|
||||||
|
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const simpleMockData = {
|
const simpleMockData = {
|
||||||
|
@ -80,7 +80,7 @@ describe('Blob content viewer component', () => {
|
||||||
const findBlobHeader = () => wrapper.findComponent(BlobHeader);
|
const findBlobHeader = () => wrapper.findComponent(BlobHeader);
|
||||||
const findBlobEdit = () => wrapper.findComponent(BlobEdit);
|
const findBlobEdit = () => wrapper.findComponent(BlobEdit);
|
||||||
const findBlobContent = () => wrapper.findComponent(BlobContent);
|
const findBlobContent = () => wrapper.findComponent(BlobContent);
|
||||||
const findBlobReplace = () => wrapper.findComponent(BlobReplace);
|
const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup);
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
|
@ -200,7 +200,7 @@ describe('Blob content viewer component', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('BlobReplace', () => {
|
describe('BlobButtonGroup', () => {
|
||||||
const { name, path } = simpleMockData;
|
const { name, path } = simpleMockData;
|
||||||
|
|
||||||
it('renders component', async () => {
|
it('renders component', async () => {
|
||||||
|
@ -210,13 +210,13 @@ describe('Blob content viewer component', () => {
|
||||||
mockData: { blobInfo: simpleMockData },
|
mockData: { blobInfo: simpleMockData },
|
||||||
stubs: {
|
stubs: {
|
||||||
BlobContent: true,
|
BlobContent: true,
|
||||||
BlobReplace: true,
|
BlobButtonGroup: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(findBlobReplace().props()).toMatchObject({
|
expect(findBlobButtonGroup().props()).toMatchObject({
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
});
|
});
|
||||||
|
@ -235,7 +235,7 @@ describe('Blob content viewer component', () => {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(findBlobReplace().exists()).toBe(false);
|
expect(findBlobButtonGroup().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue