From 770ef47a402467aa2439fc00fb2e2f188d4a0d36 Mon Sep 17 00:00:00 2001 From: gits2501 Date: Sat, 19 May 2018 12:28:18 +0200 Subject: [PATCH] Added tests and code coverage --- .eslintrc.yml | 241 ++++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + .travis.yml | 11 +++ LICENSE | 21 +++++ README.md | 2 + package.json | 13 ++- src/Options.js | 134 ++++----------------------- test/options.js | 187 +++++++++++++++++++++++++++++++++++++ 8 files changed, 491 insertions(+), 119 deletions(-) create mode 100644 .eslintrc.yml create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 test/options.js diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..2e2ac43 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,241 @@ +env: + es6: true + node: true +extends: 'eslint:recommended' +rules: + accessor-pairs: error + array-bracket-newline: error + array-bracket-spacing: error + array-callback-return: error + array-element-newline: error + arrow-body-style: error + arrow-parens: error + arrow-spacing: error + block-scoped-var: error + block-spacing: error + brace-style: + - error + - stroustrup + callback-return: error + camelcase: + - error + - properties: never + capitalized-comments: 'off' + class-methods-use-this: error + comma-dangle: error + comma-spacing: 'off' + comma-style: + - error + - last + complexity: error + computed-property-spacing: + - error + - never + consistent-return: error + consistent-this: error + curly: 'off' + default-case: 'off' + dot-location: error + dot-notation: error + eol-last: error + eqeqeq: error + for-direction: error + func-call-spacing: error + func-name-matching: 'off' + func-names: 'off' + func-style: + - error + - declaration + function-paren-newline: error + generator-star-spacing: error + getter-return: error + global-require: error + guard-for-in: 'off' + handle-callback-err: error + id-blacklist: error + id-length: error + id-match: error + implicit-arrow-linebreak: error + indent: 'off' + indent-legacy: 'off' + init-declarations: error + jsx-quotes: error + key-spacing: 'off' + keyword-spacing: 'off' + line-comment-position: 'off' + linebreak-style: + - error + - unix + lines-around-comment: 'off' + lines-around-directive: error + lines-between-class-members: error + max-depth: error + max-len: 'off' + max-lines: error + max-nested-callbacks: error + max-params: 'off' + max-statements: 'off' + max-statements-per-line: 'off' + multiline-comment-style: 'off' + new-parens: error + newline-after-var: 'off' + newline-before-return: 'off' + newline-per-chained-call: error + no-alert: error + no-array-constructor: error + no-await-in-loop: error + no-bitwise: error + no-buffer-constructor: error + no-caller: error + no-catch-shadow: error + no-confusing-arrow: error + no-continue: error + no-div-regex: error + no-duplicate-imports: error + no-else-return: 'off' + no-empty-function: error + no-eq-null: error + no-eval: error + no-extend-native: error + no-extra-bind: error + no-extra-label: error + no-extra-parens: 'off' + no-floating-decimal: error + no-implicit-coercion: error + no-implicit-globals: error + no-implied-eval: error + no-inline-comments: 'off' + no-inner-declarations: + - error + - functions + no-invalid-this: error + no-iterator: error + no-label-var: error + no-labels: error + no-lone-blocks: error + no-lonely-if: error + no-loop-func: error + no-magic-numbers: 'off' + no-mixed-operators: error + no-mixed-requires: error + no-multi-assign: error + no-multi-spaces: 'off' + no-multi-str: error + no-multiple-empty-lines: error + no-native-reassign: error + no-negated-condition: error + no-negated-in-lhs: error + no-nested-ternary: error + no-new: error + no-new-func: error + no-new-object: error + no-new-require: error + no-new-wrappers: error + no-octal-escape: error + no-param-reassign: 'off' + no-path-concat: error + no-plusplus: error + no-process-env: error + no-process-exit: error + no-proto: error + no-prototype-builtins: 'off' + no-restricted-globals: error + no-restricted-imports: error + no-restricted-modules: error + no-restricted-properties: error + no-restricted-syntax: error + no-return-assign: error + no-return-await: error + no-script-url: error + no-self-compare: error + no-sequences: 'off' + no-shadow: error + no-shadow-restricted-names: error + no-spaced-func: error + no-sync: error + no-tabs: error + no-template-curly-in-string: error + no-ternary: 'off' + no-throw-literal: error + no-trailing-spaces: 'off' + no-undef-init: error + no-undefined: error + no-underscore-dangle: error + no-unmodified-loop-condition: error + no-unneeded-ternary: error + no-unused-expressions: 'off' + no-use-before-define: error + no-useless-call: error + no-useless-computed-key: error + no-useless-concat: error + no-useless-constructor: error + no-useless-rename: error + no-useless-return: error + no-var: 'off' + no-void: error + no-warning-comments: error + no-whitespace-before-property: error + no-with: error + nonblock-statement-body-position: + - error + - any + object-curly-newline: error + object-curly-spacing: error + object-property-newline: error + object-shorthand: error + one-var: 'off' + one-var-declaration-per-line: error + operator-assignment: error + operator-linebreak: error + padded-blocks: 'off' + padding-line-between-statements: error + prefer-arrow-callback: error + prefer-const: error + prefer-destructuring: 'off' + prefer-numeric-literals: error + prefer-promise-reject-errors: error + prefer-reflect: 'off' + prefer-rest-params: error + prefer-spread: error + prefer-template: 'off' + quote-props: 'off' + quotes: 'off' + radix: error + require-await: error + require-jsdoc: 'off' + rest-spread-spacing: error + semi: 'off' + semi-spacing: + - error + - after: true + before: false + semi-style: + - error + - last + sort-imports: error + sort-keys: 'off' + sort-vars: error + space-before-blocks: 'off' + space-before-function-paren: 'off' + space-in-parens: 'off' + space-infix-ops: 'off' + space-unary-ops: error + spaced-comment: 'off' + strict: + - error + - never + switch-colon-spacing: error + symbol-description: error + template-curly-spacing: error + template-tag-spacing: error + unicode-bom: + - error + - never + valid-jsdoc: error + vars-on-top: 'off' + wrap-iife: error + wrap-regex: error + yield-star-spacing: error + yoda: + - error + - never diff --git a/.gitignore b/.gitignore index c2658d7..030fc7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +.nyc_output/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..37d8f5d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +node_js: + - '6.0.0' + - '8.6.0' + - '9.11.1' +git: + depth: 3 +cache: + directories: + - "node_modules" +after_success: 'npm run coveralls' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d46d5d9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 psychoActivePigtaur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7c502d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# twiz-server-options (wip) [![Build Status](https://travis-ci.org/gits2501/twiz-server-options.svg?branch=master)](https://travis-ci.org/gits2501/twiz-server-options) [![Coverage Status](https://coveralls.io/repos/github/gits2501/twiz-server-options/badge.svg?branch=master)](https://coveralls.io/github/gits2501/twiz-server-options?branch=master) +Sets request options out of parameters received in url. diff --git a/package.json b/package.json index a11c088..3f8f364 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,20 @@ "test": "test" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "lint": "eslint src/Options", + "mocha": "mocha test/options.js", + "test": "nyc npm run mocha", + "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "author": "gits2501", "license": "MIT", "dependencies": { - "twiz-client-utils": "file:../../../testing/TwizClientWithBroserify/dependencies/twiz-client-utils" + "twiz-client-utils": "https://github.com/gits2501/twiz-client-utils" + }, + "devDependencies": { + "coveralls": "^3.0.1", + "eslint": "^4.19.1", + "mocha": "^5.2.0", + "nyc": "^11.8.0" } } diff --git a/src/Options.js b/src/Options.js index 1af35ee..7d76535 100644 --- a/src/Options.js +++ b/src/Options.js @@ -13,95 +13,33 @@ function Options (options, vault, args){ // builds request options and confugure var reqHeaders = { // holds headers of a request 'accept': "", - 'authorization': "", 'accept-language': "", - 'content-length': '0' // must be zero when method is POST with no body + 'content-length': '' // must be zero when method is POST with no body } - - function addUtils() { - this.missingVal_SBS = { - consumer_key: 'consumer_key',// Name of consumer key as it stands in OAuth (for SBS), without 'oauth' - // prefix. Used when inserting consumer_key value - token: 'token', // Name of access token param for SBS string. Used for inserting token. - marker: percentEncode("=&"), // "%3D%26" missing value marker for signature base string - offset: 3 // Esentialy length of percent encoded "&", we place missing between "=" - // and "&" - }, - - this.missingVal_AHS = { - signature:'signature', - marker: "=\"\"", // ="" - missing value marker for authorization header string (AHS) - offset: 1 - }, - - this.SBS_AHS_insert = function(phase, key, value){ // inserts missing keyValue pair to SBS and AH - var sbs = this[phase + 'SBS']; console.log('sbs_ah insert:',phase,sbs) // sbs of a phase) - this[phase + 'SBS'] = this.insertKey(sbs, this.missingVal_SBS, key, value); // set key in SBS - - var ahs = this[phase + 'AH']; // take authorization header string of a phase - this[phase + 'AH'] = this.insertKey(ahs, this.missingVal_AHS, key , value, true);// set key/val in AH - - }, - - this.insertKey = function(insertString, missingVal, keyName, keyValue, ah){ // insert missing key/value - var str = insertString; - var len = (keyName.length + missingVal.marker.length) - missingVal.offset;// calcualte idx from where // we insert the value - var idx = str.indexOf(keyName); // take index of the key we search - // console.log("marker: "+missingVal.marker, "consumer_key: "+ value, "idx: "+idx, "len: "+len) - var front = str.slice(0, idx + len); // taking first part - var end = str.slice(idx + len ) // taking second part - // console.log("front: " + front) - keyValue = ah ? percentEncode(keyValue) : percentEncode(percentEncode(keyValue)); - // single encoding if - // insertString is AHS - str = front + keyValue + end; // assemble the string with new key/value - console.log("inserted: "+ str); - return str; - } - - this.removeSubstr = function removeSubstr(str, regstr){ // removes subtring from a string - var regexp = new RegExp(regstr); // create regexp object from string - var removed = str.replace(regexp,''); // replace regexp pattern with empty string (remove it) - - return removed; - } - - this.trimEnd = function (str, endChars){ // Trims ending chars we specify, from a string - var endlength = endChars.length; // Lenght of characters we search at the end - var strlength = str.length // Lenght of the string - var end = str.slice(strlength - endlength, strlength); // Take end of the string - console.log('end', end) - if(end === endChars) return str.slice(0, strlength - endlength); // Chars are at the end, slice them - else return str; // Or return unchanged string - } - - } - - function addPhaseParams(){ // Adds parametars for each phase we support - addUtils.call(this); // add utility function that use phase params - this.apiSBS = ''; // SBS for api calls - this.apiAH = ''; // Ah for api calls - this.apiHost = ''; // host we hit for api calls + function addParams(){ // Adds parametars for each type (phase) of request + this.apiSBS = ''; // SBS for api calls + this.apiAH = ''; // Ah for api calls + this.apiHost = ''; // host we hit for api calls this.apiPath = ''; this.apiMethod = ''; - this.legSBS = ''; // Signature base string for OAuth legs (steps) - this.legAH = ''; // Authorization header string + this.legSBS = ''; // Signature base string for OAuth legs (steps) + this.legAH = ''; // Authorization header string this.legHost = ''; this.legPath = ''; this.legMethod = ''; - this.verSBS = '' // SBS for verify credentials + this.verSBS = '' // SBS for verify credentials this.verAH = ''; this.verHost = ''; this.verPath = ''; this.verMethod = ''; } - function addFinalParams(){ // Adds parameters that node.js uses when sending a request - addPhaseParams.call(this) + function addFinalParams(){ // Adds final parameters that core http uses when sending a request + addParams.call(this) this.host = ""; this.path = ""; this.method = ""; @@ -120,19 +58,18 @@ function Options (options, vault, args){ // builds request options and confugure certNotSet: "You must provide cert (certificate) used in https encription when connecting to twitter.", keyNotSet: "You must provide key (private key) used in https encription when connecting to twitter", requestNotSet: "You must provide request (read) stream", - responseNotSet: "You must provide response (write) stream", + responseNotSet: "You must provide response (write) stream" }) this.initOptions = function init(req, res, next){ - console.log("in INIT") + // console.log("in INIT") // Encompases server logic args.request = req; args.response = res; args.next = next; this.setUserParams(args, vault); // Params needed for this lib to work - if(this.isPreflight()) return; // on preflighted requests stop here - console.log('before getOptions'); + // if(this.isPreflight()) return; // on preflighted requests stop here this.getOptions(reqHeaders); // Options sent in query portion of client request url and headers this.setOptions(vault, reqHeaders, options); // sets options used for twitter request @@ -167,8 +104,6 @@ function Options (options, vault, args){ // builds request options and confugure case "cert": vault.cert = args[name]; // reference to certificate used in https encription break; - default: - console.log(name + " not supported"); } } @@ -181,7 +116,6 @@ function Options (options, vault, args){ // builds request options and confugure for(var name in vault){ switch(name){ - case "key": if(!vault[name]) throw this.CustomError('keyNotSet'); break; @@ -203,7 +137,7 @@ function Options (options, vault, args){ // builds request options and confugure Options.prototype.getOptions = function(reqHeaders){ // gets params from query portion of request url this.sentOptions = url.parse(this.request.url, true).query // parses options sent in client request url - console.log('sentOptions: ', this.sentOptions); + // console.log('sentOptions: ', this.sentOptions); this.getRequestHeaders(reqHeaders); // gets headers from client request and puts them in reqHeaders }; @@ -234,7 +168,7 @@ function Options (options, vault, args){ // builds request options and confugure options.cert = vault.cert; // sets certificate (https) options.key = vault.key; // sets private_key used for https encription - console.log(" OPTIONS: ",options); + // console.log(" OPTIONS: ",options); }; @@ -243,47 +177,13 @@ function Options (options, vault, args){ // builds request options and confugure if(this.request.app){ // check express context this.app = this.request.app; - console.log('express confirmed'); + // console.log('express confirmed'); } else if(this.next){ // For connect context just check if there is 'next' function EventEmitter.init.call(this); // Call emitter constructor on this object this.app = this; // app is 'this', since we are linked to EventEmitter - console.log('Connect confirmed') + // console.log('Connect confirmed') } }; - - Options.prototype.isPreflight = function() { // has to go as saparate middleware - var preflight; console.log('Preflight: method:', this.request.method); - if (this.request.method == "OPTIONS"){ // Both needs to be plased for PREFLIGHT - preflight = true; - console.log("preflight request with OPTIONS"); - this.response.setHeader("Access-Control-Allow-Headers","content-type , authorization"); - this.response.setHeader("Access-Control-Allow-Origin", "https://gits2501.github.io"); - } - else { - this.response.setHeader("Access-Control-Allow-Origin","https://gits2501.github.io"); // Other (no preflight) can have just this. - // this.response.setHeader("Content-Type", "application/json"); - return preflight; - } - - console.log("URL source: " + this.request.url); console.log("url parsed:", url.parse(this.request.url, true).query) - console.log("domain: " + this.request.domain) - var body = ""; - - this.request.on('end', function(){ console.log("REQ ended") - console.log("Sent BODY: "+ body) - console.log("resp headers: " + this.response.headers) - }.bind(this)) - - this.request.on('error', function(err){ - console.log("Error: "+ err); - this.next(err) - }.bind(this)) - this.response.end(); - - - return preflight; - - } module.exports = Options; diff --git a/test/options.js b/test/options.js new file mode 100644 index 0000000..27f472c --- /dev/null +++ b/test/options.js @@ -0,0 +1,187 @@ +var Options = require('../src/Options.js'); +var assert = require('assert'); + + +var ssl_key = 'tlsServer-.pem'; // mock private key used in encription +var ssl_cert = 'tlsServerCert.pem'; // mock certificate +var cons_key = 'CONSUMER_KEY'; // mock ck +var cons_secret = 'CONSUMER_SECRET'; // mock cs + +// mock twiz-client url +var url = 'http://localhost:5000/?legHost=api.twitter.com&legPath=%2Foauth%2Frequest_token&legMethod=POST&legSBS=POST%26https%253A%252F%252Fapi.twitter.com%252Foauth%252Frequest_token%26oauth_callback%253Dhttps%25253A%25252F%25252Fgits2501.github.io%25252FQuoteOwlet%25252Findex.html%25253Fdata%25253Dquote%2525253DThey%2525252520say%2525252520the%2525252520owlet%2525252520brings%2525252520wisdom%25252526author%2525253Dtrough%2525252520random%2525252520quotes.%25252526hobbit%2525253Dname%252525253DPeregrin%2525252526lastName%252525253DTuk%25252526id%2525253D209%2526oauth_consumer_key%253D%2526oauth_nonce%253DbDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_timestamp%253D1526636582%2526oauth_version%253D1.0&legAH=OAuth+oauth_callback%3D%22https%253A%252F%252Fgits2501.github.io%252FQuoteOwlet%252Findex.html%253Fdata%253Dquote%25253DThey%25252520say%25252520the%25252520owlet%25252520brings%25252520wisdom%252526author%25253Dtrough%25252520random%25252520quotes.%252526hobbit%25253Dname%2525253DPeregrin%25252526lastName%2525253DTuk%252526id%25253D209%22%2C+oauth_consumer_key%3D%22%22%2C+oauth_nonce%3D%22bDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%22%2C+oauth_signature%3D%22%22%2C+oauth_signature_method%3D%22HMAC-SHA1%22%2C+oauth_timestamp%3D%221526636582%22%2C+oauth_version%3D%221.0%22&apiHost=api.twitter.com&apiPath=%2F1.1%2Fstatuses%2Fupdate.json%3Fstatus%3D%2522They%2520say%2520the%2520owlet%2520brings%2520wisdom%2522%250A%2520~%2520trough%2520random%2520quotes.&apiMethod=POST&apiSBS=POST%26https%253A%252F%252Fapi.twitter.com%252F1.1%252Fstatuses%252Fupdate.json%26oauth_consumer_key%253D%2526oauth_nonce%253DbDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_timestamp%253D1526636582%2526oauth_token%253D%2526oauth_version%253D1.0%2526status%253D%252522They%252520say%252520the%252520owlet%252520brings%252520wisdom%252522%25250A%252520~%252520trough%252520random%252520quotes.&apiAH=OAuth+oauth_consumer_key%3D%22%22%2C+oauth_nonce%3D%22bDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%22%2C+oauth_signature%3D%22%22%2C+oauth_signature_method%3D%22HMAC-SHA1%22%2C+oauth_timestamp%3D%221526636582%22%2C+oauth_token%3D%22%22%2C+oauth_version%3D%221.0%22&verHost=api.twitter.com&verPath=%2F1.1%2Faccount%2Fverify_credentials.json%3Finclude_entities%3Dfalse%26skip_status%3Dtrue%26include_email%3Dtrue&verMethod=GET&verSBS=GET%26https%253A%252F%252Fapi.twitter.com%252F1.1%252Faccount%252Fverify_credentials.json%26include_email%253Dtrue%2526include_entities%253Dfalse%2526oauth_consumer_key%253D%2526oauth_nonce%253DbDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_timestamp%253D1526636582%2526oauth_token%253D%2526oauth_version%253D1.0%2526skip_status%253Dtrue&verAH=OAuth+oauth_consumer_key%3D%22%22%2C+oauth_nonce%3D%22bDJZNXY2WDlCbWxRVHhXdDdHMGhDeEVSbVc5ZXQ2RQ%22%2C+oauth_signature%3D%22%22%2C+oauth_signature_method%3D%22HMAC-SHA1%22%2C+oauth_timestamp%3D%221526636582%22%2C+oauth_token%3D%22%22%2C+oauth_version%3D%221.0'; + +var headers = { // mock headers of a request + 'accept': "*/*", + 'accept-language': "en-US", + 'content-length': '0' +} + + // mock http request, response and next function +var request = { + 'url': url, + 'headers': headers +} +var response = {}; +var next = function(){}; + + +var mock = { + 'options': {}, + 'vault': {}, + + 'args':{ + 'consumer_key': cons_key, + 'consumer_secret': cons_secret, + 'key': ssl_key, + 'cert': ssl_cert + + } +} + +function errorValidation(name, err){ // used to check thrown errors by name + + if(err.name === name) return true; +} + +var op = new Options(mock.options, mock.vault, mock.args); + +describe('Options', function(){ + + describe('missing', function(){ + it('request - throw error', function(){ + assert.throws(op.initOptions.bind(op,'', response, next), errorValidation.bind(null, 'requestNotSet')) + }) + + it('response - throw error', function(){ + assert.throws(op.initOptions.bind(op, request,'', next), errorValidation.bind(null, 'responseNotSet')) + }) + + it('consumer_key - throw error', function(){ + mock.args.consumer_key = '' // simulate missing prop + assert.throws(op.initOptions.bind(op, request,response, next), errorValidation.bind(null, 'consumerKeyNotSet')) + mock.args.consumer_key = cons_key; // return its value + }) + + it('consumer_key - throw error', function(){ + mock.args.consumer_secret = '' // simulate missing prop + assert.throws(op.initOptions.bind(op, request,response, next), errorValidation.bind(null, 'consumerSecretNotSet')) + mock.args.consumer_secret = cons_secret; // return its value + }) + + + it('ssl private key - throw error', function(){ + mock.args.key = '' // simulate missing prop + assert.throws(op.initOptions.bind(op, request,response, next), errorValidation.bind(null, 'keyNotSet')) + mock.args.key = ssl_key; // return its value + }) + + it('ssl certificate - throw error', function(){ + mock.args.cert = '' // simulate missing prop + assert.throws(op.initOptions.bind(op, request,response, next), errorValidation.bind(null, 'certNotSet')) + mock.args.cert = ssl_cert; // return its value + }) + }) + + describe('get options from url', function(){ + + it('gets options', function(){ + assert.doesNotThrow(op.initOptions.bind(op, request, response, next)); + }) + + it('parse options', function(){ + assert.ok(op.sentOptions); + }) + + describe('possible options',function(){ + + it('apiHost', function(){ + assert.ok(op.sentOptions.apiHost); + }) + + it('apiPath', function(){ + assert.ok(op.sentOptions.apiPath); + }) + + it('apiMethod', function(){ + assert.ok(op.sentOptions.apiMethod); + }) + + + it('apiAuthorizationHeader', function(){ + assert.ok(op.sentOptions.apiAH); + }) + + it('apiSignatureBaseString', function(){ + assert.ok(op.sentOptions.apiSBS); + }) + + it('legHost', function(){ + assert.ok(op.sentOptions.legHost); + }) + + it('legPath', function(){ + assert.ok(op.sentOptions.legPath); + }) + + it('legMethod', function(){ + assert.ok(op.sentOptions.legMethod); + }) + + + it('legAuthorizationHeader', function(){ + assert.ok(op.sentOptions.legAH); + }) + + it('legSignatureBaseString', function(){ + assert.ok(op.sentOptions.legSBS); + }) + + it('verHost', function(){ + assert.ok(op.sentOptions.verHost); + }) + + it('verPath', function(){ + assert.ok(op.sentOptions.verPath); + }) + + it('verMethod', function(){ + assert.ok(op.sentOptions.verMethod); + }) + + + it('verAuthorizationHeader', function(){ + assert.ok(op.sentOptions.verAH); + }) + + it('verSignatureBaseString', function(){ + assert.ok(op.sentOptions.verSBS); + }) + + }) + }) + + describe('headers', function(){ + it('accept', function(){ + assert.equal(op.request.headers.accept, headers.accept); + }) + + it('accept-language', function(){ + assert.equal(op.request.headers['accept-language'], headers['accept-language']); + }) + }) + + describe('node.js framework', function(){ + it('express', function(){ + op.request.app = {}; // simulate express framework environment + op.initOptions(request, response, next) + assert.deepStrictEqual(op.app, op.request.app) + }) + + it('connect', function(){ + op.request.app = ''; // simulate no express framework + op.initOptions(request, response, next) + assert(op.app, op) + }) + }) + +})