Skip to content
This repository has been archived by the owner on Feb 27, 2022. It is now read-only.

Commit

Permalink
feat(request): add base request class
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Aug 28, 2017
1 parent 941a074 commit e50291f
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 0 deletions.
120 changes: 120 additions & 0 deletions src/Request/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
'use strict'

/*
* adonis-vow
*
* (c) Harminder Virk <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

const Macroable = require('macroable')
const nodeCookie = require('node-cookie')

module.exports = function () {
/**
* This is base request class to be used
* by other request clients. For example:
* Api client and browser client.
*
* @class BaseRequest
* @constructor
*/
class Request extends Macroable {
constructor (Config) {
super()
this.Config = Config
this._cookies = []
this._hooks = {
before: [],
after: []
}
}

/**
* Returns an array of cookies to be
* set as header
*
* @method cookies
*
* @return {Array}
*/
get cookies () {
return this._cookies
}

/**
* Add a cookie to the request
*
* @method cookie
*
* @param {String} key
* @param {Mixed} value
*
* @chainable
*/
cookie (key, value) {
const appKey = this.Config.get('app.appKey')
value = nodeCookie.packValue(value, appKey, !!appKey)
this._cookies.push({ key, value })
return this
}

/**
* Add a new hook before request starts
*
* @method before
*
* @param {Function} fn
*
* @chainable
*/
before (fn) {
this._hooks.before.push(fn)
return this
}

/**
* Add a new hook for after request completes
*
* @method after
*
* @param {Function} fn
*
* @chainable
*/
after (fn) {
this._hooks.after.push(fn)
return this
}

/**
* Execute request hooks in sequence
*
* @method exec
*
* @param {String} event - Must be `before` or `after`
*
* @return {void}
*/
async exec (event) {
if (event !== 'before' && event !== 'after') {
throw new Error(`${event} is not a valid hook event for vow request`)
}

const hooks = this._hooks[event]
for (const hook of hooks) {
await hook(this)
}
}
}

/**
* Properties for macroable
*/
Request._macros = {}
Request._getters = {}

return Request
}
9 changes: 9 additions & 0 deletions src/Suite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

const { Test, Group } = require('japa/api')
const Context = require('../Context')
const Request = require('../Request')
const props = require('../../lib/props')

/**
Expand Down Expand Up @@ -60,6 +61,14 @@ class Suite {
*/
this.Context = Context()

/**
* Reference of Request class, that should be extended
* by other request clients.
*
* @type {BaseRequest}
*/
this.Request = Request()

/**
* The timeout to be added to all the test
* under a suite.
Expand Down
127 changes: 127 additions & 0 deletions test/unit/request.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict'

/*
* adonis-vow
*
* (c) Harminder Virk <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

const test = require('japa')
const { Config } = require('@adonisjs/sink')
const Request = require('../../src/Request')()
const nodeCookie = require('node-cookie')
const sleep = function (time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}

test.group('Request', (group) => {
group.beforeEach(() => {
Request.hydrate()
})

test('instantiate request', (assert) => {
const request = new Request(new Config())
assert.instanceOf(request, Request)
})

test('define request getter', (assert) => {
Request.getter('foo', () => 'bar')
const request = new Request(new Config())
assert.equal(request.foo, 'bar')
})

test('define request macro', (assert) => {
Request.macro('foo', () => 'bar')
const request = new Request(new Config())
assert.equal(request.foo(), 'bar')
})

test('add new cookie', (assert) => {
const request = new Request(new Config())
request.cookie('name', 'foo')
assert.deepEqual(request.cookies, [{ key: 'name', value: 'foo' }])
})

test('add encrypted cookie', (assert) => {
const config = new Config()
config.set('app.appKey', 'alongrandomstring')

const request = new Request(config)
request.cookie('name', 'foo')
assert.equal(nodeCookie.unPackValue(request.cookies[0].value, config.get('app.appKey'), true), 'foo')
})

test('add before request hook', (assert) => {
const request = new Request(new Config())
const fn = function () {}
request.before(fn)
assert.deepEqual(request._hooks.before, [fn])
})

test('add after request hook', (assert) => {
const request = new Request(new Config())
const fn = function () {}
request.after(fn)
assert.deepEqual(request._hooks.after, [fn])
})

test('execute hooks in sequence', async (assert) => {
const request = new Request(new Config())
const stack = []
request.before(() => {
stack.push('1')
})

request.before(async () => {
await sleep(100)
stack.push('2')
})

request.before(() => {
stack.push('3')
})

await request.exec('before')
assert.deepEqual(stack, ['1', '2', '3'])
})

test('throw exception when invalid hook type is passed', async (assert) => {
assert.plan(1)

const request = new Request(new Config())
const stack = []
request.before(() => {
stack.push('1')
})

request.before(async () => {
await sleep(100)
stack.push('2')
})

request.before(() => {
stack.push('3')
})

try {
await request.exec('foo')
} catch ({ message }) {
assert.equal(message, 'foo is not a valid hook event for vow request')
}
})

test('should have access to request instance inside hook', async (assert) => {
assert.plan(1)
const request = new Request(new Config())

request.before((req) => {
assert.deepEqual(req, request)
})
await request.exec('before')
})
})
18 changes: 18 additions & 0 deletions test/unit/suite.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,22 @@ test.group('Suite', () => {
assert.lengthOf(suite.group._tests, 0)
props.grep = null
})

test('adding macro to one suite request should not show up on other suite', (assert) => {
props.grep = 'bar'
const suite = new Suite('foo')
const suite1 = new Suite('bar')

suite.trait(function ({ Request }) {
Request.macro('foo', () => 'bar')
})

suite.traits.forEach((trait) => trait.action(suite))

const request = new suite.Request()
assert.isFunction(request.foo)

const request1 = new suite1.Request()
assert.isUndefined(request1.foo)
})
})

0 comments on commit e50291f

Please sign in to comment.