Skip to content

Commit

Permalink
feat: Option network method createApiToken (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
wzalazar authored Aug 30, 2018
1 parent cc41e0a commit 53e8e82
Show file tree
Hide file tree
Showing 11 changed files with 587 additions and 349 deletions.
642 changes: 336 additions & 306 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
"lint": "tslint -p ./tsconfig.json",
"lint:fix": "tslint -p ./tsconfig.json --fix",
"lint:check": "tslint-config-prettier-check ./tslint.json",
"test": "ts-node --files tests/index.ts",
"test:unit": "ts-node --files tests/unit/index.ts",
"coverage": "nyc --report-dir ./.coverage npm run test:unit",
"test:integration": "ts-node --files tests/integration/index.ts",
"coverage": "nyc --report-dir ./.coverage npm run test",
"coverage:unit": "nyc --report-dir ./.coverage npm run test:unit",
"coverage:integration": "nyc --report-dir ./.coverage npm run test:integration",
"precommit": "lint-staged",
"compile": "tsc",
"prepublish": "npm run compile",
Expand Down Expand Up @@ -39,10 +43,12 @@
"devDependencies": {
"@po.et/tslint-rules": "1.4.1",
"@types/isomorphic-fetch": "0.0.34",
"@types/nock": "9.3.0",
"@types/serialize-javascript": "1.3.2",
"@types/sinon": "5.0.2",
"husky": "0.14.3",
"lint-staged": "7.2.1",
"nock": "9.6.1",
"nyc": "github:poetapp/nyc#fbc2ed1",
"prettier": "1.14.2",
"riteway": "2.0.4",
Expand Down
77 changes: 77 additions & 0 deletions src/Frost.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { describe } from 'riteway'
import { getOptions } from './Frost'
import { Method } from './utils/utils'

describe('Frost getOptions()', async (should: any) => {
const { assert } = should('')

for (const method of Object.keys(Method)) {
const currentMethod = (Method as any)[method]
{
const actual = getOptions(currentMethod)
const expected = {
method: currentMethod,
headers: { _headers: { 'content-type': ['application/json'] } },
}

assert({
given: `getOptions with the method ${currentMethod}`,
should: `return with the method: '${currentMethod}' and the header with 'Content-Type': 'application/json'`,
actual,
expected,
})
}
}

{
const actual = getOptions(Method.POST, {}).headers
const expected = { _headers: { 'content-type': ['application/json'] } }

assert({
given: 'getOptions with an object empty header',
should: `return the header with 'Content-Type': 'application/json'`,
actual,
expected,
})
}

{
const token = { token: 'token' }

const actual = getOptions(Method.POST, token).headers
const expected = { _headers: { 'content-type': ['application/json'], token: ['token'] } }

assert({
given: 'getOptions with an object empty header',
should: `return the header with 'Content-Type': 'application/json' and the object token`,
actual,
expected,
})
}

{
const actual = getOptions(Method.POST, {}, {}).body
const expected: any = undefined

assert({
given: 'getOptions with an object empty body',
should: 'be body undefined',
actual,
expected,
})
}

{
const network = { network: 'mainnet' }

const actual = getOptions(Method.POST, {}, network).body
const expected = '{"network":"mainnet"}'

assert({
given: 'getOptions with object network in the body',
should: 'return body with the objet network',
actual,
expected,
})
}
})
21 changes: 12 additions & 9 deletions src/Frost.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { WorkAttributes } from '@po.et/poet-js'
import * as fetch from 'isomorphic-fetch'
import { Path, Method, StringifySecure } from './utils/utils'
import { Path, Method, Network, StringifySecure, isEmptyObject } from './utils/utils'

export interface Configuration {
readonly host: string
Expand All @@ -9,6 +9,15 @@ export interface Configuration {
readonly timeout?: number
}

export const getOptions = (method: Method, headers = {}, body?: object): RequestInit => ({
method,
headers: new Headers({
'Content-Type': 'application/json',
...headers,
}),
...(body && !isEmptyObject(body) ? { body: StringifySecure(body) } : {}),
})

export class Frost {
private readonly email: string
private readonly password: string
Expand Down Expand Up @@ -305,14 +314,8 @@ export class Frost {
throw await response.text()
}

async createApiToken(token: string): Promise<{ readonly apiToken: string }> {
const options = {
method: Method.POST,
headers: new Headers({
'Content-Type': 'application/json',
token,
}),
}
async createApiToken(token: string, network?: Network): Promise<{ readonly apiToken: string }> {
const options = getOptions(Method.POST, { token }, { network })
const request = fetch(`${this.host}${Path.TOKENS}`, options)

const response = await Promise.race([request, this.timeoutPromise()])
Expand Down
29 changes: 0 additions & 29 deletions src/canary.test.ts

This file was deleted.

30 changes: 29 additions & 1 deletion src/utils/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe } from 'riteway'

import { StringifySecure } from './utils'
import { StringifySecure, isEmptyObject } from './utils'

describe('StringifySecure', async (should: any) => {
const { assert } = should()
Expand All @@ -25,3 +25,31 @@ describe('StringifySecure', async (should: any) => {
expected: '{}',
})
})

describe('isEmptyObject', async (should: any) => {
const { assert } = should()

{
const actual = isEmptyObject({})
const expected = true

assert({
given: 'empty object',
should: 'return true',
actual,
expected,
})
}

{
const actual = isEmptyObject({ key: 'value' })
const expected = false

assert({
given: 'object with one key',
should: 'return false',
actual,
expected,
})
}
})
6 changes: 6 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ export enum Method {
ALL = 'all',
}

export enum Network {
MAINNET = 'mainnet',
TESTNET = 'testnet',
}

export const StringifySecure = (data: object) => serialize(data, { isJSON: true })
export const isEmptyObject = (o: object) => Object.keys(o).length === 0
2 changes: 2 additions & 0 deletions tests/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import './unit/index'
import './integration/index'
116 changes: 116 additions & 0 deletions tests/integration/createApiToken.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import * as nock from 'nock'
import { describe } from 'riteway'
import { Frost } from '../../src/Frost'
import { Path, Network } from '../../src/utils/utils'

describe('Frost createApiToken()', async (should: any) => {
const { assert } = should('')
const host = 'https://api.frost.po.et'

const config = {
email: '[email protected]',
password: 'test',
timeout: 0,
host,
}

{
const serverResponse = { apiToken: '1' }
const token = 'test'

// TODO: we have to do it with the real network, no mock
nock(host)
.post(Path.TOKENS)
.reply(200, serverResponse)

const frost = new Frost(config)

const actual = await frost.createApiToken(token)
const expected = serverResponse

assert({
given: 'a status code of 200',
should: 'return the object with apiToken equal 1',
actual,
expected,
})
}

{
const serverResponse = { apiToken: '1' }
const token = 'test'
let requestBody = {}

nock(host)
.post(Path.TOKENS, (body: {}) => {
requestBody = body
return body
})
.reply(200, serverResponse)

const frost = new Frost(config)
await frost.createApiToken(token)

const actual = requestBody
const expected = {}

assert({
given: 'a request without network property',
should: 'be the request body empty',
actual,
expected,
})
}

{
const serverResponse = { apiToken: '1' }
const token = 'test'
let requestBody = {}

nock(host)
.post(Path.TOKENS, (body: {}) => {
requestBody = body
return body
})
.reply(200, serverResponse)

const frost = new Frost(config)
await frost.createApiToken(token, Network.MAINNET)

const actual = requestBody
const expected = { network: Network.MAINNET }

assert({
given: `a request with the ${Network.MAINNET} network property`,
should: `have the request body an object with { network: '${Network.MAINNET}' }`,
actual,
expected,
})
}

{
const token = 'test'

nock(host)
.post(Path.TOKENS)
.reply(500)

const frost = new Frost(config)

let actual = ''
const expected = 'string'

try {
await frost.createApiToken(token)
} catch(e) {
actual = typeof e
}

assert({
given: 'a status code of 500',
should: `return a string`,
actual,
expected,
})
}
})
1 change: 1 addition & 0 deletions tests/integration/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './createApiToken.test'
4 changes: 1 addition & 3 deletions tests/unit/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
// All unit test files should be imported here. For example,
// import '../../src/foo.test'
import '../../src/canary.test'
import '../../src/utils/utils.test'
import '../../src/Frost.test'

0 comments on commit 53e8e82

Please sign in to comment.