my express app uses one path ("/") to display a huge page which was build using several includes. To avoid confusion, I would like to test each and every ejs file on its own. But as these ejs-includes are not reachable from the express app, I have no clue how to perform that task.
- index.ejs
- mainMenu.ejs
- systemsTable.ejs
- systemRow.ejs
- systemStatusIcon.ejs
- systemName.ejs
- ....
The more complex the index.ejs file gets the more I would like to test its parts. But how can I test the result of systemStatusIcon.ejs?
Thanks
Without any knowledge of what your code looks like, the I suggest setting up a configuration JSON file of test data objects each containing:
the EJS file path to be tested
render input data
an array of regular expressions to test against the rendered output
Then your test code can iterate over these objects and render and test each in turn.
Example Template Rendering
A simple piece of code to render a template looks like this:
const ejs = require('ejs');
let template = `
value is: <%- value %>
`;
const renderData = {
value: 123
};
const output = ejs.render(template, renderData);
console.log(output);
With output:
> node index.js
value is: 123
What renderData will be required is dependent on your existing templates. Template errors will be thrown as standard JS errors.
You could also use the renderFile function to do the loading for you.
ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
EJS docs can be found at: https://ejs.co/
Related
For a given Jade/Pug template I would like to get a list of all variables which occur within the template.
My motivation is as follows: In my software, different templates are used to generate some HTML snippets. Based on a given context (i.e. values for certain variables are given), I would like to suggest only those templates, where all variables within the template can be assigned.
Example: For template myTemplate like this:
html
head
title= myTitle
body
h1 #{value.headline}
p #{paragraph.text}
I would like to get some output like this:
var variableNames = extractVariableNamesFromTemplate('myTemplate');
// variableNames = [ 'myTitle', 'value.headline', 'paragraph.text' ]
Is there something available ready-to-use? Preferably a solution which would take into account all language-specific features such as includes, extends, etc.
This is not a full answer to your problem but more of a starting point. From debugging the pug code, i have noticed you could probably "hook" a plugin in one of the steps of template "compilation" to code. Look here.
It seems that in the various steps of compilation, you can access the diffrent nodes present in the template.
You could also look at this, it seems to offer almost what you are looking for.
If you do something like
var lex = require('pug-lexer');
var filename = 'template.pug';
var src = `
html
head
title= myTitle
body
h1 #{value.headline}
p #{paragraph.text}`;
var tokens = lex(src, {filename});
The contents of tokens is an array of the diffrent tokens, the one that are of type "code" or "interpolate-code" seem to be the diffrent variables.
Hope this helps
I have a Sitecore 7.1 solution using MVC and am rendering fields using #Html.Sitecore().Field("FieldName", ContentItem). Because I want multiline text fields to render out <br/> tags I have removed the GetTextFieldValue processor from the renderField processor section in web.config using an App_Config\Include patch file as described here: http://laubplusco.net/sitecore-update-bummer/. What I'm finding is that if I use Sitecore.Web.UI.WebControls.FieldRenderer.Render() this produces the output with the line breaks as expected, but if I use the Html.Sitecore().Field() extension method no line break is rendered.
I found that you can write
#Html.Sitecore().Field("FieldName", item, new { linebreaks = "<br/>" })
which seems to do the job.
Is there some other config which needs to be set to make the Field() extension method behave in the same way as FieldRenderer.Render, or do I just have to use the method above?
The implementation of field rendering seems to be different for MVC and WebForms. You can check the code of Sitecore.Web.UI.WebControls.FieldRenderer.RenderField() in .NET Reflector. It adds line breaks for multi-line fields to the RenderFieldArgs, before calling the render field pipeline:
if (item.Fields[this.FieldName].TypeKey == "multi-line text")
{
args.RenderParameters["linebreaks"] = "<br/>";
}
In #Html.Sitecore().Field(...) the rendering pipeline is called in a similar way, but the rendering arguments are set up differently, "linebreaks" is not added. To make the behavior the same for every rendering you could add your own processor with the same logic as the code above in Sitecore.Web.UI.WebControls.FieldRenderer.RenderField(). Somehow like this:
public void Process(RenderFieldArgs args)
{
Assert.ArgumentNotNull((object)args, "args");
if (args.FieldTypeKey == "multi-line text")
args.RenderParameters["linebreaks"] = "<br/>";
}
and add this to your render field pipeline with an include file.
I'm writing directive tests for AngularJS with Jasmine, and using templateUrl with them: https://gist.github.com/tanepiper/62bd10125e8408def5cc
However, when I run the test I get the error included in the gist:
Error: Unexpected request: GET views/currency-select.html
From what I've read in the docs I thought I was doing this correctly, but it doesn't seem so - what am I missing here?
Thanks
If you're using ngMockE2E or ngMock:
all HTTP requests are processed locally using rules you specify and none are passed to the server. Since templates are requested via HTTP, they too are processed locally. Since you did not specify anything to do when your app tries to connect to views/currency-select.html, it tells you it doesn't know how to handle it. You can easily tell ngMockE2E to pass along your template request:
$httpBackend.whenGET('views/currency-select.html').passThrough();
Remember that you can also use regular expressions in your routing paths to pass through all templates if you'd like.
The docs discuss this in more detail: http://docs.angularjs.org/api/ngMockE2E.$httpBackend
Otherwise use this:
You'll need to use the $injector to access the new backend. From the linked docs:
var $httpBackend;
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('views/currency-select.html').respond(200, '');
}));
the Karma way is to load the template html dynamically into $templateCache. you could just use html2js karma pre-processor, as explained here
this boils down to adding templates '.html' to your files in the conf.js file
as well
preprocessors = {
'.html': 'html2js'
};
and use
beforeEach(module('..'));
beforeEach(module('...html', '...html'));
into your js testing file
If this is a unit-test, you won't have access to $httpBackend.passthrough(). That's only available in ngMock2E2, for end-to-end testing. I agree with the answers involving ng-html2js (used to be named html2js) but I would like to expand on them to provide a full solution here.
To render your directive, Angular uses $http.get() to fetch your template from templateUrl. Because this is unit-testing and angular-mocks is loaded, angular-mocks intercepts the call to $http.get() and give you the Unexpected request: GET error. You can try to find ways to by pass this, but it's much simpler to just use angular's $templateCache to preload your templates. This way, $http.get() won't even be an issue.
That's what the ng-html2js preprocessor do for you. To put it to work, first install it:
$ npm install karma-ng-html2js-preprocessor --save-dev
Then configure it by adding/updating the following fields in your karma.conf.js
{
files: [
//
// all your other files
//
//your htmp templates, assuming they're all under the templates dir
'templates/**/*.html'
],
preprocessors: {
//
// your other preprocessors
//
//
// tell karma to use the ng-html2js preprocessor
"templates/**/*.html": "ng-html2js"
},
ngHtml2JsPreprocessor: {
//
// Make up a module name to contain your templates.
// We will use this name in the jasmine test code.
// For advanced configs, see https://github.com/karma-runner/karma-ng-html2js-preprocessor
moduleName: 'test-templates',
}
}
Finally, in your test code, use the test-templates module that you've just created. Just add test-templates to the module call that you typically make in beforeEach, like this:
beforeEach(module('myapp', 'test-templates'));
It should be smooth sailing from here on out. For a more in depth look at this and other directive testing scenarios, check out this post
You could perhaps get the $templatecache from the injector and then do something like
$templateCache.put("views/currency-select.html","<div.....>");
where in place of <div.....> you would be putting your template.
After that you setup your directive and it should work just fine!
If this is still not working , use fiddler to see the content of the js file dynamically generated by htmltojs processor and check the path of template file.
It should be something like this
angular.module('app/templates/yourtemplate.html', []).run(function($templateCache) {
$templateCache.put('app/templates/yourtemplate.html',
In my case , it was not same as I had in my actual directive which was causing the issue.
Having the templateURL exactly same in all places got me through.
As requested, converting a comment to an answer.
For the people who want to make use of #Lior's answer in Yeoman apps:
Sometimes the way the templates are referenced in karma config and consequently - the names of modules produced by ng-html2js don't match the values specified as templateUrls in directive definitions.
You will need adjusting generated module names to match templateUrls.
These might be helpful:
https://github.com/karma-runner/karma-ng-html2js-preprocessor#configuration
gist: https://gist.github.com/vucalur/7238489
this is example how to test directive that use partial as a templateUrl
describe('with directive', function(){
var scope,
compile,
element;
beforeEach(module('myApp'));//myApp module
beforeEach(inject(function($rootScope, $compile, $templateCache){
scope = $rootScope.$new();
compile = $compile;
$templateCache.put('view/url.html',
'<ul><li>{{ foo }}</li>' +
'<li>{{ bar }}</li>' +
'<li>{{ baz }}</li>' +
'</ul>');
scope.template = {
url: 'view/url.html'
};
scope.foo = 'foo';
scope.bar = 'bar';
scope.baz = 'baz';
scope.$digest();
element = compile(angular.element(
'<section>' +
'<div ng-include="template.url" with="{foo : foo, bar : bar, baz : baz}"></div>' +
'<div ng-include="template.url" with=""></div>' +
'</section>'
))(scope);
scope.$digest();
}));
it('should copy scope parameters to ngInclude partial', function(){
var isolateScope = element.find('div').eq(0).scope();
expect(isolateScope.foo).toBeDefined();
expect(isolateScope.bar).toBeDefined();
expect(isolateScope.baz).toBeDefined();
})
});
If you are using the jasmine-maven-plugin together with RequireJS you can use the text plugin to load the template content into a variable and then put it in the template cache.
define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
"use strict";
describe('Directive TestSuite', function () {
beforeEach(inject(function( $templateCache) {
$templateCache.put("path/to/template.html", directiveTemplate);
}));
});
});
I am trying to run the default service unit test in my project (Taken from the Angular Seed project on GitHub), but I keep getting the error "module is not defined".
I have read that it could be something to do with the order of the referenced JavaScript files, but I can't seem to get it to work, so hopefully one of you might be able to help.
My configuration for the test looks like this:
basePath = '../';
files = [
'public/javascripts/lib/jquery-1.8.2.js',
'public/javascripts/lib/angular.js',
'public/javascripts/lib/angular-.js',
'public/app.js',
'public/controllers/.js',
'public/directives.js',
'public/filters.js',
'public/services.js',
JASMINE,
JASMINE_ADAPTER,
'public/javascripts/lib/angular-mocks.js',
'test/unit/*.js' ];
autoWatch = true;
browsers = ['Chrome'];
junitReporter = { outputFile: 'test_out/unit.xml', suite: 'unit'
};
The service looks like the following:
angular.module('myApp.services', []).
value('version', '0.1');
The test looks like this:
'use strict';
describe('service', function() {
beforeEach(module('myApp.services'));
describe('version', function() {
it('should return current version', inject(function(version) {
expect(version).toEqual('0.1');
}));
});
});
And the error when running the test through testacular is this:
ReferenceError: module is not defined
You are missing the angular-mocks.js file.
I had the same problem, and I understood why it wasn't working:
The jasmine.js javascript must be referenced BEFORE the angular-mocks.js file.
Indeed, the angular-mocks.js checks if Jasmine is loaded, and only if it is it will add the module function to the window.
Here is an extract of Angular Mocks code:
(Edit after the few comments about 'hacking' I had below: this is just an extract of the code, this is not something you need to write yourself, it's already there!)
window.jasmine && (function(window) {
[...]
window.module = angular.mock.module = function() {
var moduleFns = Array.prototype.slice.call(arguments, 0);
return isSpecRunning() ? workFn() : workFn;
/////////////////////
[...]
};
In a nutshell:
Just reference your jasmine.js before angular-mocks.js and off you go.
The window.module function comes in angular-mocks.js and is a shorthand for angular.mock.module. As mentioned in the docs, the module function only works with Jasmine.
Using Testacular, the following example configuration file will load angular-mocks.js.
/** example testacular.conf.js */
basePath = '../';
files = [
JASMINE,
JASMINE_ADAPTER,
'path/to/angular.js',
'path/to/angular-mocks.js', // for angular.mock.module and inject.
'src/js/**/*.js', // application sources
'test/unit/**/*.spec.js' // specs
];
autoWatch = true;
browsers = ['Chrome'];
And, as suggested elsewhere, you can run Testacular with debug logging to see what scripts are loaded (you can also see the same in the inspector):
testacular --log-level debug start config/testacular.conf.js
The angular.mock.inject docs include a pretty complete example.
We use 'module' without 'angular' in our unit tests and it works fine.
CoffeeScript:
describe 'DiscussionServicesSpec', ->
beforeEach module 'DiscussionServices'
beforeEach inject ... etc.
which compiles to
JavaScript:
describe('DiscussionServices', function() {
beforeEach(module('DiscussionServices'));
beforeEach(inject(function ... etc.
The only time I see something like the error you described is if in the testacular.conf.js file the angular-mocks.js file is not listed in the files section before the specs trying to use 'module'. If I put it after my tests in the 'files' list I get
ReferenceError: Can't find variable: module
(Our tests are being run through PhantomJS)
I had included angular-mocks.js in my karma config, but was still getting the error. It turns out the order is important in the files array. (duh) Just like in the head of an html doc, if a script calls angular before it's defined, and error occurs. So I just had to include my app.js after angular.js and angular-mocks.js.
If you're using Yeoman and its angular-generator, you probably get this error. Especially when you do the Tutorial ( ._.)
I fixed it, by copying the angular-mocks.js file, from the bower_components/angular-mocks dir to the test/mock dir. Of course you have to be sure, that your karma.conf.js file is configured correctly.
Greetings!
I had this same issue when I was doing something like var module = angular.module('my',[]). I needed to make sure it was surrounded by IIFE
I got problem when implementing my CMS using Codeigniter 1.7.2 and Dwoo. I use Phil Sturgeon Dwoo library. My problem is I want user create template from the admin panel, it means all template will be stored into database including all Dwoo variable and functions.My questions:
Is it possible to load dwoo template from database?
How to parse dwoo variable or function from database? I tried to load content from database which is include dwoo var and function inside it, and i have tried to do evaluation using dwoo eval() function and phil sturgeon string_parse() but still have no luck.
for example:
my controller
$data['header'] = "<h1>{$header}</h1>"; --> this could be loaded from database
$this->parser->parse('header',$data);
my view
{$header}
This is the error message:
<h4>A PHP Error was encountered</h4>
<p>Severity: Notice</p>
<p>Message: Undefined index: header_title</p>
<p>Filename: compiled/805659ab5e619e094cac7deb9c8cbfb5.d17.php</p>
<p>Line Number: 11</p>
header_title is dwoo variable that loaded from DB.
Thank you,
It is definitely possible to do this, but for performance reasons it would probably be faster to store the templates as files on the filesystem, even if they're edited by users. If you're smart with file naming you can avoid most hits to the database.
Anyway, if you really want to do it with the database, the following should work:
// rendering the header
$template = '<h1>{$header}</h1>'; // loaded from db, don't use double-quotes for examples or $header will be replaced by nothing
$data = array('header' => 'Hello'); // loaded from db as well I assume
$headerOutput = $this->parser->parse_string($template, $data, true); // true makes it return the output
// now rendering the full page (if needed?)
$data = array('header' => $headerOutput);
$this->parser->parse('header', $data); // no 'true', so goes straight to output
The view would then contain {$header} and the output from the header template is passed to that variable.
Now I'm not sure how CI works so it might be better to just output the result of the first template and skip the second one entirely, but I'll leave that up to you.