diff --git a/app/components/new-signup/input.hbs b/app/components/new-signup/input.hbs index 5e5e4e56..eff2476a 100644 --- a/app/components/new-signup/input.hbs +++ b/app/components/new-signup/input.hbs @@ -13,6 +13,7 @@ placeholder="Darth" aria-labelledby="signup-form-label" {{on "input" this.inputFieldChanged}} + {{on "keydown" this.handleKeydown}} data-test-signup-form-input /> {{#if @error}} diff --git a/app/components/new-signup/input.js b/app/components/new-signup/input.js index abe24686..4e4210a5 100644 --- a/app/components/new-signup/input.js +++ b/app/components/new-signup/input.js @@ -9,8 +9,31 @@ export default class SignupComponent extends Component { return LABEL_TEXT[currentStep]; } - @action inputFieldChanged({ target: { value } }) { + @action inputFieldChanged(event) { const { onChange, currentStep } = this.args; - onChange(currentStep, value); + + const rawValue = event.target.value; + + if (/\s/.test(rawValue)) { + const cursorPosition = event.target.selectionStart; + const sanitizedInput = rawValue.replace(/\s/g, ''); + + const textBeforeCursor = rawValue.substring(0, cursorPosition); + const spacesBeforeCursor = (textBeforeCursor.match(/\s/g) || []).length; + const newCursorPosition = cursorPosition - spacesBeforeCursor; + + event.target.value = sanitizedInput; + event.target.setSelectionRange(newCursorPosition, newCursorPosition); + + onChange(currentStep, sanitizedInput); + } else { + onChange(currentStep, rawValue); + } + } + + @action handleKeydown(event) { + if (/\s/.test(event.key)) { + event.preventDefault(); + } } } diff --git a/tests/integration/components/new-signup/input-test.js b/tests/integration/components/new-signup/input-test.js index e993372b..d9212b88 100644 --- a/tests/integration/components/new-signup/input-test.js +++ b/tests/integration/components/new-signup/input-test.js @@ -1,6 +1,6 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'website-www/tests/helpers'; -import { render } from '@ember/test-helpers'; +import { render, triggerEvent, typeIn } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import { NEW_SIGNUP_STEPS } from 'website-www/constants/new-signup'; @@ -136,4 +136,183 @@ module('Integration | Component | new-signup/input', function (hooks) { assert.dom('[data-test-button="signup"]').isDisabled(); }); + + module('whitespace handling', function (hooks) { + hooks.beforeEach(function () { + this.setProperties({ + currentStep: 'firstName', + onChange: (step, value) => { + this.inputValue = value; + }, + onClick: () => {}, + }); + }); + + test('should prevent single space when typing', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + + await typeIn(input, 'John Doe'); + + assert + .dom(input) + .hasValue('JohnDoe', 'Single space should be prevented when typing'); + }); + + test('should remove multiple consecutive spaces when typing', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + + await typeIn(input, 'John Doe'); + + assert + .dom(input) + .hasValue('JohnDoe', 'Multiple consecutive spaces should be removed'); + }); + + test('should remove single space when pasting', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + input.value = 'John Doe'; + await triggerEvent(input, 'input'); + + assert.strictEqual( + this.inputValue, + 'JohnDoe', + 'Single space should be removed when pasting', + ); + assert.dom(input).hasValue('JohnDoe'); + }); + + test('should remove leading and trailing spaces when pasting', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + input.value = ' John Doe '; + await triggerEvent(input, 'input'); + + assert.strictEqual( + this.inputValue, + 'JohnDoe', + 'Leading and trailing spaces should be removed', + ); + assert.dom(input).hasValue('JohnDoe'); + }); + + test('should handle input with only spaces', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + input.value = ' '; + await triggerEvent(input, 'input'); + + assert.strictEqual( + this.inputValue, + '', + 'Input with only spaces should result in empty string', + ); + assert.dom(input).hasValue(''); + }); + + test('should remove mixed whitespace characters when pasting', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + input.value = 'John\t\nDoe'; + await triggerEvent(input, 'input'); + + assert.strictEqual( + this.inputValue, + 'JohnDoe', + 'Tabs and newlines should be removed', + ); + assert.dom(input).hasValue('JohnDoe'); + }); + + test('should accept text without whitespace', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + + await typeIn(input, 'JohnDoe'); + + assert.strictEqual( + this.inputValue, + 'JohnDoe', + 'Text without whitespace should be accepted as-is', + ); + assert.dom(input).hasValue('JohnDoe'); + }); + + test('should handle combination of typing and pasting with whitespace', async function (assert) { + await render(hbs` + + `); + + const input = this.element.querySelector('[data-test-signup-form-input]'); + + // First type some text + await typeIn(input, 'John '); + + // Then paste text with spaces + input.value = input.value + ' Doe Smith'; + await triggerEvent(input, 'input'); + + assert.strictEqual( + this.inputValue, + 'JohnDoeSmith', + 'Combination of typing and pasting should remove all spaces', + ); + assert.dom(input).hasValue('JohnDoeSmith'); + }); + }); });