Skip to content
This repository was archived by the owner on Oct 19, 2022. It is now read-only.

Commit fce606b

Browse files
committed
100% test coverage
1 parent a0beda8 commit fce606b

15 files changed

+247
-116
lines changed

__tests__/consumers.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as _ from 'highland'
2+
import Decimal from 'decimal.js'
3+
import {
4+
createConsumer
5+
} from '../lib/util/consumers'
6+
import {
7+
createMockStore
8+
} from './util/createMockStore'
9+
10+
let store
11+
12+
beforeEach(() => {
13+
store = createMockStore()
14+
})
15+
16+
test('createConsumer pushes errors', (done) => {
17+
const errors = []
18+
const items = []
19+
20+
const middleware = (store) => (next) => (action) => next({})
21+
22+
_.fromError(new Error('error')).concat([1, 2, 3])
23+
.consume(createConsumer(store)(middleware))
24+
.errors((err) => {
25+
errors.push(err)
26+
})
27+
.each((item) => {
28+
items.push(item)
29+
})
30+
.done(() => {
31+
expect(errors.length).toBe(1)
32+
expect(items.length).toBe(3)
33+
34+
done()
35+
})
36+
})
37+
38+
test('createConsumer pushes the current item if next() is not supplied a new item', (done) => {
39+
const items = []
40+
const middleware = (store) => (next) => (action) => next()
41+
42+
_([1, 2, 3])
43+
.consume(createConsumer(store)(middleware))
44+
.each((item) => {
45+
items.push(item)
46+
})
47+
.done(() => {
48+
expect(items).toEqual([1, 2, 3])
49+
50+
done()
51+
})
52+
})

__tests__/createBrokerBacktest.spec.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
ORDER_PLACED,
66
ORDER_FILLED,
77
ORDER_FAILED
8-
} from '../dist/constants'
8+
} from '../lib/constants'
99

10-
import { createBrokerBacktest as createMiddleware } from '../dist/middleware/createBrokerBacktest'
10+
import { createBrokerBacktest as createMiddleware } from '../lib/middleware/createBrokerBacktest'
1111

1212
const t = { context: {} }
1313

@@ -45,6 +45,24 @@ test('synchronously dispatch order created upon order requested', () => {
4545
expect(store.dispatch.mock.calls[0][0].type).toBe(ORDER_CREATED)
4646
})
4747

48+
test('can use function as calculateCommission', () => {
49+
const { store, next } = t.context
50+
const middleware = createMiddleware(() => 5)(store)(next)
51+
const action = {
52+
type: ORDER_REQUESTED,
53+
payload: {
54+
identifier: 'GOOG',
55+
quantity: 10,
56+
price: 20,
57+
timestamp: 0
58+
}
59+
}
60+
middleware(action)
61+
62+
expect(store.dispatch.mock.calls.length).toBe(1)
63+
expect(store.dispatch.mock.calls[0][0].type).toBe(ORDER_CREATED)
64+
})
65+
4866
test('synchronously dispatch order placed and order filled upon order created', () => {
4967
const { middleware, store } = t.context
5068
const action = {

__tests__/createBrokerRealtime.spec.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,21 @@ test(`dispatch ${ORDER_CANCELLED} if cancelling succeeds`, (done) => {
168168
})
169169

170170

171-
test(`dispatch ${ORDER_FAILED} if cancelling fails`, (done) => {
171+
test.only(`dispatch ${ORDER_FAILED} if cancelling fails even though we have an order placed`, (done) => {
172172
const next = jest.fn()
173173
const initialState = rootReducer(undefined, { type: 'foobar', payload: {} })
174-
const store = createMockStore(initialState)
174+
const store = createMockStore({
175+
...initialState,
176+
orders: {
177+
'1': {
178+
identifier: 'MSFT',
179+
quantity: new Decimal(10),
180+
price: new Decimal(20),
181+
commission: new Decimal(0),
182+
timestamp
183+
}
184+
}
185+
})
175186
store.dispatch = jest.fn()
176187
const middleware = createMiddleware(createMockClient(true))(store)(next)
177188
const timestamp = Date.now()

__tests__/createGuard.spec.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ test('reject short order if instrument owned and shorting is disallowed', () =>
117117
expect(next.mock.calls[0][0].type).toBe(ORDER_REJECTED)
118118
})
119119

120-
test('reject order if it buying on margin is disallowed', () => {
120+
test('reject order if buying on margin is disallowed', () => {
121121
const next = t.context.next
122122

123123
const initialState = rootReducer(undefined, { type: 'foobar', payload: {} })
@@ -140,3 +140,27 @@ test('reject order if it buying on margin is disallowed', () => {
140140
expect(next.mock.calls.length).toBe(1)
141141
expect(next.mock.calls[0][0].type).toBe(ORDER_REJECTED)
142142
})
143+
144+
test('allow margin order if buying on margin is allowed', () => {
145+
const next = t.context.next
146+
147+
const initialState = rootReducer(undefined, { type: 'foobar', payload: {} })
148+
const store = createMockStore(initialState)
149+
150+
const order = {
151+
identifier: '123',
152+
price: new Decimal(100),
153+
quantity: new Decimal(100),
154+
commission: new Decimal(5)
155+
}
156+
const action = { type: ORDER_CREATED, payload: order }
157+
158+
const middleware = createMiddleware({
159+
margin: true
160+
})(store)(next)
161+
162+
middleware(action)
163+
164+
expect(next.mock.calls.length).toBe(1)
165+
expect(next.mock.calls[0][0].type).toBe(ORDER_CREATED)
166+
})

__tests__/order.spec.ts renamed to __tests__/orders.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,52 @@ test('createOrder throws on missing quantity', () => {
4646
})).toThrow()
4747
})
4848

49+
test('createOrder throws on missing price', () => {
50+
expect(() => createOrder(store)(calculateCommission)({
51+
identifier: 'GOOG',
52+
timestamp: 100,
53+
quantity: 100
54+
})).toThrow()
55+
})
56+
57+
test('createOrder does not support percentage orders', () => {
58+
expect(() => createOrder(store)(calculateCommission)({
59+
identifier: 'GOOG',
60+
timestamp: 100,
61+
price: 100,
62+
percent: 0.5
63+
})).toThrow()
64+
})
65+
66+
test('createOrder does not support trailing stop loss orders', () => {
67+
expect(() => createOrder(store)(calculateCommission)({
68+
identifier: 'GOOG',
69+
timestamp: 100,
70+
price: 100,
71+
threshold: 0.5,
72+
quantity: 100
73+
})).toThrow()
74+
})
75+
76+
test('createOrder does not support fixed price stop loss orders', () => {
77+
expect(() => createOrder(store)(calculateCommission)({
78+
identifier: 'GOOG',
79+
timestamp: 100,
80+
trigger: 100,
81+
price: 100,
82+
quantity: 100
83+
})).toThrow()
84+
})
85+
86+
test('createOrder throws if both quantity and percent is specified', () => {
87+
expect(() => createOrder(store)(calculateCommission)({
88+
identifier: 'GOOG',
89+
timestamp: 100,
90+
quantity: 100,
91+
percent: 0.5
92+
})).toThrow()
93+
})
94+
4995
test('createOrder returns a proper order', () => {
5096
const actual = createOrder(store)(calculateCommission)({
5197
identifier: 'GOOG',

__tests__/streams.spec.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ test('createStreamMerged runs event in arbitrary order', done => {
3939
foo: _((push, next) => {
4040
i1 = setInterval(() => {
4141
push(null, 'a')
42-
}, 100)
42+
}, 95)
4343
}),
4444
bar: _((push, next) => {
4545
i2 = setInterval(() => {
@@ -69,8 +69,8 @@ test('createStreamSorted returns a sorted stream of Redux actions', done => {
6969
const streams = {
7070
foo: _([{ timestamp: 10 }]),
7171
bar: _([{ timestamp: 5 }]),
72-
qux: _([{}]),
7372
baz: _([{}]),
73+
qux: _([{}]),
7474
quux: _([{ timestamp: 15 }]),
7575
corge: _([{ timestamp: 10 }]),
7676
grault: _([{ timestamp: -Infinity }])
@@ -97,32 +97,7 @@ test('createStreamSorted returns a sorted stream of Redux actions', done => {
9797
})
9898
})
9999

100-
test.only('createStreamSorted pushes all remaining events on the stream when it ends', done => {
101-
const streams = {
102-
foo: _([{ timestamp: 10 }, { timestamp: 15 }]),
103-
bar: _([{ timestamp: 20 }]),
104-
baz: _([{ timestamp: 25 }]),
105-
}
106-
const sorted = createStreamSorted(streams)
107-
const actions = []
108-
109-
sorted
110-
.each((x) => actions.push(x.type))
111-
.done(() => {
112-
const actual = actions
113-
const expected = [
114-
'foo',
115-
'foo',
116-
'bar',
117-
'baz'
118-
]
119-
120-
expect(actual).toEqual(expected)
121-
done()
122-
})
123-
})
124-
125-
test('createStreamSorted does not emit errors', done => {
100+
test('createStreamSorted handles errors', done => {
126101
const streams = {
127102
foo: _.fromError(new Error())
128103
}

__tests__/util/createMockClient.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export const createMockClient = (fail = false) => {
2323
cancelOrder: async ({ id }) => {
2424
/* simulate network delay */
2525
await new Promise(r => setTimeout(r, 10))
26-
2726
if (fail) {
2827
throw new Error()
2928
} else {

lib/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ export function createTrader(settings: any, strategy: Strategy) {
198198
const io = socket(app, {
199199
pingTimeout: 1000,
200200
pingInterval: 400,
201-
origins: process.env.NODE_ENV === 'production' ? 'devalpha.io:*' : '*:*'
201+
origins: /* istanbul ignore next: must be manually tested for now */
202+
process.env.NODE_ENV === 'production' ? 'devalpha.io:*' : '*:*'
202203
})
203204

204205
app.listen(config.dashboard.port)

lib/middleware/createGuard.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,8 @@ export function createGuard(options: GuardOptions): Middleware {
3232
const isDisallowedShort = (order: CreatedOrder) => {
3333
const { quantity, identifier } = order
3434
if ((!options.shorting) && quantity.isNegative()) {
35-
3635
const instrument = store.getState().positions.instruments[identifier]
37-
38-
if (!instrument) {
39-
return true
40-
}
41-
42-
if (new Decimal(instrument.quantity).lt(Decimal.abs(quantity))) {
43-
return true
44-
}
36+
return !instrument || new Decimal(instrument.quantity).lt(Decimal.abs(quantity))
4537
}
4638
return false
4739
}

lib/util/consumers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export const createConsumerCreator = (store: Store) => createConsumer(store)
2626
export const createConsumer = (store: Store) => (middleware: Middleware) => (err: Error, item: StreamAction | Highland.Nil, push: Function, next: Function): void => {
2727
if (err) {
2828
push(err)
29+
next()
2930
} else if (item === _.nil) {
3031
push(null, _.nil)
3132
} else {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy