diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..69fad35 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "bower_components" +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d5dea4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.hbs] +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7da12c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp + +# dependencies +/node_modules +/bower_components/* + +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..df6253d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +--- +language: node_js + +sudo: false + +cache: + directories: + - node_modules + +install: + - npm install -g bower + - npm install + - bower install + +script: + - npm test diff --git a/Brocfile.js b/Brocfile.js new file mode 100644 index 0000000..8c25bfe --- /dev/null +++ b/Brocfile.js @@ -0,0 +1,20 @@ +/* global require, module */ + +var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); + +var app = new EmberAddon(); + +// Use `app.import` to add additional libraries to the generated +// output files. +// +// If you need to use different assets in different +// environments, specify an object as the first parameter. That +// object's keys should be the environment name and the values +// should be the asset to use in that environment. +// +// If the library that you are including contains AMD or ES6 +// modules that you would like to import into your application +// please specify an object with the list of modules as keys +// along with the exports of each module as its value. + +module.exports = app.toTree(); diff --git a/README.md b/README.md new file mode 100644 index 0000000..d6aba1d --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Ember CLI Proxy Fixtures + +## About ## + +Capture Ember CLI proxy serer responses for faster playback on the +second run. + +## Install ## + +```bash +npm install ember-cli-proxy-fixtures --save-dev +``` + +## Usage ## + +You must start the ember app with a proxy in order to use the proxy +server. + +## Authors ## + +* [Brian Cardarella](http://twitter.com/bcardarella) + +[We are very thankful for the many contributors](https://github.com/dockyard/ember-cli-proxy-fixtures/graphs/contributors) + +## Versioning ## + +This library follows [Semantic Versioning](http://semver.org) + +## Want to help? ## + +Please do! We are always looking to improve this gem. 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. + +## Legal ## + +[DockYard](http://dockyard.com), Inc © 2014 + +[@dockyard](http://twitter.com/dockyard) + +[Licensed under the MIT license](http://www.opensource.org/licenses/mit-license.php) diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..751616f --- /dev/null +++ b/bower.json @@ -0,0 +1,13 @@ +{ + "name": "dummy", + "dependencies": { + "handlebars": "~1.3.0", + "jquery": "^1.11.1", + "ember": "1.7.0", + "ember-resolver": "~0.1.7", + "loader": "stefanpenner/loader.js#1.0.1", + "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3", + "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4", + "ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2" + } +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..bff2757 --- /dev/null +++ b/index.js @@ -0,0 +1,82 @@ +var fs = require('fs'); +var path = require('path'); +var mkdirp = require('mkdirp'); +var jsonConcat = require('broccoli-json-concat'); +var pickFiles = require('broccoli-static-compiler'); +var fileMover = require('broccoli-file-mover'); +var concat = require('broccoli-concat'); +var mergeTrees = require('broccoli-merge-trees'); +var middleware = require('./lib/middleware'); + +function unwatchedTree(dir) { + return { + read: function() { return dir; }, + cleanup: function() { } + }; +} + +module.exports = { + name: 'ember-cli-proxy-fixtures', + treeFor: function(name) { + if (name === 'vendor') { + var proxyFixturesPath = path.join(this.app.project.root, 'tests/fixtures/proxy'); + if (!fs.existsSync(proxyFixturesPath)) { + mkdirp.sync(proxyFixturesPath); + } + var proxyTree = jsonConcat(proxyFixturesPath, { + outputFile: 'proxyFixtures.js', + variableName: 'window.proxyFixtures' + }); + + var lib = unwatchedTree(path.join(__dirname, 'lib')); + var qunit = pickFiles(lib, { + files: ['qunit.js'], + srcDir: '/', + destDir: '/' + }); + + return concat(mergeTrees([proxyTree, qunit]), { + inputFiles: ['**/*.js'], + outputFile: '/qunit-proxy-fixtures.js' + }); + } + }, + included: function(app) { + this.app = app; + app.import('vendor/qunit-proxy-fixtures.js', { + type: 'test' + }); + }, + serverMiddleware: function(options) { + this.project.liveReloadFilterPatterns.push('tests/fixtures/proxy'); + var app = options.app; + options = options.options; + + if (options.proxy) { + options.srcDir = path.join(this.project.root, 'tests/fixtures/proxy'); + app.use(middleware(options)); + } + }, + postprocessTree: function(type, tree) { + var treeTestLoader = pickFiles(tree, { + files: ['test-loader.js'], + srcDir: 'assets', + destDir: 'app' + }); + + var lib = unwatchedTree(path.join(__dirname, 'lib')); + var proxyTestLoader = pickFiles(lib, { + files: ['test-loader.js'], + srcDir: '/', + destDir: 'proxy' + }); + + var testLoaderTree = concat(mergeTrees([treeTestLoader, proxyTestLoader]), { + inputFiles: ['**/*.js'], + outputFile: '/assets/test-loader.js' + }); + return mergeTrees([tree, testLoaderTree], { + overwrite: true + }); + } +} diff --git a/lib/middleware.js b/lib/middleware.js new file mode 100644 index 0000000..6d625ee --- /dev/null +++ b/lib/middleware.js @@ -0,0 +1,70 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var mkdirp = require('mkdirp'); + +module.exports = function(options) { + var fixtures; + var srcDir = options.srcDir; + + return function(req, res, next) { + var write = res.write; + res.write = function(body) { + addFixture(this, body.toString()); + return write.apply(this, arguments); + }; + + if (req.method === 'POST' && req.url === '/write-fixtures') { + writeFixtures(); + } else if (req.method === 'DELETE' && req.url === '/clear-fixtures') { + clearFixtures(); + } else { + delete req.headers['if-none-match']; + return next(); + } + + return res.end(); + + function clearFixtures() { + fixtures = {}; + }; + + function writeFixtures() { + var output; + for (var moduleName in fixtures) { + for (var testName in fixtures[moduleName]) { + mkdirp.sync(path.join(srcDir, moduleName)); + output = JSON.stringify(fixtures[moduleName][testName], null, 2); + fs.writeFileSync(path.join(srcDir, moduleName, testName + '.json'), output); + } + } + }; + + 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 fixture = { + statusCode: res.statusCode, + headers: {}, + body: body + }; + + for (var headerKey in res._headers) { + fixture.headers[res._headerNames[headerKey]] = res._headers[headerKey]; + } + + fixtures[moduleName] = fixtures[moduleName] || {}; + fixtures[moduleName][testName] = fixtures[moduleName][testName] || {}; + fixtures[moduleName][testName][res.req.originalUrl] = fixtures[moduleName][testName][res.req.originalUrl] || {}; + fixtures[moduleName][testName][res.req.originalUrl][method] = fixtures[moduleName][testName][res.req.originalUrl][method] || { + fixtures: [], + offset: 0 + }; + + fixtures[moduleName][testName][res.req.originalUrl][method].fixtures.push(fixture); + }; + }; +}; diff --git a/lib/qunit.js b/lib/qunit.js new file mode 100644 index 0000000..375632d --- /dev/null +++ b/lib/qunit.js @@ -0,0 +1,59 @@ +QUnit.proxyFixtures = function(name) { + var server; + var proxyFixtures = window[name]; + + QUnit.testStart(function(details) { + Ember.$.ajaxSetup({ + headers: { + 'x-module-name': details.module, + 'x-test-name': details.name + } + }); + + if (proxyFixtures && proxyFixtures[details.module] && proxyFixtures[details.module][details.name]) { + var fixtures = proxyFixtures[details.module][details.name]; + + server = new Pretender(function() { + for (var path in fixtures) { + for (var method in fixtures[path]) { + this[method](path, function(request) { + var fixture = fixtures[path][method].fixtures[fixtures[path][method].offset]; + fixtures[path][method].offset += 1; + return [fixture.statusCode, fixture.headers, fixture.body]; + }); + } + } + }); + } + }); + + QUnit.testDone(function() { + Ember.$.ajaxSetup({ + headers: { + 'x-module-name': undefined, + 'x-test-name': undefined + } + }); + + if (server) { + server.shutdown(); + } + }); + + QUnit.config.autostart = false; + QUnit.begin(function() { + Ember.$.ajax({ + type: 'DELETE', + url: 'clear-fixtures' + }).then(function() { + QUnit.start(); + }); + }); + + QUnit.done(function() { + Ember.$.ajax({ + type: 'POST', + url: 'write-fixtures' + }); + }); +}; diff --git a/lib/test-loader.js b/lib/test-loader.js new file mode 100644 index 0000000..b198c14 --- /dev/null +++ b/lib/test-loader.js @@ -0,0 +1 @@ +QUnit.proxyFixtures('proxyFixtures'); diff --git a/package.json b/package.json new file mode 100644 index 0000000..74ed9a2 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "ember-cli-proxy-fixtures", + "version": "0.0.0", + "directories": { + "doc": "doc", + "test": "test" + }, + "scripts": { + "start": "ember server", + "build": "ember build", + "test": "ember test" + }, + "repository": { + "type": "git", + "url": "https://github.com/dockyard/ember-cli-proxy-fixtures" + }, + "engines": { + "node": ">= 0.10.0" + }, + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "configPath": "tests/dummy/config", + "after": "ember-cli-qunit", + "before": "proxy-server-middleware" + }, + "author": { + "name": "Brian Cardarella" + }, + "license": "MIT", + "dependencies": { + "mkdirp": "0.5.0", + "ember-cli-pretender": "0.2.3", + "broccoli-json-concat": "0.0.4", + "broccoli-file-mover": "0.4.0", + "broccoli-static-compiler": "^0.1.4", + "broccoli-concat": "0.0.11", + "broccoli-merge-trees": "0.1.4", + "broccoli-file-mover": "0.3.6" + }, + "devDependencies": { + "body-parser": "^1.2.0", + "broccoli-asset-rev": "0.0.17", + "broccoli-ember-hbs-template-compiler": "^1.6.1", + "ember-cli": "0.0.42", + "ember-cli-ember-data": "0.1.0", + "ember-cli-ic-ajax": "0.1.1", + "ember-cli-qunit": "0.0.5", + "express": "^4.8.5" + } +} diff --git a/testem.json b/testem.json new file mode 100644 index 0000000..bbcd347 --- /dev/null +++ b/testem.json @@ -0,0 +1,6 @@ +{ + "framework": "qunit", + "test_page": "tests/index.html", + "launch_in_ci": ["PhantomJS"], + "launch_in_dev": ["PhantomJS", "Chrome"] +} diff --git a/tests/.jshintrc b/tests/.jshintrc new file mode 100644 index 0000000..e1892e0 --- /dev/null +++ b/tests/.jshintrc @@ -0,0 +1,74 @@ +{ + "predef": [ + "document", + "window", + "location", + "setTimeout", + "$", + "-Promise", + "QUnit", + "define", + "console", + "equal", + "notEqual", + "notStrictEqual", + "test", + "asyncTest", + "testBoth", + "testWithDefault", + "raises", + "throws", + "deepEqual", + "start", + "stop", + "ok", + "strictEqual", + "module", + "moduleFor", + "moduleForComponent", + "moduleForModel", + "process", + "expect", + "visit", + "exists", + "fillIn", + "click", + "keyEvent", + "find", + "findWithAssert", + "wait", + "DS", + "keyEvent", + "isolatedContainer", + "startApp", + "andThen", + "currentURL", + "currentPath", + "currentRouteName" + ], + "node": false, + "browser": false, + "boss": true, + "curly": false, + "debug": false, + "devel": false, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true +} diff --git a/tests/dummy/.jshintrc b/tests/dummy/.jshintrc new file mode 100644 index 0000000..427d89f --- /dev/null +++ b/tests/dummy/.jshintrc @@ -0,0 +1,33 @@ +{ + "predef": { + "document": true, + "window": true, + "-Promise": true, + "DummyENV": true + }, + "browser" : true, + "boss" : true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true, + "unused": true +} diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js new file mode 100644 index 0000000..5727e51 --- /dev/null +++ b/tests/dummy/app/app.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; +import Resolver from 'ember/resolver'; +import loadInitializers from 'ember/load-initializers'; + +Ember.MODEL_FACTORY_INJECTIONS = true; + +var App = Ember.Application.extend({ + modulePrefix: 'dummy', // TODO: loaded via config + Resolver: Resolver +}); + +loadInitializers(App, 'dummy'); + +export default App; diff --git a/tests/dummy/app/components/.gitkeep b/tests/dummy/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/controllers/.gitkeep b/tests/dummy/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/helpers/.gitkeep b/tests/dummy/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html new file mode 100644 index 0000000..afe4e53 --- /dev/null +++ b/tests/dummy/app/index.html @@ -0,0 +1,24 @@ + + +
+ + +