Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
620cd0b
Added views(quote_view and quote_list_view) with initialize and rende…
JNEdrozo Dec 12, 2017
a3e2151
Quote Model Update: Added buy() and sell() model methods; Quote_view.…
JNEdrozo Dec 12, 2017
3153711
CleanUp: Removed and commented out console log statements
JNEdrozo Dec 12, 2017
d0c840d
W2: Added logic so buy and sell button clicks also log entries in the…
JNEdrozo Dec 12, 2017
af1759e
W2 Correction: Moved buy & sell trade history logic into quote_view.j…
JNEdrozo Dec 13, 2017
d6f0fb7
Trade History Correction: Switched the buy true & false for bought an…
JNEdrozo Dec 13, 2017
4148b81
W3: Created empty model, collection, and view files for order & order…
JNEdrozo Dec 13, 2017
6925c5b
Order Entry Form DropDown Menu added added in app.js; Updated content…
JNEdrozo Dec 14, 2017
8ed504a
W2 Update: Moved trigger event for clickedBuyOrSellQuote to buy & sel…
JNEdrozo Dec 14, 2017
4ce664f
quote.js correction: changed order of trigger and set lines in buy() …
JNEdrozo Dec 14, 2017
e37b779
quote.js correction: Undid the changed order of trigger and set lines…
JNEdrozo Dec 14, 2017
ef046e7
Added Order Model Validations and newOrder validation errors are now …
JNEdrozo Dec 15, 2017
747b1b9
W3: Added conditional statements for buy & sell in priceCheck custom …
JNEdrozo Dec 15, 2017
07dc7fc
Order Model priceCheck(): Updated buy & sell conditional statements t…
JNEdrozo Dec 15, 2017
8a0a7e8
Added click event listener on quote_view's cancel button and cancelOr…
JNEdrozo Dec 15, 2017
606f826
Order_list_view cleanup: removed import line for OrderList
JNEdrozo Dec 15, 2017
4b219ee
Added additional testing (priceCheck function) for order_spec.js
JNEdrozo Dec 18, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ Congratulations! You're submitting your assignment!
| How do Backbone Views help structure your code? | |
| Did you use jQuery directly in your Views? How, and why? | |
| What was an example of an event you triggered? Why did you need to trigger it? | |
| In what was is unit testing in JavaScript similar to unit testing in Ruby? In what ways is it different? | |
| In what way is unit testing in JavaScript similar to unit testing in Ruby? In what ways is it different? | |
163 changes: 163 additions & 0 deletions spec/models/order_spec.js
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();

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.

});
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);

Choose a reason for hiding this comment

The 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);
});


});
});
50 changes: 48 additions & 2 deletions src/app.js
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 = [
{
Expand All @@ -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',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a problem, it leads your QuoteListView instance and OrderListView instance to overlap on the DOM, which means they could interfere with each other.

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();
});
8 changes: 8 additions & 0 deletions src/collections/order_list.js
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;
60 changes: 60 additions & 0 deletions src/models/order.js
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;
18 changes: 16 additions & 2 deletions src/models/quote.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,27 @@ const Quote = Backbone.Model.extend({
symbol: 'UNDEF',
price: 0.00
},

buy() {
// Implement this function to increase the price by $1.00
const tradeData = {
buy: true,
symbol: this.get('symbol'),
price: this.get('price'),
};
this.trigger('clickedBuyOrSellQuote', tradeData);
this.set('price', (this.get('price') + 1.00));
},

sell() {
// Implement this function to decrease the price by $1.00
const tradeData = {
buy: false,
symbol: this.get('symbol'),
price: this.get('price'),
};

this.trigger('clickedBuyOrSellQuote', tradeData);
this.set('price', (this.get('price') - 1.00));

},
});

Expand Down
Loading