diff --git a/src/WebformBuilder.js b/src/WebformBuilder.js index de38ce9d6b..407d699be4 100644 --- a/src/WebformBuilder.js +++ b/src/WebformBuilder.js @@ -1289,6 +1289,9 @@ export default class WebformBuilder extends Component { highlightInvalidComponents() { const repeatablePaths = this.findRepeatablePaths(); let hasInvalidComponents = false; + // Matches anything expect letters and '_' at the beginning of the key and anything except of letters, numbers, + // '-', '.' and '_' in the rest of the key + const badCharacters = /^[^A-Za-z_]+|[^A-Za-z0-9\-._]+/g; this.webform.everyComponent((comp) => { const path = comp.path; @@ -1296,6 +1299,11 @@ export default class WebformBuilder extends Component { comp.setCustomValidity(this.t('apiKey', { key: comp.key })); hasInvalidComponents = true; } + + if (comp.key.replace(badCharacters, '') === '') { + comp.setCustomValidity(this.t('apiKeyNotValid', { key: comp.key })); + hasInvalidComponents = true; + } }); this.emit('builderFormValidityChange', hasInvalidComponents); diff --git a/src/translations/en.js b/src/translations/en.js index aa3df6b2e1..163e241fb6 100644 --- a/src/translations/en.js +++ b/src/translations/en.js @@ -76,6 +76,7 @@ export default { reCaptchaTokenValidationError: 'ReCAPTCHA: Token validation error', reCaptchaTokenNotSpecifiedError: 'ReCAPTCHA: Token is not specified in submission', apiKey: 'API Key is not unique: {{key}}', + apiKeyNotValid: 'API Key is not valid: {{key}}', typeRemaining: '{{ remaining }} {{ type }} remaining.', typeCount: '{{ count }} {{ type }}', requiredDayField: '{{ field }} is required', diff --git a/test/forms/formWithNumericKeys.js b/test/forms/formWithNumericKeys.js new file mode 100644 index 0000000000..3e76bea557 --- /dev/null +++ b/test/forms/formWithNumericKeys.js @@ -0,0 +1,30 @@ +export default { + type: 'form', + display: 'form', + components: [ + { + label: 'Text Field', + applyMaskOn: 'change', + tableView: true, + key: 'test', + type: 'textfield', + input: true, + }, + { + label: 'Text Field', + applyMaskOn: 'change', + tableView: true, + key: '1234', + type: 'textfield', + input: true, + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], +}; diff --git a/test/unit/WebformBuilder.unit.js b/test/unit/WebformBuilder.unit.js index 2ef7149a91..21911c8346 100644 --- a/test/unit/WebformBuilder.unit.js +++ b/test/unit/WebformBuilder.unit.js @@ -10,6 +10,7 @@ import testApiKeysUniquifying from '../forms/testApiKeysUniquifying'; import formBasedOnWizard from '../forms/formBasedOnWizard'; import formWithFormController from '../forms/formWithFormController'; import simpleWebform from '../forms/simpleWebform'; +import formWithNumericKeys from '../forms/formWithNumericKeys'; global.requestAnimationFrame = (cb) => cb(); global.cancelAnimationFrame = () => {}; @@ -378,7 +379,17 @@ describe('WebformBuilder tests', function() { }, 200); }, 200) }).catch(done); - }) + }); + + it('Should show API error when components have invalid API keys', (done) => { + const builder = Harness.getBuilder(); + builder.webform.setForm(formWithNumericKeys).then(() => { + builder.highlightInvalidComponents(); + const component = builder.webform.components[1]; + assert.equal(component.refs.messageContainer.textContent.trim(), 'apiKeyNotValid'); + done(); + }).catch(done); + }); }); describe('Select Component selectData property', () => {