Skip to content

Commit

Permalink
Merge 594e923 into ea099a5
Browse files Browse the repository at this point in the history
  • Loading branch information
mstriemer committed Mar 3, 2016
2 parents ea099a5 + 594e923 commit 749ca8d
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 30 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ env:
matrix:
- TASK=lint
- TASK=unittest GUI=1
- TASK=unittest:server
global:
secure: m1hVHTy/jgPlj2Z79Gt++NFKKUIBMYtOVtU9WbQSTpAesspPvNZbfirUSdo/50rfLD9UWO9RGITWbBx9JJ6QakbxN0reTC40O/dbJOWmhr97vZwLNENmfqfgAttb3U1WYC0BcdYo3XsKz/8dsQVhXHDLgq+WUeyj+y7Ku+R71pZgJxDuTCzyUCEXGotVMwMtWx6JjlZtyjyJX+Ec8Em2aC81z9Udcm60cFFr7RXMpSMkOeKBj7ujCUxXsIoxTigXJaWQOcsUcBNG9Gh2QO3ATc1YiRdXhxqi3O8yVAJUpm6Lt4gBk9VAGN01cIJzOZzYq5GqwmgR8ZrRBtz/8rQL/KDQLxpuo1K9iEZ1d6OXDgcdY6CpgguFKsRhLnB758LQ51ZA4K5pTSxPPN7yY39c2tRz7GqR97TMafg5lRqBEVp9qH4dlFowh1lOOEM9swO5cljc/92HsOqd2XMRP4CmatAbb25plLYnVL4tBdQrFQzluhkYHkYcpPBSwJRAITRTlvZ28jHf7ert9u+f7jUthGxbI6RpLmAwuynWcHaWjJpBRenfAOHMUWzfzMix9Zn4gS70AC1RaPuC1DMgH/jcTaR7Q3hscTrdmarHD0kSOiIvJcZp767EtNeifiW1DOHW2vWOrrgKeXm0XwQ72jlIbKkJLykjWdpjFJmMcqec9/U=
cache:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dev:disco": "APP_NAME=disco npm run dev",
"test": "npm run version-check && npm run unittest && npm run lint",
"unittest:dev": "karma start",
"unittest:server": "NODE_PATH=src:$NODE_PATH mocha --compilers js:babel-register tests/**/Test*.js",
"unittest": "karma start --single-run",
"lint": "eslint .",
"eslint": "npm run lint",
Expand Down
7 changes: 6 additions & 1 deletion src/search/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import SearchForm from './SearchForm';
import SearchResults from './SearchResults';

export default class App extends React.Component {
state = {query: '', results: []}

state = {
query: null,
results: [],
}

handleSearch = (query) => {
const results = [{title: 'Foo'}, {title: 'Bar'}, {title: 'Baz'}];
Expand All @@ -15,6 +19,7 @@ export default class App extends React.Component {
const { query, results } = this.state;
return (
<div className="search-app">
<h1>Add-on Search</h1>
<SearchForm onSearch={this.handleSearch} />
<SearchResults results={results} query={query} />
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/search/components/SearchForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default class SearchForm extends React.Component {
render() {
return (
<form ref="form" className="search-form" onSubmit={this.handleSubmit}>
<input ref="query" type="text" name="q" placeholder="Search" />
<input ref="query" type="search" name="q" placeholder="Search" />
<button ref="submit" type="submit">Search</button>
</form>
);
Expand Down
32 changes: 29 additions & 3 deletions src/search/components/SearchResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,42 @@ export default class SearchResults extends React.Component {
}

static defaultProps = {
query: '',
query: null,
results: [],
}

render() {
const { query, results } = this.props;
const searchResultsClass = 'search-results';

let searchResults;

if (query && results.length > 0) {
searchResults = (
<div className={searchResultsClass}>
<p>Your search for "{query}" returned {results.length} results.</p>
<ul>
{results.map((result) => <li key={result.title}>{result.title}</li>)}
</ul>
</div>
);
} else if (query && results.length === 0) {
searchResults = (
<div className={searchResultsClass}>
<p>No results were found for "{query}".</p>
</div>
);
} else if (query !== null) {
searchResults = (
<div className={searchResultsClass}>
<p>Please supply a valid search</p>
</div>
);
}

return (
<div className="search-results">
<h3>Your search for "{query}" returned {results.length} results.</h3>
{results.map((result) => <div key={result.title}>{result.title}</div>)}
{searchResults}
</div>
);
}
Expand Down
11 changes: 0 additions & 11 deletions src/search/components/hello-world.js

This file was deleted.

53 changes: 39 additions & 14 deletions tests/search/components/TestSearchForm.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import { createRenderer, renderIntoDocument, Simulate } from 'react-addons-test-utils';

import SearchForm from 'search/components/SearchForm';

const render = ReactTestUtils.renderIntoDocument;
const findByTag = ReactTestUtils.findRenderedDOMComponentWithTag;
if (typeof window === 'undefined' && typeof global !== 'undefined') {
global.sinon = require('sinon');
global.assert = require('chai').assert;
}

function browser(message, test) {
if (typeof document === 'undefined') {
xit(message, test);
} else {
it(message, test);
}
}

function render(component) {
const renderer = createRenderer();
renderer.render(component);
return renderer.getRenderOutput();
}

describe('<SearchForm />', () => {
let onSearch;
let root;

beforeEach(() => {
onSearch = sinon.spy();
root = render(<SearchForm onSearch={onSearch} />);
});

it('is a form', () => {
assert.equal(root.type, 'form');
assert.equal(root.props.className, 'search-form');
});

it('renders a form', () => {
const root = render(<SearchForm onSearch={sinon.spy()} />);
const form = findByTag(root, 'form');
assert.ok(form.classList.contains('search-form'));
assert.include(root.props.className, 'search-form');
});

it('renders a search input', () => {
const root = render(<SearchForm onSearch={sinon.spy()} />);
const input = findByTag(root, 'input');
assert.equal(input.placeholder, 'Search');
assert.equal(input.type, 'text');
const query = root.props.children.filter(({ ref }) => ref === 'query')[0];
assert.equal(query.props.placeholder, 'Search');
assert.equal(query.props.type, 'search');
});

it('calls onSearch with a search query', () => {
const onSearch = sinon.spy();
const root = render(<SearchForm onSearch={onSearch} />);
browser('calls onSearch with a search query', () => {
root = renderIntoDocument(<SearchForm onSearch={onSearch} />);
root.refs.query.value = 'adblock';
ReactTestUtils.Simulate.submit(root.refs.form);
Simulate.submit(root.refs.form);
assert.ok(onSearch.calledWith('adblock'));
});
});
66 changes: 66 additions & 0 deletions tests/search/components/TestSearchResults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';

import SearchResults from 'search/components/SearchResults';

const render = ReactTestUtils.renderIntoDocument;
const findByTag = ReactTestUtils.findRenderedDOMComponentWithTag;
const findByClass = ReactTestUtils.findRenderedDOMComponentWithClass;
const isDOMComponent = ReactTestUtils.isDOMComponent;

if (typeof window === 'undefined' && typeof global !== 'undefined') {
global.sinon = require('sinon');
global.assert = require('chai').assert;
}

function browser(message, test) {
if (typeof document === 'undefined') {
xit(message, test);
} else {
it(message, test);
}
}


describe('<SearchResults />', () => {
function renderResults(props) {
return render(<SearchResults {...props} />);
}

browser('renders empty search results container', () => {
const root = renderResults();
const searchResults = findByClass(root, 'search-results');
assert.ok(isDOMComponent(searchResults));
assert.equal(searchResults.childNodes.length, 0);
});

browser('renders error when query is an empty string', () => {
const root = renderResults({query: ''});
const searchResultsMsg = findByTag(root, 'p');
assert.include(searchResultsMsg.firstChild.nodeValue, 'supply a valid search');
});

browser('renders error when no results and valid query', () => {
const root = renderResults({query: 'test'});
const searchResultsMsg = findByTag(root, 'p');
// Using textContent here since we want to see the text inside the p.
// Since it has dynamic content is wrapped in a span implicitly.
assert.include(searchResultsMsg.textContent, 'No results were found');
});

browser('renders search results when supplied', () => {
const root = renderResults({
query: 'test',
results: [
{title: 'result 1'},
{title: 'result 2'},
],
});
const searchResultsMsg = findByTag(root, 'p');
assert.include(searchResultsMsg.textContent, 'Your search for "test" returned 2');

const searchResultsList = findByTag(root, 'ul');
assert.include(searchResultsList.textContent, 'result 1');
assert.include(searchResultsList.textContent, 'result 2');
});
});

0 comments on commit 749ca8d

Please sign in to comment.