-
Notifications
You must be signed in to change notification settings - Fork 1
/
chai-events.js
112 lines (91 loc) · 3.45 KB
/
chai-events.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
function plugin(chai, utils) {
var Assertion = chai.Assertion;
/**
* Checks if a given entry is an event emitter.
* Uses EventEmitter or EventTarget if available to quickly check `instanceof`. Otherwise, checks that common methods
* to event emitters are available.
*
* Gracefully handles custom implementations of event emitters even if EventEmitter or EventTarget are available,
* checking methods if the emitter doesn't inherit from the global emitter.
*/
function isEmitter() {
// Easy check: if Node's EventEmitter or window.EventEmitter exist, check if this is an instance of it.
if(typeof EventEmitter !== "undefined" && EventEmitter !== null && this._obj instanceof EventEmitter) {
return this.assert(true, "", "expected #{this} to not be an EventEmitter");
}
// Easy check: if the browser's EventTarget exists, check if this is an instance of it.
if(typeof EventTarget !== "undefined" && EventTarget !== null && this._obj instanceof EventTarget) {
return this.assert(true, "", "expected #{this} to not be an EventTarget");
}
var obj = this._obj;
// Check for Node.js style event emitters with "on", "emit", etc.
var node = ["on", "emit"].every(function(method) {
return typeof obj[method] === "function";
});
if(node) {
return this.assert(true, "", "expected #{this} to not be an EventEmitter");
}
// Check for Browser-based event emitters with "addEventListener", etc.
var browser = ["addEventListener", "dispatchEvent", "removeEventListener"].every(function(method) {
return typeof obj[method] === "function";
});
if(browser) {
return this.assert(true, "", "expected #{this} to not be an EventEmitter");
}
this.assert(false, "expected #{this} to be an EventEmitter", "");
};
Assertion.addProperty("emitter", isEmitter);
Assertion.addProperty("target", isEmitter);
Assertion.addMethod("emit", function(name, args) {
const timeout = typeof args === "object" && typeof args.timeout === "number" ? args.timeout : 1500;
const obj = utils.flag(this, "object");
new Assertion(this._obj).to.be.an.emitter;
new Assertion(name).to.satisfy(function(_name) {
return typeof _name === 'string' || typeof _name === 'symbol';
});
const assertEmission = expr => this.assert(
expr,
`expected #{this} to emit message with key '${name.toString()}'`,
`expected #{this} to not emit message with key '${name.toString()}'`
);
return new Promise((resolve, reject) => {
let done = false;
obj.once(name, (...args) => {
if(done) {
return;
}
done = true;
try {
assertEmission(true); // Will throw error if action is unexpected.
resolve(args);
} catch (err) {
reject(err);
}
});
setTimeout(() => {
if(done) {
return;
}
done = true;
try {
assertEmission(false); // Will throw error if action is unexpected.
resolve();
} catch (err) {
reject(err);
}
}, timeout);
});
});
}
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
module.exports = plugin;
}
else if (typeof define === "function" && define.amd) {
define(function () {
return plugin;
});
}
else {
// Other environment (usually <script> tag): plug in to global chai instance directly.
chai.use(plugin);
}