Unverified Commit 2b67c4c4 authored by Tamika Tannis's avatar Tamika Tannis Committed by GitHub

Prevent entering of ':' into search term (#414)

* Do not allow input of ':'

* Hook up potential error message

* Update error text and test
parent ed4e16ee
...@@ -4,3 +4,5 @@ export const PLACEHOLDER_DEFAULT = 'search for data resources...'; ...@@ -4,3 +4,5 @@ export const PLACEHOLDER_DEFAULT = 'search for data resources...';
export const BUTTON_CLOSE_TEXT = 'Close'; export const BUTTON_CLOSE_TEXT = 'Close';
export const SIZE_SMALL = 'small'; export const SIZE_SMALL = 'small';
export const INVALID_SYNTAX_MESSAGE = "Your search term contains invalid syntax ':'.";
...@@ -16,6 +16,7 @@ import './styles.scss'; ...@@ -16,6 +16,7 @@ import './styles.scss';
import { import {
BUTTON_CLOSE_TEXT, BUTTON_CLOSE_TEXT,
INVALID_SYNTAX_MESSAGE,
PLACEHOLDER_DEFAULT, PLACEHOLDER_DEFAULT,
SIZE_SMALL SIZE_SMALL
} from './constants'; } from './constants';
...@@ -92,6 +93,7 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> { ...@@ -92,6 +93,7 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
handleValueChange = (event: React.SyntheticEvent<HTMLInputElement>) : void => { handleValueChange = (event: React.SyntheticEvent<HTMLInputElement>) : void => {
const searchTerm = (event.target as HTMLInputElement).value.toLowerCase(); const searchTerm = (event.target as HTMLInputElement).value.toLowerCase();
if (this.isFormValid(searchTerm)) {
if (searchTerm.length > 0) { if (searchTerm.length > 0) {
this.props.onInputChange(searchTerm); this.props.onInputChange(searchTerm);
this.setState({ searchTerm, showTypeAhead: true }); this.setState({ searchTerm, showTypeAhead: true });
...@@ -99,12 +101,15 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> { ...@@ -99,12 +101,15 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
else { else {
this.clearSearchTerm(); this.clearSearchTerm();
} }
} else {
this.setState({ searchTerm, showTypeAhead: false });
}
}; };
handleValueSubmit = (event: React.FormEvent<HTMLFormElement>) : void => { handleValueSubmit = (event: React.FormEvent<HTMLFormElement>) : void => {
const searchTerm = this.state.searchTerm.trim(); const searchTerm = this.state.searchTerm.trim();
event.preventDefault(); event.preventDefault();
if (this.isFormValid()) { if (this.isFormValid(searchTerm)) {
this.props.submitSearch(searchTerm); this.props.submitSearch(searchTerm);
this.hideTypeAhead(); this.hideTypeAhead();
} }
...@@ -114,9 +119,20 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> { ...@@ -114,9 +119,20 @@ export class SearchBar extends React.Component<SearchBarProps, SearchBarState> {
this.setState({ showTypeAhead: false }); this.setState({ showTypeAhead: false });
}; };
isFormValid = () : boolean => { isFormValid = (searchTerm: string) : boolean => {
const form = document.getElementById("search-bar-form") as HTMLFormElement; const form = document.getElementById("search-bar-form") as HTMLFormElement;
return form.checkValidity(); const input = document.getElementById("search-input") as HTMLInputElement;
const isValid = searchTerm.indexOf(':') < 0;
/* This will set the error message, it must be explicitly set or cleared each time */
input.setCustomValidity(isValid ? "": INVALID_SYNTAX_MESSAGE)
if (searchTerm.length > 0) {
/* This will show the error message */
form.reportValidity();
}
return isValid;
}; };
onSelectInlineResult = (resourceType: ResourceType, updateUrl: boolean = false) : void => { onSelectInlineResult = (resourceType: ResourceType, updateUrl: boolean = false) : void => {
......
...@@ -90,12 +90,33 @@ describe('SearchBar', () => { ...@@ -90,12 +90,33 @@ describe('SearchBar', () => {
describe('handleValueChange', () => { describe('handleValueChange', () => {
let props; let props;
let wrapper; let wrapper;
let isFormValidSpy;
beforeAll(() => { beforeAll(() => {
const setupResult = setup(); const setupResult = setup();
props = setupResult.props; props = setupResult.props;
wrapper = setupResult.wrapper; wrapper = setupResult.wrapper;
isFormValidSpy = jest.spyOn(wrapper.instance(), 'isFormValid');
}); });
describe('when form is not valid', () => {
beforeAll(() => {
isFormValidSpy.mockImplementation(() => false)
})
it('updates the searchTerm (for visual feedback) and hides type ahead', () => {
setStateSpy.mockClear();
const testTerm = 'hello';
// @ts-ignore: mocked events throw type errors
wrapper.instance().handleValueChange({ target: { value: testTerm } });
expect(setStateSpy).toHaveBeenCalledWith({ searchTerm: testTerm, showTypeAhead: false });
})
})
describe('when form is valid', () => {
beforeAll(() => {
isFormValidSpy.mockImplementation(() => true)
})
describe('if searchTerm has length', () => { describe('if searchTerm has length', () => {
const mockSearchTerm = 'I have Length'; const mockSearchTerm = 'I have Length';
const expectedSearchTerm = 'i have length'; const expectedSearchTerm = 'i have length';
...@@ -123,6 +144,7 @@ describe('SearchBar', () => { ...@@ -123,6 +144,7 @@ describe('SearchBar', () => {
expect(clearSearchTermSpy).toHaveBeenCalled(); expect(clearSearchTermSpy).toHaveBeenCalled();
}); });
}); });
})
}); });
describe('handleValueSubmit', () => { describe('handleValueSubmit', () => {
......
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