Last active
December 11, 2023 06:51
-
-
Save aloysius-lim/c793c1383fb17e3f4410 to your computer and use it in GitHub Desktop.
Ember.js CRUD with Validation (ember-easyForm, ember-validations and Bootstrap)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.App = Ember.Application.create(); | |
App.ApplicationAdapter = DS.FixtureAdapter.extend({ | |
namespace: 'ember-crud' | |
}); | |
Ember.EasyForm.Config.registerWrapper('bootstrap', { | |
formClass: '', | |
fieldErrorClass: 'has-error', | |
inputClass: 'form-group', | |
errorClass: 'help-block error', | |
hintClass: 'help-block', | |
labelClass: '' | |
}); | |
App.Router.map(function() { | |
this.resource('products', function() { | |
this.route('new'); | |
this.route('show', {path: '/:product_id'}); | |
this.route('edit', {path: '/:product_id/edit'}); | |
}); | |
}); | |
App.Product = DS.Model.extend(Ember.Validations.Mixin, { | |
name: DS.attr('string'), | |
author: DS.attr('string'), | |
description: DS.attr('string'), | |
price: DS.attr('number'), | |
// To identify html tag for a Product. | |
htmlID: function() { | |
return 'product' + this.get('id'); | |
}.property('id'), | |
validations: { | |
name: { | |
presence: true | |
}, | |
price: { | |
presence: true, | |
numericality: { | |
greaterThanOrEqualTo: 0 | |
} | |
} | |
} | |
}); | |
App.resetFixtures = function() { | |
App.Product.FIXTURES = [ | |
{ | |
id: 1, | |
name: 'Ember.js in Action', | |
author: 'Joachim Haagen Skeie', | |
description: 'Ember.js in Action is a crisp tutorial that introduces the Ember.js framework and shows you how to build production-quality web applications.', | |
price: 44.99 | |
}, | |
{ | |
id: 2, | |
name: 'Building Web Applications with Ember.js', | |
author: 'Jesse Cravens & Thomas Brady', | |
description: 'This guide provides example-driven instructions on how to develop applications using Ember, one of the most popular JavaScript frameworks available.', | |
price: 29.99 | |
}, | |
{ | |
id: 3, | |
name: 'The Ember.js Way', | |
author: 'Brian Cardarella & Alex Navasardyan', | |
description: "Inspired by Addison-Wesley's classic The Rails Way series, The Ember.js Way crystallizes all that's been learned about Ember.js development into a start-to-finish approach that works.", | |
price: 39.99 | |
}, | |
{ | |
id: 4, | |
name: 'Instant Ember.JS Application Development: How-to', | |
author: 'Marc Bodmer', | |
description: 'A practical guide that provides you with clear step-by-step examples. The in-depth examples take into account the key concepts and give you a solid foundation to expand your knowledge and your skills.', | |
price: 20.69 | |
} | |
]; | |
}; | |
App.resetFixtures(); | |
App.ProductsRoute = Ember.Route.extend({ | |
model: function() { | |
return this.store.find('product'); | |
}, | |
actions: { | |
// Redirect to new form. | |
new: function() { | |
this.transitionTo('products.new'); | |
}, | |
// Redirect to edit form. | |
edit: function(product) { | |
this.transitionTo('products.edit', product); | |
}, | |
// Save and transition to /products/:product_id only if validation passes. | |
save: function(product) { | |
var _this = this; | |
product.validate().then(function() { | |
product.save(); | |
_this.transitionTo('products.show', product); | |
}); | |
}, | |
// Roll back and transition to /products/:product_id. | |
cancel: function(product) { | |
product.rollback(); | |
this.transitionTo('products.show', product); | |
}, | |
// Delete specified product. | |
delete: function(product) { | |
product.destroyRecord(); | |
this.transitionTo('products'); | |
} | |
} | |
}); | |
App.ProductsController = Ember.ArrayController.extend({ | |
productsCount: function() { | |
return this.get('model.length'); | |
}.property('@each') | |
}); | |
App.ProductsIndexRoute = Ember.Route.extend({ | |
model: function() { | |
return this.modelFor('products'); | |
} | |
}); | |
App.ProductsIndexController = Ember.ArrayController.extend({ | |
needs: ['products'], | |
sortProperties: ['name'] | |
}); | |
App.ProductsEditRoute = Ember.Route.extend({ | |
model: function(params) { | |
return this.store.find('product', params.product_id); | |
}, | |
// Roll back if the user transitions away by clicking a link, clicking the | |
// browser's back button, or otherwise. | |
deactivate: function() { | |
var model = this.modelFor('products.edit'); | |
if (model && model.get('isDirty') && !model.get('isSaving')) { | |
model.rollback(); | |
} | |
} | |
}); | |
App.ProductsNewRoute = Ember.Route.extend({ | |
model: function() { | |
return this.store.createRecord('product'); | |
}, | |
isNew: true, | |
renderTemplate: function(controller, model) { | |
this.render('products.edit', { | |
controller: controller | |
}); | |
}, | |
// Roll back if the user transitions away by clicking a link, clicking the | |
// browser's back button, or otherwise. | |
deactivate: function() { | |
var model = this.modelFor('products.new'); | |
if (model && model.get('isNew') && !model.get('isSaving')) { | |
model.destroyRecord(); | |
} | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>Ember.js CRUD Example</title> | |
<!-- Bootstrap --> | |
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css"> | |
<!-- QUnit --> | |
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/qunit/1.14.0/qunit.min.css"> | |
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> | |
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | |
<!--[if lt IE 9]> | |
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> | |
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> | |
<![endif]--> | |
</head> | |
<body> | |
<div id="qunit"></div> | |
<div id="qunit-fixture"></div> | |
<div id="qunit-tests"></div> | |
<script type="text/x-handlebars"> | |
<div id="application" class="container-fluid"> | |
<div class="row"> | |
<div id="left-nav" class="col-md-3" style="background-color: #eeeeee"> | |
<ul class="nav nav-pills nav-stacked sidebar"> | |
{{#link-to "index" tagName="li"}}{{#link-to "index"}}Dashboard{{/link-to}}{{/link-to}} | |
{{#link-to "products" tagName="li"}}{{#link-to "products"}}Products{{/link-to}}{{/link-to}} | |
</ul> | |
</div> | |
<div id="main" class="col-md-9"> | |
{{outlet}} | |
</div> | |
</div> | |
</div> | |
</script> | |
<script type="text/x-handlebars" data-template-name="index"> | |
<div class="jumbotron"> | |
<h1>Welcome!</h1> | |
<p>This app demonstrates CRUD with validation in Ember.js</p> | |
</div> | |
</script> | |
<script type="text/x-handlebars" data-template-name="products"> | |
<h1>Products</h1> | |
{{outlet}} | |
</script> | |
<script type="text/x-handlebars" data-template-name="products/index"> | |
<table id="products_table" class="table"> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Author</th> | |
<th>Price</th> | |
<th><button type="button" class="btn btn-default new-button" {{action "new"}}><span class="glyphicon glyphicon-plus"></span></button></th> | |
</tr> | |
</thead> | |
<tbody> | |
{{#each product in model}} | |
<tr {{bind-attr id=product.htmlID}}> | |
<td class="name">{{#link-to "products.show" product}}{{product.name}}{{/link-to}}</td> | |
<td class="author">{{product.author}}</td> | |
<td class="price">{{product.price}}</td> | |
<td class="action-buttons"><button type="button" class="btn btn-default edit-button" {{action "edit" product}}><span class="glyphicon glyphicon-pencil"></span></button> | |
<button type="button" class="btn btn-default delete-button" {{action "delete" product}}><span class="glyphicon glyphicon-remove"></button></td> | |
</tr> | |
{{/each}} | |
</tbody> | |
</table> | |
<p id="products_count">Total: {{controllers.products.productsCount}} products.</p> | |
</script> | |
<script type="text/x-handlebars" data-template-name="products/show"> | |
<h2><span class="name">{{name}}</span></h2> | |
<p>By <span class="author">{{author}}</span></p> | |
<p><strong>$<span class="price">{{price}}</span></strong></p> | |
<p><span class="description">{{description}}</span></p> | |
<p class="action-buttons"><button type="button" class="btn btn-default edit-button" {{action "edit" model}}><span class="glyphicon glyphicon-pencil"></span></button> | |
<button type="button" class="btn btn-default delete-button" {{action "delete" model}}><span class="glyphicon glyphicon-remove"></button></p> | |
<p>{{#link-to 'products' class="index-link"}}Back to products index{{/link-to}}</p> | |
</script> | |
<script type="text/x-handlebars" data-template-name="products/edit"> | |
<h2>{{#if isNew}}New{{else}}Edit{{/if}} Product</h2> | |
{{#form-for controller id="form-product" wrapper="bootstrap"}} | |
{{#input name}} | |
{{label-field name text="Product"}} | |
{{input-field name class="form-control" autofocus="true"}} | |
{{#if view.showError}} | |
{{error-field name}} | |
{{/if}} | |
{{/input}} | |
{{#input author}} | |
{{label-field author text="Author"}} | |
{{input-field author class="form-control"}} | |
{{#if view.showError}} | |
{{error-field author}} | |
{{/if}} | |
{{/input}} | |
{{#input description}} | |
{{label-field description text="Description"}} | |
{{input-field description class="form-control"}} | |
{{#if view.showError}} | |
{{error-field description}} | |
{{/if}} | |
{{/input}} | |
{{#input price}} | |
{{label-field price text="Price"}} | |
{{input-field price class="form-control"}} | |
{{#if view.showError}} | |
{{error-field price}} | |
{{/if}} | |
{{/input}} | |
<button type="submit" class="btn btn-primary save-button" {{action "save" model}}>Save</button> | |
{{#if isNew}} | |
<button type="button" class="btn btn-default cancel-button" {{action "delete" model}}>Cancel</button> | |
{{else}} | |
<button type="button" class="btn btn-default cancel-button" {{action "cancel" model}}>Cancel</button> | |
<button type="button" class="btn btn-danger delete-button" {{action "delete" model}}>Delete</button> | |
{{/if}} | |
{{/form-for}} | |
</script> | |
<!-- jQuery --> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> | |
<!-- Handlebars --> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.min.js"></script> | |
<!-- Ember.js --> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/ember.js/1.5.1/ember.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/ember-data.js/1.0.0-beta.8/ember-data.min.js"></script> | |
<!-- ember-easyForm --> | |
<script src="http://builds.dockyard.com.s3.amazonaws.com/ember-easyForm/canary/shas/add6a40a68c8b081557a9011cf99ea255414e1b1/ember-easyForm.min.js"></script> | |
<!-- ember-validations --> | |
<script src="http://builds.dockyard.com.s3.amazonaws.com/ember-validations/canary/shas/2ff28c6ba4d227b0f863b327cdff23c381c37afb/ember-validations.min.js"></script> | |
<!-- Bootstrap --> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js"></script> | |
<!-- QUnit --> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/qunit/1.14.0/qunit.min.js"></script> | |
<!-- JavaScript files for our application and tests --> | |
<script src="app.js"></script> | |
<script src="tests.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
App.rootElement = '#qunit-tests'; | |
App.setupForTesting(); | |
App.injectTestHelpers(); | |
module('Integration: Index', { | |
setup: function() { | |
App.reset(); | |
} | |
}); | |
test('app test', function() { | |
expect(1); | |
visit('/').then(function() { | |
equal(find('h1').text(), 'Welcome!'); | |
}); | |
}); | |
module('Integration: Products Index', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('products renders', function() { | |
expect(5); | |
visit('/products').then(function() { | |
equal(find('h1').text(), 'Products'); | |
equal(find('table#products_table').length, 1); | |
equal(find('table#products_table thead tr th').length, 4); | |
var productCount = find('table#products_table tbody tr').length; | |
equal(productCount, App.Product.FIXTURES.length); | |
equal(find('p#products_count').text(), 'Total: ' + productCount + ' products.'); | |
}); | |
}); | |
test('delete button works', function() { | |
expect(4); | |
var productID = 1; | |
visit('/products').then(function() { | |
var productCount = find('table#products_table tbody tr').length; | |
equal(productCount, App.Product.FIXTURES.length); | |
click('#product' + productID + ' .delete-button').then(function() { | |
var newproductCount = find('table#products_table tbody tr').length; | |
equal(App.Product.FIXTURES.length, productCount - 1); | |
equal(newproductCount, productCount - 1); | |
equal(find('#product' + productID).length, 0); | |
}); | |
}); | |
}); | |
test('show link works', function() { | |
expect(3); | |
var productID = 3; | |
visit('/products').then(function() { | |
click('#product' + productID + ' td.name a').then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(currentURL(), '/products/' + productID); | |
}); | |
}); | |
}); | |
test('edit button works', function() { | |
expect(3); | |
var productID = 2; | |
visit('/products').then(function() { | |
click('#product' + productID + ' .edit-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
}); | |
}); | |
}); | |
test('new button works', function() { | |
expect(3); | |
visit('/products').then(function() { | |
click('.new-button').then(function() { | |
equal(currentRouteName(), 'products.new'); | |
equal(currentPath(), 'products.new'); | |
equal(currentURL(), '/products/new'); | |
visit('/products'); // To cancel new. | |
}); | |
}); | |
}); | |
module('Integration: Products Show', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('product renders', function() { | |
expect(7); | |
var productID = 1; | |
visit('/products/' + productID).then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(currentURL(), '/products/' + productID); | |
var product = App.Product.FIXTURES.findBy('id', productID.toString()); | |
equal(find('h2').text(), product.name); | |
equal(find('.author').text(), product.author); | |
equal(find('.price').text(), product.price); | |
equal(find('.description').text(), product.description); | |
}); | |
}); | |
test('delete button works', function() { | |
expect(4); | |
var productID = 2; | |
visit('/products/' + productID).then(function() { | |
click('.delete-button').then(function() { | |
equal(currentRouteName(), 'products.index'); | |
equal(currentPath(), 'products.index'); | |
equal(currentURL(), '/products'); | |
equal(find('#product' + productID).length, 0); | |
}); | |
}); | |
}); | |
test('index link works', function() { | |
expect(3); | |
var productID = 4; | |
visit('/products/' + productID).then(function() { | |
click('.index-link').then(function() { | |
equal(currentRouteName(), 'products.index'); | |
equal(currentPath(), 'products.index'); | |
equal(currentURL(), '/products'); | |
}); | |
}); | |
}); | |
test('edit button works', function() { | |
expect(3); | |
var productID = 3; | |
visit('/products/' + productID).then(function() { | |
click('.edit-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
}); | |
}); | |
}); | |
module('Integration: Products Edit', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('product edit renders', function() { | |
expect(10); | |
var productID = 1; | |
visit('/products/' + productID + '/edit').then(function() { | |
equal(find('h1').text(), 'Products'); | |
equal(find('h2').text(), 'Edit Product'); | |
equal(find('form#form-product').length, 1); | |
var product = App.Product.FIXTURES.findBy('id', productID.toString()); | |
equal(find('div.name input').val(), product.name); | |
equal(find('div.author input').val(), product.author); | |
equal(find('div.description input').val(), product.description); | |
equal(find('div.price input').val(), product.price); | |
equal(find('form#form-product button.save-button').length, 1); | |
equal(find('form#form-product button.cancel-button').length, 1); | |
equal(find('form#form-product button.delete-button').length, 1); | |
}); | |
}); | |
test('save button works', function() { | |
expect(7); | |
var productID = 2; | |
visit('/products/' + productID + '/edit').then(function() { | |
var name = find('div.name input').val(); | |
var author = find('div.author input').val(); | |
var description = find('div.description input').val(); | |
var price = find('div.price input').val(); | |
fillIn('div.name input', name + 'test'); | |
fillIn('div.author input', author + 'test'); | |
fillIn('div.description input', description + 'test'); | |
fillIn('div.price input', '1' + price); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(currentURL(), '/products/' + productID); | |
equal(find('.name').text(), name + 'test'); | |
equal(find('.author').text(), author + 'test'); | |
equal(find('.description').text(), description + 'test'); | |
equal(find('.price').text(), '1' + price); | |
}); | |
}); | |
}); | |
test('cancel button works', function() { | |
expect(7); | |
var productID = 3; | |
visit('/products/' + productID + '/edit').then(function() { | |
var name = find('div.name input').val(); | |
var author = find('div.author input').val(); | |
var description = find('div.description input').val(); | |
var price = find('div.price input').val(); | |
fillIn('div.name input', name + 'test'); | |
fillIn('div.author input', author + 'test'); | |
fillIn('div.description input', description + 'test'); | |
fillIn('div.price input', '1' + price); | |
click('#form-product .cancel-button').then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(currentURL(), '/products/' + productID); | |
equal(find('.name').text(), name); | |
equal(find('.author').text(), author); | |
equal(find('.description').text(), description); | |
equal(find('.price').text(), price); | |
}); | |
}); | |
}); | |
test('delete button works', function() { | |
expect(4); | |
var productID = 4; | |
visit('/products/' + productID + '/edit'); | |
click('#form-product .delete-button').then(function() { | |
equal(currentRouteName(), 'products.index'); | |
equal(currentPath(), 'products.index'); | |
equal(currentURL(), '/products'); | |
equal(find('#product' + productID).length, 0); | |
}); | |
}); | |
test('navigating away rolls back changes', function() { | |
expect(7); | |
var productID = 3; | |
visit('/products/' + productID + '/edit').then(function() { | |
var name = find('div.name input').val(); | |
var author = find('div.author input').val(); | |
var description = find('div.description input').val(); | |
var price = find('div.price input').val(); | |
fillIn('div.name input', name + 'test'); | |
fillIn('div.author input', author + 'test'); | |
fillIn('div.description input', description + 'test'); | |
fillIn('div.price input', '1' + price); | |
visit('/products/' + productID).then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(currentURL(), '/products/' + productID); | |
equal(find('.name').text(), name); | |
equal(find('.author').text(), author); | |
equal(find('.description').text(), description); | |
equal(find('.price').text(), price); | |
}); | |
}); | |
}); | |
module('Integration: Products Edit Validations', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('validator catches empty name field', function() { | |
expect(3); | |
var productID = 1; | |
visit('/products/' + productID + '/edit').then(function() { | |
fillIn('div.name input', ''); | |
fillIn('div.price input', '1.00'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
visit('/products'); // To cancel edit. | |
}); | |
}); | |
}); | |
test('validator catches empty price field', function() { | |
expect(3); | |
var productID = 1; | |
visit('/products/' + productID + '/edit').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', ''); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
visit('/products'); // To cancel edit. | |
}); | |
}); | |
}); | |
test('validator catches non-numeric price field', function() { | |
expect(3); | |
var productID = 1; | |
visit('/products/' + productID + '/edit').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', 'a'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
visit('/products'); // To cancel edit. | |
}); | |
}); | |
}); | |
test('validator catches negative price field', function() { | |
expect(3); | |
var productID = 1; | |
visit('/products/' + productID + '/edit').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', '-1'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.edit'); | |
equal(currentPath(), 'products.edit'); | |
equal(currentURL(), '/products/' + productID + '/edit'); | |
visit('/products'); // To cancel edit. | |
}); | |
}); | |
}); | |
module('Integration: Products New', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('product new renders', function() { | |
expect(9); | |
visit('/products/new').then(function() { | |
equal(find('h1').text(), 'Products'); | |
equal(find('h2').text(), 'New Product'); | |
equal(find('form#form-product').length, 1); | |
equal(find('div.name input').val(), ''); | |
equal(find('div.author input').val(), ''); | |
equal(find('div.description input').val(), ''); | |
equal(find('div.price input').val(), ''); | |
equal(find('form#form-product button.save-button').length, 1); | |
equal(find('form#form-product button.cancel-button').length, 1); | |
visit('/products'); // To cancel new | |
}); | |
}); | |
test('save button works', function() { | |
expect(6); | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'NameTest'); | |
fillIn('div.author input', 'AuthorTest'); | |
fillIn('div.description input', 'DescriptionTest'); | |
fillIn('div.price input', '999'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.show'); | |
equal(currentPath(), 'products.show'); | |
equal(find('.name').text(), 'NameTest'); | |
equal(find('.author').text(), 'AuthorTest'); | |
equal(find('.description').text(), 'DescriptionTest'); | |
equal(find('.price').text(), '999'); | |
}); | |
}); | |
}); | |
test('cancel button works', function() { | |
expect(4); | |
visit('products').then(function() { | |
var productCount = find('table#products_table tbody tr').length; | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'NameTest'); | |
fillIn('div.author input', 'AuthorTest'); | |
fillIn('div.description input', 'DescriptionTest'); | |
fillIn('div.price input', '999'); | |
click('#form-product .cancel-button').then(function() { | |
equal(currentRouteName(), 'products.index'); | |
equal(currentPath(), 'products.index'); | |
equal(currentURL(), '/products'); | |
equal(find('table#products_table tbody tr').length, productCount); | |
}); | |
}); | |
}); | |
}); | |
test('navigating away rolls back changes', function() { | |
expect(4); | |
visit('products').then(function() { | |
var productCount = find('table#products_table tbody tr').length; | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'NameTest'); | |
fillIn('div.author input', 'AuthorTest'); | |
fillIn('div.description input', 'DescriptionTest'); | |
fillIn('div.price input', '999'); | |
visit('products').then(function() { | |
equal(currentRouteName(), 'products.index'); | |
equal(currentPath(), 'products.index'); | |
equal(currentURL(), 'products'); | |
equal(find('table#products_table tbody tr').length, productCount); | |
}); | |
}); | |
}); | |
}); | |
module('Integration: Products New Validations', { | |
setup: function() { | |
App.reset(); | |
App.resetFixtures(); | |
} | |
}); | |
test('validator catches empty name field', function() { | |
expect(3); | |
visit('/products/new').then(function() { | |
fillIn('div.name input', ''); | |
fillIn('div.price input', '1.00'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.new'); | |
equal(currentPath(), 'products.new'); | |
equal(currentURL(), '/products/new'); | |
visit('/products'); // To cancel new. | |
}); | |
}); | |
}); | |
test('validator catches empty price field', function() { | |
expect(3); | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', ''); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.new'); | |
equal(currentPath(), 'products.new'); | |
equal(currentURL(), '/products/new'); | |
visit('/products'); // To cancel new. | |
}); | |
}); | |
}); | |
test('validator catches non-numeric price field', function() { | |
expect(3); | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', 'a'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.new'); | |
equal(currentPath(), 'products.new'); | |
equal(currentURL(), '/products/new'); | |
visit('/products'); // To cancel new. | |
}); | |
}); | |
}); | |
test('validator catches negative price field', function() { | |
expect(3); | |
visit('/products/new').then(function() { | |
fillIn('div.name input', 'Title'); | |
fillIn('div.price input', '-1'); | |
click('#form-product .save-button').then(function() { | |
equal(currentRouteName(), 'products.new'); | |
equal(currentPath(), 'products.new'); | |
equal(currentURL(), '/products/new'); | |
visit('/products'); // To cancel new. | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment