-
Notifications
You must be signed in to change notification settings - Fork 43
Jan Edrozo | Carets #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
620cd0b
a3e2151
3153711
d0c840d
af1759e
d6f0fb7
4148b81
6925c5b
8ed504a
4ce664f
e37b779
ef046e7
747b1b9
07dc7fc
8a0a7e8
606f826
4b219ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| import Backbone from 'backbone'; | ||
| import _ from 'underscore'; | ||
|
|
||
| import Order from 'models/order'; | ||
| import Quote from 'models/quote'; | ||
|
|
||
| import OrderList from 'collections/order_list' | ||
|
|
||
| describe('Order spec', () => { | ||
| let quote; | ||
|
|
||
| let buyOrder100; | ||
| let buyOrder80; | ||
|
|
||
| let sellOrder100; | ||
| let sellOrder120; | ||
|
|
||
| beforeEach(() => { | ||
| quote = new Quote ({ | ||
| symbol: 'HELLO', | ||
| price: 100.00, | ||
| }); | ||
|
|
||
| buyOrder100 = new Order({ | ||
| buy: true, | ||
| symbol: 'HELLO', | ||
| targetPrice: 100.00, | ||
| matchedQuote: quote, | ||
| }); | ||
|
|
||
| buyOrder80 = new Order({ | ||
| buy: true, | ||
| symbol: 'HELLO', | ||
| targetPrice: 80.00, | ||
| matchedQuote: quote, | ||
| }); | ||
|
|
||
| sellOrder100 = new Order({ | ||
| buy: false, | ||
| symbol: 'HELLO', | ||
| targetPrice: 100.00, | ||
| matchedQuote: quote, | ||
| }); | ||
|
|
||
| sellOrder120 = new Order({ | ||
| buy: false, | ||
| symbol: 'HELLO', | ||
| targetPrice: 120.00, | ||
| matchedQuote: quote, | ||
| }); | ||
| }); | ||
|
|
||
| describe('validate function', () => { | ||
| it('is valid with good buy data', () => { | ||
| expect(buyOrder100.isValid()).toBe(true); | ||
| expect(buyOrder80.isValid()).toBe(true); | ||
| }); | ||
|
|
||
| it('is valid with good sell data', () => { | ||
| expect(sellOrder100.isValid()).toBe(true); | ||
| expect(sellOrder120.isValid()).toBe(true); | ||
| }); | ||
|
|
||
| it('is not valid without a symbol', () => { | ||
| buyOrder100.set('symbol', ''); | ||
| expect(buyOrder100.isValid()).toBe(false); | ||
|
|
||
| sellOrder100.set('symbol', ''); | ||
| expect(sellOrder100.isValid()).toBe(false); | ||
| }); | ||
|
|
||
| it('is not valid without a targetPrice', () => { | ||
| buyOrder100.set('targetPrice', null); | ||
| expect(buyOrder100.isValid()).toBe(false); | ||
|
|
||
| sellOrder100.set('targetPrice', null); | ||
| expect(sellOrder100.isValid()).toBe(false); | ||
| }); | ||
|
|
||
| it('is not valid with bad targetPrice', () => { | ||
| buyOrder100.set('targetPrice', 200); | ||
| expect(buyOrder100.isValid()).toBe(false); | ||
|
|
||
| sellOrder100.set('targetPrice', 50); | ||
| expect(sellOrder100.isValid()).toBe(false); | ||
| }); | ||
|
|
||
| }); | ||
|
|
||
| describe('priceCheck function', () => { | ||
|
|
||
| let buyOrder; | ||
| let sellOrder; | ||
| let listener; | ||
| let testOrderList; | ||
|
|
||
| beforeEach(() => { | ||
| listener = {}; | ||
| listener = _.extend(listener, Backbone.Events); | ||
|
|
||
| quote = new Quote ({ | ||
| symbol: 'HELLO', | ||
| price: 100.00, | ||
| }); | ||
|
|
||
| buyOrder = new Order({ | ||
| buy: true, | ||
| symbol: 'HELLO', | ||
| targetPrice: 99, | ||
| matchedQuote: quote, | ||
| }); | ||
|
|
||
| sellOrder = new Order({ | ||
| buy: false, | ||
| symbol: 'HELLO', | ||
| targetPrice: 101.00, | ||
| matchedQuote: quote, | ||
| }); | ||
|
|
||
| testOrderList = new OrderList([buyOrder, sellOrder]); | ||
| }); | ||
|
|
||
| it("buys if quote's price is equal to or below order's targetPrice", () => { | ||
| listener.listenTo(buyOrder, 'destroy', () => { | ||
| expect(true).toBeTruthy(); | ||
| }); | ||
| buyOrder.get('matchedQuote').set('price', 99); | ||
| buyOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(1); | ||
|
|
||
| buyOrder.get('matchedQuote').set('price', 98); | ||
| buyOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(1); | ||
| }); | ||
|
|
||
| it("sells if quote's price is equal to or above order's targetPrice", () => { | ||
| listener.listenTo(sellOrder, 'destroy', () => { | ||
| expect(true).toBeTruthy(); | ||
| }); | ||
| sellOrder.get('matchedQuote').set('price', 101); | ||
| sellOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(1); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good place to do the testing for destroying models however, nice work! |
||
|
|
||
| sellOrder.get('matchedQuote').set('price', 102); | ||
| sellOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(1); | ||
| }); | ||
|
|
||
| it("won't buy if quote's price is above order's targetPrice",() => { | ||
| buyOrder.get('matchedQuote').set('price', 1000); | ||
| buyOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(2); | ||
| }); | ||
|
|
||
| it("won't sell if quote's price is below order's targetPrice",() => { | ||
| sellOrder.get('matchedQuote').set('price', 1); | ||
| sellOrder.priceCheck(); | ||
| expect(testOrderList.length).toEqual(2); | ||
| }); | ||
|
|
||
|
|
||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,23 @@ | ||
| // Vendor Modules | ||
| import $ from 'jquery'; | ||
| import _ from 'underscore'; | ||
|
|
||
| // CSS | ||
| import 'foundation-sites/dist/foundation.css'; | ||
| import 'css/app.css'; | ||
|
|
||
| import $ from 'jquery'; | ||
|
|
||
| // Models | ||
| import Quote from 'models/quote'; | ||
| import Order from 'models/order'; | ||
| import Simulator from 'models/simulator'; | ||
| import QuoteList from 'collections/quote_list'; | ||
| import OrderList from 'collections/order_list'; | ||
|
|
||
| // Views | ||
| import QuoteView from 'views/quote_view'; | ||
| import QuoteListView from 'views/quote_list_view'; | ||
| import OrderView from 'views/order_view'; | ||
| import OrderListView from 'views/order_list_view'; | ||
|
|
||
| const quoteData = [ | ||
| { | ||
|
|
@@ -27,9 +40,42 @@ const quoteData = [ | |
|
|
||
| $(document).ready(function() { | ||
| const quotes = new QuoteList(quoteData); | ||
|
|
||
| const simulator = new Simulator({ | ||
| quotes: quotes, | ||
| }); | ||
|
|
||
| console.log(quotes); | ||
| const quoteListView = new QuoteListView({ | ||
| model: quotes, | ||
| template: _.template($('#quote-template').html()), | ||
| tradeTemplate: _.template($('#trade-template').html()), | ||
| el: 'main', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of a problem, it leads your Best practices in Backbone is for independent views to NOT overlap in the DOM. You can have subviews, but views that don't know about each other (one isn't managing the other) should not overlap. |
||
| }); | ||
|
|
||
| const formDropDown = function formDropDown() { | ||
| const $formSelect = $('select[name=symbol]'); | ||
|
|
||
| quotes.forEach((quote) => { | ||
| const quoteSymbol = quote.get('symbol'); | ||
| $formSelect.append(`<option value=${quoteSymbol}>${quoteSymbol}</option>`); | ||
| }); | ||
| }; | ||
|
|
||
| const orders = new OrderList(); | ||
|
|
||
| //console.log(orders); | ||
| const orderListView = new OrderListView({ | ||
| model: orders, | ||
| template: _.template($('#order-template').html()), | ||
| quoteList: quotes, | ||
| el: '#order-workspace', | ||
| }); | ||
|
|
||
| //console.log('TEST'); | ||
|
|
||
| formDropDown(); | ||
| quoteListView.render(); | ||
| orderListView.render(); | ||
| simulator.start(); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import Backbone from 'backbone'; | ||
| import Order from 'models/order'; | ||
|
|
||
| const OrderList = Backbone.Collection.extend({ | ||
| model: Order, | ||
| }); | ||
|
|
||
| export default OrderList; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import Backbone from 'backbone'; | ||
|
|
||
| const Order = Backbone.Model.extend({ | ||
| initialize(attributes) { | ||
| //raise an error if you didn't get a quote | ||
| }, | ||
| validate(attributes) { | ||
| const errors = {}; | ||
|
|
||
| if (!attributes.symbol) { | ||
| errors['symbol'] = ['Symbol is required']; | ||
| } | ||
|
|
||
| if (!attributes.targetPrice) { | ||
| errors['price-target'] = ['Invalid target price']; | ||
| } | ||
|
|
||
| if (attributes.targetPrice <= 0) { | ||
| errors['price-target'] = ['Invalid target price']; | ||
| } | ||
|
|
||
| //Don't BUY: if order's target price is greater than quote's price | ||
| if (attributes.buy && (attributes.targetPrice > attributes.matchedQuote.get('price')) ) { | ||
| errors['price-target'] = ['Price higher than market price!']; | ||
| } | ||
|
|
||
| //Don't SELL: if order's target price is less than quote's price | ||
| if (!attributes.buy && (attributes.targetPrice < attributes.matchedQuote.get('price')) ) { | ||
| errors['price-target'] = ['Price lower than market price!']; | ||
| } | ||
|
|
||
| if ( Object.keys(errors).length > 0 ) { | ||
| return errors; | ||
| } else { | ||
| return false; | ||
| } | ||
| }, | ||
| priceCheck() { | ||
| //BUY: if order's target price is equal to or below quote's price | ||
| if (this.attributes.buy && (this.attributes.targetPrice >= this.attributes.matchedQuote.get('price')) ) { | ||
| // alert('hey buy!'); | ||
| const matchedQuoteCopy = this.attributes.matchedQuote; | ||
|
|
||
| this.destroy(); | ||
| matchedQuoteCopy.buy(); | ||
| } | ||
|
|
||
| //SELL: if order's target price is equal to or above quote's price | ||
| if (!this.attributes.buy && (this.attributes.targetPrice <= this.attributes.matchedQuote.get('price')) ) { | ||
| // alert('hey sell!'); | ||
| const matchedQuoteCopy = this.attributes.matchedQuote; | ||
|
|
||
| this.destroy(); | ||
| matchedQuoteCopy.sell(); | ||
| } | ||
| }, | ||
|
|
||
| }); | ||
|
|
||
| export default Order; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part doesn't actually test anything since it only runs the test if destroy was called. You'd instead probably want to use a spy (part of Jasmine) and check to see if the event handler had been called.
Good work trying to test these however.