Git Product home page Git Product logo

promises-tests's Introduction

Promises/A+ logo

Promises/A+ Compliance Test Suite

This suite tests compliance of a promise implementation with the Promises/A+ specification.

Passing the tests in this repo means that you have a Promises/A+ compliant implementation of the then() method, and you can display the Promises/A+ logo in your README. You can also send a pull request to have your implementation listed on the implementations page.

How To Run

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

Adapters

In order to test your promise library, you must expose a very minimal adapter interface. These are written as Node.js modules with a few well-known exports:

  • resolved(value): creates a promise that is resolved with value.
  • rejected(reason): creates a promise that is already rejected with reason.
  • deferred(): creates an object consisting of { promise, resolve, reject }:
    • promise is a promise that is currently in the pending state.
    • resolve(value) resolves the promise with value.
    • reject(reason) moves the promise from the pending state to the rejected state, with rejection reason reason.

The resolved and rejected exports are actually optional, and will be automatically created by the test runner using deferred if they are not present. But, if your promise library has the capability to create already-resolved or already-rejected promises, then you should include these exports, so that the test runner can provide you with better code coverage and uncover any bugs in those methods.

Note that the tests will never pass a promise or a thenable as a resolution. That means that we never use the promise- or thenable-accepting forms of the resolve operation directly, and instead only use the direct fulfillment operation, since fulfill and resolve are equivalent when not given a thenable.

Finally, note that none of these functions, including deferred().resolve and deferred().reject, should throw exceptions. The tests are not structured to deal with that, and if your implementation has the potential to throw exceptions—e.g., perhaps it throws when trying to resolve an already-resolved promise—you should wrap direct calls to your implementation in try/catch when writing the adapter.

From the CLI

This package comes with a command-line interface that can be used either by installing it globally with npm install promises-aplus-tests -g or by including it in your package.json's devDependencies and using npm's scripts feature. In the latter case, your setup might look something like

{
    "devDependencies": {
        "promises-aplus-tests": "*"
    },
    "scripts": {
        "test": "run-my-own-tests && promises-aplus-tests test/my-adapter"
    }
}

The CLI takes as its first argument the filename of your adapter file, relative to the current working directory. It tries to pass through any subsequent options to Mocha, so you can use e.g. --reporter spec or --grep 2.2.4.

Programmatically

The main export of this package is a function that allows you to run the tests against an adapter:

var promisesAplusTests = require("promises-aplus-tests");

promisesAplusTests(adapter, function (err) {
    // All done; output is in the console. Or check `err` for number of failures.
});

You can also pass any Mocha options as the second parameter, e.g.

promisesAplusTests(adapter, { reporter: "dot" }, function (err) {
  // As before.
});

Within an Existing Mocha Test Suite

If you already have a Mocha test suite and want to include these tests in it, you can do:

describe("Promises/A+ Tests", function () {
    require("promises-aplus-tests").mocha(adapter);
});

This also works in the browser, if you have your Mocha tests running there, as long as you use browserify.

promises-tests's People

Contributors

aheckmann avatar briancavalier avatar calvinmetcalf avatar domenic avatar dtao avatar etki avatar eventualbuddha avatar fidian avatar forbeslindesay avatar marklin-latte avatar mgol avatar novemberborn avatar petkaantonov avatar timjansen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

promises-tests's Issues

potential loose test coverage for resolving foreign thenables resolved in handlers

While doing some work on RSVP, I may have noticed that the promise tests have loose test coverage when it comes to foreign thenables introduced as handler return value.

Scenario:
I was able to introduce a foreign thenable, that could cause a settled promise to fulfill and reject multiple times. Clearly this is was a bug in RSVP and I have since tested and corrected it, but it would seem like a good scenario for the promise tests to cover.

Example:

var resolver, rejector, thenable,
     wrapped, rejected = 0, fulfilled = 0;

thenable = {
  then: function(resolve, reject) {
    resolver = resolve;
    rejector = reject
  } 
};

promise = new Promise(function(resolve, reject) {
  resolve(1);
});

promise.then(function(value) {
  return thenable;
}).then(function(value) {
  fulfilled++;
}, function(reason) {
  rejected++;
});

resolver(1);
resolver(1);
rejector(1);
rejector(1);

nextTurn(function(){
  resolved // => 2
  rejected  // => 2
}, 0);

How to run tests at requirebin?

Received this error at chromium 50 /tmp/jquery116312-32362-fp0l9k/node_modules/jquery/dist/jquery.js:9977 Uncaught TypeError: fs.readdir is not a function at requirebin.com/?gist=ce7a014d0ec638de5c13516d69a1e64e ; this error TypeError: undefined is not a function /tmp/promises-aplus-tests11638-18974-ukg7u2/node_modules/promises-aplus-tests/li‌​b/programmaticRunne…:79 at chromium 37. gist: http://requirebin.com/?gist=ce7a014d0ec638de5c13516d69a1e64e. How to solve?

CLI exit code is wrong

For use in CI environments, the cli program should have an exit code that is not 0 in the event that any of the tests failed. Currently travis builds using this test suite always look like they've passed (I now comply, I didn't before though)

2.3.3 Tests don't use valid thenables.

I've been working on bringing a library up to spec and ran into an issue I wanted to get some feedback on.

The spec states that "then must return a promise". However, in quite a few of the 2.3.3 tests the then methods exposed by the test fixtures do not return promises. Examples:
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/2.3.3.js#L41
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/2.3.3.js#L137
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/2.3.3.js#L165
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/2.3.3.js#L248

During resolution, I make use of the fact that then returns a promise regardless of A+ implementation and expect that to be the case. In the case that it doesn't the promise being resolved simply becomes rejected with an appropriate error. Generic example:

try {
  var then = value.then;
  if (typeof then === "function") {
    then.call(value, onResolve, onReject).then(stuff).then(moreStuff);
  }
} catch (err) {
  this.rejectPromise(err);
}

Questions:

  • Is this a test bug?
  • Does the specification preclude the use of promises returned by a thenable during the resolution of a promise?
  • Is there a particular behaviour specified for when a thenable does not return a promise on then?

Edge case?

Hi there, I was testing my little Promise/A+ library against the 2.0.0 test suite and after some fiddling it finally passed all tests. Then I got back to testing to see how it's working in the wild and I found this issue; here is my contrived test case:

new Promise(function (resolve, reject) {
    var val = Math.random();

    if (val >= 0.5) {
        resolve(val);
    }
    else {
        reject(new Error('Value "' + val + '" too low.'));
    }
})
.then(function (value) {
    console.log('  promise.then.resolved', arguments);
    return 100 * value;
})
.then(null, function (reason) {
    console.warn('  next.promise.then.rejected', arguments);
    return 'error handled';
});

What I would have expected is:
val >= 0.5 -> log('promise.then.resolved')
val < 0.5 -> warn('next.promise.then.rejected')

but instead I saw the first promise resolved after val >= 0.5 but the rejection of val < 0.5 didn't propagate to the next promise so in this case there would be no activity.
val >= 0.5 -> log ...
val < 0.5 -> ...

I was wondering if this is the expected behavior; is it just me not getting the specs or is this a bug in the test suite?

Right now I've fixed this in my lib and the tests still pass - don't know what to make of it...

thx

Calling resolve twice is not specified

Hi,
Say that there are two implementations q1 and q2, what the behavior of the code below should be?

var p1 = q1.deferred();
var p2 = q2.deferred();
p1.promise.then(console.log);
p1.resolve(p2.promise);
p1.resolve('foo');
p2.resolve('bar');

Should it print 'foo' or 'bar'?

http://promisesaplus.com/#point-14 reads that for a promise to be fulfilled, it must have a value. So that would mean that after p1.resolve(p2.promise); then p1 is still pending. If that is the case, then p1.resolve('foo'); should fulfill p1 and it should print 'foo'. On the other side, given if p1 and p2 belong to the same implementation http://promisesaplus.com/#point-50 mandates that p1 to remain unresolved until p2 is resolved, then it should print 'bar'. The issue is that there is no such a point for generic thenables

BTW, it is possible to write an implementation that prints 'foo' or 'bar' and in both cases it passes the tests. This being the case when p1 and p2 belong to the same implementation or different implementations

Pass through mocha command line options

Many of mocha's command line options I don't care that much about, but it would be very very helpful to pass through:

-b, --bail                      bail after first test failure
-g, --grep <pattern>            only run tests matching <pattern>

Also of some (limited) use would be:

  -i, --invert            inverts --grep matches
  -t, --timeout <ms>      set test-case timeout in milliseconds [200]
  --debug-brk             enable node's debugger breaking on the first line
  --globals <names>       allow the given comma-delimited global [names]

Question about the tests

I'm currently trying to understand the tests to port them for the ActionScript implementation (see CC-Archived/promise-as3#11).

When i look at the first section suite I'm recognizing that it is only asserted that the promise doesn't get rejected but i don't see an assertion that it was fulfilled.

Which i would expect like this

setTimeout(function (){
  assert.strictEqual(onFulfilledCalled, true);
  done();
}, 100);

is this checked somewhere else or did i miss something in how the tests are executed?

3.2.2.3 "if onRejected called" tests are ambiguous

Please correct me if this was your intent, but I found the tests under 3.2.2.3 to be ambiguous. My understanding is that they're trying to ensure that the "onFulfilled" block is not called at all if "onRejected" is called, but they are only confirm a weaker subset of that: that "onFulfilled" is not called after "onRejected" is called.

It appears that the tests would pass if "onFulfilled" were called first, then "onRejected" were either called or not.

Should these tests be strengthened to fail completely if the onFulfilled block is called at all? Since in each of the scenarios the promise is never fulfilled, only rejected?

Test for .then inside a .then callback

E.g.

fulfilledPromise.then(function () {
  // this should happen first
  fulfilledPromise.then(function () {
    // this should happen third
  });
});
fulfilledPromise.then(function () {
  // this should happen second
});

Adapters needing `fulfilled(Value)` and `rejected(reason)` methods

Couldn't these just be implimented from pending and tested that way, reducing the number of methods to be implemented in adapters:

exports.fulfilled = function (value) {
  let {promise, fulfill} = exports.pending();
  fulfill(value);
  return promise;
};

exports.rejected= function (value) {
  let {promise, reject} = exports.pending();
  reject(value);
  return promise;
};

(obviously you'd need to convert that to ES5 😄)

Typos in 2.3.3.js

Lines 667 and 690 in 2.3.3.js should both be rejectPromise(other) rather than resolvePromise(other), no?

-Steve

Benchmarks

Perhaps this is not the right place for this, but I think centralized benchmarks (using the promises-tests adaptors) would be a great addition under promises-aplus, given general lack of proper benchmarks in the wild (see for example thanpolas/perf-promises#2)

Switch adapter to `resolve` instead of `fulfill`

Instead of calling it "fulfill" and saying "we promise to only call it as if it's the intersection of fulfill and resolve," we should call it "resolve" and give the same promise. This will reduce confusion from people thinking that they should implement pass-through fulfillment in their libraries in order to match the adapter interface.

This will be a backward-incompat change, but will go along well with the 1.1 launch.

publish to npm

I know this isn't finished yet, but I think it would still be worth beginning to publish versions to npm.

Adapters are not called with promises, are they?

The adapters section of the readme says:

Note that the tests will never pass a promise or a thenable as a resolution. That means that we never use the promise- or thenable-accepting forms of the resolve operation directly, and instead only use the direct fulfillment operation, since fulfill and resolve are equivalent when not given a thenable.

I'm not sure whether this is wrong, outdated or uses outdated terminology after #39 ?

The implementation that I'm currently testing does not (yet?) have a Promise constructor with a resolve callback, it only offers a fulfill callback which accepts any value and does not [[resolve]] its arguments recursively (yes, I'm allowing algebraic nesting of promises). I also did pass the monadic Promise.of for adapter.resolve.

However, this has bitten me heavily, and it took me some time to figure out that deferred.resolve is indeed called a few times with one of my Promises. Is this a bug in the test cases? An error in the documentation? Or did I just misunderstand that sentence?

Tests 3.2.6 fails if promise is a function

According to the spec, a promise can be either an object or a function. My Promises lib implements promises as a function, which causes test 3.2.6 (promises-aplus-tests/lib/tests/3.2.6.js:20:16) to fail. The test expects the promise to be an object.

2.2.2.2 fails when resolving synchronously outside of .then's event-loop-turn

This is the test for 2.2.2.2:

        var d = deferred();
        var isFulfilled = false;
        d.promise.then(function onFulfilled() {
            assert.strictEqual(isFulfilled, true);
            done();
        });
        setTimeout(function () {
            d.resolve(dummy);
            isFulfilled = true;
        }, 50);

I think the spec says that onFulfilled should be called with a clean stack with regards to the then, but not necessarily WRT resolve. Spec 2.2.4 says:

onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

Where note 3.1 clarifies:

In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack.

Depending on interpretation, specifically of "and with a fresh stack" but mostly because then's context is mentioned explicitly while resolve/reject are not, if d.resolve(dummy) executes onFulfilled synchronously, which at this test is not at the same execution context where then was called, then I think the spec says it's OK, but this test will fail because it expects onFulfilled to be at a different context to resolve (i.e. that isFulfilled = true; runs before onFulfilled)

Personally I think that the spec should enforce fully async of resolve/reject as well (like the test expects), and even further that two onFulfilled/onRejected should also not be called at the same execution context, but if an implementer tries to squeeze every ounce of speed by using synchronous executions where the spec allows, then I think this test should pass if resolve executes onFulfilled synchronously (same for the equivalent reject and possibly other tests).

Publish to npm

What do we need in order to be comfortable publishing this in npm?

Sample adapters?

I found example adapters on this deprecated test suite, but the promises-aplus repo and readme don't talk much about how adapters are supposed to be implemented for the a+ test. Are the ones from the link usable with both?

If so, maybe they should be in this repo, or referenced from the readme.

Call for help on making D.js compliant to latest spec

Hi,
I'm the author of D.js a tiny promise implementation that try to be compliant with the specs. After many attempts I'm still stuck with some (60) failing tests of the latest specs.

Here's a gist of the failing tests report: https://gist.github.com/malko/7798195

As suggested by Domenic i'm asking for help here, so if you can give me any hint i'll be glad to add your name to the contributors list.

To launch the test don't use the adapter but rather use the command:
promises-aplus-tests lib/D.js or if you install test suite as D.js dependencies: ./node_modules/promises-aplus-tests/lib/cli.js lib/D.js

Thanks to anyone that will at least have a look at it.

@domenic thank's for the great job with the specs and the test material, and also for your mail answer given earlier.

Package for use in a browser

Would it be possible to package these tests to be used in a browser? It would be great to be able to check that a library meets the spec if every browser?

Less self-writing tests, more generated tests?

A lot of the tests, especially for 2.3, are created programmatically via various permutations of the objects and possibilities involved. This has always been problematic, and recently @jcoglan has run into it and discussed on Twitter.

It might be nicer if we generated test cases that were readable by themselves, somehow. Or just wrote them all out manually, I dunno.

This is probably necessary for adaptation to test-262 as well; I can't imagine the test harness there is nearly as flexible as Mocha, from what I've seen.

Contradiction between tests

In test 3.2.6.2, in case of a rejection, exact value should be passed to the next rejection in chain, even if it is a thenable or a promise:
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/3.2.6.js#L63-100

However, on tests 3.2.6.3.2 and 3.2.6.3.3, test require that incase the onReject returns a thenable, promise should try to chain itself to that promise.
https://github.com/promises-aplus/promises-tests/blob/master/lib/tests/3.2.6.js#L157-272

Am I misunderstanding the tests?

This is the only thing blocking me from passing all tests

Can you assist me in satisfying promises aplus spec 2.2.4 in NodeJS?

I am writing an HTTP Promises package for nodeJS. I need it to be promises aplus compliant. I am using promises-aplus-tests - https://www.npmjs.com/package/promises-aplus-tests

I have created an adapter as follows ..

var adapter = {
    deferred: function() {
        var d = {}
        d.promise = new HTTPromise(new GETOptions('/path', DEFAULT_OPTIONS));
        d.resolve = executorResponseFunc;
        d.reject = executorRejectFunc;        
        return d;
    }
}

promisesAplusTests(adapter, function (err) {
    done(err);
});

My tests are failin on https://promisesaplus.com/#point-34 ... with further help on https://promisesaplus.com/#point-67

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code

3.1 Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

But I can't get it passing this promises aplus test. I am using the bog standard JavaScript Promises library (which on its own passes the tests) documented at ...

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise

new Promise(executor);

new Promise(function(resolve, reject) { ... });

In the executor I have tried ...

if (response.statusCode === 200) {
    process.nextTick(() => {
        resolve(finalResponse);   
    });
} else {
    process.nextTick(() => {
        reject(finalResponse);
    });
}

and also ...

process.nextTick(() => {
    if (response.statusCode === 200) {
        resolve(finalResponse);      
    } else {
         reject(finalResponse);
    }
});

There seems to be a lot of talk on the Internet but not many code examples of how to comply. Can anyone provide a code sample please on how to satisfy this test and how you would use nextTick or another suitable solution?

Worthing mentioning I have another call to reject within an HTTP error handler within the executor function;

Many thanks

Sequencing of promise resolution not being tested

I have run across a bug (thanks to @smikes) in my native-promise-only promise polyfill that is not caught by the current promises/a+ test suite (which NPO already passes).

I just checked the open issues here, and the issue I've found may indeed be the same as, or related to, that reported in #59. However, my test case is expressed a little differently, so documenting here separately just in case they are two different things needing to be tested.

In particular, I have a latent bug in the internal scheduler of NPO (which I've already diagnosed and understand) that affects how the sequencing of two different promise then(..) handlers are fired compared to what would be expected.

Here's the test case:

T1

var resolveP1, rejectP2;

(new Promise(function(resolve, reject) {
    resolveP1 = resolve;
}))
.then(function(msg){
    console.log(msg);
});

(new Promise(function(resolve, reject) {
    rejectP2 = reject;
}))
.catch(function(msg){
    console.log(msg);
});

rejectP2("A");
resolveP1("B");

According to my understanding of the spec, and according to v8, the print out should be "A B".

My unfixed library prints out "B A". When I correct my scheduler bug, I get "A B" as I would expect.

The problem, as stated above and in #59, is that NPO is already passing all 872 tests for its then(..) behavior, even with this sequencing bug, because the test suite is apparently not asserting anything about this expected sequencing (though it is clearly implied by the spec).

What concerns me is that it seems like maybe this is more than just one test that's missing, but potentially a whole class of tests that make assertions about then-sequencing semantics between independent promises.

OTOH, perhaps the promises/a+ spec isn't specific enough about such inter-promise semantics, and maybe that accounts for the shortfall of tests.

Ractive.Promise pass all tests, but behaves incorrectly.

Ractive.Promise promises implementation pass all tests, but fails to convert exceptions to rejections. Here is the test code:

var promisesAplusTests = require("promises-aplus-tests");
var Promise = require('ractive').Promise;
//var Promise = require('promise');
//var Promise = require('q').Promise;   // get stuck at tests
//var Promise = require('when').Promise;

var adapter = {
    resolved: Promise.resolve,
    rejected: Promise.reject,
    deferred: function() {
        var res, rej;
        var p = new Promise(function (resolve, reject) {
            res = resolve;
            rej = reject;
        });
        return {
            promise: p,
            resolve: res,
            reject: rej
        };
    }
};

var throw_test = function () {
    var p = new Promise(function (resolve, reject) {
        throw new Error('Bad happens');
    });
    return p;
};

if(0) promisesAplusTests(adapter, function (err) {
    if(err) console.log('Errors:', err);
});

if(1) throw_test().then(undefined, function (err) {
    console.log('Error in promise:', err);
});

Other three implementations (commented-out in code above) reject the promise, which I believe is correct.

So, should Ractive.Promise fail compliance test?

Add test case for very nested promises

When attempting to fix a memory leak caused by nested promises I inadvertently completely broke my library once more than a couple of promises were nested (see then/promise#67). I caught it with the following test:

    var promises = [];
    var resolveFns = [];
    for (var i = 0; i < 100; i++) {
      promises.push(new Promise(function (resolve) {
        resolveFns.push(resolve);
      }));
    }
    for (var i = 0; i < 99; i++) {
      resolveFns[i](promises[i + 1]);
    }
    resolveFns[99]('foo');
    return promises[0].then(function (result) {
      assert(result === 'foo');
    });

It took me a long time to realise that I might have an bug in that place so it would be great if we could add a test like this so that other people don't suffer the same problem.

2.2.6.2 wrong test?

I might be wrong, but shouldn't this test:

        describe("results in multiple branching chains with their own fulfillment values", function () {
            testRejected(sentinel, function (promise, done) {
                var semiDone = callbackAggregator(3, done);

                promise.then(null, function () {
                    return sentinel;
                }).then(function (value) {
                    assert.strictEqual(value, sentinel);
                    semiDone();
                });

                promise.then(null, function () {
                    throw sentinel2;
                }).then(null, function (reason) {
                    assert.strictEqual(reason, sentinel2);
                    semiDone();
                });

                promise.then(null, function () {
                    return sentinel3;
                }).then(function (value) {
                    assert.strictEqual(value, sentinel3);
                    semiDone();
                });
            });
        });

be

        describe("results in multiple branching chains with their own fulfillment values", function () {
            testRejected(sentinel, function (promise, done) {
                var semiDone = callbackAggregator(3, done);

                promise.then(null, function () {
                    return sentinel;
                }).then(null, function (value) {
                    assert.strictEqual(value, sentinel);
                    semiDone();
                });

                promise.then(null, function () {
                    throw sentinel2;
                }).then(null, function (reason) {
                    assert.strictEqual(reason, sentinel2);
                    semiDone();
                });

                promise.then(null, function () {
                    return sentinel3;
                }).then(null, function (value) {
                    assert.strictEqual(value, sentinel3);
                    semiDone();
                });
            });
        });

Test incorrect state transitions of promises

It seems like the first part of the Promises/A+ spec isn't tested:

A promise must be in one of three states: pending, fulfilled, or rejected.

When pending, a promise:
  may transition to either the fulfilled or rejected state.
When fulfilled, a promise:
  must not transition to any other state.
  must have a fulfillment value, which must not change.
When rejected, a promise:
  must not transition to any other state.
  must have a rejection reason, which must not change.

I wrote a promise implementation which passed all tests, but failed to protect against incorrect state transitions. It should be fairly simple to write these tests given the existing adapter interface, I think.

I'd be willing to write these tests, I just wanted to run this by you first before I spend the time on creating a pull request.

Align better with the spec

Maybe change the titles of tests, and perhaps align their ordering to the bullet points and include which bullet point is being tested.

Help wanted: Own tests or promises-tests tests?

I am writing a Promises A+ implementation (just for fun and in order to understand promises better), but I don't understand what is the purpose of writing my own tests VS using promises-aplus/promises-tests or even both. I see some implementations write their own tests, but isn't it enough to make promises-tests pass? I would like to know if I am missing something.

Cheers.

Rejecting with a promise is not fully tested

For learning promises, I made my own little implementation, see code below. I'm a Javascript newbie, so Douglas, don't be too hard on me please ;-)

For simplicity, it uses process.nextTick, so it only works in nodejs for now.

However, all 872 specs of your test suite pass, whether or not I 'adopt the state' of a 'thenable' passed as an argument to the reject method. See the single comment in the code.

What is the correct behavior?

Thanks a lot,
Peter Verswyvelen

var deferred = (function() {

    function Deferred() {
        this.promise = {
            then: this.then.bind(this),
        };
        this.thens = [];
    }

    function call_thens(state, value, thens) {
        thens.forEach(function (then) {
            var cfn = then[state],
                next_value = value,
                next_state = state;
            if (typeof cfn === "function") {
                try {
                    next_value = cfn(value);
                    next_state = "done";
                } catch (error) {
                    next_value = error;
                    next_state = "fail";
                }
            }

            then.next.transit(next_state, next_value);
        });
    }

    function then_transit(id, state, value) {
        if (this.state === id) {
            delete this.state;
            this.transit(state, value);
        }
    }

    var next_then_id = 0;

    Deferred.prototype = {
        asap: function () {
            process.nextTick(call_thens.bind(
                     this, this.state, this.value, this.thens));
            this.thens = [];
        },

        switchTo: function(state, value) {
            this.value = value;
            this.state = state;
            this.asap();
        },

        transit: function (state, value) {
            if (typeof this.state === "undefined") {
                // All tests succeeds with or without the state === "done" check?
                if (state === "done" && 
                     (typeof value === "function" || 
                         (typeof value === "object" && value !== null))) {
                    try {
                        if (value === this.promise)
                            throw new TypeError();

                        var then = value.then;
                        if (typeof then === "function") {
                            this.promise.then = then.bind(value);
                            var id = this.state = ++next_then_id;
                            try {
                                then.call(value,
                                    then_transit.bind(this, id, "done"),
                                    then_transit.bind(this, id, "fail"));
                            } catch (error) {
                                if (this.state === id)
                                    this.switchTo("fail", error);
                            } finally {
                                return;
                            }
                        }
                    } catch (error) {
                        value = error;
                        state = "fail";
                    }
                }

                this.switchTo(state, value);
            }
        },

        resolve: function (value) {
            this.transit("done", value);
        },

        reject: function (value) {
            this.transit("fail", value);
        },

        then: function (done, fail) {
            var then = {
                next: new Deferred(),
                done: done,
                fail: fail
            }

            this.thens.push(then);

            if (this.state)
                this.asap();

            return then.next.promise;
        }
    }

    return function () {
        return new Deferred();
    }
})();

var promisesAplusTests = require("promises-aplus-tests");

promisesAplusTests({
    deferred: deferred
}, {
    reporter: "spec"
});

Create a Bot

It would be really nice if this automatically got run against every known, compliant promises/A+ implementation every time it was updated so that:

a) authors wouldn't need to re-run tests even if they haven't changed anything
b) we'd know that authors weren't just telling people they were promises/A+ compliant without running this test suite.

mocha test runner failures

I am getting mocha crashes while trying to debug problems with my promises lib and running the test suite:

/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:32
    return Array(indents).join('  ')
           ^
RangeError: Invalid array length
    at indent (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:32:12)
    at Runner.<anonymous> (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:73:17)
    at Runner.emit (events.js:117:20)
    at Runner.fail (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:199:8)
    at Runner.uncaught (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:549:8)
    at process.uncaught (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:580:10)
    at process.emit (events.js:95:17)
    at process._fatalException (node.js:272:26)
npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0

Any ideas what's going on?

Here's another variation I get of the error:

/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:0
(function (exports, require, module, __filename, __dirname) {

RangeError: Invalid array length
    at indent (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:32:12)
    at Runner.<anonymous> (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/reporters/spec.js:73:17)
    at emitTwo (events.js:92:20)
    at Runner.emit (events.js:172:7)
    at Runner.fail (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:199:8)
    at Runner.uncaught (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:549:8)
    at process.uncaught (/tmp/node_modules/promises-aplus-tests/node_modules/mocha/lib/runner.js:580:10)
    at emitOne (events.js:77:13)
    at process.emit (events.js:169:7)
    at process._fatalException (node.js:211:26)
npm ERR! Test failed.  See above for more details.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.