Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock polymer core ajax, for unit testing

I am building the scaffolding for my new polymer project, and am considering unit tests. I think I will be using the karma/jasmine combination. There is an interesting post at http://japhr.blogspot.co.uk/2014/03/polymer-page-objects-and-jasmine-20.html which I understand enough to get me started, but the key question I will have to address and haven't found any standard way to do it is how do I mock the ajax calls.

When I was using jasmine, standalone, on a JQuery Mobile project, I was able to directly use the Jasmine SpyOn ability to mock the JQuery.ajax call. Is there something similar for Polymer?

I came across an element <polymer-mock-data> but there is no real documentation for it, so I couldn't figure out if they might help

like image 675
akc42 Avatar asked Jul 02 '14 12:07

akc42


2 Answers

Instead of importing core-ajax/core-ajax.html, create your own core-ajax element.

<polymer-element name="core-ajax" attributes="response">
<script>
  Polymer('core-ajax', {
    attached: function() {
      this.response = ['a', 'b', 'c'];
    }
  });
</script>
</polymer-element>

Obviously, this is just an example, the actual implementation depends on the desired mocking behavior.

This is just one way to solve it, there are many others. I'm interested to hear what you find (in)convenient.

like image 146
Scott Miles Avatar answered Nov 05 '22 03:11

Scott Miles


It turns out that Jasmine2.0 has an Jasmine-ajax plugin that will mock the global XMLHttpRequest. core-ajax uses this under the hood, so I can directly get at the call.

It works well, in a beforeEach function at the top the suite you call jasmine.Ajax.install and in the afterEach function you call jasmine.Ajax.uninstall, and it automatically replaces the XMLHttpRequest.

Timing is also crucial, in that you need to ensure you have mocked the Ajax call before the element under test uses it. I achieve that using a separate function to specifically load the fixture which contains the element under test, which is called after jasmine.Ajax.install has been called. I use a special setup script thus

(function(){
  var PolymerTests = {};
  //I am not sure if we can just do this once, or for every test.  I am hoping just once
  var script = document.createElement("script");
  script.src = "/base/components/platform/platform.js";
  document.getElementsByTagName("head")[0].appendChild(script);

  var POLYMER_READY = false;
  var container;  //Used to hold fixture
  PolymerTests.loadFixture = function(fixture,done) {
    window.addEventListener('polymer-ready', function(){
      POLYMER_READY = true;
     done();
    });
    container = document.createElement("div");
    container.innerHTML = window.__html__[fixture];
    document.body.appendChild(container);
    if (POLYMER_READY) done();
  };
  //After every test, we remove the fixture
  afterEach(function(){
    document.body.removeChild(container);
  });

  window.PolymerTests = PolymerTests;

})();

The only point to note here is that the fixture files have been loaded by the karma html2js pre-processor, which loads them into the window.__html__ array, from where we use the code to add to the test context

My test suite is like so

describe('<smf-auth>',function(){
  beforeEach(function(done){
    jasmine.Ajax.install();
    PolymerTests.loadFixture('client/smf-auth/smf-auth-fixture.html',done);
  });
  afterEach(function(){
    jasmine.Ajax.uninstall();
  });
  describe("The element authenticates",function(){
    it("Should Make an Ajax Request to the url given in the login Attribute",function(){
      var req = jasmine.Ajax.requests;
      expect(req.mostRecent().url).toBe('/football/auth_json.php'); //Url declared in our fixture
    });

  })
});
like image 21
akc42 Avatar answered Nov 05 '22 02:11

akc42