Skip to content

Commit 3991ab5

Browse files
feat: restrict user to enter space in signup component input field (#1107)
1 parent 0f0b914 commit 3991ab5

File tree

3 files changed

+206
-3
lines changed

3 files changed

+206
-3
lines changed

app/components/new-signup/input.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
placeholder="Darth"
1414
aria-labelledby="signup-form-label"
1515
{{on "input" this.inputFieldChanged}}
16+
{{on "keydown" this.handleKeydown}}
1617
data-test-signup-form-input
1718
/>
1819
{{#if @error}}

app/components/new-signup/input.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,31 @@ export default class SignupComponent extends Component {
99
return LABEL_TEXT[currentStep];
1010
}
1111

12-
@action inputFieldChanged({ target: { value } }) {
12+
@action inputFieldChanged(event) {
1313
const { onChange, currentStep } = this.args;
14-
onChange(currentStep, value);
14+
15+
const rawValue = event.target.value;
16+
17+
if (/\s/.test(rawValue)) {
18+
const cursorPosition = event.target.selectionStart;
19+
const sanitizedInput = rawValue.replace(/\s/g, '');
20+
21+
const textBeforeCursor = rawValue.substring(0, cursorPosition);
22+
const spacesBeforeCursor = (textBeforeCursor.match(/\s/g) || []).length;
23+
const newCursorPosition = cursorPosition - spacesBeforeCursor;
24+
25+
event.target.value = sanitizedInput;
26+
event.target.setSelectionRange(newCursorPosition, newCursorPosition);
27+
28+
onChange(currentStep, sanitizedInput);
29+
} else {
30+
onChange(currentStep, rawValue);
31+
}
32+
}
33+
34+
@action handleKeydown(event) {
35+
if (/\s/.test(event.key)) {
36+
event.preventDefault();
37+
}
1538
}
1639
}

tests/integration/components/new-signup/input-test.js

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { module, test } from 'qunit';
22
import { setupRenderingTest } from 'website-www/tests/helpers';
3-
import { render } from '@ember/test-helpers';
3+
import { render, triggerEvent, typeIn } from '@ember/test-helpers';
44
import { hbs } from 'ember-cli-htmlbars';
55
import { NEW_SIGNUP_STEPS } from 'website-www/constants/new-signup';
66

@@ -136,4 +136,183 @@ module('Integration | Component | new-signup/input', function (hooks) {
136136

137137
assert.dom('[data-test-button="signup"]').isDisabled();
138138
});
139+
140+
module('whitespace handling', function (hooks) {
141+
hooks.beforeEach(function () {
142+
this.setProperties({
143+
currentStep: 'firstName',
144+
onChange: (step, value) => {
145+
this.inputValue = value;
146+
},
147+
onClick: () => {},
148+
});
149+
});
150+
151+
test('should prevent single space when typing', async function (assert) {
152+
await render(hbs`
153+
<NewSignup::Input
154+
@currentStep={{this.currentStep}}
155+
@onChange={{this.onChange}}
156+
@onClick={{this.onClick}}
157+
/>
158+
`);
159+
160+
const input = this.element.querySelector('[data-test-signup-form-input]');
161+
162+
await typeIn(input, 'John Doe');
163+
164+
assert
165+
.dom(input)
166+
.hasValue('JohnDoe', 'Single space should be prevented when typing');
167+
});
168+
169+
test('should remove multiple consecutive spaces when typing', async function (assert) {
170+
await render(hbs`
171+
<NewSignup::Input
172+
@currentStep={{this.currentStep}}
173+
@onChange={{this.onChange}}
174+
@onClick={{this.onClick}}
175+
/>
176+
`);
177+
178+
const input = this.element.querySelector('[data-test-signup-form-input]');
179+
180+
await typeIn(input, 'John Doe');
181+
182+
assert
183+
.dom(input)
184+
.hasValue('JohnDoe', 'Multiple consecutive spaces should be removed');
185+
});
186+
187+
test('should remove single space when pasting', async function (assert) {
188+
await render(hbs`
189+
<NewSignup::Input
190+
@currentStep={{this.currentStep}}
191+
@onChange={{this.onChange}}
192+
@onClick={{this.onClick}}
193+
/>
194+
`);
195+
196+
const input = this.element.querySelector('[data-test-signup-form-input]');
197+
input.value = 'John Doe';
198+
await triggerEvent(input, 'input');
199+
200+
assert.strictEqual(
201+
this.inputValue,
202+
'JohnDoe',
203+
'Single space should be removed when pasting',
204+
);
205+
assert.dom(input).hasValue('JohnDoe');
206+
});
207+
208+
test('should remove leading and trailing spaces when pasting', async function (assert) {
209+
await render(hbs`
210+
<NewSignup::Input
211+
@currentStep={{this.currentStep}}
212+
@onChange={{this.onChange}}
213+
@onClick={{this.onClick}}
214+
/>
215+
`);
216+
217+
const input = this.element.querySelector('[data-test-signup-form-input]');
218+
input.value = ' John Doe ';
219+
await triggerEvent(input, 'input');
220+
221+
assert.strictEqual(
222+
this.inputValue,
223+
'JohnDoe',
224+
'Leading and trailing spaces should be removed',
225+
);
226+
assert.dom(input).hasValue('JohnDoe');
227+
});
228+
229+
test('should handle input with only spaces', async function (assert) {
230+
await render(hbs`
231+
<NewSignup::Input
232+
@currentStep={{this.currentStep}}
233+
@onChange={{this.onChange}}
234+
@onClick={{this.onClick}}
235+
/>
236+
`);
237+
238+
const input = this.element.querySelector('[data-test-signup-form-input]');
239+
input.value = ' ';
240+
await triggerEvent(input, 'input');
241+
242+
assert.strictEqual(
243+
this.inputValue,
244+
'',
245+
'Input with only spaces should result in empty string',
246+
);
247+
assert.dom(input).hasValue('');
248+
});
249+
250+
test('should remove mixed whitespace characters when pasting', async function (assert) {
251+
await render(hbs`
252+
<NewSignup::Input
253+
@currentStep={{this.currentStep}}
254+
@onChange={{this.onChange}}
255+
@onClick={{this.onClick}}
256+
/>
257+
`);
258+
259+
const input = this.element.querySelector('[data-test-signup-form-input]');
260+
input.value = 'John\t\nDoe';
261+
await triggerEvent(input, 'input');
262+
263+
assert.strictEqual(
264+
this.inputValue,
265+
'JohnDoe',
266+
'Tabs and newlines should be removed',
267+
);
268+
assert.dom(input).hasValue('JohnDoe');
269+
});
270+
271+
test('should accept text without whitespace', async function (assert) {
272+
await render(hbs`
273+
<NewSignup::Input
274+
@currentStep={{this.currentStep}}
275+
@onChange={{this.onChange}}
276+
@onClick={{this.onClick}}
277+
/>
278+
`);
279+
280+
const input = this.element.querySelector('[data-test-signup-form-input]');
281+
282+
await typeIn(input, 'JohnDoe');
283+
284+
assert.strictEqual(
285+
this.inputValue,
286+
'JohnDoe',
287+
'Text without whitespace should be accepted as-is',
288+
);
289+
assert.dom(input).hasValue('JohnDoe');
290+
});
291+
292+
test('should handle combination of typing and pasting with whitespace', async function (assert) {
293+
await render(hbs`
294+
<NewSignup::Input
295+
@currentStep={{this.currentStep}}
296+
@onChange={{this.onChange}}
297+
@onClick={{this.onClick}}
298+
/>
299+
`);
300+
301+
const input = this.element.querySelector('[data-test-signup-form-input]');
302+
303+
// First type some text
304+
await typeIn(input, 'John ');
305+
306+
// Then paste text with spaces
307+
input.value = input.value + ' Doe Smith';
308+
await triggerEvent(input, 'input');
309+
310+
assert.strictEqual(
311+
this.inputValue,
312+
'JohnDoeSmith',
313+
'Combination of typing and pasting should remove all spaces',
314+
);
315+
assert.dom(input).hasValue('JohnDoeSmith');
316+
});
317+
});
139318
});

0 commit comments

Comments
 (0)