From 8a08ac5c5ddff43c6c8e9db5760cd04a83d5704b Mon Sep 17 00:00:00 2001 From: Jake Craige Date: Wed, 8 Oct 2014 06:52:13 -0500 Subject: [PATCH] Remove --proxy requirement Remove pretender and use jquery-mockjax instead Add a generator to add jquery-mockjax --- README.md | 7 +- blueprints/ember-cli-proxy-fixtures/index.js | 11 ++ index.js | 25 +++- lib/middleware.js | 61 +++++++--- lib/qunit.js | 117 +++++++++++++++---- package.json | 6 +- 6 files changed, 182 insertions(+), 45 deletions(-) create mode 100644 blueprints/ember-cli-proxy-fixtures/index.js diff --git a/README.md b/README.md index c5363eb..d0bff16 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,13 @@ module. ```bash npm install ember-cli-proxy-fixtures --save-dev +ember generate ember-cli-proxy-fixtures ``` ## Usage ## -You must start the ember app with a proxy in order to use the proxy -fixtures. +All requests that `jQuery.ajax` will be captured through `jquery-mockjax`. This +includes requests that go through ember-cli's proxy. All proxy fixtures are saved to `tests/fixtures/proxy`. They will be namespaced under a directory matching the module name for the test and each file name will @@ -58,7 +59,7 @@ This library follows [Semantic Versioning](http://semver.org) ## Want to help? ## -Please do! We are always looking to improve this gem. Please see our +Please do! We are always looking to improve this addon. Please see our [Contribution Guidelines](https://github.com/dockyard/ember-cli-proxy-fixtures/blob/master/CONTRIBUTING.md) on how to properly submit issues and pull requests. diff --git a/blueprints/ember-cli-proxy-fixtures/index.js b/blueprints/ember-cli-proxy-fixtures/index.js new file mode 100644 index 0000000..2b7bbad --- /dev/null +++ b/blueprints/ember-cli-proxy-fixtures/index.js @@ -0,0 +1,11 @@ +module.exports = { + normalizeEntityName: function() { + // this prevents an error when the entityName is + // not specified (since that doesn't actually matter + // to us + }, + + afterInstall: function() { + return this.addBowerPackageToProject('jquery-mockjax', '~1.6.0'); + } +}; diff --git a/index.js b/index.js index 4f36006..e5a1848 100644 --- a/index.js +++ b/index.js @@ -3,12 +3,20 @@ var path = require('path'); var mkdirp = require('mkdirp'); var jsonConcat = require('broccoli-json-concat'); var middleware = require('./lib/middleware'); +var bodyParser = require('body-parser'); +var path = require('path'); module.exports = { name: 'ember-cli-proxy-fixtures', + validEnv: function() { return this.app.env !== 'production' && this.app.env !== 'staging'; }, + + blueprintsPath: function() { + return path.join(__dirname, 'blueprints'); + }, + treeForVendor: function() { if(!this.validEnv()) { return; } @@ -33,6 +41,7 @@ module.exports = { outputFile: '/qunit-proxy-fixtures.js' }); }, + included: function(app) { this.app = app; @@ -41,25 +50,30 @@ module.exports = { app.import('vendor/qunit-proxy-fixtures.js', { type: 'test' }); + app.import(app.bowerDirectory + '/jquery-mockjax/jquery.mockjax.js', { + type: 'test' + }); }, + serverMiddleware: function(options) { if(!this.validEnv()) { return; } this.project.liveReloadFilterPatterns.push('tests/fixtures/proxy'); - - if (options.options.proxy) { - this.middleware(options.app, options.options); - } + this.middleware(options.app, options.options); }, + middleware: function(app, options) { options.srcDir = path.join(this.project.root, 'tests/fixtures/proxy'); + app.use(bodyParser.json()); app.use(middleware(options)); }, + testemMiddleware: function(app) { if(!this.validEnv()) { return; } this.middleware(app, {}); }, + postprocessTree: function(type, tree) { if(!this.validEnv()) { return tree; } @@ -82,8 +96,9 @@ module.exports = { inputFiles: ['**/*.js'], outputFile: '/assets/test-loader.js' }); + return this.mergeTrees([tree, testLoaderTree], { overwrite: true }); } -} +}; diff --git a/lib/middleware.js b/lib/middleware.js index 4ebfc5a..173d988 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -16,15 +16,29 @@ module.exports = function(options) { if (res._headers['content-encoding'] === 'gzip') { var _this = this; zlib.unzip(body, function(err, body) { - addFixture(_this, body.toString()); + addFixtureFromProxy(_this, body.toString()); }); } else { - addFixture(this, body.toString()); + addFixtureFromProxy(this, body.toString()); } return write.apply(this, arguments); }; if (req.method === 'POST' && req.url === '/write-fixtures') { + if(req.body.length) { + req.body.forEach(function(request) { + var options = { + moduleName: request.reqHeaders['x-module-name'], + testName: request.reqHeaders['x-test-name'], + method: request.method, + url: request.url, + statusCode: request.statusCode, + headers: request.headers + }; + addFixture(options, JSON.stringify(request.body)); + }); + } + writeFixtures(); } else if (req.method === 'DELETE' && req.url === '/clear-fixtures') { clearFixtures(); @@ -50,25 +64,43 @@ module.exports = function(options) { } }; - function addFixture (res, body) { - var moduleName = req.headers['x-module-name']; - var testName = req.headers['x-test-name']; - var method = res.req.method.toLowerCase(); - var parsedUrl = url.parse(res.req.url); - var pathname = parsedUrl.pathname; + function addFixtureFromProxy(req, body) { + if(!req.headers || !req.headers['x-module-name'] || !req.headers['x-test-name']) { + return; + } + + var options = { + moduleName: req.headers['x-module-name'], + testName: req.headers['x-test-name'], + method: res.req.method.toLowerCase(), + url: res.req.url, + headers: {} + }; + + if (moduleName && testName) { + for (var headerKey in res._headers) { + options.headers[res._headerNames[headerKey]] = res._headers[headerKey]; + } + } + + return addFixture(options, body); + } + + function addFixture (options, body) { + var moduleName = options.moduleName; + var testName = options.testName; + var method = options.method.toLowerCase(); + var parsedUrl = url.parse(options.url); + var pathname = url.format(parsedUrl).split('?')[0]; var query = parsedUrl.query || ''; if (moduleName && testName) { var fixture = { - statusCode: res.statusCode, - headers: {}, + statusCode: options.statusCode, + headers: options.headers, body: body }; - for (var headerKey in res._headers) { - fixture.headers[res._headerNames[headerKey]] = res._headers[headerKey]; - } - delete fixture.headers['content-encoding']; fixtures[moduleName] = fixtures[moduleName] || {}; @@ -85,3 +117,4 @@ module.exports = function(options) { }; }; }; + diff --git a/lib/qunit.js b/lib/qunit.js index 7a3f0e2..c5b360a 100644 --- a/lib/qunit.js +++ b/lib/qunit.js @@ -1,7 +1,7 @@ var proxyFixtures = function proxyFixtures(name) { - var server; var proxyFixtures = window[name]; var useProxyFixtures = false; + var cachedRequests = []; QUnit.testStart(function(details) { if (useProxyFixtures) { @@ -12,6 +12,9 @@ var proxyFixtures = function proxyFixtures(name) { } }); + Ember.$(document).on('ajaxSuccess', cacheRequest); + + var proxyFixtures = window[name]; if (proxyFixtures && proxyFixtures[details.module] && proxyFixtures[details.module][details.name]) { var fixtures = proxyFixtures[details.module][details.name]; @@ -19,20 +22,42 @@ var proxyFixtures = function proxyFixtures(name) { return str.replace(/'/g, "\\'"); } - server = new Pretender(function() { - for (var path in fixtures) { - for (var method in fixtures[path]) { - var code = "" + - "var proxyFixtures = window['"+name+"'];\n" + - "var query = Ember.$.param(request.queryParams);\n" + - "var fixtures = proxyFixtures['"+escape(details.module)+"']['"+escape(details.name)+"'];\n" + - "var fixture = fixtures['"+path+"']['"+method+"'][query].fixtures[fixtures['"+path+"']['"+method+"'][query].offset];\n" + - "fixtures['"+path+"']['"+method+"'][query].offset += 1;\n" + - "return [fixture.statusCode, fixture.headers, fixture.body];\n"; - var fn = new Function("server", "request", code); - this[method](path, fn.bind("request", this)); - } - } + Ember.keys(fixtures).forEach(function(fixtureUrl) { + Ember.keys(fixtures[fixtureUrl]).forEach(function(method){ + Ember.$.mockjax(function(settings) { + var url = parseUrl(settings.url); + var settingsMethod = settings.method || settings.type; + + if(url.path === fixtureUrl && settingsMethod.toLowerCase() === method.toLowerCase()) { + var path = url.path; + var query = ''; + + if(settingsMethod === 'GET') { + if(settings.data) { + query = Ember.$.param(settings.data) + } else { + query = url.query; + } + } + + var proxyFixtures = window[name]; + var fixtures = proxyFixtures[escape(details.module)][escape(details.name)]; + var fixture = fixtures[path][method][query].fixtures[fixtures[path][method][query].offset]; + fixtures[path][method][query].offset += 1; + + fixture.headers['x-mockjax-response'] = 'true'; + + return { + responseTime: 0, + method: settingsMethod, + headers: fixture.headers, + responseText: JSON.parse(fixture.body) + } + } + + return false; + }); + }); }); } } @@ -47,9 +72,8 @@ var proxyFixtures = function proxyFixtures(name) { } }); - if (server) { - server.shutdown(); - } + Ember.$(document).off('ajaxSuccess', cacheRequest); + Ember.$.mockjax.clear(); } }); @@ -60,6 +84,7 @@ var proxyFixtures = function proxyFixtures(name) { url: 'clear-fixtures' }).done(function() { useProxyFixtures = true; + cachedRequests = []; }).always(function() { QUnit.start(); }); @@ -68,11 +93,63 @@ var proxyFixtures = function proxyFixtures(name) { QUnit.done(function() { if (useProxyFixtures) { Ember.$.ajax({ - type: 'POST', - url: 'write-fixtures' + type: 'POST', + url: 'write-fixtures', + contentType: 'application/json', + dataType: 'json', + data: JSON.stringify(cachedRequests) }); } }); + + function cacheRequest(e, xhr, settings) { + if(!settings.headers || !settings.headers['x-module-name'] || !settings.headers['x-test-name']) { + return; + } + + var headers = headerStringToObject(xhr.getAllResponseHeaders()); + + // This prevents mocked requests from being re-saved + if(headers['x-mockjax-response'] === 'true') { + return; + } + + var cachedRequest = { + url: settings.url, + statusCode: xhr.status, + method: settings.type, + reqHeaders: settings.headers, + headers: headers, + body: JSON.parse(xhr.responseText.length > 1 ? xhr.responseText : '{}') + }; + + cachedRequests.push(cachedRequest); + } + + function parseUrl(url) { + var urlParts = url.toString().split('?'); + + return { + url: url, + path: urlParts[0], + query: urlParts[1] || '' + }; + } + + function headerStringToObject(headers) { + return Ember.A(headers.split(/\r\n|\n/)).reduce(function(acc, str) { + var split = str.split(':'); + var key = split[0]; + var value = split[1]; + + if(key && value) { + acc[key.trim()] = value.trim(); + } + + return acc; + }, {}); + } + }; QUnit.proxyFixtures = proxyFixtures; diff --git a/package.json b/package.json index 014e9bb..26ea1f6 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ }, "license": "MIT", "dependencies": { - "mkdirp": "0.5.0", - "ember-cli-pretender": "0.2.3", - "broccoli-json-concat": "0.0.4" + "body-parser": "^1.9.0", + "broccoli-json-concat": "0.0.4", + "mkdirp": "0.5.0" }, "devDependencies": { "assert": "1.1.2",