Skip to content

Commit

Permalink
Remove --proxy requirement
Browse files Browse the repository at this point in the history
Remove pretender and use jquery-mockjax instead
Add a generator to add jquery-mockjax
  • Loading branch information
jakecraige committed Nov 4, 2014
1 parent 77a085b commit 8a08ac5
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 45 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.

Expand Down
11 changes: 11 additions & 0 deletions blueprints/ember-cli-proxy-fixtures/index.js
Original file line number Diff line number Diff line change
@@ -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');
}
};
25 changes: 20 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand All @@ -33,6 +41,7 @@ module.exports = {
outputFile: '/qunit-proxy-fixtures.js'
});
},

included: function(app) {
this.app = app;

Expand All @@ -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; }

Expand All @@ -82,8 +96,9 @@ module.exports = {
inputFiles: ['**/*.js'],
outputFile: '/assets/test-loader.js'
});

return this.mergeTrees([tree, testLoaderTree], {
overwrite: true
});
}
}
};
61 changes: 47 additions & 14 deletions lib/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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] || {};
Expand All @@ -85,3 +117,4 @@ module.exports = function(options) {
};
};
};

117 changes: 97 additions & 20 deletions lib/qunit.js
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -12,27 +12,52 @@ 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];

function escape(str) {
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;
});
});
});
}
}
Expand All @@ -47,9 +72,8 @@ var proxyFixtures = function proxyFixtures(name) {
}
});

if (server) {
server.shutdown();
}
Ember.$(document).off('ajaxSuccess', cacheRequest);
Ember.$.mockjax.clear();
}
});

Expand All @@ -60,6 +84,7 @@ var proxyFixtures = function proxyFixtures(name) {
url: 'clear-fixtures'
}).done(function() {
useProxyFixtures = true;
cachedRequests = [];
}).always(function() {
QUnit.start();
});
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 8a08ac5

Please sign in to comment.