Moves form related JS modules out of global
This commit is contained in:
parent
a30417e5c5
commit
44d3745e51
8 changed files with 224 additions and 233 deletions
|
@ -79,6 +79,8 @@ import initChangesDropdown from './init_changes_dropdown';
|
|||
import AbuseReports from './abuse_reports';
|
||||
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
|
||||
import AjaxLoadingSpinner from './ajax_loading_spinner';
|
||||
import GlFieldErrors from './gl_field_errors';
|
||||
import GLForm from './gl_form';
|
||||
import U2FAuthenticate from './u2f/authenticate';
|
||||
|
||||
(function() {
|
||||
|
@ -230,7 +232,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
case 'groups:milestones:update':
|
||||
new ZenMode();
|
||||
new gl.DueDateSelectors();
|
||||
new gl.GLForm($('.milestone-form'), true);
|
||||
new GLForm($('.milestone-form'), true);
|
||||
break;
|
||||
case 'projects:compare:show':
|
||||
new gl.Diff();
|
||||
|
@ -247,7 +249,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
case 'projects:issues:new':
|
||||
case 'projects:issues:edit':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
new gl.GLForm($('.issue-form'), true);
|
||||
new GLForm($('.issue-form'), true);
|
||||
new IssuableForm($('.issue-form'));
|
||||
new LabelsSelect();
|
||||
new MilestoneSelect();
|
||||
|
@ -271,7 +273,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
case 'projects:merge_requests:edit':
|
||||
new gl.Diff();
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
new gl.GLForm($('.merge-request-form'), true);
|
||||
new GLForm($('.merge-request-form'), true);
|
||||
new IssuableForm($('.merge-request-form'));
|
||||
new LabelsSelect();
|
||||
new MilestoneSelect();
|
||||
|
@ -280,7 +282,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
break;
|
||||
case 'projects:tags:new':
|
||||
new ZenMode();
|
||||
new gl.GLForm($('.tag-form'), true);
|
||||
new GLForm($('.tag-form'), true);
|
||||
new RefSelectDropdown($('.js-branch-select'));
|
||||
break;
|
||||
case 'projects:snippets:show':
|
||||
|
@ -290,17 +292,17 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
case 'projects:snippets:edit':
|
||||
case 'projects:snippets:create':
|
||||
case 'projects:snippets:update':
|
||||
new gl.GLForm($('.snippet-form'), true);
|
||||
new GLForm($('.snippet-form'), true);
|
||||
break;
|
||||
case 'snippets:new':
|
||||
case 'snippets:edit':
|
||||
case 'snippets:create':
|
||||
case 'snippets:update':
|
||||
new gl.GLForm($('.snippet-form'), false);
|
||||
new GLForm($('.snippet-form'), false);
|
||||
break;
|
||||
case 'projects:releases:edit':
|
||||
new ZenMode();
|
||||
new gl.GLForm($('.release-form'), true);
|
||||
new GLForm($('.release-form'), true);
|
||||
break;
|
||||
case 'projects:merge_requests:show':
|
||||
new gl.Diff();
|
||||
|
@ -606,7 +608,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
new Wikis();
|
||||
shortcut_handler = new ShortcutsWiki();
|
||||
new ZenMode();
|
||||
new gl.GLForm($('.wiki-form'), true);
|
||||
new GLForm($('.wiki-form'), true);
|
||||
break;
|
||||
case 'snippets':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
|
@ -657,7 +659,7 @@ import U2FAuthenticate from './u2f/authenticate';
|
|||
|
||||
Dispatcher.prototype.initFieldErrors = function() {
|
||||
$('.gl-show-field-errors').each((i, form) => {
|
||||
new gl.GlFieldErrors(form);
|
||||
new GlFieldErrors(form);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ const inputErrorClass = 'gl-field-error-outline';
|
|||
const errorAnchorSelector = '.gl-field-error-anchor';
|
||||
const ignoreInputSelector = '.gl-field-error-ignore';
|
||||
|
||||
class GlFieldError {
|
||||
export default class GlFieldError {
|
||||
constructor({ input, formErrors }) {
|
||||
this.inputElement = $(input);
|
||||
this.inputDomElement = this.inputElement.get(0);
|
||||
|
@ -159,6 +159,3 @@ class GlFieldError {
|
|||
this.fieldErrorElement.hide();
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.GlFieldError = GlFieldError;
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */
|
||||
|
||||
import './gl_field_error';
|
||||
import GlFieldError from './gl_field_error';
|
||||
|
||||
const customValidationFlag = 'gl-field-error-ignore';
|
||||
|
||||
class GlFieldErrors {
|
||||
export default class GlFieldErrors {
|
||||
constructor(form) {
|
||||
this.form = $(form);
|
||||
this.state = {
|
||||
inputs: [],
|
||||
valid: false
|
||||
valid: false,
|
||||
};
|
||||
this.initValidators();
|
||||
}
|
||||
|
||||
initValidators () {
|
||||
initValidators() {
|
||||
// register selectors here as needed
|
||||
const validateSelectors = [':text', ':password', '[type=email]']
|
||||
.map((selector) => `input${selector}`).join(',');
|
||||
.map(selector => `input${selector}`).join(',');
|
||||
|
||||
this.state.inputs = this.form.find(validateSelectors).toArray()
|
||||
.filter((input) => !input.classList.contains(customValidationFlag))
|
||||
.map((input) => new window.gl.GlFieldError({ input, formErrors: this }));
|
||||
.filter(input => !input.classList.contains(customValidationFlag))
|
||||
.map(input => new GlFieldError({ input, formErrors: this }));
|
||||
|
||||
this.form.on('submit', this.catchInvalidFormSubmit);
|
||||
this.form.on('submit', GlFieldErrors.catchInvalidFormSubmit);
|
||||
}
|
||||
|
||||
/* Neccessary to prevent intercept and override invalid form submit
|
||||
* because Safari & iOS quietly allow form submission when form is invalid
|
||||
* and prevents disabling of invalid submit button by application.js */
|
||||
|
||||
catchInvalidFormSubmit (event) {
|
||||
const $form = $(event.currentTarget);
|
||||
static catchInvalidFormSubmit(e) {
|
||||
const $form = $(e.currentTarget);
|
||||
|
||||
if (!$form.attr('novalidate')) {
|
||||
if (!event.currentTarget.checkValidity()) {
|
||||
|
@ -50,11 +48,9 @@ class GlFieldErrors {
|
|||
});
|
||||
}
|
||||
|
||||
focusOnFirstInvalid () {
|
||||
const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0];
|
||||
focusOnFirstInvalid() {
|
||||
const firstInvalid = this.state.inputs
|
||||
.filter(input => !input.inputDomElement.validity.valid)[0];
|
||||
firstInvalid.inputElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.GlFieldErrors = GlFieldErrors;
|
||||
|
|
|
@ -1,104 +1,99 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, max-len */
|
||||
/* global GitLab */
|
||||
/* global DropzoneInput */
|
||||
/* global autosize */
|
||||
|
||||
import GfmAutoComplete from './gfm_auto_complete';
|
||||
|
||||
window.gl = window.gl || {};
|
||||
|
||||
function GLForm(form, enableGFM = false) {
|
||||
this.form = form;
|
||||
this.textarea = this.form.find('textarea.js-gfm-input');
|
||||
this.enableGFM = enableGFM;
|
||||
// Before we start, we should clean up any previous data for this form
|
||||
this.destroy();
|
||||
// Setup the form
|
||||
this.setupForm();
|
||||
this.form.data('gl-form', this);
|
||||
}
|
||||
|
||||
GLForm.prototype.destroy = function() {
|
||||
// Clean form listeners
|
||||
this.clearEventListeners();
|
||||
if (this.autoComplete) {
|
||||
this.autoComplete.destroy();
|
||||
export default class GLForm {
|
||||
constructor(form, enableGFM = false) {
|
||||
this.form = form;
|
||||
this.textarea = this.form.find('textarea.js-gfm-input');
|
||||
this.enableGFM = enableGFM;
|
||||
// Before we start, we should clean up any previous data for this form
|
||||
this.destroy();
|
||||
// Setup the form
|
||||
this.setupForm();
|
||||
this.form.data('gl-form', this);
|
||||
}
|
||||
return this.form.data('gl-form', null);
|
||||
};
|
||||
|
||||
GLForm.prototype.setupForm = function() {
|
||||
var isNewForm;
|
||||
isNewForm = this.form.is(':not(.gfm-form)');
|
||||
this.form.removeClass('js-new-note-form');
|
||||
if (isNewForm) {
|
||||
this.form.find('.div-dropzone').remove();
|
||||
this.form.addClass('gfm-form');
|
||||
// remove notify commit author checkbox for non-commit notes
|
||||
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
|
||||
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
|
||||
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
|
||||
emojis: true,
|
||||
members: this.enableGFM,
|
||||
issues: this.enableGFM,
|
||||
milestones: this.enableGFM,
|
||||
mergeRequests: this.enableGFM,
|
||||
labels: this.enableGFM,
|
||||
destroy() {
|
||||
// Clean form listeners
|
||||
this.clearEventListeners();
|
||||
if (this.autoComplete) {
|
||||
this.autoComplete.destroy();
|
||||
}
|
||||
this.form.data('gl-form', null);
|
||||
}
|
||||
|
||||
setupForm() {
|
||||
const isNewForm = this.form.is(':not(.gfm-form)');
|
||||
this.form.removeClass('js-new-note-form');
|
||||
if (isNewForm) {
|
||||
this.form.find('.div-dropzone').remove();
|
||||
this.form.addClass('gfm-form');
|
||||
// remove notify commit author checkbox for non-commit notes
|
||||
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
|
||||
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
|
||||
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
|
||||
emojis: true,
|
||||
members: this.enableGFM,
|
||||
issues: this.enableGFM,
|
||||
milestones: this.enableGFM,
|
||||
mergeRequests: this.enableGFM,
|
||||
labels: this.enableGFM,
|
||||
});
|
||||
new DropzoneInput(this.form); // eslint-disable-line no-new
|
||||
autosize(this.textarea);
|
||||
}
|
||||
// form and textarea event listeners
|
||||
this.addEventListeners();
|
||||
gl.text.init(this.form);
|
||||
// hide discard button
|
||||
this.form.find('.js-note-discard').hide();
|
||||
this.form.show();
|
||||
if (this.isAutosizeable) this.setupAutosize();
|
||||
}
|
||||
|
||||
setupAutosize() {
|
||||
this.textarea.off('autosize:resized')
|
||||
.on('autosize:resized', this.setHeightData.bind(this));
|
||||
|
||||
this.textarea.off('mouseup.autosize')
|
||||
.on('mouseup.autosize', this.destroyAutosize.bind(this));
|
||||
|
||||
setTimeout(() => {
|
||||
autosize(this.textarea);
|
||||
this.textarea.css('resize', 'vertical');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
setHeightData() {
|
||||
this.textarea.data('height', this.textarea.outerHeight());
|
||||
}
|
||||
|
||||
destroyAutosize() {
|
||||
const outerHeight = this.textarea.outerHeight();
|
||||
|
||||
if (this.textarea.data('height') === outerHeight) return;
|
||||
|
||||
autosize.destroy(this.textarea);
|
||||
|
||||
this.textarea.data('height', outerHeight);
|
||||
this.textarea.outerHeight(outerHeight);
|
||||
this.textarea.css('max-height', window.outerHeight);
|
||||
}
|
||||
|
||||
clearEventListeners() {
|
||||
this.textarea.off('focus');
|
||||
this.textarea.off('blur');
|
||||
gl.text.removeListeners(this.form);
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
this.textarea.on('focus', function focusTextArea() {
|
||||
$(this).closest('.md-area').addClass('is-focused');
|
||||
});
|
||||
this.textarea.on('blur', function blurTextArea() {
|
||||
$(this).closest('.md-area').removeClass('is-focused');
|
||||
});
|
||||
new DropzoneInput(this.form);
|
||||
autosize(this.textarea);
|
||||
}
|
||||
// form and textarea event listeners
|
||||
this.addEventListeners();
|
||||
gl.text.init(this.form);
|
||||
// hide discard button
|
||||
this.form.find('.js-note-discard').hide();
|
||||
this.form.show();
|
||||
if (this.isAutosizeable) this.setupAutosize();
|
||||
};
|
||||
|
||||
GLForm.prototype.setupAutosize = function () {
|
||||
this.textarea.off('autosize:resized')
|
||||
.on('autosize:resized', this.setHeightData.bind(this));
|
||||
|
||||
this.textarea.off('mouseup.autosize')
|
||||
.on('mouseup.autosize', this.destroyAutosize.bind(this));
|
||||
|
||||
setTimeout(() => {
|
||||
autosize(this.textarea);
|
||||
this.textarea.css('resize', 'vertical');
|
||||
}, 0);
|
||||
};
|
||||
|
||||
GLForm.prototype.setHeightData = function () {
|
||||
this.textarea.data('height', this.textarea.outerHeight());
|
||||
};
|
||||
|
||||
GLForm.prototype.destroyAutosize = function () {
|
||||
const outerHeight = this.textarea.outerHeight();
|
||||
|
||||
if (this.textarea.data('height') === outerHeight) return;
|
||||
|
||||
autosize.destroy(this.textarea);
|
||||
|
||||
this.textarea.data('height', outerHeight);
|
||||
this.textarea.outerHeight(outerHeight);
|
||||
this.textarea.css('max-height', window.outerHeight);
|
||||
};
|
||||
|
||||
GLForm.prototype.clearEventListeners = function() {
|
||||
this.textarea.off('focus');
|
||||
this.textarea.off('blur');
|
||||
return gl.text.removeListeners(this.form);
|
||||
};
|
||||
|
||||
GLForm.prototype.addEventListeners = function() {
|
||||
this.textarea.on('focus', function() {
|
||||
return $(this).closest('.md-area').addClass('is-focused');
|
||||
});
|
||||
return this.textarea.on('blur', function() {
|
||||
return $(this).closest('.md-area').removeClass('is-focused');
|
||||
});
|
||||
};
|
||||
|
||||
window.gl.GLForm = GLForm;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'vendor/jquery.atwho';
|
|||
import AjaxCache from '~/lib/utils/ajax_cache';
|
||||
import Flash from './flash';
|
||||
import CommentTypeToggle from './comment_type_toggle';
|
||||
import GLForm from './gl_form';
|
||||
import loadAwardsHandler from './awards_handler';
|
||||
import './autosave';
|
||||
import './dropzone_input';
|
||||
|
@ -557,7 +558,7 @@ export default class Notes {
|
|||
*/
|
||||
setupNoteForm(form) {
|
||||
var textarea, key;
|
||||
new gl.GLForm(form, this.enableGFM);
|
||||
new GLForm(form, this.enableGFM);
|
||||
textarea = form.find('.js-note-text');
|
||||
key = [
|
||||
'Note',
|
||||
|
@ -1152,7 +1153,7 @@ export default class Notes {
|
|||
var targetId = $originalContentEl.data('target-id');
|
||||
var targetType = $originalContentEl.data('target-type');
|
||||
|
||||
new gl.GLForm($editForm.find('form'), this.enableGFM);
|
||||
new GLForm($editForm.find('form'), this.enableGFM);
|
||||
|
||||
$editForm.find('form')
|
||||
.attr('action', postUrl)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
import Translate from '../vue_shared/translate';
|
||||
import GlFieldErrors from '../gl_field_errors';
|
||||
import intervalPatternInput from './components/interval_pattern_input.vue';
|
||||
import TimezoneDropdown from './components/timezone_dropdown';
|
||||
import TargetBranchDropdown from './components/target_branch_dropdown';
|
||||
|
@ -39,7 +40,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
gl.timezoneDropdown = new TimezoneDropdown();
|
||||
gl.targetBranchDropdown = new TargetBranchDropdown();
|
||||
gl.pipelineScheduleFieldErrors = new gl.GlFieldErrors(formElement);
|
||||
gl.pipelineScheduleFieldErrors = new GlFieldErrors(formElement);
|
||||
|
||||
setupPipelineVariableList($('.js-pipeline-variable-list'));
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import Flash from '../../../flash';
|
||||
import GLForm from '../../../gl_form';
|
||||
import markdownHeader from './header.vue';
|
||||
import markdownToolbar from './toolbar.vue';
|
||||
|
||||
|
@ -85,7 +86,7 @@
|
|||
/*
|
||||
GLForm class handles all the toolbar buttons
|
||||
*/
|
||||
return new gl.GLForm($(this.$refs['gl-form']), true);
|
||||
return new GLForm($(this.$refs['gl-form']), true);
|
||||
},
|
||||
beforeDestroy() {
|
||||
const glForm = $(this.$refs['gl-form']).data('gl-form');
|
||||
|
|
|
@ -1,110 +1,108 @@
|
|||
/* eslint-disable space-before-function-paren, arrow-body-style */
|
||||
|
||||
import '~/gl_field_errors';
|
||||
import GlFieldErrors from '~/gl_field_errors';
|
||||
|
||||
((global) => {
|
||||
describe('GL Style Field Errors', function() {
|
||||
preloadFixtures('static/gl_field_errors.html.raw');
|
||||
|
||||
describe('GL Style Field Errors', function() {
|
||||
beforeEach(function() {
|
||||
loadFixtures('static/gl_field_errors.html.raw');
|
||||
const $form = this.$form = $('form.gl-show-field-errors');
|
||||
this.fieldErrors = new global.GlFieldErrors($form);
|
||||
});
|
||||
|
||||
it('should select the correct input elements', function() {
|
||||
expect(this.$form).toBeDefined();
|
||||
expect(this.$form.length).toBe(1);
|
||||
expect(this.fieldErrors).toBeDefined();
|
||||
const inputs = this.fieldErrors.state.inputs;
|
||||
expect(inputs.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should ignore elements with custom error handling', function() {
|
||||
const customErrorFlag = 'gl-field-error-ignore';
|
||||
const customErrorElem = $(`.${customErrorFlag}`);
|
||||
|
||||
expect(customErrorElem.length).toBe(1);
|
||||
|
||||
const customErrors = this.fieldErrors.state.inputs.filter((input) => {
|
||||
return input.inputElement.hasClass(customErrorFlag);
|
||||
});
|
||||
expect(customErrors.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not show any errors before submit attempt', function() {
|
||||
this.$form.find('.email').val('not-a-valid-email').keyup();
|
||||
this.$form.find('.text-required').val('').keyup();
|
||||
this.$form.find('.alphanumberic').val('?---*').keyup();
|
||||
|
||||
const errorsShown = this.$form.find('.gl-field-error-outline');
|
||||
expect(errorsShown.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should show errors when input valid is submitted', function() {
|
||||
this.$form.find('.email').val('not-a-valid-email').keyup();
|
||||
this.$form.find('.text-required').val('').keyup();
|
||||
this.$form.find('.alphanumberic').val('?---*').keyup();
|
||||
|
||||
this.$form.submit();
|
||||
|
||||
const errorsShown = this.$form.find('.gl-field-error-outline');
|
||||
expect(errorsShown.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should properly track validity state on input after invalid submission attempt', function() {
|
||||
this.$form.submit();
|
||||
|
||||
const emailInputModel = this.fieldErrors.state.inputs[1];
|
||||
const fieldState = emailInputModel.state;
|
||||
const emailInputElement = emailInputModel.inputElement;
|
||||
|
||||
// No input
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(true);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then invalid input
|
||||
emailInputElement.val('not-a-valid-email').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then valid input
|
||||
emailInputElement.val('email@gitlab.com').keyup();
|
||||
expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(true);
|
||||
|
||||
// Then invalid input
|
||||
emailInputElement.val('not-a-valid-email').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then empty input
|
||||
emailInputElement.val('').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(true);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then valid input
|
||||
emailInputElement.val('email@gitlab.com').keyup();
|
||||
expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(true);
|
||||
});
|
||||
|
||||
it('should properly infer error messages', function() {
|
||||
this.$form.submit();
|
||||
const trackedInputs = this.fieldErrors.state.inputs;
|
||||
const inputHasTitle = trackedInputs[1];
|
||||
const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error');
|
||||
const inputNoTitle = trackedInputs[2];
|
||||
const noTitleErrorElem = inputNoTitle.inputElement.siblings('.gl-field-error');
|
||||
|
||||
expect(noTitleErrorElem.text()).toBe('This field is required.');
|
||||
expect(hasTitleErrorElem.text()).toBe('Please provide a valid email address.');
|
||||
});
|
||||
beforeEach(function() {
|
||||
loadFixtures('static/gl_field_errors.html.raw');
|
||||
const $form = this.$form = $('form.gl-show-field-errors');
|
||||
this.fieldErrors = new GlFieldErrors($form);
|
||||
});
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
||||
it('should select the correct input elements', function() {
|
||||
expect(this.$form).toBeDefined();
|
||||
expect(this.$form.length).toBe(1);
|
||||
expect(this.fieldErrors).toBeDefined();
|
||||
const inputs = this.fieldErrors.state.inputs;
|
||||
expect(inputs.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should ignore elements with custom error handling', function() {
|
||||
const customErrorFlag = 'gl-field-error-ignore';
|
||||
const customErrorElem = $(`.${customErrorFlag}`);
|
||||
|
||||
expect(customErrorElem.length).toBe(1);
|
||||
|
||||
const customErrors = this.fieldErrors.state.inputs.filter((input) => {
|
||||
return input.inputElement.hasClass(customErrorFlag);
|
||||
});
|
||||
expect(customErrors.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not show any errors before submit attempt', function() {
|
||||
this.$form.find('.email').val('not-a-valid-email').keyup();
|
||||
this.$form.find('.text-required').val('').keyup();
|
||||
this.$form.find('.alphanumberic').val('?---*').keyup();
|
||||
|
||||
const errorsShown = this.$form.find('.gl-field-error-outline');
|
||||
expect(errorsShown.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should show errors when input valid is submitted', function() {
|
||||
this.$form.find('.email').val('not-a-valid-email').keyup();
|
||||
this.$form.find('.text-required').val('').keyup();
|
||||
this.$form.find('.alphanumberic').val('?---*').keyup();
|
||||
|
||||
this.$form.submit();
|
||||
|
||||
const errorsShown = this.$form.find('.gl-field-error-outline');
|
||||
expect(errorsShown.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should properly track validity state on input after invalid submission attempt', function() {
|
||||
this.$form.submit();
|
||||
|
||||
const emailInputModel = this.fieldErrors.state.inputs[1];
|
||||
const fieldState = emailInputModel.state;
|
||||
const emailInputElement = emailInputModel.inputElement;
|
||||
|
||||
// No input
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(true);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then invalid input
|
||||
emailInputElement.val('not-a-valid-email').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then valid input
|
||||
emailInputElement.val('email@gitlab.com').keyup();
|
||||
expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(true);
|
||||
|
||||
// Then invalid input
|
||||
emailInputElement.val('not-a-valid-email').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then empty input
|
||||
emailInputElement.val('').keyup();
|
||||
expect(emailInputElement).toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(true);
|
||||
expect(fieldState.valid).toBe(false);
|
||||
|
||||
// Then valid input
|
||||
emailInputElement.val('email@gitlab.com').keyup();
|
||||
expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
|
||||
expect(fieldState.empty).toBe(false);
|
||||
expect(fieldState.valid).toBe(true);
|
||||
});
|
||||
|
||||
it('should properly infer error messages', function() {
|
||||
this.$form.submit();
|
||||
const trackedInputs = this.fieldErrors.state.inputs;
|
||||
const inputHasTitle = trackedInputs[1];
|
||||
const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error');
|
||||
const inputNoTitle = trackedInputs[2];
|
||||
const noTitleErrorElem = inputNoTitle.inputElement.siblings('.gl-field-error');
|
||||
|
||||
expect(noTitleErrorElem.text()).toBe('This field is required.');
|
||||
expect(hasTitleErrorElem.text()).toBe('Please provide a valid email address.');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue