I'm new to Javascript in general, especially EmberJS and Ember CLI. I'm trying to figure out what is the best practice to manage mock data within a Ember CLI based project. I'm on 0.1.14 EmberCLI now.
According to Ember CLI documentation, http-mock is the preferred way of providing mock data for Ember Data models. So I use generated http-mock and added some test data to it.
var testData = [
...
];
module.exports = function(app) {
var express = require('express');
var todosRouter = express.Router();
todosRouter.get('/', function(req, res) {
res.send({
"todos": testData
});
});
Then I found out that the http-mock does not work during integration, so I added Pretende.
import Ember from 'ember';
import { test } from 'ember-qunit';
import Pretender from 'pretender';
import startApp from '../helpers/start-app';
var App;
var server;
var testData = [
...
];
module('An Integration test', {
setup: function() {
App = startApp();
server = new Pretender(function(){
this.get('/api/todos', function(request){
return [ 200, {"Content-Type": "application/json"},
JSON.stringify({'todos': testData) ];
});
});
},
teardown: function() {
...
}
});
test('3 items loaded at startup', function() {
...
});
Both http-mock and integration test work fine, then I tried put the test data in a separate module so that they can be shared. The thing is that the integration test uses ES6 style module import, and http-mock uses CommonJS style module definition, and I don't know how to combine them into the project.
If I construct the data into an ES6 module,
var mockData = [
...
];
export default {
all: mockData
};
it works with integration test but http-mock complains about unexpected reserved word "export". If a convert it to a CommonJS style module.export, then I can't see the data in the integration test.
Now the questions:
I think if Broccoli 'compile' ES6 module into CommonJS format it should work with http-mock, but I have no idea how to do that. Is this the right direction to go, and how?
Do I have to use both http-mock and Pretender in the same project? Can I use one for both development and integration test?
I'm stuck here and comments, suggestions and code samples are really appreciated.
I'm not sure, but I think that this Ember CLI addon, called ember-cli-mirage might do what you're looking for. I haven't used it myself yet, but I have heard good things about it and it seems to take care of the case where you want to use a mock server for development and testing without keeping two sets of fixtures.
Related
We have a legacy Backbone application that we are moving over to React. An interim step we are attempting is loading a bundled Backbone module into a React page, until we have time to fully rewrite it. I am halfway there, I can bundle up the app and all its dependencies with r.js using a config like this:
({
...
baseUrl: './',
name: 'myapp',
paths: {
'myapp': './legacy/app'
},
out: 'src/appbuilt.js'
...
})
The module is set up like this:
define(function(require) {
var $ = require('jquery'),
_ = require('underscore'),
...
templates = $(require('text!templates/app.html')),
app = {};
app.View = .....
app.Model = .....
return app;
});
That bundle works on the Backbone side. Next I need to turn that into something I can import into React and render. I am trying things like this:
npx babel src/appbuilt.js --out-file src/appbuilt.es6.js --plugins=#babel/transform-modules-umd
Which works to give me a UMD module, but importing it like this:
import * as legacyapp from '../../appbuilt.es6';
Gives me warnings on the build like:
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
And errors on page load that are probably symptoms of something:
Uncaught TypeError: name.split is not a function
What is the secret sauce to get my module converted into something I can use? I am open to modifying how the Backbone app does its imports, or making a wrapper of some kind that is more easily translatable.
I am not sure but I can guess that the format of your AMD modules is the problem here. Try converting them to regular AMD modules:
define(
['jquery', 'underscore', 'text!templates/app.html' /* add rest of dependencies here */],
function ($, underscore, templates /** add parameters for rest of dependencies here */)
{
var app = {};
// app.View = ...
// app.Model = ...
return app;
}
);
I am trying to manually include the #material/drawer npm package into my Ember app. I tried following this guide but I'm running into some weird errors in my Chrome dev console:
Uncaught SyntaxError: Unexpected token *
Uncaught ReferenceError: define is not defined
The first is from the imported node_modules/#material/drawer/index.js file and the second is from my generated shim.
My component code:
import Component from '#ember/component';
import { MDCTemporaryDrawer, MDCTemporaryDrawerFoundation, util } from '#material/drawer';
export default Component.extend({
init() {
this._super(...arguments);
const drawer = new MDCTemporaryDrawer(document.querySelector('.mdc-drawer--temporary'));
document.querySelector('.menu').addEventListener('click', () => drawer.open = true);
}
});
In my ember-cli-build.js:
app.import('node_modules/#material/drawer/index.js');
app.import('vendor/shims/#material/drawer.js');
My generated shim:
(function() {
function vendorModule() {
'use strict';
return {
'default': self['#material/drawer'],
__esModule: true,
};
}
define('#material/drawer', [], vendorModule);
})();
What exactly am I doing wrong? It almost seems as though raw ES6 code got imported rather than compiled into my JS build output.
I also read this SO post but there are too many answers and I'm not sure which to do. It seems this specific answer is what I'm trying to do but not verbatim enough.
Creating a shim only ensures that ember-cli gets an AMD module, which you then can import in your app files.
If the npm package needs a build or transpiling step beforhand, this won't work.
You need a way to get the package build within the ember-cli build pipeline.
Luckily there are addons which can take care of this for you: ember-auto-import and ember-cli-cjs-transform.
You may have also heard of ember-browserify, which does the same thing, but it's deprectaed in favor of ember-auto-import.
I'd suggest you try ember-auto-import:
ember install ember-auto-import
You then should be able to import as you tried:
import { MDCTemporaryDrawer, MDCTemporaryDrawerFoundation, util } from '#material/drawer';
No shim or app.import needed, as ember-auto-import will take care of this for you.
I have a small EmberJS application that uses Ember-Cli. My application has a private ES6 library that is a bower dependency. Basically, what I want is to import the library and use it wherever I want.
If I'm not wrong, I should transpile the library in my brocfile.js and use it afterwards. Unfortunately, I cannot provide too much concrete information but I'll try my best to be the clearer possible.
My external library is named main-lib and is structured the following way (it is working in another project):
bower_components
main-lib
api.js
main.js
message.js
In the main.js file, I have the following:
import Api from 'main/api';
import Message from 'main/message';
var main = {};
main.api = Api;
main.message = Message;
export default main;
So, what I want to do, is, in my application, to import main and use the different functions it contains.
Example, in a certain emberjs controller:
import Main from 'main';
//use Main here
To do so, I thought of doing the following in my brocfile.js
var tree = 'bower_components/main-lib';
var ES6Modules = require('broccoli-es6modules');
var amdFiles = new ES6Modules(tree, {
format: 'amd',
bundleOptions: {
entry: 'main.js',
name: 'mainLib'
}
});
However, this does nothing. Basically, I want the transpiled files to be included in vendor.js or somewhere where I would be able to use the library by importing it.
There's something I'm missing here but I can't pinpoint it.
Edit1: After adding these lines at the end of my brocfile.js:
mergeTrees = require('broccoli-merge-trees')
module.exports = mergeTrees([app.toTree(), amdFiles]);
I can get an ES5 that looks like this:
define(['main/api', 'main/message'], function(api, message) {
var main = {};
main.api = Api;
main.message = Message;
var _main = main;
return _main;
});
The problem is that it does not import main/api and main/message as well. Do I have to repeat the code for each file that I want ?
Also, the file is not concatenated in vendor.js but simply but at the root of /dist
You have the following: import Api from 'main/api' - but I don't see a folder called main in what you've explained - only a folder called main-lib ...
Could it be that main/api and main/message are not included because they actually don't exist? You might need to use main-lib/api and main-lib/message in your main.js file
The integration of Broccoli with ember-cli already includes a transpiler, so I think something like this should be enough:
app.import('bower_components/main-lib/main.js', {
type: 'vendor',
exports: { 'main': ['default'] }
);
And then you can:
import Main from 'main';
With what you currently have in your Brocfile you still need to merge your amdFiles (app.import would do that for you).
Something like:
mergeTrees = require('broccoli-merge-trees')
module.exports = mergeTrees([app.toTree(), amdFiles]);
None of this is tested, but you get the idea.
Ember seem to be advocating using: https://www.npmjs.com/package/broccoli-es6modules
This would mean importing your module would look something like:
var mergeTrees = require('broccoli-merge-trees');
var tree = './bower_components/main-lib';
var ES6Modules = require('broccoli-es6modules');
var amdFiles = new ES6Modules(tree, {
format: 'amd',
bundleOptions: {
entry: 'main.js',
name: 'main-lib'
}
});
module.exports = mergeTrees([app.toTree(), amdFiles])
I'm in early stages of a node.js project, and I'm looking to improve the overall app organization. In the past I worked with Symfony2 (PHP) and now I code a lot in Angular, both of which relly heavily on DI. So, I really like the idea of applying the same principles in my node.js project.
I know the existence of packages like Rewire, but for now I'll like to try the DI approach. The issue is, how to achieve an equilibrium to keep the lightweight feeling that gives working with node with the solidity of a well tested dependency injected app (I know that well tested is what gives the solidity ;-)).
Node modules
One of the issues, would be how to manage the external modules, what to do if some object needs fs module? As Vojta Jina (from AngularJS) states in this article:
So the best way that works for me right now is something like this: Modules are stateless. They only contain definitions of classes/functions/constants.
So, I suppose that I would have to inject everything:
function Foo(fs) {
this.fs = fs;
}
Foo.prototype.doSomething: function () {
// this.fs...
};
module.exports = Foo;
Somewhere:
var fs = require('fs');
var Foo = require('./Foo');
var foo = new Foo(fs);
foo.doSomething();
Express
Since Express uses apply() to call the handlers the context is lost and we can't use this. So we're left with these:
// foo.js
function Foo(fs) {
this.fs = fs;
}
Foo.prototype.index = function () {
var self = this;
return function (req, res, next) {
// self.fs...
};
};
module.exports = Foo;
// bar.js
module.exports.index = function (fs) {
return function (req, res, next) {
// fs...
};
};
// app.js
var express = require('express');
var fs = require('fs');
var app = express();
var Foo = require('./foo');
var foo = new Foo(fs);
var bar = require('./bar');
app.get('/foo', foo.index());
app.get('/bar', bar.index(fs));
So...
Has someone taken this approach? What about the use of DI frameworks? (like di.js) And how to keep the experience lean? All ideas are welcome. Thanks!
You have some good thoughts to which I'd like to add:
Having stateless modules will help you to scale your app horizontally. If all state is in a database it will be easy to run multiple node.js instances in parallel.
I also prefer to inject everything. Otherwise the time will come when I would like to write a unit test and it gets hard because I have a hardcoded (not injected) dependencies I can't mock.
To keep this lightweight feeling when working with node you need an approach for dependency injection that doesn't add too much complexity. Your express example above reminds me of a talk by Vojta Jina in which he makes an important point about the wiring part of dependency injection. (Watch minute 3:35 to 8:05) I can't explain it any better than Vojtja does in his talk but basically he says that we need a di framework that takes care of the wiring (what is injected into what). Otherwise the code we manually write to set up the wiring won't be maintainable. Also each unit test would need such wiring code. And that IMO is where manual dependency injection is not an option anymore.
When you use a di framework (or a di container as many people say) the basic idea is that each individual module states which dependencies it requires and through which id it can be required by other modules. Then the di framework can be invoked to initialize the module that serves as an entry point (e.g. app.js) and the framework will look up all dependencies and takes over the hard work of injecting the appropriate module instances.
There are many di frameworks for node.js to which I'd like to add my own: "Fire Up!" If you would use it your example would look like this:
foo.js
// Fire me up!
function Foo(fs) {
this.fs = fs;
}
Foo.prototype.index = function () {
var self = this;
return function (req, res, next) {
// self.fs...
};
};
module.exports = {
implements: 'foo',
inject: ['require(fs)'],
_constructor: Foo
};
bar.js
// Fire me up!
module.exports = {
implements: 'bar',
inject: ['require(fs)'],
factory: function (fs) {
return {
index: function (req, res, next) {
// fs...
}
};
}
};
app.js
// Fire me up!
module.exports = {
implements: 'app',
inject: ['require(express)', 'foo', 'bar']
};
module.exports.factory = function (express, foo, bar) {
var app = express();
app.get('/foo', foo.index());
app.get('/bar', bar.index);
};
index.js
var fireUpLib = require('fire-up');
var fireUp = fireUpLib.newInjector({
basePath: __dirname,
modules: ['./lib/**/*.js'] // foo.js, bar.js, app.js are on this path
});
fireUp('app'); // This is where the injection is kicked off.
When running node index.js you get the following output:
fireUp# INFO Requested: app, implemented in: lib/app.js
fireUp# INFO |-- Requested: require(express)
fireUp# INFO |-- Requested: foo, implemented in: lib/foo.js
fireUp# INFO |-- Requested: require(fs)
fireUp# INFO |-- Requested: bar, implemented in: lib/bar.js
fireUp# INFO |-- Requested: require(fs)
If this looks worth trying out you might be interested in the Getting Started section which shows an example based on express.
Hope that helps!
You can check https://www.npmjs.com/package/plus.container
This is close to DIC in Symfony
This page,
ember-cli testing,
says "The included tests demonstrate how to write both unit tests and acceptance/integration tests using the new
ember-testing package."
However in order to get an integration test working, I need to find module and visit or any of the ember test helpers.
Where are they found, where can I import them from?
Details:
The closest I have found to module is moduleFor, which can be imported from ember-qunit. Module for is not suitable for integration testing as I am testing an entire page or series of pages within the app, rather than an individual model, route, controller, view, etc.
My best guess is that visit can be found within Ember itself, but I am not sure where to import it from.
Using neither module nor moduleFor, I am able to run the tests, but they error out:
ReferenceError: visit is not defined
ember-cli generates start-app.js file which includes function that prepare ember for testing.
in your integration test file...
import startApp from '../../helpers/start-app'; // change this due to your folder hierarchy
var App;
module('Integration Test', {
setup: function(){
App = startApp();
},
teardown: function(){
Ember.run(App, 'destroy');
}
}
now your Ember App is ready for testing. You can use ember-testing helpers.
Extending #saygun`s answer.
As of now instead of module we will be using moduleForComponent or moduleFor as needed.
Eg:
moduleForComponent('comp-name', 'Integration | Component | comp name', {
integration: true,
setup: function(){
App = startApp();
},
teardown: function(){
Ember.run(App, 'destroy');
}
});