1// Flags: --expose-internals --no-warnings
2'use strict';
3
4const common = require('../common');
5const { NodeEventTarget } = require('internal/event_target');
6
7const {
8  deepStrictEqual,
9  ok,
10  strictEqual,
11  throws,
12} = require('assert');
13
14const { on } = require('events');
15
16{
17  const eventTarget = new NodeEventTarget();
18  strictEqual(eventTarget.listenerCount('foo'), 0);
19  deepStrictEqual(eventTarget.eventNames(), []);
20
21  const ev1 = common.mustCall(function(event) {
22    strictEqual(event.type, 'foo');
23    strictEqual(this, eventTarget);
24  }, 2);
25
26  const ev2 = {
27    handleEvent: common.mustCall(function(event) {
28      strictEqual(event.type, 'foo');
29      strictEqual(this, ev2);
30    })
31  };
32
33  eventTarget.addEventListener('foo', ev1);
34  eventTarget.addEventListener('foo', ev2, { once: true });
35  strictEqual(eventTarget.listenerCount('foo'), 2);
36  ok(eventTarget.dispatchEvent(new Event('foo')));
37  strictEqual(eventTarget.listenerCount('foo'), 1);
38  eventTarget.dispatchEvent(new Event('foo'));
39
40  eventTarget.removeEventListener('foo', ev1);
41  strictEqual(eventTarget.listenerCount('foo'), 0);
42  eventTarget.dispatchEvent(new Event('foo'));
43}
44
45{
46  const eventTarget = new NodeEventTarget();
47  strictEqual(eventTarget.listenerCount('foo'), 0);
48  deepStrictEqual(eventTarget.eventNames(), []);
49
50  const ev1 = common.mustCall((event) => {
51    strictEqual(event.type, 'foo');
52  }, 2);
53
54  const ev2 = {
55    handleEvent: common.mustCall((event) => {
56      strictEqual(event.type, 'foo');
57    })
58  };
59
60  strictEqual(eventTarget.on('foo', ev1), eventTarget);
61  strictEqual(eventTarget.once('foo', ev2, { once: true }), eventTarget);
62  strictEqual(eventTarget.listenerCount('foo'), 2);
63  eventTarget.dispatchEvent(new Event('foo'));
64  strictEqual(eventTarget.listenerCount('foo'), 1);
65  eventTarget.dispatchEvent(new Event('foo'));
66
67  strictEqual(eventTarget.off('foo', ev1), eventTarget);
68  strictEqual(eventTarget.listenerCount('foo'), 0);
69  eventTarget.dispatchEvent(new Event('foo'));
70}
71
72{
73  const eventTarget = new NodeEventTarget();
74  strictEqual(eventTarget.listenerCount('foo'), 0);
75  deepStrictEqual(eventTarget.eventNames(), []);
76
77  const ev1 = common.mustCall((event) => {
78    strictEqual(event.type, 'foo');
79  }, 2);
80
81  const ev2 = {
82    handleEvent: common.mustCall((event) => {
83      strictEqual(event.type, 'foo');
84    })
85  };
86
87  eventTarget.addListener('foo', ev1);
88  eventTarget.once('foo', ev2, { once: true });
89  strictEqual(eventTarget.listenerCount('foo'), 2);
90  eventTarget.dispatchEvent(new Event('foo'));
91  strictEqual(eventTarget.listenerCount('foo'), 1);
92  eventTarget.dispatchEvent(new Event('foo'));
93
94  eventTarget.removeListener('foo', ev1);
95  strictEqual(eventTarget.listenerCount('foo'), 0);
96  eventTarget.dispatchEvent(new Event('foo'));
97}
98
99{
100  const eventTarget = new NodeEventTarget();
101  strictEqual(eventTarget.listenerCount('foo'), 0);
102  deepStrictEqual(eventTarget.eventNames(), []);
103
104  // Won't actually be called.
105  const ev1 = () => {};
106
107  // Won't actually be called.
108  const ev2 = { handleEvent() {} };
109
110  eventTarget.addListener('foo', ev1);
111  eventTarget.addEventListener('foo', ev1);
112  eventTarget.once('foo', ev2, { once: true });
113  eventTarget.once('foo', ev2, { once: false });
114  eventTarget.on('bar', ev1);
115  strictEqual(eventTarget.listenerCount('foo'), 2);
116  strictEqual(eventTarget.listenerCount('bar'), 1);
117  deepStrictEqual(eventTarget.eventNames(), ['foo', 'bar']);
118  strictEqual(eventTarget.removeAllListeners('foo'), eventTarget);
119  strictEqual(eventTarget.listenerCount('foo'), 0);
120  strictEqual(eventTarget.listenerCount('bar'), 1);
121  deepStrictEqual(eventTarget.eventNames(), ['bar']);
122  strictEqual(eventTarget.removeAllListeners(), eventTarget);
123  strictEqual(eventTarget.listenerCount('foo'), 0);
124  strictEqual(eventTarget.listenerCount('bar'), 0);
125  deepStrictEqual(eventTarget.eventNames(), []);
126}
127
128{
129  const target = new NodeEventTarget();
130
131  process.on('warning', common.mustCall((warning) => {
132    ok(warning instanceof Error);
133    strictEqual(warning.name, 'MaxListenersExceededWarning');
134    strictEqual(warning.target, target);
135    strictEqual(warning.count, 2);
136    strictEqual(warning.type, 'foo');
137    ok(warning.message.includes(
138      '2 foo listeners added to NodeEventTarget'));
139  }));
140
141  strictEqual(target.getMaxListeners(), NodeEventTarget.defaultMaxListeners);
142  target.setMaxListeners(1);
143  target.on('foo', () => {});
144  target.on('foo', () => {});
145}
146{
147  // Test NodeEventTarget emit
148  const emitter = new NodeEventTarget();
149  emitter.addEventListener('foo', common.mustCall((e) => {
150    strictEqual(e.type, 'foo');
151    strictEqual(e.detail, 'bar');
152    ok(e instanceof Event);
153  }), { once: true });
154  emitter.once('foo', common.mustCall((e, droppedAdditionalArgument) => {
155    strictEqual(e, 'bar');
156    strictEqual(droppedAdditionalArgument, undefined);
157  }));
158  emitter.emit('foo', 'bar', 'baz');
159}
160{
161  // Test NodeEventTarget emit unsupported usage
162  const emitter = new NodeEventTarget();
163  throws(() => {
164    emitter.emit();
165  }, /ERR_INVALID_ARG_TYPE/);
166}
167
168(async () => {
169  // test NodeEventTarget async-iterability
170  const emitter = new NodeEventTarget();
171  const interval = setInterval(() => {
172    emitter.dispatchEvent(new Event('foo'));
173  }, 0);
174  let count = 0;
175  for await (const [ item ] of on(emitter, 'foo')) {
176    count++;
177    strictEqual(item.type, 'foo');
178    if (count > 5) {
179      break;
180    }
181  }
182  clearInterval(interval);
183})().then(common.mustCall());
184