Created
October 2, 2013 08:59
-
-
Save nickknissen/6790962 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Middleware to mock GoCardless API requests | |
*/ | |
'use strict'; | |
var url = require('url'); | |
var _ = require('lodash'); | |
var db = require('./database.js'); | |
var POST = 'POST'; | |
var PUT = 'PUT'; | |
var PARAM_EXTRACT_BLACKLIST = ['/api/applied_plans']; | |
// Some POST data looks like: { endpoint_name: {actual: 'params'} } | |
// This function is used to extract the contents of `endpoint_name` if necessary | |
function extractParams(dataType, params) { | |
if (_.contains(PARAM_EXTRACT_BLACKLIST, dataType)) { | |
return params; | |
} else { | |
return params[Object.keys(params)[0]]; | |
} | |
} | |
// Set response headers if any are passed | |
function setHeaders(res, headers) { | |
if (_.isObject(headers)) { | |
Object.keys(headers).forEach(function(key) { | |
res.setHeader(key, JSON.stringify(headers[key])); | |
}); | |
} | |
} | |
module.exports = function(req, res, next) { | |
var pathName = url.parse(req.url).pathname; | |
if (!pathName.match(/\/api/)) return next(); | |
var method = req.method; | |
var response = db.find(pathName); | |
var params; | |
// If it's a POST, store the attributes to be returned on the next GET. | |
if (method === POST) { | |
params = extractParams(pathName, req.body); | |
response = db.create(pathName, params); | |
} | |
// If it's a PUT, update the attributes to be returned on the next GET. | |
if (method === PUT) { | |
params = extractParams(pathName, req.body); | |
response = db.update(pathName, params); | |
} | |
if (response == null) { | |
res.writeHead(404, 'API mock not found'); | |
return res.end(); | |
} | |
setHeaders(res, response.headers); | |
res.end(JSON.stringify(response.body)); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var _ = require('lodash'); | |
// Initial data - contains data required by every spec, e.g. user. | |
var data = { | |
'/api/features': { | |
headers: {}, | |
body: {} | |
}, | |
'/api/user': { | |
headers: {}, | |
body: { | |
id: '123ABC', | |
authorized: true, | |
developer_enabled: true, | |
email: '[email protected]', | |
first_name: 'Barry', | |
last_name: 'White' | |
} | |
}, | |
'/api/settings/merchant': { | |
headers: {}, | |
body: { | |
use_custom_reference: true | |
} | |
} | |
}; | |
function deepClone(input) { | |
return JSON.parse(JSON.stringify(input)); | |
} | |
// Store a clone of the initial data to allow resetting. | |
var originalData = deepClone(data); | |
module.exports = { | |
find: function(url) { | |
return data[url]; | |
}, | |
// Store POSTed data and add a created_at attribute. | |
create: function(url, requestData) { | |
requestData = requestData || {}; | |
requestData.created_at = new Date(); | |
var dataSet = data[url]; | |
// Create a db object if it doesn't exist | |
if (dataSet == null) { | |
dataSet = { | |
headers: {}, | |
body: [] | |
}; | |
data[url] = dataSet; | |
} | |
dataSet.body.push(requestData); | |
return data; | |
}, | |
// Find and update PUTed records. | |
update: function(url, requestdata) { | |
var dataSet = data[url] && data[url].body; | |
// If there's no dataset, try to find one based on the /route/:id pattern | |
if (dataSet == null) { | |
var splitUrl = url.split('/'); | |
var id = splitUrl[splitUrl.length - 1]; | |
var urlBase = splitUrl.slice(0, -1).join('/'); | |
dataSet = data[urlBase].body; | |
} | |
// Search the dataSet array for the matching record. | |
if (_.isArray(dataSet)) { | |
dataSet = _.find(dataSet, function(record) { | |
return record.id === id; | |
}); | |
} | |
// Update the found record and return the new reppresentation. | |
return _.extend(dataSet, requestdata); | |
}, | |
// TODO: probably need to handle DELETE /object/:id | |
destroy: function(url) { | |
var dataSet = data[url].body; | |
data[url] = (_.isArray(dataSet) ? [] : {}); | |
}, | |
// Add a new mock, overwriting the old one if it existed | |
mock: function(url, body, headers) { | |
data[url] = { | |
body: body, | |
headers: headers || {} | |
}; | |
}, | |
// Set the data store back to pristine state and reclone originalData | |
reset: function() { | |
data = originalData; | |
originalData = deepClone(originalData); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var _ = require('lodash'); | |
var db = require('../../config/integration/database.js'); | |
var glob = require('glob'); | |
var factories = {}; | |
function getFactory(type) { | |
var factory = factories[type]; | |
if (factory == null) { | |
throw new Error('Factory ' + type + ' is not defined'); | |
} | |
return factory; | |
} | |
function define(type, url, attrs) { | |
if (factories[type]) { | |
throw new Error('Factory ' + type + ' is already defined'); | |
} | |
var factory = factories[type] = { | |
url: url, | |
attrs: attrs | |
}; | |
return factory; | |
} | |
function build(type) { | |
var factory = getFactory(type); | |
return _.chain(factory.attrs).map(function(val, key) { | |
// Return a [key, value] tuple which we can call `object` on later | |
return [key, (_.isFunction(val) ? val() : val)]; | |
}).object().value(); | |
} | |
function create(type) { | |
var data = build(type); | |
var url = getFactory(type).url; | |
db.create(url, data); | |
return data; | |
} | |
module.exports = { | |
define: define, | |
create: create, | |
build: build | |
}; | |
// Bootstrap - reuire all factories which each call to factory.define | |
glob.sync(__dirname + '/**-factory.js').forEach(require); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An example configuration file. | |
exports.config = { | |
// ----- How to setup Selenium | |
// There are three ways to specify how to use Selenium. Specify one of the | |
// following: | |
// 1. seleniumServerJar - to start Selenium Standalone locally. | |
// 2. seleniumAddress - to connect to a Selenium server which is already | |
// running. | |
// 3. sauceUser/sauceKey - to use remote Selenium servers via SauceLabs. | |
// The location of the selenium standalone server .jar file. | |
seleniumServerJar: './selenium/selenium-server-standalone-2.33.0.jar', | |
// The port to start the selenium server on, or null if the server should | |
// find its own unused port. | |
seleniumPort: 4321, | |
// Chromedriver location is used to help the selenium standalone server | |
// find chromedriver. This will be passed to the selenium jar as | |
// the system property webdriver.chrome.driver. If null, selenium will | |
// attempt to find chromedriver using PATH. | |
chromeDriver: './selenium/chromedriver', | |
// Additional command line options to pass to selenium. For example, | |
// if you need to change the browser timeout, use | |
// seleniumArgs: [-browserTimeout=60], | |
seleniumArgs: [], | |
// If sauceUser and sauceKey are specified, seleniumServerJar will be ignored. | |
// sauceUser: null, | |
// sauceKey: null, | |
// The address of a running selenium server. | |
// seleniumAddress: 'http://localhost:4444/wd/hub', | |
// Spec patterns are relative to the current working directly when | |
// protractor is called. | |
specs: ['./client/spec/config/protractor.init.js'], | |
// ----- Capabilities to be passed to the webdriver instance. | |
// For a full list of available capabilities, see | |
// https://code.google.com/p/selenium/wiki/DesiredCapabilities | |
capabilities: { | |
'browserName': 'chrome' | |
}, | |
// A base URL for your application under test. Calls to protractor.get() | |
// with relative paths will be prepended with this. | |
baseUrl: 'http://localhost:4003', | |
// ----- Options to be passed to minijasminenode. | |
jasmineNodeOpts: { | |
// onComplete will be called before the driver quits. | |
onComplete: null, | |
isVerbose: false, | |
showColors: true, | |
includeStackTrace: true | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Protractor Bootstrap - configure protractor globals and require all spec | |
* files. | |
*/ | |
'use strict'; | |
var url = require('url'); | |
var path = require('path'); | |
var glob = require('glob'); | |
var connect = require('connect'); | |
var config = require('./protractor.conf.js').config; | |
var middleware = require('./protractor.server.js'); | |
// Run test server in same process as specs | |
var port = url.parse(config.baseUrl).port; | |
var server = connect(); | |
middleware = middleware(connect); | |
middleware.forEach(server.use.bind(server)); | |
server.listen(port); | |
// Export protractor globals to use in spec files | |
global.protractor = require('protractor'); | |
global.ptor = global.protractor.getInstance(); | |
require('protractor/jasminewd'); | |
var specPath = path.join(process.cwd(), 'client', 'spec', 'integration'); | |
// Require and run helpers | |
var helperPath = path.join(specPath, 'helpers'); | |
glob.sync(helperPath + '/**/*.js').forEach(require); | |
// Require (and run) all integration specs | |
glob.sync(specPath + '/**/*spec.js').forEach(require); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* | |
* This file defines a set of connect middleware to build an integration test | |
* server. | |
* 1. Serve static files | |
* 2. Concatenate and serve the application files | |
* 3. Serve the index.html to all Angular-looking requests | |
*/ | |
var fs = require('fs'); | |
var path = require('path'); | |
var mockApi = require('./integration/api.js'); | |
var publicPath = path.join(process.cwd(), 'public'); | |
module.exports = function(connect /*, options*/) { | |
return [ | |
connect.json(), | |
mockApi, | |
connect.static(publicPath), | |
// Serve index for Angular routes | |
function(req, res, next) { | |
// Fall through to 404 if there's a path extension. | |
// Our Angular routes don't have this so it must be a request for a | |
// resource that's not there. | |
if (path.extname(req.url) !== '') { return next(); } | |
// Else render the index.html and let our router handle it. | |
res.setHeader('Content-Type', 'text/html'); | |
res.writeHead(200); | |
var indexPath = path.join(publicPath, 'app-index.html'); | |
fs.createReadStream(indexPath).pipe(res); | |
} | |
]; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment