Browse Source

workout on method specification

tags/v1.0.0-alpha.0
ojizero 1 year ago
parent
commit
1220331d45
No account linked to committer's email address
10 changed files with 479 additions and 61 deletions
  1. 205
    0
      package-lock.json
  2. 10
    0
      package.json
  3. 2
    2
      src/client.ts
  4. 65
    13
      src/method.ts
  5. 29
    0
      src/validation.ts
  6. 159
    28
      test/method.spec.ts
  7. 0
    14
      test/mocks/client.ts
  8. 6
    4
      test/setup.ts
  9. 2
    0
      test/typings/globals.d.ts
  10. 1
    0
      tsconfig.json

+ 205
- 0
package-lock.json View File

@@ -128,6 +128,35 @@
"to-fast-properties": "^2.0.0"
}
},
"@sinonjs/commons": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz",
"integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
"@sinonjs/formatio": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz",
"integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==",
"dev": true,
"requires": {
"@sinonjs/samsam": "^2 || ^3"
}
},
"@sinonjs/samsam": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.0.2.tgz",
"integrity": "sha512-m08g4CS3J6lwRQk1pj1EO+KEVWbrbXsmi9Pw0ySmrIbcVxVaedoFgLvFsV8wHLwh01EpROVz3KvVcD1Jmks9FQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.0.2",
"array-from": "^2.1.1",
"lodash.get": "^4.4.2"
}
},
"@types/chai": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz",
@@ -149,6 +178,27 @@
"integrity": "sha512-g0+CQosizg1hjNn06fKB2tEvS5kExrvVOkIfsGuIRfsQ/A9u/Xjp/6/czJVyLuCYdkmMbplDUXvQW+YjBQK7dA==",
"dev": true
},
"@types/joi": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/@types/joi/-/joi-14.0.1.tgz",
"integrity": "sha512-0uZZ+nffpr480zwwUXsk0Z5O0szllffNW1EbkI+dDzKhNKhiX4QOwpwK37WpKIpaPLk9V8U9y2We/VOeD6zyhQ==",
"dev": true
},
"@types/lodash": {
"version": "4.14.119",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.119.tgz",
"integrity": "sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw==",
"dev": true
},
"@types/lodash.defaultsdeep": {
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/@types/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.4.tgz",
"integrity": "sha512-Y0HdW4etNMY+U+DfZBgew0c6QjWLk0tk8FESYzOtIgglLO4WFOgei20V3vOa2+p/Grcxgm39Ysp/SvY2OJajFw==",
"dev": true,
"requires": {
"@types/lodash": "*"
}
},
"@types/mocha": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz",
@@ -161,6 +211,22 @@
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
"dev": true
},
"@types/sinon": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.2.tgz",
"integrity": "sha512-YvJOqPk4kh1eQyxuASDD4MDK27XWAhtw6hJ7rRayEOkkTpZkqDWpDb4OjLVzFGdapOuUgZdnqO+71Q3utCJtcA==",
"dev": true
},
"@types/sinon-chai": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.2.tgz",
"integrity": "sha512-5zSs2AslzyPZdOsbm2NRtuSNAI2aTWzNKOHa/GRecKo7a5efYD7qGcPxMZXQDayVXT2Vnd5waXxBvV31eCZqiA==",
"dev": true,
"requires": {
"@types/chai": "*",
"@types/sinon": "*"
}
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -170,6 +236,12 @@
"color-convert": "^1.9.0"
}
},
"array-from": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
"integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=",
"dev": true
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
@@ -363,6 +435,11 @@
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
"dev": true
},
"hoek": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz",
"integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -379,6 +456,20 @@
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"isemail": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
"integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==",
"requires": {
"punycode": "2.x.x"
}
},
"istanbul-lib-coverage": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
@@ -400,6 +491,16 @@
"semver": "^5.5.0"
}
},
"joi": {
"version": "14.3.0",
"resolved": "https://registry.npmjs.org/joi/-/joi-14.3.0.tgz",
"integrity": "sha512-0HKd1z8MWogez4GaU0LkY1FgW30vR2Kwy414GISfCU41OYgUC2GWpNe5amsvBZtDqPtt7DohykfOOMIw1Z5hvQ==",
"requires": {
"hoek": "6.x.x",
"isemail": "3.x.x",
"topo": "3.x.x"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -412,12 +513,35 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
"just-extend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz",
"integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==",
"dev": true
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
"lodash.defaultsdeep": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz",
"integrity": "sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
"lolex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-3.0.0.tgz",
"integrity": "sha512-hcnW80h3j2lbUfFdMArd5UPA/vxZJ+G8vobd+wg3nVEQA0EigStbYcrG030FJxL6xiDDPEkoMatV9xIh5OecQQ==",
"dev": true
},
"make-error": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
@@ -473,6 +597,27 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"nise": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz",
"integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==",
"dev": true,
"requires": {
"@sinonjs/formatio": "^3.1.0",
"just-extend": "^4.0.2",
"lolex": "^2.3.2",
"path-to-regexp": "^1.7.0",
"text-encoding": "^0.6.4"
},
"dependencies": {
"lolex": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz",
"integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==",
"dev": true
}
}
},
"nyc": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-13.1.0.tgz",
@@ -1627,18 +1772,64 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-to-regexp": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
"dev": true,
"requires": {
"isarray": "0.0.1"
}
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
"dev": true
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true
},
"sinon": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.2.tgz",
"integrity": "sha512-WLagdMHiEsrRmee3jr6IIDntOF4kbI6N2pfbi8wkv50qaUQcBglkzkjtoOEbeJ2vf1EsrHhLI+5Ny8//WHdMoA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.2.0",
"@sinonjs/formatio": "^3.1.0",
"@sinonjs/samsam": "^3.0.2",
"diff": "^3.5.0",
"lolex": "^3.0.0",
"nise": "^1.4.7",
"supports-color": "^5.5.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"sinon-chai": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.3.0.tgz",
"integrity": "sha512-r2JhDY7gbbmh5z3Q62pNbrjxZdOAjpsqW/8yxAZRSqLZqowmfGZPGUZPFf3UX36NLis0cv8VEM5IJh9HgkSOAA==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -1672,12 +1863,26 @@
"has-flag": "^3.0.0"
}
},
"text-encoding": {
"version": "0.6.4",
"resolved": "http://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
"integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
"dev": true
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
"dev": true
},
"topo": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
"integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
"requires": {
"hoek": "6.x.x"
}
},
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",

+ 10
- 0
package.json View File

@@ -23,16 +23,26 @@
"url": "https://github.com/ojizero/portal/issues"
},
"homepage": "https://github.com/ojizero/portal#readme",
"dependencies": {
"joi": "^14.3.0",
"lodash.defaultsdeep": "^4.6.0"
},
"devDependencies": {
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/expect": "^1.20.3",
"@types/joi": "^14.0.1",
"@types/lodash.defaultsdeep": "^4.6.4",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"@types/sinon": "^7.0.2",
"@types/sinon-chai": "^3.2.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
"sinon": "^7.2.2",
"sinon-chai": "^3.3.0",
"ts-node": "^7.0.1",
"typescript": "^3.2.2"
}

+ 2
- 2
src/client.ts View File

@@ -1,5 +1,5 @@
export interface Client {
request (method: string, path: string, options: any): void // TODO:
request (method: string, path: string, payload: {}, options: any): void // TODO:
}

export class PortalClient implements Client {
@@ -7,7 +7,7 @@ export class PortalClient implements Client {
// TODO:
}

request (method: string, path: string, options: any) {
request (method: string, path: string, payload: {}, options: any) {
// TODO:
}
}

+ 65
- 13
src/method.ts View File

@@ -1,12 +1,16 @@
import { Client } from './client'

import defaults from 'lodash.defaultsdeep'
import { ValdiationSpec, ensureValidData, Validator } from './validation';

const applicationJson = 'application/json'

export interface MethodSpec {
path: string,
method?: string,
body?: {},
queryString?: {},
params?: ValdiationSpec,
body?: ValdiationSpec,
queryString?: ValdiationSpec,
contentType?: string,
accept?: string,
strict?: boolean,
@@ -17,23 +21,71 @@ export function method (client: Client) {
const {
path,
method = 'GET',
body = {},
queryString = {},
params = undefined,
body = undefined,
queryString = undefined,
contentType = applicationJson,
accept = applicationJson,
strict = true
} = spec

// It's ok for args here to be of implicit type any[]
// @ts-ignore
return function (...args) {
// TODO: replace path params with args
// TODO: reject if args doesn't match path params if strict
const defaultOptions = {
headers: {
'Accept': accept,
'Content-Type': contentType,
}
}

return async function (...args: any[]) {
let length = args.length

let query
let payload
let options

if (typeof args[length - 1] === 'object') {
options = args[length - 1]
args = args.slice(0, length - 1)
length -= 1
}

if (typeof args[length - 1] === 'object') {
payload = args[length - 1]
args = args.slice(0, length - 1)
length -= 1
} else if (typeof options !== 'undefined') {
payload = options
options = undefined
}

if (typeof queryString !== 'undefined' && typeof args[length - 1] === 'object') {
query = args[length - 1]
args = args.slice(0, length - 1)
length -= 1
} else if (typeof queryString !== 'undefined' && typeof payload !== 'undefined') {
query = payload
payload = undefined
}

ensureValidData(params, args)
ensureValidData(body, payload)
ensureValidData(queryString, query)

let paramsCount = (path.match(/:[^\/]*/) || []).length

const fullPath = args.reduce((acc, arg) => {
paramsCount -= 1

return acc.replace(/:[^\/]*/, arg)
}, path)

if (paramsCount !== 0) throw new Error('TODO: give me a meangingful error')

// TODO: add query

options = defaults({}, defaultOptions, options)

// TODO: last argument is allowed to be object, JSON payload
// TODO: reject if body doesn't match body spec if strict

return client.request(method, path, {})
return client.request(method, fullPath, payload, options)
}
}
}

+ 29
- 0
src/validation.ts View File

@@ -0,0 +1,29 @@
import { SchemaLike, validate } from 'joi'

export interface Validator {
validate (data: any[] | {}): boolean
}

function isCustomValidator (spec: any): spec is Validator {
return !!spec && !spec.isJoi && 'validate' in spec
}

export function ensureValidData (spec: SchemaLike | Validator | undefined, data: any[]) {
if (!spec) return

if (isCustomValidator(spec)) {
const valid = spec.validate(data)

if (valid) return
}

const { error } = validate(data, spec)

if (!error) return

throw new Error('TODO: give me a meangingful error')
}

export { SchemaLike }

export type ValdiationSpec = SchemaLike | Validator

+ 159
- 28
test/method.spec.ts View File

@@ -1,59 +1,190 @@
/// <reference path='typings/globals.d.ts' />

import method from '../src/method'
import method, { MethodSpec } from '../src/method'

import { Client } from '../src/client'
import { MockClient } from './mocks/client'
import Joi from 'joi'

const mockMethodSpec = {}
const mockGetMethodNoParams: MethodSpec = {
path: '/mock-path',
accept: 'mock/type',
contentType: 'mock/type',
}

describe('Method', () => {
let mockClient: Client
const mockGetMethodWithParams: MethodSpec = {
path: '/mock-path/:param',
accept: 'mock/type',
contentType: 'mock/type',
}

const mockPostMethodNoParams: MethodSpec = {
path: '/mock-path',
method: 'POST',
body: Joi.object({
some: Joi.object({ mock: Joi.string().required() }).required()
}).required(),
accept: 'mock/type',
contentType: 'mock/type',
}

const mockPostMethodWithParams: MethodSpec = {
path: '/mock-path/:param',
method: 'POST',
// TODO: specify body spec
accept: 'mock/type',
contentType: 'mock/type',
}

const mockGetMethodWithQueryString: MethodSpec = {
path: '/mock-path/:param',
accept: 'mock/type',
contentType: 'mock/type',
queryString: {
some_arg: Joi.string().required()
}
}

describe('Method', async () => {
let client: Client
let methodGenerator
let methodFunction

before(() => {
mockClient = new MockClient()
client = { request (method, path, options) {} }
})

it('accepts client and returns generator function', () => {
methodGenerator = method(mockClient)
it('accepts client and returns generator function', async () => {
methodGenerator = method(client)

expect(true).to.deep.equal(true)
// expect(methodFunction).to.be.a.function() // TODO:
expect(methodGenerator).to.be.a('function')
})

it('accepts a method specification and returns a method function', () =>{
methodFunction = methodGenerator(mockMethodSpec)
methodFunction = methodGenerator(mockGetMethodNoParams)

// expect(methodFunction).to.be.a.function() // TODO:
expect(methodFunction).to.be.a('function')
})

describe('Method function', () => {
it('calls underlying request on client', () => {
methodFunction()
describe('Generated method function', async () => {
beforeEach(() => {
client = { request: sinon.spy() }
methodGenerator = method(client)
})

it('calls underlying request on client', async () => {
methodFunction = methodGenerator(mockGetMethodNoParams)

await methodFunction()

expect(client.request)
.to.have.been.calledOnceWithExactly(
'GET',
'/mock-path',
undefined,
{
headers: {
'Accept': mockGetMethodNoParams.accept,
'Content-Type': mockGetMethodNoParams.contentType,
}
}
)
})

it('requires path parameters if specified', async () => {
methodFunction = methodGenerator(mockGetMethodWithParams)

return expect(methodFunction()).to.eventually.be.rejected
})

it('passes path parameters if specified', async () => {
methodFunction = methodGenerator(mockGetMethodWithParams)

await methodFunction(10)

expect(client.request)
.to.have.been.calledOnceWithExactly(
'GET',
'/mock-path/10',
undefined,
{
headers: {
'Accept': mockGetMethodNoParams.accept,
'Content-Type': mockGetMethodNoParams.contentType,
}
}
)
})

it('requires body arguments if specified', async () => {
methodFunction = methodGenerator(mockPostMethodNoParams)

// expect(someSpy).to.be.called.once.with.exaclty() // TODO:
return expect(methodFunction()).to.eventually.be.rejected
})

it('requires path parameters if specified', () => {
// methodFunction = undefined
// methodFunction() // should throw
it('passes body arguments if specified', async () => {
methodFunction = methodGenerator(mockPostMethodNoParams)
const payload = { some: { mock: 'payload '} }

await methodFunction(payload)

expect(client.request)
.to.have.been.calledOnceWithExactly(
'POST',
'/mock-path',
payload,
{
headers: {
'Accept': mockGetMethodNoParams.accept,
'Content-Type': mockGetMethodNoParams.contentType,
}
}
)
})

it('passes path parameters if specified', () => {
// methodFunction = undefined
// methodFunction(1) // should not throw
it('passes positional parameter and body arguments if specified', async () => {
methodFunction = methodGenerator(mockPostMethodWithParams)
const payload = { some: { mock: 'payload '} }

await methodFunction(10, payload)

expect(client.request)
.to.have.been.calledOnceWithExactly(
'POST',
'/mock-path/10',
payload,
{
headers: {
'Accept': mockGetMethodNoParams.accept,
'Content-Type': mockGetMethodNoParams.contentType,
}
}
)
})

it('requires body arguments if specified', () => {
// methodFunction = undefined
// methodFunction() // should throw
it('requires query string arguments if specified', async () => {
methodFunction = methodGenerator(mockGetMethodWithQueryString)

return expect(methodFunction()).to.eventually.be.rejected
})

it('passes body arguments if specified', () => {
// methodFunction = undefined
// methodFunction({ some: 'payload' })
it('passes query string arguments if specified', async () => {
methodFunction = methodGenerator(mockGetMethodWithQueryString)
const query = { some_arg: 'a-string' }

await methodFunction(10, query)

expect(client.request)
.to.have.been.calledOnceWithExactly(
'GET',
'/mock-path/10?some_arg=a-string',
undefined,
{
headers: {
'Accept': mockGetMethodNoParams.accept,
'Content-Type': mockGetMethodNoParams.contentType,
}
}
)
})
})
})

+ 0
- 14
test/mocks/client.ts View File

@@ -1,14 +0,0 @@
import { Client } from '../../src/client'


export class MockClient implements Client {
constructor () {
//
}

request (method: string, options: any) {
//
}
}

// TODO: export spies as well

+ 6
- 4
test/setup.ts View File

@@ -1,13 +1,15 @@
/// <reference path='typings/globals.d.ts' />

import chai from 'chai'
import sinon from 'sinon'

import sinonChai from 'sinon-chai'
import chaiAsPromised from 'chai-as-promised'

chai.use(sinonChai)
chai.use(chaiAsPromised)

global.chai = chai
global.expect = chai.expect
global.sinon = sinon

console.log('**************')
console.log('* SETUP DONE *')
console.log('**************')
global.expect = chai.expect

+ 2
- 0
test/typings/globals.d.ts View File

@@ -1,8 +1,10 @@
declare const sinon: any
declare const expect: any

declare namespace NodeJS {
interface Global {
chai: any
sinon: any
expect: any
}
}

+ 1
- 0
tsconfig.json View File

@@ -4,6 +4,7 @@
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"lib": [ "es2015" ],
"allowJs": false,
"declaration": true,
"declarationMap": true,

Loading…
Cancel
Save