Commit f7c1860b5bb9ed4bde0cd7198931fa2f48adb05d
1 parent
b2b910457f
Exists in
master
add basic acceptance tests for signup and login with Chimp
Showing
12 changed files
with
115 additions
and
55 deletions
Show diff stats
.meteor/packages
.meteor/versions
... | ... | @@ -24,6 +24,7 @@ caching-compiler@1.0.2 |
24 | 24 | caching-html-compiler@1.0.4 |
25 | 25 | callback-hook@1.0.6 |
26 | 26 | check@1.1.2 |
27 | +coffeescript@1.0.15 | |
27 | 28 | ddp@1.2.3 |
28 | 29 | ddp-client@1.2.3 |
29 | 30 | ddp-common@1.2.3 |
... | ... | @@ -66,6 +67,11 @@ npm-bcrypt@0.7.8_2 |
66 | 67 | npm-mongo@1.4.41 |
67 | 68 | observe-sequence@1.0.9 |
68 | 69 | ordered-dict@1.0.5 |
70 | +practicalmeteor:chai@2.1.0_1 | |
71 | +practicalmeteor:loglevel@1.2.0_2 | |
72 | +practicalmeteor:mocha@2.1.0_8 | |
73 | +practicalmeteor:mocha-core@0.1.4 | |
74 | +practicalmeteor:sinon@1.14.1_2 | |
69 | 75 | promise@0.6.5 |
70 | 76 | raix:eventemitter@0.1.3 |
71 | 77 | random@1.0.7 |
... | ... | @@ -84,14 +90,18 @@ spacebars-compiler@1.0.9 |
84 | 90 | srp@1.0.6 |
85 | 91 | standard-minifier-css@1.0.4 |
86 | 92 | standard-minifier-js@1.0.4 |
93 | +static-html@1.0.5 | |
87 | 94 | templating@1.1.7 |
88 | 95 | templating-tools@1.0.2 |
89 | 96 | themeteorchef:bert@2.1.0 |
90 | 97 | themeteorchef:jquery-validation@1.14.0 |
91 | 98 | tmeasday:check-npm-versions@0.2.0 |
99 | +tmeasday:test-reporter-helpers@0.2.1 | |
92 | 100 | tracker@1.0.11 |
93 | 101 | ui@1.0.9 |
94 | 102 | underscore@1.0.6 |
95 | 103 | url@1.0.7 |
96 | 104 | webapp@1.2.6 |
97 | 105 | webapp-hashing@1.0.7 |
106 | +xolvio:backdoor@0.1.2 | |
107 | +xolvio:cleaner@0.2.0 | ... | ... |
client/main.html
... | ... | @@ -0,0 +1,12 @@ |
1 | +<head> | |
2 | + <meta charset="utf-8"> | |
3 | + <title>Application Name</title> | |
4 | + <meta name="description" content="A description for the application."> | |
5 | + <meta name="viewport" content="initial-scale=1, minimal-ui, maximum-scale=1, minimum-scale=1" /> | |
6 | + <link rel="shortcut icon" type="image/png" href="favicon.png?v1" sizes="16x16 32x32 64x64"> | |
7 | + <link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-precomposed.png"> | |
8 | +</head> | |
9 | + | |
10 | +<body> | |
11 | + <div id="react-root"></div> | |
12 | +</body> | ... | ... |
client/stylesheets/application.scss
client/stylesheets/state/_navbar.scss
imports/startup/client/routes.jsx
... | ... | @@ -19,15 +19,7 @@ const requireAuth = ( nextState, replace ) => { |
19 | 19 | } |
20 | 20 | }; |
21 | 21 | |
22 | -const renderReactRoot = () => { | |
23 | - let container = document.createElement( 'div' ); | |
24 | - container.id = 'react-root'; | |
25 | - document.body.appendChild( container ); | |
26 | -}; | |
27 | - | |
28 | 22 | Meteor.startup( () => { |
29 | - renderReactRoot(); | |
30 | - | |
31 | 23 | render( |
32 | 24 | <Router history={ browserHistory }> |
33 | 25 | <Route path="/" component={ App }> | ... | ... |
imports/ui/components/app-navigation.js
1 | 1 | import React from 'react'; |
2 | 2 | import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; |
3 | +import { Link } from 'react-router'; | |
3 | 4 | import { PublicNavigation } from './public-navigation'; |
4 | 5 | import { AuthenticatedNavigation } from './authenticated-navigation'; |
5 | 6 | |
... | ... | @@ -12,10 +13,13 @@ export class AppNavigation extends React.Component { |
12 | 13 | return <Navbar> |
13 | 14 | <Navbar.Header> |
14 | 15 | <Navbar.Brand> |
15 | - <a href="/">Application Name</a> | |
16 | + <Link to="/">Application Name</Link> | |
16 | 17 | </Navbar.Brand> |
18 | + <Navbar.Toggle /> | |
17 | 19 | </Navbar.Header> |
18 | - { this.renderNavigation( this.props.hasUser, this.props.activeRoute ) } | |
20 | + <Navbar.Collapse> | |
21 | + { this.renderNavigation( this.props.hasUser, this.props.activeRoute ) } | |
22 | + </Navbar.Collapse> | |
19 | 23 | </Navbar>; |
20 | 24 | } |
21 | 25 | } | ... | ... |
imports/ui/components/authenticated-navigation.js
1 | 1 | import React from 'react'; |
2 | -import { browserHistory } from 'react-router'; | |
2 | +import { browserHistory, IndexLink, Link } from 'react-router'; | |
3 | 3 | import { Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; |
4 | -import { IndexLinkContainer, LinkContainer } from 'react-router-bootstrap'; | |
5 | 4 | |
6 | 5 | const handleLogout = () => { |
7 | 6 | return Meteor.logout( () => browserHistory.push( '/login' ) ); |
... | ... | @@ -15,28 +14,16 @@ const userName = () => { |
15 | 14 | } |
16 | 15 | }; |
17 | 16 | |
18 | -export const AuthenticatedNavigation = React.createClass({ | |
19 | - isActive( route, indexOnly ) { | |
20 | - return this.props.activeRoute( route, indexOnly ); | |
21 | - }, | |
22 | - handleRouteChange() { | |
23 | - this.forceUpdate(); | |
24 | - }, | |
25 | - render() { | |
26 | - return <div> | |
27 | - <Nav> | |
28 | - <li className={ this.isActive( '/', true ) } onClick={ this.handleRouteChange }> | |
29 | - <Link to="/">Index</Link> | |
30 | - </li> | |
31 | - <li className={ this.isActive( '/dashboard' ) } onClick={ this.handleRouteChange }> | |
32 | - <Link to="/dashboard">Dashboard</Link> | |
33 | - </li> | |
34 | - </Nav> | |
35 | - <Nav pullRight> | |
36 | - <NavDropdown eventKey={ 3 } title={ userName() } id="basic-nav-dropdown"> | |
37 | - <MenuItem eventKey={ 3.3 } onClick={ handleLogout }>Logout</MenuItem> | |
38 | - </NavDropdown> | |
39 | - </Nav> | |
40 | - </div>; | |
41 | - } | |
42 | -}); | |
17 | +export const AuthenticatedNavigation = () => ( | |
18 | + <div> | |
19 | + <Nav> | |
20 | + <li><IndexLink to="/" activeClassName="active">Index</IndexLink></li> | |
21 | + <li><Link to="/dashboard" activeClassName="active">Dashboard</Link></li> | |
22 | + </Nav> | |
23 | + <Nav pullRight> | |
24 | + <NavDropdown eventKey={ 3 } title={ userName() } id="basic-nav-dropdown"> | |
25 | + <MenuItem eventKey={ 3.1 } onClick={ handleLogout }>Logout</MenuItem> | |
26 | + </NavDropdown> | |
27 | + </Nav> | |
28 | + </div> | |
29 | +) | ... | ... |
imports/ui/components/public-navigation.js
... | ... | @@ -2,21 +2,9 @@ import React from 'react'; |
2 | 2 | import { Link } from 'react-router'; |
3 | 3 | import { Nav, NavItem } from 'react-bootstrap'; |
4 | 4 | |
5 | -export const PublicNavigation = React.createClass({ | |
6 | - isActive( route, indexOnly ) { | |
7 | - return this.props.activeRoute( route, indexOnly ) ? 'active' : ''; | |
8 | - }, | |
9 | - handleRouteChange() { | |
10 | - this.forceUpdate(); | |
11 | - }, | |
12 | - render() { | |
13 | - return <Nav pullRight> | |
14 | - <li className={ this.isActive( '/signup' ) } onClick={ this.handleRouteChange }> | |
15 | - <Link to="/signup">Sign Up</Link> | |
16 | - </li> | |
17 | - <li className={ this.isActive( '/login' ) } onClick={ this.handleRouteChange }> | |
18 | - <Link to="/login">Log In</Link> | |
19 | - </li> | |
20 | - </Nav>; | |
21 | - } | |
22 | -}); | |
5 | +export const PublicNavigation = () => ( | |
6 | + <Nav pullRight> | |
7 | + <li role="presentation"><Link to="/signup">Sign Up</Link></li> | |
8 | + <li role="presentation"><Link to="/login">Log In</Link></li> | |
9 | + </Nav> | |
10 | +) | ... | ... |
package.json
... | ... | @@ -4,11 +4,14 @@ |
4 | 4 | "description": "Application description.", |
5 | 5 | "scripts": { |
6 | 6 | "start": "meteor --settings settings-development.json", |
7 | + "chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests", | |
8 | + "chimp-test": "chimp --ddp=http://localhost:3000 --mocha --path=tests", | |
7 | 9 | "staging": "meteor deploy staging.meteor.com --settings settings-development.json", |
8 | 10 | "production": "meteor deploy production.meteor.com --settings settings-production.json" |
9 | 11 | }, |
10 | 12 | "devDependencies": {}, |
11 | 13 | "dependencies": { |
14 | + "chimp": "^0.33.0", | |
12 | 15 | "react": "^0.14.8", |
13 | 16 | "react-addons-pure-render-mixin": "^0.14.8", |
14 | 17 | "react-bootstrap": "^0.28.4", | ... | ... |
tests/login.js
... | ... | @@ -0,0 +1,30 @@ |
1 | +describe( 'Log In', function() { | |
2 | + beforeEach( function() { | |
3 | + server.execute( function() { | |
4 | + var user = Meteor.users.findOne( { 'emails.address': 'carl.winslow@abc.com' } ); | |
5 | + if ( user ) { | |
6 | + Meteor.users.remove( user._id ); | |
7 | + } | |
8 | + }); | |
9 | + }); | |
10 | + | |
11 | + it( 'should allow us to login @watch', function() { | |
12 | + server.execute( function() { | |
13 | + Accounts.createUser({ | |
14 | + email: 'carl.winslow@abc.com', | |
15 | + password: 'bigguy1989', | |
16 | + profile: { | |
17 | + name: { first: 'Carl', last: 'Winslow' } | |
18 | + } | |
19 | + }); | |
20 | + }); | |
21 | + | |
22 | + browser.url( 'http://localhost:3000/login' ) | |
23 | + .setValue( '[name="emailAddress"]', 'carl.winslow@abc.com' ) | |
24 | + .setValue( '[name="password"]', 'bigguy1989' ) | |
25 | + .submitForm( 'form' ); | |
26 | + | |
27 | + browser.waitForExist( '.jumbotron' ); | |
28 | + expect( browser.getUrl() ).to.equal( 'http://localhost:3000/' ); | |
29 | + }); | |
30 | +}); | ... | ... |
tests/signup.js
... | ... | @@ -0,0 +1,22 @@ |
1 | +describe( 'Sign Up', function() { | |
2 | + beforeEach( function() { | |
3 | + server.execute( function() { | |
4 | + var user = Meteor.users.findOne( { 'emails.address': 'carl.winslow@abc.com' } ); | |
5 | + if ( user ) { | |
6 | + Meteor.users.remove( user._id ); | |
7 | + } | |
8 | + }); | |
9 | + }); | |
10 | + | |
11 | + it( 'should create a new user and login with redirect to index @watch', function() { | |
12 | + browser.url( 'http://localhost:3000/signup' ) | |
13 | + .setValue( '[name="firstName"]', 'Carl' ) | |
14 | + .setValue( '[name="lastName"]', 'Winslow' ) | |
15 | + .setValue( '[name="emailAddress"]', 'carl.winslow@abc.com' ) | |
16 | + .setValue( '[name="password"]', 'bigguy1989' ) | |
17 | + .submitForm( 'form' ); | |
18 | + | |
19 | + browser.waitForExist( '.jumbotron' ); | |
20 | + expect( browser.getUrl() ).to.equal( 'http://localhost:3000/' ); | |
21 | + }); | |
22 | +}); | ... | ... |