Bug 1259788 - Create haveEvents() and friends in head.js. r?jib
When we expect multiple events of the same type (in this case "addtrack" on
MediaStream) we can use this convenience function to attach a listener and
wait for the expected number of events before removing the listener and resolving.
This also adds a function to check that there were no extra events of the same
kind after the expected N events, and a function that checks that we don't see
a certain event within a given timeout period.
MozReview-Commit-ID: 1P8MkEI0Yzm
--- a/dom/media/tests/mochitest/head.js
+++ b/dom/media/tests/mochitest/head.js
@@ -588,34 +588,97 @@ function createOneShotEventWrapper(wrapp
e.wrapper = wrapper;
wrapper[onx](e);
wrapper[onx] = unexpected;
};
}
/**
* Returns a promise that resolves when `target` has raised an event with the
+ * given name the given number of times. Cancel the returned promise by passing
+ * in a `cancelPromise` and resolve it.
+ *
+ * @param {object} target
+ * The target on which the event should occur.
+ * @param {string} name
+ * The name of the event that should occur.
+ * @param {integer} count
+ * Optional number of times the event should be raised before resolving.
+ * @param {promise} cancelPromise
+ * Optional promise that on resolving rejects the returned promise,
+ * so we can avoid logging results after a test has finished.
+ * @returns {promise} A promise that resolves to the last of the seen events.
+ */
+function haveEvents(target, name, count, cancelPromise) {
+ var listener;
+ var counter = count || 1;
+ return Promise.race([
+ (cancelPromise || new Promise(() => {})).then(e => Promise.reject(e)),
+ new Promise(resolve =>
+ target.addEventListener(name, listener = e => (--counter < 1 && resolve(e))))
+ ])
+ .then(e => (target.removeEventListener(name, listener), e));
+};
+
+/**
+ * Returns a promise that resolves when `target` has raised an event with the
* given name. Cancel the returned promise by passing in a `cancelPromise` and
* resolve it.
*
* @param {object} target
* The target on which the event should occur.
* @param {string} name
* The name of the event that should occur.
* @param {promise} cancelPromise
- * A promise that on resolving rejects the returned promise,
+ * Optional promise that on resolving rejects the returned promise,
* so we can avoid logging results after a test has finished.
+ * @returns {promise} A promise that resolves to the seen event.
*/
function haveEvent(target, name, cancelPromise) {
- var listener;
- var p = Promise.race([
- (cancelPromise || new Promise()).then(e => Promise.reject(e)),
- new Promise(resolve => target.addEventListener(name, listener = resolve))
- ]);
- return p.then(event => (target.removeEventListener(name, listener), event));
+ return haveEvents(target, name, 1, cancelPromise);
+};
+
+/**
+ * Returns a promise that resolves if the target has not seen the given event
+ * after one crank (or until the given timeoutPromise resolves) of the event
+ * loop.
+ *
+ * @param {object} target
+ * The target on which the event should not occur.
+ * @param {string} name
+ * The name of the event that should not occur.
+ * @param {promise} timeoutPromise
+ * Optional promise defining how long we should wait before resolving.
+ * @returns {promise} A promise that is rejected if we see the given event, or
+ * resolves after a timeout otherwise.
+ */
+function haveNoEvent(target, name, timeoutPromise) {
+ return haveEvent(target, name, timeoutPromise || wait(0))
+ .then(() => Promise.reject(new Error("Too many " + name + " events")),
+ () => {});
+};
+
+/**
+ * Returns a promise that resolves after the target has seen the given number
+ * of events but no such event in a following crank of the event loop.
+ *
+ * @param {object} target
+ * The target on which the events should occur.
+ * @param {string} name
+ * The name of the event that should occur.
+ * @param {integer} count
+ * Optional number of times the event should be raised before resolving.
+ * @param {promise} cancelPromise
+ * Optional promise that on resolving rejects the returned promise,
+ * so we can avoid logging results after a test has finished.
+ * @returns {promise} A promise that resolves to the last of the seen events.
+ */
+function haveEventsButNoMore(target, name, count, cancelPromise) {
+ return haveEvents(target, name, count, cancelPromise)
+ .then(e => haveNoEvent(target, name).then(() => e));
};
/**
* This class executes a series of functions in a continuous sequence.
* Promise-bearing functions are executed after the previous promise completes.
*
* @constructor
* @param {object} framework
--- a/dom/media/tests/mochitest/test_peerConnection_addtrack_removetrack_events.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addtrack_removetrack_events.html
@@ -27,31 +27,27 @@ runNetworkTest(function (options) {
let videoSenderIndex =
test.pcLocal._pc.getSenders().findIndex(s => s.track.kind == "video");
isnot(videoSenderIndex, -1, "Should have video sender");
test.pcLocal.removeSender(videoSenderIndex);
test.pcLocal.attachLocalTrack(stream.getTracks()[0], localStream);
- let onNextLoop = wait(0);
eventsPromise = haveEvent(remoteStream, "addtrack", wait(50000, "No addtrack event"))
.then(trackEvent => {
ok(trackEvent instanceof MediaStreamTrackEvent,
"Expected event to be instance of MediaStreamTrackEvent");
is(trackEvent.type, "addtrack",
"Expected addtrack event type");
is(trackEvent.track.id, newTrack.id, "Expected track in event");
is(trackEvent.track.readyState, "live",
"added track should be live");
})
- .then(() => haveEvent(remoteStream, "addtrack", onNextLoop)
- .then(() => Promise.reject("Unexpected addtrack event for remote stream " + remoteStream.id),
- () => Promise.resolve())
- );
+ .then(() => haveNoEvent(remoteStream, "addtrack"));
remoteStream.addEventListener("removetrack",
function onRemovetrack(trackEvent) {
ok(false, "UA shouldn't raise 'removetrack' when receiving peer connection");
})
});
},
],
[