ember addons test-support directory - ember.js

I've some test helpers in my addon. I want to:
use these helpers for my addon's own tests.
make these helpers available to my addon's users, for testing their own codes.
In the documentation, it is said that test-support can be used to satisfy the second requirement mentioned above; but I couldn't find a way to make it work for both.

The docs say "merged with the application’s tests/",
An applications test-helpers reside in test/helpers/, any helper specified here should be registered automatically.
When sharing an addons test-helper, make sure it resides in test-support/helpers,
Once the directory get merged, the file should end up in the tests/helpers directory and be registered automatically.
As a reference one could take a look at the emberx-select addon,
A "select"-helper is shared using the same method specified in this answer.

Related

Ember JS automatically register directory classes to DI

Creating in-repo-addon in Ember.JS gives a lot of possibilities. Today I've stumbled into a case when I wanted to register all classes in directory (for example my-dir) into Dependency Injector (same way it's done with services by Ember, but I wanted to use some other namespace).
For example I want to allow developer to create multiple classes inside proxy directory, and register all of them in DI under proxy: namespace. So later we can use:
Ember.Component.extend({
myProxy: Ember.inject('proxy:my'),
});
You'll need to do this using an initializer. More details on this here: https://guides.emberjs.com/v2.12.0/applications/dependency-injection/
The hard part may be getting all proxy items in s folder to automatically register ...
Edit
Looks like I didn't spend enough time thinking about this. You should be able to do at least part of this easily. There are two parts to this.
Part 1
Ember currently uses the ember-resolver to handle lookups for various items. If you check the tests for the resolver you'll notice that you should be able to map in anything you want: https://github.com/ember-cli/ember-resolver/blob/master/tests/unit/resolvers/classic/basic-test.js
So in your case, if you do a Ember.getOwner(this).lookup('proxy:main') from within an Ember instantiated class (a route, controller or component for instance) it would look in app/proxy/main.js which your addon could be populating.
Details on the Ember.getOwner lookup are available here: https://emberjs.com/api/classes/Ember.html#method_getOwner
Part 2
So at this point you can lookup proxies (which would be doable in an init method). But if we want to get truly elegant we'd want to allow Ember.inject.proxy('main') syntax.
Doing so would involve calling a private method inside of Ember.inject in an initializer. Because that naming scheme is changing in the new Javascript modules RFC, it may be unwise to try to add this syntactic sugar ...
So I'd advise avoiding touching that private API unless it's really important to your app design.

Moving admin-related files out of their models and controller folders and into a separate admin folder in Rails. How to organize this code?

I am working on a legacy app with 100s of related admin models, controllers, services, jobs, etc. We decided to move all of these files in a folder at the top-level of the app directory called admin. So our ideal file structure would be:
app/admin/models/admin.rb
app/admin/controllers/admin_controller.rb
app/admin/services/admin_service_of_some_kind.rb
app/admin/models/audit.rb
etc
We want the call sites in our code to be:
Admin::Admin.create...
Admin::AdminService.retrieve_all_audit_logs...
Admin::Audit.scope_by_admin...
etc
The problem is that after reading these links:
http://urbanautomaton.com/blog/2013/08/27/rails-autoloading-hell/
http://guides.rubyonrails.org/autoloading_and_reloading_constants.html
I understand that Rails infers file path names from the constants. So if I want to call Admin::AdminService.some_task... Rails will believe the Admin constant and the nested AdminService constant would exist in a file at (assuming that app/admin is autoloaded... which I believe it is) app/admin/admin_service.rb which is not true... they exist in app/admin/services/admin_service.rb.
How can I make this happen given that I want the call site to be Admin::AdminService.some_task?
Given the folder structure of app/admin/services/admin_service.rb, the call site would have to be Services::AdminService.some_task right? (this assumes that app/admin is autoloaded) right? However, this is not what I want.
Why not just move them into
app/models/admin/*.rb
app/services/admin/*.rb

Lazy Loaded Ember Application

I am typically searching for answers here but I finlly gotten to the point where I can't find a good answer.
I am looking to build an ember app which only initially loads in the things that it needs just to start and open the main route. All other controllers, views, templates, etc. Would be loaded lazily when a specific route gets triggered.
I have found a good example of how to accomplIsh this here:
http://madhatted.com/2013/6/29/lazy-loading-with-ember
My main question is to determine what build tools out there support this theory of lazy loading application code? So far, I've seen that Brunch, Yeoman, and Ember App Kit seemed to minify and concatenate all the scripts and templates. I am very happy with minification but need those files separate. I have thought about just putting this code into the app/assets location so that it gets copied over without concat but it does not get minified.
Does anyone have a solution? Thanks!
You can do this with brunch by adding the following to your brunch config
files: {
javascripts: {
joinTo: {
'javascripts/app.js': /^app(\/|\\)(?!admin)/, // concat everything in app, except /app/admin
'javascripts/vendor.js': /^vendor/,
'javascripts/admin.js': /^app(\/|\\)admin/ // concat only /app/admin
}
}
}
Grunt (used in yeoman and ember app kit) is ridiculously flexible, so I'm sure you can set up the same thing there by diving into Gruntfile.js
The question was: "I am looking to build an ember app which only initially loads in the things that it needs just to start and open the main route. All other controllers, views, templates, etc. Would be loaded lazily when a specific route gets triggered.".
Ember expects to have anything it needs right there when the page gets loaded. I wouldn't be wrong, but lazy loading of routes doesn't seem to be a feature of Ember. Ember CLI is the same. It uses bundling and minification to reduce the overload. But everything should be there to make it work.
Instead, people like me would like to load things only when they are required.
When you try to implement lazy loading in Ember, everything should be represented by a module (file.js): a route, a module; a controller, a module; and so on.
You should follow a schema (like POD), to which apply a mechanism to find things where they are supposed to be.
Every module should know its dependencies. But some of them are very frequent (route, controller, template).
You should use a module loader for the browser. It can be requirejs or whatever you like. But ES6 is at the door. Let's think about that.
Many people use beforeModel hook to achieve a result. I did it, and it works, if you don't use link-to component. Otherwise everything crashes. Why? Because of href computed property. When a link-to has been inserted, an href is calculated for it. Because of that, Ember looks for the route where the link points to. If the route doesn't exist, one is created from route:basic.
A solution could be the preloading of all the routes represented by all link-tos inserted in the page. Too much expensive!
An integration to this answer can be found at Lazy loading route definitions in Ember.js
For an initial solution to lazy loading of routes organized in POD, have a look at https://github.com/ricottatosta/ember-wiz. It is an ES6 based approach, which relay on SystemJS as module loader.

How do I tell Dojo build to ignore a 'missing' template

Our application has a number of widgets that use templates that are generated on the fly via a JSP.
In the front-end code, they are included using the dojo/text plugin. This ensures that Widget lifecycle isn't kicked off until the template has been resolved and it works just fine.
Unfortunately, when we try to perform our build, we get a 311 error:
error(311) Missing dependency. module:
app/navigation/NavigationManager; dependency:
dojo/text!/author/app/templates/NavigationManager-content.html; error:
Error: text resource
(/author/app/templates/NavigationManager-content.html/x) missing
I understand what's happening here, the build process is trying to internalize the string, but when it goes to look for it, it can't locate it and so flags it as a missing dependency.
I see a number of options here:
Somehow, tell Dojo to ignore this missing dependency - this would be fine, but I'd need to be able to be specific, so that I get alerted to any other dependencies that might be missing
Somehow, tell Dojo not to try and internalize this template - this would also be fine, since there's nothing to internalize here.
Somehow, stub out the dependency so that the dependency resolution passes, but the internalization doesn't occur.
I've seen references to the
internStringsSkipList
value, but none of the following helped:
internStringsSkipList: ['/author/pepper/templates/NavigationManager-content.html']
internStringsSkipList: ['dojo/text!/author/pepper/templates/NavigationManager-content.html']
internStringsSkipList: ['/author/pepper/templates/NavigationManager-content.html/x']
Any suggestions?
I faced exactly the same problem and after reading lots of dojo documentation and source code I came to the conclusion that it's very difficult if almost impossible to do. There is, however, a very simple and elegant workaround. But before telling you how to solve the problem firstly why there is a workaround needed in the first place (so you can adjust the solution to your own circumstances):
First issue, the resource is undiscoverable
According to the Overview section of the dojo build system Reference Guide:
[The build system] “discovers” a set of resources and then applies a synchronized, ordered set of resource-dependent transforms to those resources. (…) When a resource is discovered, it is tagged with one or more flags that help identify the role of that resource. (…) After a resource is discovered and tagged, the system assigns a set of transforms that are to be applied to that resource.
So in short, any resources generated on the fly can't be discovered by the build system because they don't reside on the file system. If they can't be discovered, then they can't be tagged and no transformation can be applied to it. In particular, resourceTags is not called for such resources and you can't put them on the exclude list of a profile layer definition (compare section Layers in Creating Builds).
BTW, as far as I understand the documentation to depsScan transform, internStringsSkipList can only be used to skip resources specified using the legacy notation (dojo.something, e.g. dojo.moduleUrl).
Second issue, the plugin resolver expects a physical file
Notation dojo/text!/some/url says to use the dojo/text.js component as a plugin. I found this note in this ticket:
Every AMD plugin should have a plugin resolver in util/build/plugins and have it registered in util/build/buildControlDefault.
If you check util/build/plugins/text.js (e.g. on Github) you'll see that the error is being thrown because the dependency (that part after dojo/text! is stored in moduleInfo) is not in the resources array:
textResource = bc.resources[moduleInfo.url];
if (!textResource){
throw new Error("text resource (" + moduleInfo.url + ") missing");
}
And this is precisely because the resource couldn't be discovered during the "discovery" phase.
The difficult solution
In the difficult solution, that might or might not work, you would need to change how the transformation depsScan works. Basically, when depsScan encounters dojo/text!/some/url it calls the plugin resolver to check if the dependency exists. From the depsScan documentation:
Once all dependencies are found, the transform ensures all dependencies exist in the discovered modules. Missing dependencies result in an error being logged to the console and the build report.
That might be possible by redefining transformJobs to contain a custom transform for depsScan. See util/build/buildControlDefault.js (on Github) and this forum post for more insights.
The simple workaround
Just create your own plugin to load the resource. Your own plugin won't have the plugin resolver registered (see the second issue above) and all you'll get when compiling is the dreaded
warn(224) A plugin dependency was encountered but there was no build-time plugin resolver.
This is my example of such plugin that loads a JSON resource dynamically:
define(["dojo/text", "dojo/_base/lang", "dojo/json"],
function(text,lang,json){
return lang.delegate(text, {
load: function(id, require, load){
text.load(id, require, function(data){
load(json.parse(data));
});
}
});
});
It reuses dojo/text adding its custom load function. This is an adaptation of another example posted on this dojo-toolkit forum post. You can see their code on JSFiddle.
In my project I use the plugin like this:
define(["./json!/path/to/an/json"],
function(values){
return values;
});
Your plugin can just return the loaded template without parsing it as JSON, and as long as you don't specify your custom plugin resolver (which would expect the file to exist physically on disk) the project will compile fine.
This wasn't your issue, but the most common solution to those facing the error(311) problem is going to be this:
Don't start template paths with a slash.
Bad:
"dojo/text!/app/template/widget.html"
Good:
"dojo/text!app/template/widget.html"
Your template path isn't a normal, plain-ol' URL. It's still part of the Dojo build, so you use Dojo build pathing to get to the template.

Accessing 't' (from r18n) in a rack-unit test of a Sinatra app

When using sinatra-r18n to handle internationalisation, the r18n lib exposes a variable t for use within your helpers, routes and templates, as per these instructions.
I have written a simple unit test using rack-unit to confirm that some of my pluralisations work but the test throws an error claiming t is nil.
I've tried referencing it via app.t, MySillyApp.t (where MySillyApp is the name of my Sinatra app), MySillyApp.settings.t etc and none of them give me access to the t I need.
What I am trying to achieve is a confirmation that my translation files include all the keys I need corresponding to plurals of various metric units my app needs to understand. Perhaps there is a more direct way of testing this without going via the Sinatra app itself. I'd welcome any insight here.
I had similar task to check localized strings in my Cucumber scenarios.
I've made working example.
Here you can find how strings got translated.
This file halps to understand how to add R18n support to your testing framework:
require 'r18n-core'
...
class SinCucR18nWorld
...
include R18n::Helpers
end
As you can see instead of rack/unit I'm using RSpec/Cucumber, sorry.