Skip to content
This repository has been archived by the owner on May 29, 2021. It is now read-only.

Commit

Permalink
Add unit tests for headers module (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedsakr authored Jan 23, 2021
1 parent 63599c1 commit 09be74f
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wstrade-api",
"version": "1.1.3",
"version": "1.1.4",
"description": "WealthSimple Trade API Wrapper",
"main": "dist/wstrade.js",
"scripts": {
Expand Down
94 changes: 94 additions & 0 deletions src/__test__/headers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import headers from '../headers';

const stubHeaders = [];

/*
* Create a stub Headers constructor for node-fetch so we can
* eliminate this external dependency when testing the headers
* module.
*/
jest.mock('node-fetch', () => ({
Headers: () => ({
append: (name, value) => stubHeaders.push([name, value]),
delete: (name) => stubHeaders.forEach((item, id) => {
if (name === item[0]) {
stubHeaders.splice(id, 1);
}
}),
[Symbol.iterator]: () => stubHeaders[Symbol.iterator](),
}),
}));

// Reset the headers list before every test case to avoid
// any side effects from one test to the ext.
beforeEach(() => {
// clear the array
stubHeaders.length = 0;
});

// Confirm correct insertion of header key-value pair
test('headers.add accepts key-value pair', () => {
headers.add('Content-Type', 'application/json');

expect(stubHeaders.length).toBe(1);
expect(stubHeaders[0]).toStrictEqual(['Content-Type', 'application/json']);
});

// headers.add should relay all key-value pairs to be stored
test('several invocations on headers.add stores all custom headers', () => {
headers.add('Content-Type', 'application/json');
headers.add('Content-Encoding', 'gzip');
headers.add('Keep-Alive', 'timeout=5, max=1000');

expect(stubHeaders.length).toBe(3);
expect(stubHeaders[0]).toStrictEqual(['Content-Type', 'application/json']);
expect(stubHeaders[1]).toStrictEqual(['Content-Encoding', 'gzip']);
expect(stubHeaders[2]).toStrictEqual(['Keep-Alive', 'timeout=5, max=1000']);
});

// removing a non-existant key-value pair should not cause any problems
test('headers.remove with key that is not stored', () => {
expect(stubHeaders.length).toBe(0);
headers.remove('Content-Type');
expect(stubHeaders.length).toBe(0);
});

// removing an existing key-value pair will delete it from the list
test('headers.remove with key that is stored', () => {
headers.add('Content-Type', 'application/json');
expect(stubHeaders.length).toBe(1);
expect(stubHeaders[0]).toStrictEqual(['Content-Type', 'application/json']);

headers.remove('Content-Type');
expect(stubHeaders.length).toBe(0);
});

// headers.clear should reset us back to empty list
test('headers.clear wipes out all entries', () => {
headers.add('Content-Type', 'application/json');
headers.add('Content-Encoding', 'gzip');
headers.add('Keep-Alive', 'timeout=5, max=1000');

expect(stubHeaders.length).toBe(3);

headers.clear();
expect(stubHeaders.length).toBe(0);
});

// headers.values return a list of all key-value pairs (each as 2-element lists)
test('headers.values retrieves all custom headers', () => {
headers.add('Content-Type', 'application/json');
headers.add('Content-Encoding', 'gzip');
headers.add('Keep-Alive', 'timeout=5, max=1000');

const pairs = headers.values();
expect(pairs.length).toBe(3);
expect(pairs[0]).toStrictEqual(['Content-Type', 'application/json']);
expect(pairs[1]).toStrictEqual(['Content-Encoding', 'gzip']);
expect(pairs[2]).toStrictEqual(['Keep-Alive', 'timeout=5, max=1000']);
});

// An empty list should be returned when no custom headers are stored.
test('headers.values returns empty list when no custom headers stored', () => {
expect(headers.values().length).toBe(0);
});
90 changes: 45 additions & 45 deletions src/core/__test__/ticker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,97 +3,97 @@ import Ticker from '../ticker';
// Empty strings are not allowed because we need the symbol at least
// to make any use out of it
test('Ticker empty string', () => {
expect(() => new Ticker('')).toThrow('Empty ticker');
expect(() => new Ticker('')).toThrow('Empty ticker');
});

// Symbol only is a common way to pass around tickers. The symbol
// is usually sufficient to uniquely identify a security.
test('Ticker as symbol only', () => {
let ticker = new Ticker('AAPL');
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('AAPL');
const ticker = new Ticker('AAPL');
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('AAPL');
});

// Attempting to pass an invalid exchange in a composite format.
test('Ticker as symbol and (invalid) exchange composite', () => {
expect(() => new Ticker('AAPL:ME')).toThrow(`Invalid exchange 'ME'!`);
})
expect(() => new Ticker('AAPL:ME')).toThrow('Invalid exchange \'ME\'!');
});

// Valid symbol and exchange format. Symbol and exchange are expected
// to be successfully extracted
test('Ticker as symbol and (valid) exchange composite', () => {
let ticker = new Ticker('AAPL:NASDAQ');
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe('NASDAQ');
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('AAPL:NASDAQ');
const ticker = new Ticker('AAPL:NASDAQ');
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe('NASDAQ');
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('AAPL:NASDAQ');
});

// Empty ticker objects are also rejected by the constructor.
test('Ticker as empty object', () => {
expect(() => new Ticker({})).toThrow();
expect(() => new Ticker({})).toThrow();
});

// Symbol is sufficient information for a ticker
test('Ticker as object with symbol only', () => {
let ticker = new Ticker({ symbol: 'AAPL' });
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe(undefined);
expect(ticker.format()).toBe('AAPL');
const ticker = new Ticker({ symbol: 'AAPL' });
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe(undefined);
expect(ticker.format()).toBe('AAPL');
});

// Symbol and exchange will be stored in the ticker object.
test('Ticker as object with symbol and exchange', () => {
let ticker = new Ticker({ symbol: 'AAPL', exchange: 'NASDAQ' });
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe('NASDAQ');
expect(ticker.id).toBe(undefined);
expect(ticker.format()).toBe('AAPL:NASDAQ');
const ticker = new Ticker({ symbol: 'AAPL', exchange: 'NASDAQ' });
expect(ticker.symbol).toBe('AAPL');
expect(ticker.exchange).toBe('NASDAQ');
expect(ticker.id).toBe(undefined);
expect(ticker.format()).toBe('AAPL:NASDAQ');
});

// Securities under NEO are identified by WS trade under the full name
// of the exchange rather than the acronym, unlike all other exchanges.
// The Ticker constructor does the necessary translation.
test('Ticker with NEO exchange is internally mapped to full name', () => {
let ticker = new Ticker("CYBN:NEO");
expect(ticker.symbol).toBe('CYBN');
expect(ticker.exchange).toBe('AEQUITAS NEO EXCHANGE');
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('CYBN:NEO');
})
const ticker = new Ticker('CYBN:NEO');
expect(ticker.symbol).toBe('CYBN');
expect(ticker.exchange).toBe('AEQUITAS NEO EXCHANGE');
expect(ticker.id).toBe(null);
expect(ticker.format()).toBe('CYBN:NEO');
});

// The user can specify the internal id of the security instead of
// a symbol.
test('Ticker as internal id', () => {
let ticker = new Ticker({ id: 'sec-s-76a7155242e8477880cbb43269235cb6' });
expect(ticker.symbol).toBe(undefined);
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe('sec-s-76a7155242e8477880cbb43269235cb6');
expect(ticker.format()).toBe('sec-s-76a7155242e8477880cbb43269235cb6');
const ticker = new Ticker({ id: 'sec-s-76a7155242e8477880cbb43269235cb6' });
expect(ticker.symbol).toBe(undefined);
expect(ticker.exchange).toBe(undefined);
expect(ticker.id).toBe('sec-s-76a7155242e8477880cbb43269235cb6');
expect(ticker.format()).toBe('sec-s-76a7155242e8477880cbb43269235cb6');
});

// A weak comparison does not consider exchanges with evaluating if tickers
// are equal. This is used to to filter orders by tickers in the orders module,
// but the order data returned by WS trade does not contain exchange.
test('Weak comparison between two tickers with same symbol but different exchanges', () => {
let ticker1 = new Ticker('AAPL:NASDAQ');
let ticker2 = new Ticker('AAPL');
expect(ticker1.weakEquals(ticker2)).toBe(true);
const ticker1 = new Ticker('AAPL:NASDAQ');
const ticker2 = new Ticker('AAPL');
expect(ticker1.weakEquals(ticker2)).toBe(true);
});

// Varying symbols will return a false comparison
test('Weak comaprison between two tickers with different symbols', () => {
let ticker1 = new Ticker('AAPL');
let ticker2 = new Ticker('SU');
expect(ticker1.weakEquals(ticker2)).toBe(false);
const ticker1 = new Ticker('AAPL');
const ticker2 = new Ticker('SU');
expect(ticker1.weakEquals(ticker2)).toBe(false);
});

// Varying ids will return a false comparison
test('Weak comaprison between two tickers with different ids', () => {
let ticker1 = new Ticker({ id: 'sec-s-76a7155242e8477880cbb43269235cb6' });
let ticker2 = new Ticker({ id: 'sec-s-72a7155241e8479880cbb43269235cb6' });
expect(ticker1.weakEquals(ticker2)).toBe(false);
});
const ticker1 = new Ticker({ id: 'sec-s-76a7155242e8477880cbb43269235cb6' });
const ticker2 = new Ticker({ id: 'sec-s-72a7155241e8479880cbb43269235cb6' });
expect(ticker1.weakEquals(ticker2)).toBe(false);
});
10 changes: 5 additions & 5 deletions src/helpers/__test__/time.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { epochSeconds } from '../time';

function wait(seconds) {
return new Promise((res, rej) => setTimeout(res, seconds * 1000));
return new Promise((res, rej) => setTimeout(res, seconds * 1000));
}

// Measure the difference in epochSeconds() after waiting 1 second
test('epoch seconds is accurate', async () => {
let base = epochSeconds();
await wait(1);
expect(epochSeconds()).toBe(base + 1);
});
const base = epochSeconds();
await wait(1);
expect(epochSeconds()).toBe(base + 1);
});

0 comments on commit 09be74f

Please sign in to comment.