Commit eca2ef23 authored by Mark Florian's avatar Mark Florian

Merge branch 'jivanvl-remove-ci-variables-table-feature-flag' into 'master'

Remove new_ci_variables_list feature flag

See merge request gitlab-org/gitlab!41412
parents 29280bee b26853f6
import { escape } from 'lodash';
import axios from '../lib/utils/axios_utils';
import { s__ } from '../locale';
import { deprecatedCreateFlash as Flash } from '../flash';
import { parseBoolean } from '../lib/utils/common_utils';
import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
function generateErrorBoxContent(errors) {
const errorList = [].concat(errors).map(
errorString => `
<li>
${escape(errorString)}
</li>
`,
);
return `
<p>
${s__('CiVariable|Validation failed')}
</p>
<ul>
${errorList.join('')}
</ul>
`;
}
// Used for the variable list on CI/CD projects/groups settings page
export default class AjaxVariableList {
constructor({
container,
saveButton,
errorBox,
formField = 'variables',
saveEndpoint,
maskableRegex,
}) {
this.container = container;
this.saveButton = saveButton;
this.errorBox = errorBox;
this.saveEndpoint = saveEndpoint;
this.maskableRegex = maskableRegex;
this.variableList = new VariableList({
container: this.container,
formField,
maskableRegex,
});
this.bindEvents();
this.variableList.init();
}
bindEvents() {
this.saveButton.addEventListener('click', this.onSaveClicked.bind(this));
}
onSaveClicked() {
const loadingIcon = this.saveButton.querySelector('.js-ci-variables-save-loading-icon');
loadingIcon.classList.toggle('hide', false);
this.errorBox.classList.toggle('hide', true);
// We use this to prevent a user from changing a key before we have a chance
// to match it up in `updateRowsWithPersistedVariables`
this.variableList.toggleEnableRow(false);
return axios
.patch(
this.saveEndpoint,
{
variables_attributes: this.variableList.getAllData(),
},
{
// We want to be able to process the `res.data` from a 400 error response
// and print the validation messages such as duplicate variable keys
validateStatus: status =>
(status >= statusCodes.OK && status < statusCodes.MULTIPLE_CHOICES) ||
status === statusCodes.BAD_REQUEST,
},
)
.then(res => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
if (res.status === statusCodes.OK && res.data) {
this.updateRowsWithPersistedVariables(res.data.variables);
this.variableList.hideValues();
} else if (res.status === statusCodes.BAD_REQUEST) {
// Validation failed
this.errorBox.innerHTML = generateErrorBoxContent(res.data);
this.errorBox.classList.toggle('hide', false);
}
})
.catch(() => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
Flash(s__('CiVariable|Error occurred while saving variables'));
});
}
updateRowsWithPersistedVariables(persistedVariables = []) {
const persistedVariableMap = [].concat(persistedVariables).reduce(
(variableMap, variable) => ({
...variableMap,
[variable.key]: variable,
}),
{},
);
this.container.querySelectorAll('.js-row').forEach(row => {
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const destroyInput = row.querySelector('.js-ci-variable-input-destroy');
if (parseBoolean(destroyInput.value)) {
row.remove();
// Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
const key = row.querySelector('.js-ci-variable-input-key').value;
const persistedVariable = persistedVariableMap[key];
if (persistedVariable) {
// eslint-disable-next-line no-param-reassign
row.querySelector('.js-ci-variable-input-id').value = persistedVariable.id;
row.setAttribute('data-is-persisted', 'true');
}
}
});
}
}
......@@ -60,7 +60,7 @@ export default {
</script>
<template>
<gl-dropdown :text="value">
<gl-search-box-by-type v-model.trim="searchTerm" />
<gl-search-box-by-type v-model.trim="searchTerm" data-testid="ci-environment-search" />
<gl-dropdown-item
v-for="environment in filteredResults"
:key="environment"
......@@ -75,7 +75,7 @@ export default {
}}</gl-dropdown-item>
<template v-if="shouldRenderCreateButton">
<gl-dropdown-divider />
<gl-dropdown-item @click="createClicked">
<gl-dropdown-item data-testid="create-wildcard-button" @click="createClicked">
{{ composedCreateButtonLabel }}
</gl-dropdown-item>
</template>
......
......@@ -236,6 +236,7 @@ export default {
:label="__('Environment scope')"
label-for="ci-variable-env"
class="w-50"
data-testid="environment-scope"
>
<ci-environments-dropdown
class="w-100"
......@@ -247,7 +248,11 @@ export default {
</div>
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
<gl-form-checkbox v-model="protected_variable" class="mb-0">
<gl-form-checkbox
v-model="protected_variable"
class="mb-0"
data-testid="ci-variable-protected-checkbox"
>
{{ __('Protect variable') }}
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
......@@ -261,6 +266,7 @@ export default {
ref="masked-ci-variable"
v-model="masked"
data-qa-selector="ci_variable_masked_checkbox"
data-testid="ci-variable-masked-checkbox"
>
{{ __('Mask variable') }}
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
......
import initSettingsPanels from '~/settings_panels';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import initVariableList from '~/ci_variable_list';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import GroupRunnersFilteredSearchTokenKeys from '~/filtered_search/group_runners_filtered_search_token_keys';
......@@ -17,19 +16,6 @@ document.addEventListener('DOMContentLoaded', () => {
useDefaultState: false,
});
if (gon.features.newVariablesUi) {
initVariableList();
} else {
const variableListEl = document.querySelector('.js-ci-variable-list-section');
// eslint-disable-next-line no-new
new AjaxVariableList({
container: variableListEl,
saveButton: variableListEl.querySelector('.js-ci-variables-save-button'),
errorBox: variableListEl.querySelector('.js-ci-variable-error-box'),
saveEndpoint: variableListEl.dataset.saveEndpoint,
maskableRegex: variableListEl.dataset.maskableRegex,
});
}
initSharedRunnersForm();
initVariableList();
});
import initSettingsPanels from '~/settings_panels';
import SecretValues from '~/behaviors/secret_values';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
import initVariableList from '~/ci_variable_list';
import initDeployFreeze from '~/deploy_freeze';
......@@ -18,19 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
runnerTokenSecretValue.init();
}
if (gon.features.newVariablesUi) {
initVariableList();
} else {
const variableListEl = document.querySelector('.js-ci-variable-list-section');
// eslint-disable-next-line no-new
new AjaxVariableList({
container: variableListEl,
saveButton: variableListEl.querySelector('.js-ci-variables-save-button'),
errorBox: variableListEl.querySelector('.js-ci-variable-error-box'),
saveEndpoint: variableListEl.dataset.saveEndpoint,
maskableRegex: variableListEl.dataset.maskableRegex,
});
}
initVariableList();
// hide extra auto devops settings based checkbox state
const autoDevOpsExtraSettings = document.querySelector('.js-extra-settings');
......
......@@ -8,9 +8,6 @@ module Groups
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
before_action do
push_frontend_feature_flag(:new_variables_ui, @group, default_enabled: true)
end
before_action :define_variables, only: [:show]
feature_category :continuous_integration
......
......@@ -8,7 +8,6 @@ module Projects
before_action :authorize_admin_pipeline!
before_action :define_variables
before_action do
push_frontend_feature_flag(:new_variables_ui, @project, default_enabled: true)
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
end
......
......@@ -5,42 +5,20 @@
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
= s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
- if Feature.enabled?(:new_variables_ui, @project || @group, default_enabled: true)
- is_group = !@group.nil?
- is_group = !@group.nil?
#js-ci-project-variables{ data: { endpoint: save_endpoint,
project_id: @project&.id || '',
group: is_group.to_s,
maskable_regex: ci_variable_maskable_regex,
protected_by_default: ci_variable_protected_by_default?.to_s,
aws_logo_svg_path: image_path('aws_logo.svg'),
aws_tip_deploy_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'deploy-your-application-to-the-aws-elastic-container-service-ecs'),
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'run-aws-commands-from-gitlab-cicd'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'aws'),
protected_environment_variables_link: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable'),
masked_environment_variables_link: help_page_path('ci/variables/README', anchor: 'mask-a-custom-variable'),
} }
- else
.row
.col-lg-12.js-ci-variable-list-section{ data: { save_endpoint: save_endpoint, maskable_regex: ci_variable_maskable_regex } }
.hide.gl-alert.gl-alert-danger.js-ci-variable-error-box
%ul.ci-variable-list
= render 'ci/variables/variable_header'
- @variables.each.each do |variable|
= render 'ci/variables/variable_row', form_field: 'variables', variable: variable
= render 'ci/variables/variable_row', form_field: 'variables'
.prepend-top-20
%button.btn.btn-success.js-ci-variables-save-button{ type: 'button' }
%span.hide.js-ci-variables-save-loading-icon
.spinner.spinner-light.mr-1
= _('Save variables')
%button.btn.btn-info.btn-inverted.gl-ml-3.js-secret-value-reveal-button{ type: 'button', data: { secret_reveal_status: "#{@variables.size == 0}" } }
- if @variables.size == 0
= n_('Hide value', 'Hide values', @variables.size)
- else
= n_('Reveal value', 'Reveal values', @variables.size)
#js-ci-project-variables{ data: { endpoint: save_endpoint,
project_id: @project&.id || '',
group: is_group.to_s,
maskable_regex: ci_variable_maskable_regex,
protected_by_default: ci_variable_protected_by_default?.to_s,
aws_logo_svg_path: image_path('aws_logo.svg'),
aws_tip_deploy_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'deploy-your-application-to-the-aws-elastic-container-service-ecs'),
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'run-aws-commands-from-gitlab-cicd'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'aws'),
protected_environment_variables_link: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable'),
masked_environment_variables_link: help_page_path('ci/variables/README', anchor: 'mask-a-custom-variable'),
} }
- if !@group && @project.group
.settings-header.border-top.prepend-top-20
......
---
title: Remove new_variables_ui feature flag
merge_request: 41412
author:
type: other
---
name: new_variables_ui
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25260
rollout_issue_url:
group: group::continuous integration
type: development
default_enabled: true
import $ from 'jquery';
import VariableList from '~/ci_variable_list/ci_variable_list';
describe('VariableList (EE features)', () => {
preloadFixtures('projects/ci_cd_settings.html');
let $wrapper;
let variableList;
describe('with all inputs(key, value, protected, environment)', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
describe('environment dropdown', () => {
function addRowByNewEnvironment(newEnv) {
const $row = $wrapper.find('.js-row:last-child');
// Open the dropdown
$row.find('.js-variable-environment-toggle').click();
// Filter for the new item
$row
.find('.js-variable-environment-dropdown-wrapper .dropdown-input-field')
.val(newEnv)
.trigger('input');
// Create the new item
$row.find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click();
}
it('should add another row when editing the last rows environment dropdown', () => {
addRowByNewEnvironment('someenv');
jest.runOnlyPendingTimers();
expect($wrapper.find('.js-row')).toHaveLength(2);
// Check for the correct default in the new row
const $environmentInput = $wrapper
.find('.js-row:last-child')
.find('input[name="variables[variables_attributes][][environment_scope]"]');
expect($environmentInput.val()).toBe('*');
});
it('should update dropdown with new environment values and remove values when row is removed', () => {
addRowByNewEnvironment('someenv');
const $row = $wrapper.find('.js-row:last-child');
$row.find('.js-variable-environment-toggle').click();
jest.runOnlyPendingTimers();
const $dropdownItemsBeforeRemove = $row.find(
'.js-variable-environment-dropdown-wrapper .dropdown-content a',
);
expect($dropdownItemsBeforeRemove).toHaveLength(2);
expect($dropdownItemsBeforeRemove[0].textContent.trim()).toBe('someenv');
expect($dropdownItemsBeforeRemove[1].textContent.trim()).toBe('* (All environments)');
$wrapper.find('.js-row-remove-button').trigger('click');
expect($wrapper.find('.js-row')).toHaveLength(0);
jest.runOnlyPendingTimers();
const $dropdownItemsAfterRemove = $row.find(
'.js-variable-environment-dropdown-wrapper .dropdown-content a',
);
expect($dropdownItemsAfterRemove).toHaveLength(1);
expect($dropdownItemsAfterRemove[0].textContent.trim()).toBe('* (All environments)');
});
});
});
});
......@@ -5321,9 +5321,6 @@ msgstr ""
msgid "CiVariable|Create wildcard"
msgstr ""
msgid "CiVariable|Error occurred while saving variables"
msgstr ""
msgid "CiVariable|Masked"
msgstr ""
......@@ -5342,9 +5339,6 @@ msgstr ""
msgid "CiVariable|Toggle protected"
msgstr ""
msgid "CiVariable|Validation failed"
msgstr ""
msgid "Classification Label (optional)"
msgstr ""
......@@ -23050,9 +23044,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
msgid "Save variables"
msgstr ""
msgid "Saved scan settings and target site settings which are reusable."
msgstr ""
......
......@@ -11,7 +11,7 @@ RSpec.describe 'Group variables', :js do
before do
group.add_owner(user)
gitlab_sign_in(user)
stub_feature_flags(new_variables_ui: false)
wait_for_requests
visit page_path
end
......
......@@ -24,7 +24,6 @@ RSpec.describe 'Project group variables', :js do
sign_in(user)
project.add_maintainer(user)
group.add_owner(user)
stub_feature_flags(new_variables_ui: false)
end
it 'project in group shows inherited vars from ancestor group' do
......@@ -53,9 +52,13 @@ RSpec.describe 'Project group variables', :js do
it 'project origin keys link to ancestor groups ci_cd settings' do
visit project_path
find('.group-origin-link').click
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq(key1)
wait_for_requests
page.within('.ci-variable-table') do
expect(find('.js-ci-variable-row:nth-child(1) [data-label="Key"]').text).to eq(key1)
end
end
end
......@@ -12,32 +12,29 @@ RSpec.describe 'Project variables', :js do
sign_in(user)
project.add_maintainer(user)
project.variables << variable
stub_feature_flags(new_variables_ui: false)
visit page_path
end
it_behaves_like 'variable list'
it 'adds new variable with a special environment scope' do
page.within('.js-ci-variable-list-section .js-row:last-child') do
find('.js-ci-variable-input-key').set('somekey')
find('.js-ci-variable-input-value').set('somevalue')
it 'adds a new variable with an environment scope' do
click_button('Add Variable')
find('.js-variable-environment-toggle').click
find('.js-variable-environment-dropdown-wrapper .dropdown-input-field').set('review/*')
find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click
page.within('#add-ci-variable') do
find('[data-qa-selector="ci_variable_key_field"] input').set('akey')
find('#ci-variable-value').set('akey_value')
find('[data-testid="environment-scope"]').click
find_button('clear').click
find('[data-testid="ci-environment-search"]').set('review/*')
find('[data-testid="create-wildcard-button"]').click
expect(find('input[name="variables[variables_attributes][][environment_scope]"]', visible: false).value).to eq('review/*')
click_button('Add variable')
end
click_button('Save variables')
wait_for_requests
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('somekey')
expect(page).to have_content('review/*')
page.within('.ci-variable-table') do
expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
end
end
end
......@@ -18,7 +18,6 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
sign_in(user)
stub_container_registry_config(enabled: container_registry_enabled)
stub_feature_flags(new_variables_ui: false)
end
context 'as owner' do
......
import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import AjaxFormVariableList from '~/ci_variable_list/ajax_variable_list';
const VARIABLE_PATCH_ENDPOINT = 'http://test.host/frontend-fixtures/builds-project/-/variables';
const HIDE_CLASS = 'hide';
describe('AjaxFormVariableList', () => {
preloadFixtures('projects/ci_cd_settings.html');
preloadFixtures('projects/ci_cd_settings_with_variables.html');
let container;
let saveButton;
let errorBox;
let mock;
let ajaxVariableList;
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
container = document.querySelector('.js-ci-variable-list-section');
mock = new MockAdapter(axios);
const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section');
saveButton = ajaxVariableListEl.querySelector('.js-ci-variables-save-button');
errorBox = container.querySelector('.js-ci-variable-error-box');
ajaxVariableList = new AjaxFormVariableList({
container,
formField: 'variables',
saveButton,
errorBox,
saveEndpoint: container.dataset.saveEndpoint,
maskableRegex: container.dataset.maskableRegex,
});
jest.spyOn(ajaxVariableList, 'updateRowsWithPersistedVariables');
jest.spyOn(ajaxVariableList.variableList, 'toggleEnableRow');
});
afterEach(() => {
mock.restore();
});
describe('onSaveClicked', () => {
it('shows loading spinner while waiting for the request', () => {
const loadingIcon = saveButton.querySelector('.js-ci-variables-save-loading-icon');
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(() => {
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(false);
return [200, {}];
});
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
it('calls `updateRowsWithPersistedVariables` with the persisted variables', () => {
const variablesResponse = [{ id: 1, key: 'foo', value: 'bar' }];
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {
variables: variablesResponse,
});
return ajaxVariableList.onSaveClicked().then(() => {
expect(ajaxVariableList.updateRowsWithPersistedVariables).toHaveBeenCalledWith(
variablesResponse,
);
});
});
it('hides any previous error box', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
it('disables remove buttons while waiting for the request', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(() => {
expect(ajaxVariableList.variableList.toggleEnableRow).toHaveBeenCalledWith(false);
return [200, {}];
});
return ajaxVariableList.onSaveClicked().then(() => {
expect(ajaxVariableList.variableList.toggleEnableRow).toHaveBeenCalledWith(true);
});
});
it('hides secret values', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {});
const row = container.querySelector('.js-row');
const valueInput = row.querySelector('.js-ci-variable-input-value');
const valuePlaceholder = row.querySelector('.js-secret-value-placeholder');
valueInput.value = 'bar';
$(valueInput).trigger('input');
expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(true);
expect(valueInput.classList.contains(HIDE_CLASS)).toBe(false);
return ajaxVariableList.onSaveClicked().then(() => {
expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(false);
expect(valueInput.classList.contains(HIDE_CLASS)).toBe(true);
});
});
it('shows error box with validation errors', () => {
const validationError = 'some validation error';
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(400, [validationError]);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(false);
expect(errorBox.textContent.trim().replace(/\n+\s+/m, ' ')).toEqual(
`Validation failed ${validationError}`,
);
});
});
it('shows flash message when request fails', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(500);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
});
describe('updateRowsWithPersistedVariables', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings_with_variables.html');
container = document.querySelector('.js-ci-variable-list-section');
const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section');
saveButton = ajaxVariableListEl.querySelector('.js-ci-variables-save-button');
errorBox = container.querySelector('.js-ci-variable-error-box');
ajaxVariableList = new AjaxFormVariableList({
container,
formField: 'variables',
saveButton,
errorBox,
saveEndpoint: container.dataset.saveEndpoint,
});
});
it('removes variable that was removed', () => {
expect(container.querySelectorAll('.js-row').length).toBe(3);
container.querySelector('.js-row-remove-button').click();
expect(container.querySelectorAll('.js-row').length).toBe(3);
ajaxVariableList.updateRowsWithPersistedVariables([]);
expect(container.querySelectorAll('.js-row').length).toBe(2);
});
it('updates new variable row with persisted ID', () => {
const row = container.querySelector('.js-row:last-child');
const idInput = row.querySelector('.js-ci-variable-input-id');
const keyInput = row.querySelector('.js-ci-variable-input-key');
const valueInput = row.querySelector('.js-ci-variable-input-value');
keyInput.value = 'foo';
$(keyInput).trigger('input');
valueInput.value = 'bar';
$(valueInput).trigger('input');
expect(idInput.value).toEqual('');
ajaxVariableList.updateRowsWithPersistedVariables([
{
id: 3,
key: 'foo',
value: 'bar',
},
]);
expect(idInput.value).toEqual('3');
expect(row.dataset.isPersisted).toEqual('true');
});
});
describe('maskableRegex', () => {
it('takes in the regex provided by the data attribute', () => {
expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
expect(ajaxVariableList.maskableRegex).toBe(container.dataset.maskableRegex);
});
});
});
import $ from 'jquery';
import waitForPromises from 'helpers/wait_for_promises';
import VariableList from '~/ci_variable_list/ci_variable_list';
const HIDE_CLASS = 'hide';
......@@ -7,7 +6,6 @@ const HIDE_CLASS = 'hide';
describe('VariableList', () => {
preloadFixtures('pipeline_schedules/edit.html');
preloadFixtures('pipeline_schedules/edit_with_variables.html');
preloadFixtures('projects/ci_cd_settings.html');
let $wrapper;
let variableList;
......@@ -113,92 +111,6 @@ describe('VariableList', () => {
});
});
describe('with all inputs(key, value, protected)', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
$wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
it('should not add another row when editing the last rows protected checkbox', () => {
const $row = $wrapper.find('.js-row:last-child');
$row.find('.ci-variable-protected-item .js-project-feature-toggle').click();
return waitForPromises().then(() => {
expect($wrapper.find('.js-row').length).toBe(1);
});
});
it('should not add another row when editing the last rows masked checkbox', () => {
jest.spyOn(variableList, 'checkIfRowTouched');
const $row = $wrapper.find('.js-row:last-child');
$row.find('.ci-variable-masked-item .js-project-feature-toggle').click();
return waitForPromises().then(() => {
// This validates that we are checking after the event listener has run
expect(variableList.checkIfRowTouched).toHaveBeenCalled();
expect($wrapper.find('.js-row').length).toBe(1);
});
});
describe('validateMaskability', () => {
let $row;
const maskingErrorElement = '.js-row:last-child .masking-validation-error';
const clickToggle = () =>
$row.find('.ci-variable-masked-item .js-project-feature-toggle').click();
beforeEach(() => {
$row = $wrapper.find('.js-row:last-child');
});
it('has a regex provided via a data attribute', () => {
clickToggle();
expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
});
it('allows values that are 8 characters long', () => {
$row.find('.js-ci-variable-input-value').val('looooong');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toHaveClass('hide');
});
it('rejects values that are shorter than 8 characters', () => {
$row.find('.js-ci-variable-input-value').val('short');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toBeVisible();
});
it('allows values with base 64 characters', () => {
$row.find('.js-ci-variable-input-value').val('abcABC123_+=/-');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toHaveClass('hide');
});
it('rejects values with other special characters', () => {
$row.find('.js-ci-variable-input-value').val('1234567$');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toBeVisible();
});
});
});
describe('toggleEnableRow method', () => {
beforeEach(() => {
loadFixtures('pipeline_schedules/edit_with_variables.html');
......@@ -247,36 +159,4 @@ describe('VariableList', () => {
expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3);
});
});
describe('hideValues', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
it('should hide value input and show placeholder stars', () => {
const $row = $wrapper.find('.js-row');
const $inputValue = $row.find('.js-ci-variable-input-value');
const $placeholder = $row.find('.js-secret-value-placeholder');
$row
.find('.js-ci-variable-input-value')
.val('foo')
.trigger('input');
expect($placeholder.hasClass(HIDE_CLASS)).toBe(true);
expect($inputValue.hasClass(HIDE_CLASS)).toBe(false);
variableList.hideValues();
expect($placeholder.hasClass(HIDE_CLASS)).toBe(false);
expect($inputValue.hasClass(HIDE_CLASS)).toBe(true);
});
});
});
......@@ -15,7 +15,6 @@ RSpec.describe 'Groups (JavaScript fixtures)', type: :controller do
end
before do
stub_feature_flags(new_variables_ui: false)
group.add_maintainer(admin)
sign_in(admin)
end
......@@ -27,12 +26,4 @@ RSpec.describe 'Groups (JavaScript fixtures)', type: :controller do
expect(response).to be_successful
end
end
describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'groups/ci_cd_settings.html' do
get :show, params: { group_id: group }
expect(response).to be_successful
end
end
end
......@@ -20,7 +20,6 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
end
before do
stub_feature_flags(new_variables_ui: false)
project.add_maintainer(admin)
sign_in(admin)
allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon')
......@@ -58,27 +57,4 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
expect(response).to be_successful
end
end
describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'projects/ci_cd_settings.html' do
get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project
}
expect(response).to be_successful
end
it 'projects/ci_cd_settings_with_variables.html' do
create(:ci_variable, project: project_variable_populated)
create(:ci_variable, project: project_variable_populated)
get :show, params: {
namespace_id: project_variable_populated.namespace.to_param,
project_id: project_variable_populated
}
expect(response).to be_successful
end
end
end
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