1

According to jQuery 3.0 Beta Released

jQuery.Deferred is now Promises/A+ compatible jQuery.Deferred objects have been updated for compatibility with Promises/A+ and ES2015 Promises, verified with the Promises/A+ Compliance Test Suite.


How To Run

The tests can run in either a Node.js environment or, if you set things up correctly, in the browser.

How to run the tests in browser, without nodejs to verify ?


Note, have not yet achieved running tests in browser without nodejs. @JaredSmith 's assistance was essential to running tests at all using nodejs.

guest271314
  • 1
  • 15
  • 104
  • 177
  • Please ask a single question per post only. – Bergi Apr 05 '16 at 22:36
  • You can easily put jQuery's deferred implementation in a nodejs module and test it there, it shouldn't make a difference. – Bergi Apr 05 '16 at 22:37
  • @Bergi Have little experience with `nodejs` or `nodejs` modules . _"if you set things up correctly, in the browser."_ Thus the present inquiry . Updated OP to single Question – guest271314 Apr 05 '16 at 22:41
  • 1
    To "set things up correctly, in the browser" requires running browserify to make the test suite's node modules importable. The catch is that browserify uses node, so either way you'll have to learn some node. – aebabis Apr 05 '16 at 23:37
  • @Bergi Would the tests at http://stackoverflow.com/a/23744774/ and http://jsfiddle.net/jdiamond/kqv3m/ from https://gist.github.com/domenic/3889970 suffice as tests to check if version 3.0.0-beta meets compliance with Promises/A+ specification? – guest271314 Apr 06 '16 at 14:28
  • @guest271314: No, those don't offer full coverage by far. They can serve as an indicator that something changed since jQuery 2.x, and in the right direction, but they're not equivalent to the test suite. And never forget that tests cannot prove compliance, they only can show noncompliance. – Bergi Apr 06 '16 at 14:35
  • @Bergi Have not been able to get node to install browserify. How to convert tests to version that can be run in browser without node? Or how to create an adapter without node equivalent to adapter expected by tests? – guest271314 Apr 06 '16 at 14:57
  • This is actually quite a large project. If you're having Node troubles, then your best bet is probably to make an `html` page with Mocha, Sinon, and Underscore included in the head, then copy-paste the unit tests from the repo into the document, then write an adapter to match the expected promise construction interface. – aebabis Apr 06 '16 at 18:51
  • @acbabis Can you post demonstration of solution described at last comment as Answer? – guest271314 Apr 11 '16 at 02:00
  • 1
    @guest271314 That's an involved project that I'm frankly not interested in. However, I just looked at jQuery on GitHub. Turns out they've updated their `Deferred` unit test just 11 days ago: https://github.com/jquery/jquery/blob/master/test/unit/deferred.js. Maybe this meets your requirement. – aebabis Apr 11 '16 at 02:54
  • @acbabis Was able to run `deferred.js` using `QUnit` , passed each of the twenty-eight tests. Not certain if comparable to https://github.com/promises-aplus/promises-tests? – guest271314 Apr 11 '16 at 05:22
  • @Bergi _"You can easily put jQuery's deferred implementation in a nodejs module and test it there, it shouldn't make a difference."_ Re-installed `nodejs` , `browserify`, `pug`, and `promises-aplus-tests`. How to compose an `adapter` , `nodejs` module that exposes jQuery 3.0.0-beta1 `$.Deferred()` to run tests? Is it possible to port the tests to `QUnit`? Are tests at https://github.com/jquery/jquery/blob/master/test/unit/deferred.js comparable to tests at https://github.com/promises-aplus/promises-tests? – guest271314 Apr 11 '16 at 14:59
  • @guest271314: You wouldn't need `browserify` or `pug` for that. Just put jQuery in a module (or install it via npm), get a hold onto its `Deferred` object, write the adapter and expose it with the commonjs interface. – Bergi Apr 11 '16 at 15:04
  • @Bergi Have not previously composed an "adapter" or a "module". What is the procedure? Should another Question be asked as to this? – guest271314 Apr 11 '16 at 15:05
  • @guest271314: Check the docs or a tutorial for how to write a nodejs module – Bergi Apr 11 '16 at 15:06
  • @Bergi Is version 3.0.0-beta1 available at node https://www.npmjs.com/package/jQuery ? – guest271314 Apr 11 '16 at 15:11
  • @guest271314: I don't know, surely you can check yourself. If not, manually copying it into a file works just as well. – Bergi Apr 11 '16 at 15:25
  • @Bergi 3.0.0-beta1 does not appear to be available, at least as far as could gather. Copy into a file, then do what? Just found this https://github.com/jquery/jquery/issues/2152 – guest271314 Apr 11 '16 at 15:28
  • @guest271314 An "adapter" is just a piece of code that converts one interface to another. For example, `$.ajax` is an adapter for `XMLHttpRequest`. When the A+ spec says to write an adapter, they're basically just saying to make it so the code runs. – aebabis Apr 12 '16 at 19:37

3 Answers3

2

The adapter referenced in the comments means adapting the jQuery deferred constructor to meet the API in the spec. The way to do so might be as follows (taken more or less from here):

var promisesAplusTests = require("promises-aplus-tests");
var jq                 = require('jquery');
var jsdom              = require('jsdom');
jsdom.env('<p></p>', function(err, window) {
    if (err != null) {
        throw err;
    } else {
        var $ = jq(window);
        var adapter = {};
        adapter.deferred = function() {
            var deferred = $.Deferred();

            return {
                promise: deferred.promise(),
                resolve: deferred.resolve.bind( deferred ),
                reject: deferred.reject.bind( deferred )
            };
        };
        promisesAplusTests(adapter, function (err) {
            // All done; output is in the console. 
            // Or check `err` for number of failures:
            if (err) {
                console.log(err);
            }
        });
    }
});

At which point you need to install the dependencies via npm and run the file. Note that using jquery requires a proper document (hence the need for jsdom).

Or you could take the easy route:

  • git clone the jquery repo
  • cd jquery directory
  • npm install
  • wait forever for it to finish, ignore all warnings
  • npm test -which runs the jquery unit tests (including A+ suite)

Running in the browser, despite the glib comment in the spec readme, will involve some of work. You will need to use a commonJS module loader like browserify. Browserify will shim the native node assertion library and I believe filesystem api. Mocha should work fine in the browser. Then the above code should run.

If you want to avoid node.js entirely (and not just for running the tests) , you'll have more work to do.

Step 1. Find or write a compatible assertion library and include it in a script tag.

Step 2. Include mocha in a script tag.

Step 3. Write your own stubs for require, assert, fs, etc. Each of those is a question in its own right.

Step 4. Use the adapter code.

Whether its worth doing all that or not to avoid node is your call.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • Can you include a detailed approach to solve, for example, converting a single test to being capable of returning results in browser? Is using `require` library necessary? Can you create a stacksnippets to demonstrate results? – guest271314 Apr 11 '16 at 19:55
  • Necessary? No its not *necessary*, but the alternative is to edit the source code of the tests to use something like assigning to global variables instead. You would also have to replace the assertion library with another one. Just use browserify. Or port all the tests (a la my answer to your other question). – Jared Smith Apr 11 '16 at 20:08
  • Is `browserify` nodejs-based? The Question seeks to return expected results without using `node.js` . Can browserify be used as a standalone library? – guest271314 Apr 11 '16 at 20:10
  • No. Only way to do this with no node.js is to edit the source code of the tests to export to a global variable, stick it in a script tag src, have another script that calls the function via the global variable you assigned to, include the adapter code I wrote in-line, include an assertion library in another script tag, and include mocha in a script tag. That's a lot of work to avoid a few dozen megs of downloads and a couple of terminal commands. – Jared Smith Apr 11 '16 at 20:13
  • Yes, perhaps some effort, though appears possible. Can you detail the steps in the process in a list or other format at Answer; possibly include a brief example at stacksnippets demonstrating the process? The requirement of the present Question is to be able to run the tests in the browser; at `console` or within an `html` `document`. – guest271314 Apr 11 '16 at 20:14
  • @guest271314 Just updated. More specific directions are beyond the scope of an SO answer. – Jared Smith Apr 11 '16 at 20:18
  • Missing closing `}` at IIFE. Trying approach described at Answer at command line, receiving `TypeError: adapter.deferred is not a function` – guest271314 Apr 12 '16 at 03:33
  • Receiving error `/tmp/jquery116312-32362-fp0l9k/node_modules/jquery/dist/jquery.js:9977 Uncaught TypeError: fs.readdir is not a function` at http://requirebin.com/?gist=ce7a014d0ec638de5c13516d69a1e64e – guest271314 Apr 12 '16 at 05:39
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/108948/discussion-between-jared-smith-and-guest271314). – Jared Smith Apr 12 '16 at 14:04
1

The biggest difference between A+ compliant Promises and old jQuery Deferreds is that A+ Promises have proper error handling. You can verify that jQuery 3 promises now have proper error handling by running this simple test.

function test(name, $) {
  var $name = $('<td>').text(name);
  var $result = $('<td>');
  var $row = $('<tr>')
      .append($name)
      .append($result)
      .appendTo('tbody');
  
  var def = $.Deferred();
  def.rejectWith(new Error("Error"));
  def.then(undefined, function() {
    $result.text('Fail').css('color', 'red'); // This will be overriden by success case
  }).then(function() {
    $result.text('Success').css('color', 'green');
  });
}

test('jQuery 1', $1);
test('jQuery 2', $2);
test('jQuery 3', $3);
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script>
  var $1 = $;
  $.noConflict();
</script>
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<script>
  var $2 = $;
  $.noConflict();
</script>
<script src="https://code.jquery.com/jquery-3.0.0-beta1.js"></script>
<script>
  var $3 = $;
  $.noConflict();
</script>

<table>
  <thead>
    <tr>
      <td>Version</td>
      <td>Result</td>
    </tr>
  </thead>
  <tbody>
    </tbody>
</table>
aebabis
  • 3,657
  • 3
  • 22
  • 40
  • 1
    How to run Compliance Test Suite in browser ? – guest271314 Apr 05 '16 at 23:13
  • @guest271314 I'm sorry, I misread the question. The answer to the question you asked is "You will have to write an adapter in order to meet the interface the test suite expects." I'll change my answer. – aebabis Apr 05 '16 at 23:19
0

How to run the tests in browser, without nodejs to verify ?


Note, have not yet achieved running tests in browser without nodejs. @JaredSmith 's assistance was essential to running tests at all using nodejs.

Have been able to achieve requirement described at Question by utilizing and adjusting files at Unofficial mirror of the WebKit SVN repository -> master -> LayoutTests -> js -> promises-tests.

Attempted to change as little as possible. Updated promises-tests version to 2.1.1 from 2.0.5 that was present at webkit repo; included .js files from other portions of repo to resources directory; added jQuery-3.0.0-pre source within adapter.js; commented promises-in-workers.html which tests Promise in Worker environment where jQuery() initialization checks document features.

Run tests by downloading jquery-3.0.0-promises-tests-in-browser, opening index.html in browser.

$(document).ready(function() {
  $("title, h3")
  .html("jQuery version " + jQuery().jquery + " Promises/A+ Compliance Tests");
  var tests = ["promises-tests-2-1-2.html"
               , "promises-tests-2-1-3.html"
               , "promises-tests-2-2-1.html"
               , "promises-tests-2-2-2.html"
               , "promises-tests-2-2-3.html"
               , "promises-tests-2-2-4.html"
               , "promises-tests-2-2-5.html"
               , "promises-tests-2-2-6.html"
               , "promises-tests-2-2-7.html"
               , "promises-tests-2-3-1.html"
               , "promises-tests-2-3-2.html"
               , "promises-tests-2-3-3.html"
               , "promises-tests-2-3-4.html"
               , "Promise-types.html" 
               // TODO test `jQuery.Deferred()` in `Worker` 
               // see http://stackoverflow.com/q/10491448/
               /* , "promises-in-workers.html" */ ];
  $.each(tests, function(index, test) {
    $("<iframe>", {
        width: "100%"
      }).on("load", function(e) {
        setTimeout(function() {
          e.target.height = e.target.contentWindow
                            .document.body.scrollHeight * 1.1 + "px";
        }, 2000 * (1 + index));
        // if (index === tests.length - 1) {
        //    $(e.target.contentWindow.document.body)
        //    .prepend("<span style='font-family:Times New Roman'>"
        //               + "Promises in Workers Test</span>")
        // }
      })
      .attr("src", test).appendTo("body")
  })
});

Demonstration

guest271314
  • 1
  • 15
  • 104
  • 177