Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve html template imports to work better with Angular.js #330

Closed
squadwuschel opened this issue Feb 27, 2015 · 33 comments
Closed

Improve html template imports to work better with Angular.js #330

squadwuschel opened this issue Feb 27, 2015 · 33 comments

Comments

@squadwuschel
Copy link
Contributor

Hi,

I've read in this old post
https://chutzpah.codeplex.com/workitem/144
and here
#138
about the template path

/// <template path="../../MvcAngularJs1_3/ScriptsApp/directives/Templates/testTemplate.html" /> 

but when I use this Syntax in my Unit Tests before the first Descripe block I can't find the generated Script Tag in my HTML File with the content of my testTemplate.html

did I miss something?

my Template file:

   <div class="row">
        <div class="col-lg-12">
           <h1>Tempalte Test</h1>
       </div>
   </div>

(very cool tool by the way - respect)

@squadwuschel
Copy link
Contributor Author

Found the error - had too much references in my Test about 20 or so there seems to be some Problems. I've reduced the References and it works now.

  • I am writing AngularJS Tests and it would be cool if you could provide an alternate method to create the /// template ....

Like:

/// <template path="mytemplate.html" id="templateId" type="text/ng-template" />

the Markup in the Template "mytemplate.html" is e.g.

<div class="row">
    <div class="col-lg-12">
       <h1> Tempalte Test </h1>
   </div>
</div>

that will create the following markup in the test

<script id="templateId" type="text/ng-template">
  <div class="row">
       <div class="col-lg-12">
          <h1> Tempalte Test </h1>
     </div>
  </div>
</script>

that would be very helpfull when you write AngularJS Unit Tests with chutzpah. When you add the id in the template tag then surround the created html with the script Tag and the given ID and Type

@mmanela
Copy link
Owner

mmanela commented Mar 1, 2015

Currently, Chutzpah just takes what you give it verbatim. So why cant you just write that last thing (the html in the script tag) in your template so chutzpah injects that?

Also, you can also reference your HTML templates using your chutzpah.json file.

@squadwuschel
Copy link
Contributor Author

You cannot place the template inside the script tags because AngularJs did not work this way with templates. You need the plain HTML templates in AngularJS.
The script tag are only there that I can find the templates in the test HTML with jQuery Selector and get the pure HTML out of it to add the html to the angularJS template cache. And here it would be nice if I don't need to modify my AngularJS templates that they fit into my tests.

at the moment I need to add a unique class to my template only for the tests

//Get the template out of the test HTML
var template = jQuery(".templateTestTemplate")[0].outerHTML;
//Add the Template HTML to the AngularJS template cache
$templateCache.put("ScriptsApp/directives/Templates/testTemplate.html", template);

and here it would be very cool if you could provide the above mentioned system with the ID and if possible with the type is nice to have.

Do you have an example how the chutpah.json file works with Visual Studio.

thx much

@mmanela
Copy link
Owner

mmanela commented Mar 1, 2015

I am not very well versed in Angular.js at this point so I am not familiar with what it would like for HTMl templates.

The chutzpah.json file just works, you put it somewhere in your tree (above where your tests are) and chutzpah will find it and use it.

@squadwuschel
Copy link
Contributor Author

AngularJS uses templates like I descriped it above - when the templates used as external HTML files in AngularJS then the above mentioned solution would be very cool then I don't need to modify my html template only to pass the unit tests.

In this issue

#138

they have the same problem and for the alternate solution you have to modify your html template only for the unit tests and I prever not to change my code to success the unit tests - with my suggested solution you don't need to modify the html template.

When you have more Questions about AngularJS and the usage of Templates then just ask me.

It would be great if you could implement this optional feature in Chutzpah

@mmanela
Copy link
Owner

mmanela commented Mar 7, 2015

Since I don't know angular that well it would help me if you could give me a minimal sample project using angualr templates that shows

  1. How you get them to work with Chutzpah.
  2. The ideal way for them to work.

@squadwuschel
Copy link
Contributor Author

Hello try to open this sln
http://squadwuschel.codeplex.com/SourceControl/latest#Testprojekte/MvcAngularJs/MvcAngularJs.sln
from my Codeplex account

In short terms that it actually works with Chutzpah:

First of all I have this AngularJS directive:
http://squadwuschel.codeplex.com/SourceControl/latest#Testprojekte/MvcAngularJs/MvcAngularJs1_3/ScriptsApp/directives/testTemplateDirective.js

angular.module("testTemplateDirective", [])
    .directive("testTemplate", function() {
        return {
            restrict: 'A',
            replace: true,
            templateUrl: 'ScriptsApp/directives/Templates/testTemplate.html'
        }
});

The Template lays in an HTML file and look like this:
http://squadwuschel.codeplex.com/SourceControl/latest#Testprojekte/MvcAngularJs/MvcAngularJs1_3/ScriptsApp/directives/Templates/testTemplate.html

 <div class="row templateTestTemplate">
     <div class="col-lg-12">
         <h1>Tempalte Test</h1>
     </div>
  </div>

And to use the template in Angular you have to create an angular app and add the dependency to the angular directive and then I can simply use the following HTML to render the template in my angular application
http://squadwuschel.codeplex.com/SourceControl/latest#Testprojekte/MvcAngularJs/MvcAngularJs1_3/Views/Home/TemplateUrlTest.cshtml

<body> 
   <div test-template>
 </body>

The jasmine test to test if the Template renders the right HTML looks like this:
http://squadwuschel.codeplex.com/SourceControl/latest#Testprojekte/MvcAngularJs/UnitTestsJs/MvcAngularJs1_3/testTemplateDirectiveTests.js

/// <template path="../../MvcAngularJs1_3/ScriptsApp/directives/Templates/testTemplate.html" /> 
/// <reference path="../../mvcangularjs1_3/scripts/jquery-2.1.1.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular-mocks.js" />
/// <reference path="../../mvcangularjs1_3/scriptsapp/directives/testtemplatedirective.js" />

angular.module("app.testtmplate", ["testTemplateDirective"]);
describe("Unit Tests für die Direktive 'testTemplateDirective' ", function() {
    var $rootScope, $compile;
    beforeEach(function() {
        module('app.testtmplate');
        inject(function(_$rootScope_, _$compile_) {
            $rootScope = _$rootScope_;
            $compile = _$compile_;
        });
    });

    describe('Tests für Direktive "testTemplateDirective"', function () {
        beforeEach(function () {
            inject(function ($templateCache) {
                var template = jQuery(".templateTestTemplate")[0].outerHTML;
                $templateCache.put("ScriptsApp/directives/Templates/testTemplate.html", template);
            });
        });

        it('Es wurde ein H1 mit dem Text "Template Test" angelegt', function () {
            var element = $compile("<div><div test-template></div>")($rootScope);
            $rootScope.$digest();

            expect(element.html()).toContain("<h1>Tempalte Test</h1>");
            expect(element.find("h1").length).toBe(1);
        });
    });
})

I hope this helps a bit - thats how I solve it at the moment, if you could provide to wrap this in script tags with ID then I don't need to add the extra css class. The above linked sln contains many examples with AngularJS I don't have a sln ready only with this one example. If it helps you I can provide some plunker AngularJs sample.

@mmanela
Copy link
Owner

mmanela commented Mar 7, 2015

Some basic Angular sample would help since I can then turn it into an integration test.

@squadwuschel
Copy link
Contributor Author

here

http://plnkr.co/edit/1O765S?p=preview

you can find a very basic Angular application with an directive and templateUrl - there is also a jasmine unit test which is not working with plunker but you can see what I am doing there to test the directive. If you have some detailed question then ask them here I try to answer them :-)

@mmanela
Copy link
Owner

mmanela commented Apr 5, 2015

Ok, so pretty much you are asking if Chutzpah could add the id to your html instead of doing it yourself?

Or are you asking something different

@squadwuschel
Copy link
Contributor Author

"yes" it would be nice if Chutzpah can support to add a script Tag which includes my Template like

<script id="templateId" type="text/template">
  <div class="row">
       <div class="col-lg-12">
         <h1> Tempalte Test </h1>
    </div>
  </div>
</script>

with the template reference so it would be meaningful if you also could add the type Tag but not necessary

/// <template path="mytemplate.html" id="templateId" type="text/template" />

and only when you add the id in the template reference then add it to the script tag otherwise do it like before.

@squadwuschel
Copy link
Contributor Author

hi,

what about implementing this feature, is there something planed?

@mmanela
Copy link
Owner

mmanela commented May 27, 2015

I have not had time to dig into this feature. If you are interested I would welcome you to fork and look at adding it. Otherwise, it may be some time before I can get to it.

@mmanela mmanela changed the title The "/// <template path="...." " is not working with vs 2013 and chutzpah 3.3.1 Improve html template imports to work better with Angular.js Sep 6, 2015
@jongunter
Copy link

This feature would be really nice. I know a lot of Angular devs in the Microsoft stack (myself included) that are using hacky workarounds to get our templates in the cache since we can't make an HTTP request in a test.

@mmanela
Copy link
Owner

mmanela commented Jan 12, 2016

Given the discussion above what would be the simplest things that would help you?

@jongunter
Copy link

Provide the option to embed each template in the page in a script tag, as shown below:

So I write the following in the my-test.spec.js file:

/// <template path="/templates/tpl.html" id="tpl.html" script="true" />

The following renders in the test harness HTML file

<script type="text/ng-template" id="tpl.html">
  Content of the template.
</script>

Ideally, the user should be able to set the id of the template. And of course, the contents of the HTML file we include would go inside the script tag. I believe this should go after the body tag at the top of the test harness file.

See more here: https://docs.angularjs.org/api/ng/directive/script

Might want to also confirm with another AngularJS developer that this is the ideal functionality.

@squadwuschel
Copy link
Contributor Author

I agree - like I've mentioned above that would be the best solution for templates.

@bbehling
Copy link

+1 this request.

Sorry, but I will have to switch to Karma if this isn't resolved soon :(

@mmanela
Copy link
Owner

mmanela commented Jan 15, 2016

Thanks for the comments @squadwuschel, @bbehling and @jongunter. I am already implementing the proposed solution. One thing that would help a lot is a minimal angularJS sample using HTML templates and including JS tests which try to use the proposed solution. I will then be able to integrate these into Chutzpah has the official AngularJS samples as part of documenting this feature

@jongunter
Copy link

Awesome. Thank you so much! It's looking like a busy week for me but I'll see if I can make some sample tests for Angular templates ASAP.

@squadwuschel
Copy link
Contributor Author

you have tried my plunkr yet?

http://plnkr.co/edit/1O765S?p=preview

there is also a jasmine unit test which is not working with plunker but you can see what I am doing there to test the directive. If you have some detailed question then ask them here I try to answer them :-)

@mmanela
Copy link
Owner

mmanela commented Jan 19, 2016

I missed that! Thanks. That was enough for me to make a sample and test case out of. I committed my changes!!!

You can now reference a template in a angular friendly way by either using the chutzpah.json file:

  "References": [
    { "Path": "directiveTemplate_json.html", 
      "TemplateOptions": {"Mode": "Script", "Id": "template_json", "Type": "text/ng-template"}}
  ]

Or through a reference comment:

/// <template path="directiveTemplate_comment.html" mode="script" id="template_comment" type="text/ng-template" /> 

Please take a look at the sample I pushed (and use as my test case) here : https://github.com/mmanela/chutzpah/tree/master/Samples/Angular/TemplateDirective

If you feel this solution seems good I can close the issue and will include these changes in the next release.

@squadwuschel
Copy link
Contributor Author

Hi,
I've taken a look at the example and I've created some pull request for some simple changes. My plunker example shows how I need to setup the unit test at the moment, so I've fixed this in your code. I think this should be right now.

@mmanela
Copy link
Owner

mmanela commented Jan 19, 2016

I see, no need to edit index.html. I am deleting that file since it is not needed for the test. But the other changes look great. Thanks!

@mmanela
Copy link
Owner

mmanela commented Jan 23, 2016

Closing issue, fix will be in next release which should be in a week or less

@mmanela mmanela closed this as completed Jan 23, 2016
@bbehling
Copy link

Hello.

Using the latest 4.2.0 build, my template is loaded into the DOM. But when I look at the the compiled element, the HTML is empty. If I run the test through the browser, I can see the template is added.

Any ideas?

    describe("Unit Tests for the Template Direkti ", function () {
    var $rootScope, $compile;

    beforeEach(function () {
        //Load Main App
        module('landStudioApp');

        inject(function (_$rootScope_, _$compile_) {
            $rootScope = _$rootScope_;
            $compile = _$compile_;
        });
    }); 

    describe('Tests Directive', function () {

        beforeEach(function () {
            inject(function ($templateCache) {
                //Find The Template in the current Unit Test HTML

                //console.log(document.getElementById("rrTemplate")); //has value
                var templateFromJson = document.getElementById("rrTemplate").innerHTML;

                $templateCache.put("rrTemplate.html", templateFromJson);
            });
        });

        it('contains the text template from reference comment', function () {
            var element = $compile("<rapid-report/>")($rootScope);
            $rootScope.$digest();

            console.log(element.html()); //empty string

            expect(element.html()).toContain("Source");
        });
    });
}) 

@squadwuschel
Copy link
Contributor Author

can you post the hole test including the template and Chutzpath definitions like:

 /// <template path="directiveTemplate_comment.html" mode="script" id="template_comment" type="text/ng-template" />
/// <reference path="../../mvcangularjs1_3/scripts/jquery-2.1.1.js" />

@bbehling
Copy link

Hello.

Here is plunk

[https://plnkr.co/edit/YieJvcxRgCFD2rtR9NcA?p=catalogue]

Its pretty much the same as your Angular sample, with a couple modifications, which include: Using Jasmine V1.x; loading additional JS libraries; no class in HTML templates; the test.js file is not loaded as a test reference (if I place is it as a test reference, tests are not found)

So far this works, but I need to figure out why my directives are not working.

EDIT -

Updated the plunk with my directive and tests. If I add the directive to the chutzpah config file, I get an unexpected GET request error. Without loading the directive, the element.HTML is empty. Which makes sense.

The template URL in the application cant be a file reference, but looks like chutzpah wants to load the template as a file URL?

chutzpah.json -
{
"Path": "../LandStudio.Web/app/js/ls/RapidReports/rrTemplate.html",
"TemplateOptions": { "Mode": "Script", "Id": "rrTemplate", "Type": "text/ng-template" }
}

directive template URL -

templateUrl: 'landstudio/app/js/ls/RapidReports/rrTemplate.html'

I did find a work around for this, which is to load the template using a XMLHttpRequest, but I thought this was supposed to be fixed in this version?

@squadwuschel
Copy link
Contributor Author

yes the searching for the template with the element name should work, but its a while since my last unit test with AngularJs. Perhaps @mmanela can check this.

@mmanela
Copy link
Owner

mmanela commented Mar 12, 2016

With the current version of chutzpah, it will inject into your HTML test harness the appropriate script tag such like:

<script type="text/ng-template" id="tpl.html">
  Content of the template.
</script>

And I proved at least in the use case I was told above for angular that works. I am not an angular expert so if there are other scenarios that this doesn't work for I am not sure.

Can you confirm in the HTML harness Chutzpah generates the script template is injected properly?

@jongunter
Copy link

I'm using it in a few of my tests and it seems to work. Let me take a look at how my test is set up when I get in to work Monday AM.

@AbhishekPandey12
Copy link

Any update @jongunter/ @mmanela whether the html mentioned in templateUrl in the directive is available for writing specs for directive.........

@jonesprabu
Copy link

jonesprabu commented Jul 12, 2018

Hi @mmanela @squadwuschel
My directive test was working fine earlier, code as below. It is not working now.

describe('clients/directives/clientInformation.js', function () {

    var directive, $scope, $httpBackend;

    beforeEach(angular.mock.module('clientManager'));

    beforeEach(inject(function ($compile, $rootScope, $injector) {
        $scope = $rootScope.$new();
        $scope.mockClient = { clientTypeId: 0 };
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.expectGET('/App/clients/templates/clientInformation.html').respond(200, '<div></div>');
        directive = angular.element('<client-information client="mockClient"></client-information>');
        directive = $compile(directive)($scope);
        $httpBackend.flush();
        $httpBackend.resetExpectations();
        $rootScope.$digest();
    }));

    it('should add a custom class to the directives element', function () {
        expect(directive.hasClass('client-information')).toBe(true);
    });

    it('should add template children', function () {
        expect(directive.children().length).not.toBe(0);
    });

    afterEach(function () {
        $scope.$destroy();
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });
});

Below error is coming:

Test 'clients/directives/clientInformation.js:should add a custom class to the directives element' failed
Error: No pending request to flush ! (line 1856)

If i comment the $httpBacked.flush(); then the first case is getting passed
and the second fails as there is no children in the directive element.

Test 'clients/directives/clientInformation.js:should add template children' failed
Expected 0 not to be 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants