imapflow 1.7.8 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +8 -2
- package/dist/cjs/charsets.d.ts +1 -0
- package/dist/cjs/charsets.js +294 -0
- package/dist/cjs/commands/append.d.ts +22 -0
- package/dist/cjs/commands/append.js +151 -0
- package/dist/cjs/commands/authenticate.d.ts +24 -0
- package/dist/cjs/commands/authenticate.js +223 -0
- package/dist/cjs/commands/capability.d.ts +8 -0
- package/dist/cjs/commands/capability.js +32 -0
- package/dist/cjs/commands/close.d.ts +8 -0
- package/dist/cjs/commands/close.js +39 -0
- package/dist/cjs/commands/compress.d.ts +8 -0
- package/dist/cjs/commands/compress.js +56 -0
- package/dist/cjs/commands/copy.d.ts +13 -0
- package/dist/cjs/commands/copy.js +44 -0
- package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
- package/dist/cjs/commands/copyuid-parser.js +32 -0
- package/dist/cjs/commands/create.d.ts +11 -0
- package/dist/cjs/commands/create.js +80 -0
- package/dist/cjs/commands/delete.d.ts +11 -0
- package/dist/cjs/commands/delete.js +40 -0
- package/dist/cjs/commands/enable.d.ts +9 -0
- package/dist/cjs/commands/enable.js +61 -0
- package/dist/cjs/commands/esearch-parser.d.ts +17 -0
- package/dist/cjs/commands/esearch-parser.js +91 -0
- package/dist/cjs/commands/expunge.d.ts +12 -0
- package/dist/cjs/commands/expunge.js +60 -0
- package/dist/cjs/commands/fetch.d.ts +30 -0
- package/dist/cjs/commands/fetch.js +241 -0
- package/dist/cjs/commands/id.d.ts +10 -0
- package/dist/cjs/commands/id.js +80 -0
- package/dist/cjs/commands/idle.d.ts +9 -0
- package/dist/cjs/commands/idle.js +347 -0
- package/dist/cjs/commands/list.d.ts +16 -0
- package/dist/cjs/commands/list.js +520 -0
- package/dist/cjs/commands/login.d.ts +11 -0
- package/dist/cjs/commands/login.js +42 -0
- package/dist/cjs/commands/logout.d.ts +8 -0
- package/dist/cjs/commands/logout.js +47 -0
- package/dist/cjs/commands/move.d.ts +13 -0
- package/dist/cjs/commands/move.js +57 -0
- package/dist/cjs/commands/namespace.d.ts +25 -0
- package/dist/cjs/commands/namespace.js +139 -0
- package/dist/cjs/commands/noop.d.ts +8 -0
- package/dist/cjs/commands/noop.js +22 -0
- package/dist/cjs/commands/quota.d.ts +10 -0
- package/dist/cjs/commands/quota.js +119 -0
- package/dist/cjs/commands/rename.d.ts +12 -0
- package/dist/cjs/commands/rename.js +48 -0
- package/dist/cjs/commands/search.d.ts +15 -0
- package/dist/cjs/commands/search.js +228 -0
- package/dist/cjs/commands/select.d.ts +25 -0
- package/dist/cjs/commands/select.js +250 -0
- package/dist/cjs/commands/starttls.d.ts +8 -0
- package/dist/cjs/commands/starttls.js +30 -0
- package/dist/cjs/commands/status-fields.d.ts +14 -0
- package/dist/cjs/commands/status-fields.js +61 -0
- package/dist/cjs/commands/status.d.ts +12 -0
- package/dist/cjs/commands/status.js +108 -0
- package/dist/cjs/commands/store.d.ts +19 -0
- package/dist/cjs/commands/store.js +93 -0
- package/dist/cjs/commands/subscribe.d.ts +9 -0
- package/dist/cjs/commands/subscribe.js +31 -0
- package/dist/cjs/commands/unsubscribe.d.ts +9 -0
- package/dist/cjs/commands/unsubscribe.js +31 -0
- package/dist/cjs/connection-deadline.d.ts +49 -0
- package/dist/cjs/connection-deadline.js +91 -0
- package/dist/cjs/errors.d.ts +83 -0
- package/dist/cjs/errors.js +13 -0
- package/dist/cjs/handler/imap-compiler.d.ts +24 -0
- package/dist/cjs/handler/imap-compiler.js +285 -0
- package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/cjs/handler/imap-formal-syntax.js +121 -0
- package/dist/cjs/handler/imap-handler.d.ts +9 -0
- package/dist/cjs/handler/imap-handler.js +10 -0
- package/dist/cjs/handler/imap-parser.d.ts +16 -0
- package/dist/cjs/handler/imap-parser.js +90 -0
- package/dist/cjs/handler/imap-stream.d.ts +181 -0
- package/dist/cjs/handler/imap-stream.js +446 -0
- package/dist/cjs/handler/limits.d.ts +25 -0
- package/dist/cjs/handler/limits.js +51 -0
- package/dist/cjs/handler/parser-instance.d.ts +68 -0
- package/dist/cjs/handler/parser-instance.js +223 -0
- package/dist/cjs/handler/token-parser.d.ts +91 -0
- package/dist/cjs/handler/token-parser.js +673 -0
- package/dist/cjs/handler/types.d.ts +91 -0
- package/dist/cjs/handler/types.js +4 -0
- package/dist/cjs/imap-commands.d.ts +16 -0
- package/dist/cjs/imap-commands.js +74 -0
- package/dist/cjs/imap-flow.d.ts +676 -0
- package/dist/cjs/imap-flow.js +3956 -0
- package/dist/cjs/jp-decoder.d.ts +12 -0
- package/dist/cjs/jp-decoder.js +79 -0
- package/dist/cjs/limited-passthrough.d.ts +25 -0
- package/dist/cjs/limited-passthrough.js +54 -0
- package/dist/cjs/logger.d.ts +3 -0
- package/dist/cjs/logger.js +11 -0
- package/dist/cjs/package-info.d.ts +3 -0
- package/dist/cjs/package-info.js +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/proxy-connection.d.ts +33 -0
- package/dist/cjs/proxy-connection.js +392 -0
- package/dist/cjs/search-compiler.d.ts +34 -0
- package/dist/cjs/search-compiler.js +476 -0
- package/dist/cjs/special-use.d.ts +22 -0
- package/dist/cjs/special-use.js +911 -0
- package/dist/cjs/tools.d.ts +427 -0
- package/dist/cjs/tools.js +1496 -0
- package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +387 -517
- package/dist/cjs/types.js +5 -0
- package/dist/esm/charsets.d.ts +1 -0
- package/{lib → dist/esm}/charsets.js +1 -6
- package/dist/esm/commands/append.d.ts +22 -0
- package/{lib → dist/esm}/commands/append.js +22 -52
- package/dist/esm/commands/authenticate.d.ts +24 -0
- package/{lib → dist/esm}/commands/authenticate.js +62 -87
- package/dist/esm/commands/capability.d.ts +8 -0
- package/{lib → dist/esm}/commands/capability.js +6 -9
- package/dist/esm/commands/close.d.ts +8 -0
- package/{lib → dist/esm}/commands/close.js +6 -10
- package/dist/esm/commands/compress.d.ts +8 -0
- package/{lib → dist/esm}/commands/compress.js +7 -11
- package/dist/esm/commands/copy.d.ts +13 -0
- package/{lib → dist/esm}/commands/copy.js +12 -20
- package/dist/esm/commands/copyuid-parser.d.ts +11 -0
- package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
- package/dist/esm/commands/create.d.ts +11 -0
- package/{lib → dist/esm}/commands/create.js +13 -27
- package/dist/esm/commands/delete.d.ts +11 -0
- package/{lib → dist/esm}/commands/delete.js +9 -14
- package/dist/esm/commands/enable.d.ts +9 -0
- package/{lib → dist/esm}/commands/enable.js +23 -30
- package/dist/esm/commands/esearch-parser.d.ts +17 -0
- package/dist/esm/commands/esearch-parser.js +88 -0
- package/dist/esm/commands/expunge.d.ts +12 -0
- package/{lib → dist/esm}/commands/expunge.js +17 -22
- package/dist/esm/commands/fetch.d.ts +30 -0
- package/{lib → dist/esm}/commands/fetch.js +32 -64
- package/dist/esm/commands/id.d.ts +10 -0
- package/{lib → dist/esm}/commands/id.js +17 -23
- package/dist/esm/commands/idle.d.ts +9 -0
- package/{lib → dist/esm}/commands/idle.js +47 -81
- package/dist/esm/commands/list.d.ts +16 -0
- package/{lib → dist/esm}/commands/list.js +60 -123
- package/dist/esm/commands/login.d.ts +11 -0
- package/{lib → dist/esm}/commands/login.js +10 -15
- package/dist/esm/commands/logout.d.ts +8 -0
- package/{lib → dist/esm}/commands/logout.js +9 -11
- package/dist/esm/commands/move.d.ts +13 -0
- package/{lib → dist/esm}/commands/move.js +13 -21
- package/dist/esm/commands/namespace.d.ts +25 -0
- package/{lib → dist/esm}/commands/namespace.js +34 -44
- package/dist/esm/commands/noop.d.ts +8 -0
- package/{lib → dist/esm}/commands/noop.js +6 -7
- package/dist/esm/commands/quota.d.ts +10 -0
- package/{lib → dist/esm}/commands/quota.js +18 -36
- package/dist/esm/commands/rename.d.ts +12 -0
- package/{lib → dist/esm}/commands/rename.js +10 -15
- package/dist/esm/commands/search.d.ts +15 -0
- package/{lib → dist/esm}/commands/search.js +36 -135
- package/dist/esm/commands/select.d.ts +25 -0
- package/{lib → dist/esm}/commands/select.js +33 -64
- package/dist/esm/commands/starttls.d.ts +8 -0
- package/{lib → dist/esm}/commands/starttls.js +6 -8
- package/dist/esm/commands/status-fields.d.ts +14 -0
- package/{lib → dist/esm}/commands/status-fields.js +5 -16
- package/dist/esm/commands/status.d.ts +12 -0
- package/{lib → dist/esm}/commands/status.js +18 -29
- package/dist/esm/commands/store.d.ts +19 -0
- package/{lib → dist/esm}/commands/store.js +24 -37
- package/dist/esm/commands/subscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/subscribe.js +8 -12
- package/dist/esm/commands/unsubscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
- package/dist/esm/connection-deadline.d.ts +49 -0
- package/{lib → dist/esm}/connection-deadline.js +14 -25
- package/dist/esm/errors.d.ts +83 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/handler/imap-compiler.d.ts +24 -0
- package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
- package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/esm/handler/imap-formal-syntax.js +117 -0
- package/dist/esm/handler/imap-handler.d.ts +9 -0
- package/dist/esm/handler/imap-handler.js +9 -0
- package/dist/esm/handler/imap-parser.d.ts +16 -0
- package/{lib → dist/esm}/handler/imap-parser.js +31 -44
- package/dist/esm/handler/imap-stream.d.ts +181 -0
- package/{lib → dist/esm}/handler/imap-stream.js +29 -121
- package/dist/esm/handler/limits.d.ts +25 -0
- package/{lib → dist/esm}/handler/limits.js +13 -22
- package/dist/esm/handler/parser-instance.d.ts +68 -0
- package/{lib → dist/esm}/handler/parser-instance.js +19 -47
- package/dist/esm/handler/token-parser.d.ts +91 -0
- package/{lib → dist/esm}/handler/token-parser.js +71 -155
- package/dist/esm/handler/types.d.ts +91 -0
- package/dist/esm/handler/types.js +3 -0
- package/dist/esm/imap-commands.d.ts +16 -0
- package/dist/esm/imap-commands.js +67 -0
- package/dist/esm/imap-flow.d.ts +676 -0
- package/{lib → dist/esm}/imap-flow.js +769 -1790
- package/dist/esm/jp-decoder.d.ts +12 -0
- package/{lib → dist/esm}/jp-decoder.js +6 -21
- package/dist/esm/limited-passthrough.d.ts +25 -0
- package/{lib → dist/esm}/limited-passthrough.js +7 -20
- package/dist/esm/logger.d.ts +3 -0
- package/dist/esm/logger.js +4 -0
- package/dist/esm/package-info.d.ts +3 -0
- package/dist/esm/package-info.js +4 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/proxy-connection.d.ts +33 -0
- package/{lib → dist/esm}/proxy-connection.js +56 -127
- package/dist/esm/search-compiler.d.ts +34 -0
- package/{lib → dist/esm}/search-compiler.js +54 -110
- package/dist/esm/special-use.d.ts +22 -0
- package/dist/esm/special-use.js +907 -0
- package/dist/esm/tools.d.ts +427 -0
- package/dist/esm/tools.js +1446 -0
- package/dist/esm/types.d.ts +828 -0
- package/dist/esm/types.js +4 -0
- package/package.json +60 -20
- package/.gitattributes +0 -1
- package/.github/CODE_OF_CONDUCT.md +0 -76
- package/.github/FUNDING.yml +0 -4
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/.github/contributing.md +0 -17
- package/.github/workflows/release.yaml +0 -36
- package/.github/workflows/stale.yml +0 -29
- package/.github/workflows/test.yml +0 -51
- package/.ncurc.js +0 -4
- package/.prettierignore +0 -4
- package/.prettierrc.js +0 -8
- package/.release-please-manifest.json +0 -3
- package/CLAUDE.md +0 -104
- package/Gruntfile.js +0 -23
- package/eslint.config.js +0 -45
- package/lib/handler/imap-formal-syntax.js +0 -189
- package/lib/handler/imap-handler.js +0 -17
- package/lib/imap-commands.js +0 -45
- package/lib/logger.js +0 -5
- package/lib/special-use.js +0 -923
- package/lib/tools.js +0 -1612
- package/release-please-config.json +0 -10
- package/test/authentication-test.js +0 -101
- package/test/auto-idle-test.js +0 -470
- package/test/bodystructure-test.js +0 -899
- package/test/charsets-test.js +0 -161
- package/test/commands-branches-test.js +0 -1095
- package/test/commands-integration-test.js +0 -11124
- package/test/commands-test.js +0 -73
- package/test/connection-edge-cases-test.js +0 -1828
- package/test/connection-test.js +0 -162
- package/test/copyuid-parser-test.js +0 -173
- package/test/fetch-generator-test.js +0 -218
- package/test/fixtures/fake-timers.js +0 -115
- package/test/fixtures/serialized-mimetorture.js +0 -2738
- package/test/fixtures/test-client.js +0 -101
- package/test/fixtures/test-tls.js +0 -8
- package/test/handler-branches-test.js +0 -310
- package/test/idle-polling-test.js +0 -518
- package/test/imap-compiler-test.js +0 -809
- package/test/imap-flow-compress-test.js +0 -166
- package/test/imap-flow-coverage-test.js +0 -612
- package/test/imap-flow-fetch-download-test.js +0 -909
- package/test/imap-flow-internals-test.js +0 -725
- package/test/imap-flow-methods-test.js +0 -889
- package/test/imap-flow-proxy-paths-test.js +0 -366
- package/test/imap-flow-secure-test.js +0 -573
- package/test/imap-flow-server-test.js +0 -1474
- package/test/imap-formal-syntax-test.js +0 -293
- package/test/imap-parser-test.js +0 -1474
- package/test/imap-stream-edge-cases-test.js +0 -666
- package/test/imap-stream-test.js +0 -177
- package/test/imapflow-test.js +0 -258
- package/test/integration/README.md +0 -52
- package/test/integration/dovecot-test.conf +0 -27
- package/test/integration/rev2-live-test.js +0 -431
- package/test/integration/run-rev2-tests.sh +0 -75
- package/test/integration-test.js +0 -83
- package/test/jp-decoder-test.js +0 -304
- package/test/limited-passthrough-test.js +0 -299
- package/test/memory-cleanup-test.js +0 -144
- package/test/memory-leak-test.js +0 -667
- package/test/parser-limits-test.js +0 -292
- package/test/proxy-connection-test.js +0 -738
- package/test/reliability-improvements-test.js +0 -548
- package/test/search-compiler-test.js +0 -1300
- package/test/search-test.js +0 -329
- package/test/special-use-test.js +0 -418
- package/test/starttls-injection-test.js +0 -181
- package/test/tag-correlation-test.js +0 -333
- package/test/timer-policy-test.js +0 -227
- package/test/token-parser-test.js +0 -456
- package/test/tools-test.js +0 -2013
- package/test/unhandled-rejection-test.js +0 -661
package/test/connection-test.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { ImapFlow } = require('../lib/imap-flow');
|
|
4
|
-
|
|
5
|
-
module.exports['Connection: Basic connection options'] = test => {
|
|
6
|
-
let client = new ImapFlow({
|
|
7
|
-
host: 'imap.example.com',
|
|
8
|
-
port: 993,
|
|
9
|
-
auth: { user: 'test', pass: 'test' }
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test.equal(client.host, 'imap.example.com');
|
|
13
|
-
test.equal(client.port, 993);
|
|
14
|
-
test.done();
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
module.exports['Connection: Default options'] = test => {
|
|
18
|
-
let client = new ImapFlow({
|
|
19
|
-
host: 'imap.example.com',
|
|
20
|
-
auth: { user: 'test', pass: 'test' }
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test.equal(client.port, 143);
|
|
24
|
-
test.equal(client.secureConnection, false);
|
|
25
|
-
test.done();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
module.exports['Connection: Secure connection defaults'] = test => {
|
|
29
|
-
let client = new ImapFlow({
|
|
30
|
-
host: 'imap.example.com',
|
|
31
|
-
port: 993,
|
|
32
|
-
auth: { user: 'test', pass: 'test' }
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test.equal(client.secureConnection, true);
|
|
36
|
-
test.done();
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
module.exports['Connection: TLS options'] = test => {
|
|
40
|
-
let client = new ImapFlow({
|
|
41
|
-
host: 'imap.example.com',
|
|
42
|
-
auth: { user: 'test', pass: 'test' },
|
|
43
|
-
tls: {
|
|
44
|
-
rejectUnauthorized: false,
|
|
45
|
-
minVersion: 'TLSv1.3'
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test.equal(client.options.tls.rejectUnauthorized, false);
|
|
50
|
-
test.equal(client.options.tls.minVersion, 'TLSv1.3');
|
|
51
|
-
test.done();
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
module.exports['Connection: Authentication options'] = test => {
|
|
55
|
-
let client = new ImapFlow({
|
|
56
|
-
host: 'imap.example.com',
|
|
57
|
-
auth: {
|
|
58
|
-
user: 'testuser',
|
|
59
|
-
pass: 'testpass',
|
|
60
|
-
accessToken: 'token123'
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test.equal(client.options.auth.user, 'testuser');
|
|
65
|
-
test.equal(client.options.auth.pass, 'testpass');
|
|
66
|
-
test.equal(client.options.auth.accessToken, 'token123');
|
|
67
|
-
test.done();
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
module.exports['Connection: Proxy configuration'] = test => {
|
|
71
|
-
let client = new ImapFlow({
|
|
72
|
-
host: 'imap.example.com',
|
|
73
|
-
auth: { user: 'test', pass: 'test' },
|
|
74
|
-
proxy: 'socks5://proxy.example.com:1080'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test.equal(client.options.proxy, 'socks5://proxy.example.com:1080');
|
|
78
|
-
test.done();
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
module.exports['Connection: Client info'] = test => {
|
|
82
|
-
let clientInfo = {
|
|
83
|
-
name: 'Test Client',
|
|
84
|
-
version: '1.0.0',
|
|
85
|
-
vendor: 'Test Corp'
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
let client = new ImapFlow({
|
|
89
|
-
host: 'imap.example.com',
|
|
90
|
-
auth: { user: 'test', pass: 'test' },
|
|
91
|
-
clientInfo
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test.equal(client.clientInfo.name, 'Test Client');
|
|
95
|
-
test.equal(client.clientInfo.version, '1.0.0');
|
|
96
|
-
test.equal(client.clientInfo.vendor, 'Test Corp');
|
|
97
|
-
test.done();
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
module.exports['Connection: Logger configuration'] = test => {
|
|
101
|
-
let client = new ImapFlow({
|
|
102
|
-
host: 'imap.example.com',
|
|
103
|
-
auth: { user: 'test', pass: 'test' },
|
|
104
|
-
logger: false
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test.equal(client.options.logger, false);
|
|
108
|
-
test.done();
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
module.exports['Connection: Stats tracking'] = test => {
|
|
112
|
-
let client = new ImapFlow({
|
|
113
|
-
host: 'imap.example.com',
|
|
114
|
-
auth: { user: 'test', pass: 'test' }
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
let stats = client.stats();
|
|
118
|
-
test.ok(Object.prototype.hasOwnProperty.call(stats, 'sent'));
|
|
119
|
-
test.ok(Object.prototype.hasOwnProperty.call(stats, 'received'));
|
|
120
|
-
test.equal(typeof stats.sent, 'number');
|
|
121
|
-
test.equal(typeof stats.received, 'number');
|
|
122
|
-
test.done();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
module.exports['Connection: Random ID generation'] = test => {
|
|
126
|
-
let client = new ImapFlow({
|
|
127
|
-
host: 'imap.example.com',
|
|
128
|
-
auth: { user: 'test', pass: 'test' }
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
let id1 = client.getRandomId();
|
|
132
|
-
let id2 = client.getRandomId();
|
|
133
|
-
|
|
134
|
-
test.ok(typeof id1 === 'string' && id1.length > 0);
|
|
135
|
-
test.ok(typeof id2 === 'string' && id2.length > 0);
|
|
136
|
-
test.notEqual(id1, id2, 'IDs should be unique');
|
|
137
|
-
test.done();
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
module.exports['Connection: State management'] = test => {
|
|
141
|
-
let client = new ImapFlow({
|
|
142
|
-
host: 'imap.example.com',
|
|
143
|
-
auth: { user: 'test', pass: 'test' }
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test.equal(client.state, client.states.NOT_AUTHENTICATED);
|
|
147
|
-
test.equal(client.authenticated, false);
|
|
148
|
-
test.ok(client.capabilities instanceof Map);
|
|
149
|
-
test.done();
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
module.exports['Connection: Event emitter setup'] = test => {
|
|
153
|
-
let client = new ImapFlow({
|
|
154
|
-
host: 'imap.example.com',
|
|
155
|
-
auth: { user: 'test', pass: 'test' }
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test.equal(typeof client.on, 'function');
|
|
159
|
-
test.equal(typeof client.emit, 'function');
|
|
160
|
-
test.equal(typeof client.removeListener, 'function');
|
|
161
|
-
test.done();
|
|
162
|
-
};
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { parseCopyUid } = require('../lib/commands/copyuid-parser');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Builds a minimal IMAP response object with a COPYUID-style section.
|
|
7
|
-
*
|
|
8
|
-
* @param {Array} section - Array of section elements with value properties
|
|
9
|
-
* @returns {Object} Response object suitable for parseCopyUid
|
|
10
|
-
*/
|
|
11
|
-
function makeResponse(section) {
|
|
12
|
-
return { attributes: [{ section }] };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// ============================================
|
|
16
|
-
// Single UID pair
|
|
17
|
-
// ============================================
|
|
18
|
-
|
|
19
|
-
module.exports['CopyUID Parser: single UID pair sets uidValidity and uidMap entry'] = test => {
|
|
20
|
-
let map = {};
|
|
21
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '12345' }, { value: '1' }, { value: '100' }]), map);
|
|
22
|
-
|
|
23
|
-
test.equal(map.uidValidity, BigInt('12345'));
|
|
24
|
-
test.ok(map.uidMap instanceof Map);
|
|
25
|
-
test.equal(map.uidMap.get(1), 100);
|
|
26
|
-
test.equal(map.uidMap.size, 1);
|
|
27
|
-
test.done();
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// ============================================
|
|
31
|
-
// UID ranges
|
|
32
|
-
// ============================================
|
|
33
|
-
|
|
34
|
-
module.exports['CopyUID Parser: contiguous UID range maps all source UIDs to destinations'] = test => {
|
|
35
|
-
let map = {};
|
|
36
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '99' }, { value: '1:3' }, { value: '10:12' }]), map);
|
|
37
|
-
|
|
38
|
-
test.equal(map.uidValidity, BigInt('99'));
|
|
39
|
-
test.ok(map.uidMap instanceof Map);
|
|
40
|
-
test.equal(map.uidMap.size, 3);
|
|
41
|
-
test.equal(map.uidMap.get(1), 10);
|
|
42
|
-
test.equal(map.uidMap.get(2), 11);
|
|
43
|
-
test.equal(map.uidMap.get(3), 12);
|
|
44
|
-
test.done();
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// ============================================
|
|
48
|
-
// Comma-separated UIDs
|
|
49
|
-
// ============================================
|
|
50
|
-
|
|
51
|
-
module.exports['CopyUID Parser: comma-separated UIDs map each source to its destination'] = test => {
|
|
52
|
-
let map = {};
|
|
53
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '200' }, { value: '1,5,9' }, { value: '100,105,109' }]), map);
|
|
54
|
-
|
|
55
|
-
test.equal(map.uidMap.size, 3);
|
|
56
|
-
test.equal(map.uidMap.get(1), 100);
|
|
57
|
-
test.equal(map.uidMap.get(5), 105);
|
|
58
|
-
test.equal(map.uidMap.get(9), 109);
|
|
59
|
-
test.done();
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// ============================================
|
|
63
|
-
// Non-COPYUID response code
|
|
64
|
-
// ============================================
|
|
65
|
-
|
|
66
|
-
module.exports['CopyUID Parser: non-COPYUID response code leaves map unchanged'] = test => {
|
|
67
|
-
let map = {};
|
|
68
|
-
parseCopyUid(makeResponse([{ value: 'APPENDUID' }, { value: '12345' }, { value: '1' }, { value: '100' }]), map);
|
|
69
|
-
|
|
70
|
-
test.equal(map.uidValidity, undefined);
|
|
71
|
-
test.equal(map.uidMap, undefined);
|
|
72
|
-
test.done();
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// ============================================
|
|
76
|
-
// Missing / malformed input
|
|
77
|
-
// ============================================
|
|
78
|
-
|
|
79
|
-
module.exports['CopyUID Parser: missing attributes leaves map unchanged'] = test => {
|
|
80
|
-
let map = {};
|
|
81
|
-
parseCopyUid({}, map);
|
|
82
|
-
|
|
83
|
-
test.equal(map.uidValidity, undefined);
|
|
84
|
-
test.equal(map.uidMap, undefined);
|
|
85
|
-
test.done();
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
module.exports['CopyUID Parser: empty attributes array leaves map unchanged'] = test => {
|
|
89
|
-
let map = {};
|
|
90
|
-
parseCopyUid({ attributes: [] }, map);
|
|
91
|
-
|
|
92
|
-
test.equal(map.uidValidity, undefined);
|
|
93
|
-
test.equal(map.uidMap, undefined);
|
|
94
|
-
test.done();
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
module.exports['CopyUID Parser: null section leaves map unchanged'] = test => {
|
|
98
|
-
let map = {};
|
|
99
|
-
parseCopyUid({ attributes: [{ section: null }] }, map);
|
|
100
|
-
|
|
101
|
-
test.equal(map.uidValidity, undefined);
|
|
102
|
-
test.equal(map.uidMap, undefined);
|
|
103
|
-
test.done();
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// ============================================
|
|
107
|
-
// Non-numeric uidValidity
|
|
108
|
-
// ============================================
|
|
109
|
-
|
|
110
|
-
module.exports['CopyUID Parser: non-numeric uidValidity skips uidValidity but still builds uidMap'] = test => {
|
|
111
|
-
let map = {};
|
|
112
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: 'abc' }, { value: '1' }, { value: '100' }]), map);
|
|
113
|
-
|
|
114
|
-
test.equal(map.uidValidity, undefined);
|
|
115
|
-
test.ok(map.uidMap instanceof Map);
|
|
116
|
-
test.equal(map.uidMap.get(1), 100);
|
|
117
|
-
test.done();
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// ============================================
|
|
121
|
-
// Mismatched source/destination lengths
|
|
122
|
-
// ============================================
|
|
123
|
-
|
|
124
|
-
module.exports['CopyUID Parser: mismatched source and destination lengths sets uidValidity but skips uidMap'] = test => {
|
|
125
|
-
let map = {};
|
|
126
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '12345' }, { value: '1:3' }, { value: '10' }]), map);
|
|
127
|
-
|
|
128
|
-
test.equal(map.uidValidity, BigInt('12345'));
|
|
129
|
-
test.equal(map.uidMap, undefined);
|
|
130
|
-
test.done();
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// ============================================
|
|
134
|
-
// Large uidValidity
|
|
135
|
-
// ============================================
|
|
136
|
-
|
|
137
|
-
module.exports['CopyUID Parser: large uidValidity is stored as BigInt'] = test => {
|
|
138
|
-
let map = {};
|
|
139
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '999999999999' }, { value: '1' }, { value: '100' }]), map);
|
|
140
|
-
|
|
141
|
-
test.equal(map.uidValidity, BigInt('999999999999'));
|
|
142
|
-
test.done();
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
module.exports['CopyUID Parser: uidValidity zero is stored as BigInt(0)'] = test => {
|
|
146
|
-
let map = {};
|
|
147
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '0' }, { value: '1' }, { value: '100' }]), map);
|
|
148
|
-
|
|
149
|
-
test.strictEqual(map.uidValidity, BigInt(0));
|
|
150
|
-
test.ok(map.uidMap instanceof Map);
|
|
151
|
-
test.equal(map.uidMap.get(1), 100);
|
|
152
|
-
test.done();
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
// ============================================
|
|
156
|
-
// Hostile server input
|
|
157
|
-
// ============================================
|
|
158
|
-
|
|
159
|
-
module.exports['CopyUID Parser: non-decimal uidValidity is ignored, uidMap still parsed'] = test => {
|
|
160
|
-
// isNaN() passed values like "1e5" and "Infinity" through, and BigInt() then threw,
|
|
161
|
-
// losing the whole COPYUID result
|
|
162
|
-
let map = {};
|
|
163
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: '1e5' }, { value: '1' }, { value: '100' }]), map);
|
|
164
|
-
test.equal(map.uidValidity, undefined);
|
|
165
|
-
test.ok(map.uidMap instanceof Map);
|
|
166
|
-
test.equal(map.uidMap.get(1), 100);
|
|
167
|
-
|
|
168
|
-
let map2 = {};
|
|
169
|
-
parseCopyUid(makeResponse([{ value: 'COPYUID' }, { value: 'Infinity' }, { value: '1' }, { value: '100' }]), map2);
|
|
170
|
-
test.equal(map2.uidValidity, undefined);
|
|
171
|
-
test.equal(map2.uidMap.get(1), 100);
|
|
172
|
-
test.done();
|
|
173
|
-
};
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { ImapFlow } = require('../lib/imap-flow');
|
|
4
|
-
|
|
5
|
-
// Helper: create a minimal mock context with the fetch() generator bound to it.
|
|
6
|
-
// The `run` override controls how untagged FETCH responses are delivered.
|
|
7
|
-
const createFetchContext = runOverride => ({
|
|
8
|
-
id: 'test-cid',
|
|
9
|
-
mailbox: { path: 'INBOX', exists: 10 },
|
|
10
|
-
isClosed: false,
|
|
11
|
-
socket: { destroyed: false },
|
|
12
|
-
resolveRange: async range => range,
|
|
13
|
-
createConnectionError: ImapFlow.prototype.createConnectionError,
|
|
14
|
-
run: runOverride
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
// Helper: invoke the fetch generator on a mock context
|
|
18
|
-
function callFetch(ctx, range, query, options) {
|
|
19
|
-
return ImapFlow.prototype.fetch.call(ctx, range, query, options);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Helper: create a mock `run` that delivers `count` untagged FETCH responses,
|
|
23
|
-
// each with a `next` callback for backpressure. Returns a tracking object.
|
|
24
|
-
function createMockRun(count) {
|
|
25
|
-
const tracker = {
|
|
26
|
-
nextCalls: [], // records which message indices had next() called
|
|
27
|
-
onUntaggedFetch: null,
|
|
28
|
-
runResolved: false
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const run = async (_cmd, _range, _query, opts) => {
|
|
32
|
-
tracker.onUntaggedFetch = opts.onUntaggedFetch;
|
|
33
|
-
|
|
34
|
-
for (let i = 0; i < count; i++) {
|
|
35
|
-
await new Promise(resolve => {
|
|
36
|
-
opts.onUntaggedFetch({ seq: i + 1, uid: 100 + i }, () => {
|
|
37
|
-
tracker.nextCalls.push(i);
|
|
38
|
-
resolve();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
tracker.runResolved = true;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return { tracker, run };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
|
-
// Test: early break releases backpressure
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
module.exports['fetch generator: early break releases backpressure'] = async test => {
|
|
52
|
-
const { tracker, run } = createMockRun(5);
|
|
53
|
-
const ctx = createFetchContext(run);
|
|
54
|
-
|
|
55
|
-
const gen = callFetch(ctx, '1:5', { uid: true });
|
|
56
|
-
// Consume only the first message and break
|
|
57
|
-
for await (let msg of gen) {
|
|
58
|
-
test.ok(msg.seq === 1, 'should receive the first message');
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Allow microtasks to flush (the finally block runs synchronously with
|
|
63
|
-
// generator return, but the remaining run() deliveries are async)
|
|
64
|
-
await new Promise(r => setTimeout(r, 50));
|
|
65
|
-
|
|
66
|
-
// The first message had next() called by the yield loop (res.next()).
|
|
67
|
-
// Remaining queued/future messages should have next() called by the
|
|
68
|
-
// finally block or the aborted guard.
|
|
69
|
-
test.equal(tracker.nextCalls.length, 5, 'all 5 messages should have next() called');
|
|
70
|
-
test.done();
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
// Test: subsequent operations work after early exit
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
module.exports['fetch generator: connection usable after early break'] = async test => {
|
|
77
|
-
let runCallCount = 0;
|
|
78
|
-
|
|
79
|
-
const run = async (_cmd, _range, _query, opts) => {
|
|
80
|
-
runCallCount++;
|
|
81
|
-
// Deliver 3 messages
|
|
82
|
-
for (let i = 0; i < 3; i++) {
|
|
83
|
-
await new Promise(resolve => {
|
|
84
|
-
opts.onUntaggedFetch({ seq: i + 1, uid: 200 + i }, () => resolve());
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const ctx = createFetchContext(run);
|
|
90
|
-
|
|
91
|
-
// First fetch: break early
|
|
92
|
-
const gen1 = callFetch(ctx, '1:3', { uid: true });
|
|
93
|
-
for await (let msg of gen1) {
|
|
94
|
-
test.ok(msg.seq === 1);
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await new Promise(r => setTimeout(r, 50));
|
|
99
|
-
|
|
100
|
-
// Second fetch: should work (run gets called again)
|
|
101
|
-
const gen2 = callFetch(ctx, '1:3', { uid: true });
|
|
102
|
-
let secondFetchMessages = [];
|
|
103
|
-
for await (let msg of gen2) {
|
|
104
|
-
secondFetchMessages.push(msg);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
test.ok(runCallCount === 2, 'run was called for both fetch operations');
|
|
108
|
-
test.ok(secondFetchMessages.length === 3, 'second fetch received all 3 messages');
|
|
109
|
-
test.done();
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// ---------------------------------------------------------------------------
|
|
113
|
-
// Test: normal full iteration works correctly
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
module.exports['fetch generator: normal full iteration receives all messages'] = async test => {
|
|
116
|
-
const { tracker, run } = createMockRun(4);
|
|
117
|
-
const ctx = createFetchContext(run);
|
|
118
|
-
|
|
119
|
-
let messages = [];
|
|
120
|
-
for await (let msg of callFetch(ctx, '1:4', { uid: true })) {
|
|
121
|
-
messages.push(msg);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
test.equal(messages.length, 4, 'should receive all 4 messages');
|
|
125
|
-
test.equal(messages[0].seq, 1);
|
|
126
|
-
test.equal(messages[3].seq, 4);
|
|
127
|
-
test.equal(tracker.nextCalls.length, 4, 'all next() callbacks were called');
|
|
128
|
-
test.done();
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// Test: error thrown in loop body releases backpressure
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
module.exports['fetch generator: error in loop body releases backpressure'] = async test => {
|
|
135
|
-
const { tracker, run } = createMockRun(5);
|
|
136
|
-
const ctx = createFetchContext(run);
|
|
137
|
-
|
|
138
|
-
const gen = callFetch(ctx, '1:5', { uid: true });
|
|
139
|
-
|
|
140
|
-
let caught = false;
|
|
141
|
-
try {
|
|
142
|
-
for await (let msg of gen) {
|
|
143
|
-
if (msg.seq === 2) {
|
|
144
|
-
throw new Error('intentional test error');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} catch (err) {
|
|
148
|
-
caught = true;
|
|
149
|
-
test.equal(err.message, 'intentional test error');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
await new Promise(r => setTimeout(r, 50));
|
|
153
|
-
|
|
154
|
-
test.ok(caught, 'error was caught');
|
|
155
|
-
// Messages 0 and 1 had next() called by the yield loop. The rest should
|
|
156
|
-
// be drained by the finally block or the aborted guard.
|
|
157
|
-
test.equal(tracker.nextCalls.length, 5, 'all 5 messages should have next() called');
|
|
158
|
-
test.done();
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// ---------------------------------------------------------------------------
|
|
162
|
-
// Test: zero messages from server
|
|
163
|
-
// ---------------------------------------------------------------------------
|
|
164
|
-
module.exports['fetch generator: zero messages yields nothing'] = async test => {
|
|
165
|
-
const { tracker, run } = createMockRun(0);
|
|
166
|
-
const ctx = createFetchContext(run);
|
|
167
|
-
|
|
168
|
-
let messages = [];
|
|
169
|
-
for await (let msg of callFetch(ctx, '1:*', { uid: true })) {
|
|
170
|
-
messages.push(msg);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
test.equal(messages.length, 0, 'no messages should be yielded');
|
|
174
|
-
test.equal(tracker.nextCalls.length, 0, 'no next() calls needed');
|
|
175
|
-
test.ok(tracker.runResolved, 'run should have resolved');
|
|
176
|
-
test.done();
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
// Test: connection closed during iteration throws and releases backpressure
|
|
181
|
-
// ---------------------------------------------------------------------------
|
|
182
|
-
module.exports['fetch generator: connection closed mid-iteration throws and cleans up'] = async test => {
|
|
183
|
-
const tracker = {
|
|
184
|
-
nextCalls: []
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const run = async (_cmd, _range, _query, opts) => {
|
|
188
|
-
for (let i = 0; i < 3; i++) {
|
|
189
|
-
await new Promise(resolve => {
|
|
190
|
-
opts.onUntaggedFetch({ seq: i + 1, uid: 300 + i }, () => {
|
|
191
|
-
tracker.nextCalls.push(i);
|
|
192
|
-
resolve();
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const ctx = createFetchContext(run);
|
|
199
|
-
|
|
200
|
-
let caught = false;
|
|
201
|
-
try {
|
|
202
|
-
for await (let msg of callFetch(ctx, '1:3', { uid: true })) {
|
|
203
|
-
if (msg.seq === 1) {
|
|
204
|
-
// Simulate connection closing after first message
|
|
205
|
-
ctx.isClosed = true;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
} catch (err) {
|
|
209
|
-
caught = true;
|
|
210
|
-
test.equal(err.code, 'EConnectionClosed', 'should throw EConnectionClosed');
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
await new Promise(r => setTimeout(r, 50));
|
|
214
|
-
|
|
215
|
-
test.ok(caught, 'error was caught');
|
|
216
|
-
test.equal(tracker.nextCalls.length, 3, 'all next() callbacks should be called for cleanup');
|
|
217
|
-
test.done();
|
|
218
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Deterministic stand-in for global.setTimeout/clearTimeout, so tests can drive timer-based
|
|
4
|
-
// loops (auto-IDLE, IDLE restart, fallback polling) without wall-clock sleeps.
|
|
5
|
-
//
|
|
6
|
-
// It is the suite's existing "swap global.setTimeout for the duration of a test and restore it
|
|
7
|
-
// in finally" idiom, made reusable and able to handle recursively scheduled timers: firing a
|
|
8
|
-
// timer whose callback schedules the next one records the new timer instead of losing it.
|
|
9
|
-
//
|
|
10
|
-
// Only timers scheduled while installed are faked. Everything else (setImmediate, socket
|
|
11
|
-
// timeouts, nodeunit's own bookkeeping) is untouched, and clearTimeout still forwards real
|
|
12
|
-
// handles to the real implementation. Install for as short a window as possible and always
|
|
13
|
-
// restore in a finally block.
|
|
14
|
-
const installFakeTimers = () => {
|
|
15
|
-
const realSetTimeout = global.setTimeout;
|
|
16
|
-
const realClearTimeout = global.clearTimeout;
|
|
17
|
-
|
|
18
|
-
let seq = 0;
|
|
19
|
-
const timers = new Map();
|
|
20
|
-
// Every timer ever scheduled, including cleared and fired ones, so tests can assert timer
|
|
21
|
-
// identity and cleanup (which timer was armed, was it unref'd, was it cleared) without sleeps.
|
|
22
|
-
const history = [];
|
|
23
|
-
|
|
24
|
-
global.setTimeout = (fn, delay, ...args) => {
|
|
25
|
-
const id = ++seq;
|
|
26
|
-
const timer = { id, fn, delay, args, unrefd: false, cleared: false, fired: false };
|
|
27
|
-
timers.set(id, timer);
|
|
28
|
-
history.push(timer);
|
|
29
|
-
return {
|
|
30
|
-
_fakeTimerId: id,
|
|
31
|
-
unref() {
|
|
32
|
-
const timer = timers.get(id);
|
|
33
|
-
if (timer) {
|
|
34
|
-
timer.unrefd = true;
|
|
35
|
-
}
|
|
36
|
-
return this;
|
|
37
|
-
},
|
|
38
|
-
ref() {
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
global.clearTimeout = handle => {
|
|
45
|
-
if (handle && handle._fakeTimerId) {
|
|
46
|
-
const timer = timers.get(handle._fakeTimerId);
|
|
47
|
-
if (timer) {
|
|
48
|
-
timer.cleared = true;
|
|
49
|
-
timers.delete(timer.id);
|
|
50
|
-
}
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
return realClearTimeout(handle);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// Lets pending asynchronous work (a poll's promise chain) settle between timer firings.
|
|
57
|
-
const drain = async (turns = 3) => {
|
|
58
|
-
for (let i = 0; i < turns; i++) {
|
|
59
|
-
await new Promise(resolve => setImmediate(resolve));
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
// Scheduled timers that have not fired or been cleared yet, in scheduling order
|
|
65
|
-
pending: () => Array.from(timers.values()).map(timer => ({ id: timer.id, delay: timer.delay, unrefd: timer.unrefd })),
|
|
66
|
-
count: () => timers.size,
|
|
67
|
-
|
|
68
|
-
// Every timer scheduled while installed, in scheduling order, with its final state
|
|
69
|
-
history: () => history.map(timer => ({ id: timer.id, delay: timer.delay, unrefd: timer.unrefd, cleared: timer.cleared, fired: timer.fired })),
|
|
70
|
-
|
|
71
|
-
// Fires every currently pending timer once, oldest first, letting async callbacks settle.
|
|
72
|
-
// Timers scheduled by those callbacks stay pending for the next fire() call, which is what
|
|
73
|
-
// makes a recursive loop (poll -> schedule -> poll) observable one step at a time.
|
|
74
|
-
fire: async () => {
|
|
75
|
-
const due = Array.from(timers.values());
|
|
76
|
-
for (const timer of due) {
|
|
77
|
-
if (!timers.has(timer.id)) {
|
|
78
|
-
// cleared by an earlier callback in this batch
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
timers.delete(timer.id);
|
|
82
|
-
timer.fired = true;
|
|
83
|
-
timer.fn(...timer.args);
|
|
84
|
-
await drain();
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
drain,
|
|
89
|
-
|
|
90
|
-
restore: () => {
|
|
91
|
-
global.setTimeout = realSetTimeout;
|
|
92
|
-
global.clearTimeout = realClearTimeout;
|
|
93
|
-
timers.clear();
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Runs `fn` with faked timers installed, restoring the real ones afterwards. Always use this
|
|
100
|
-
* rather than installing by hand: leaking faked globals into the rest of the run breaks
|
|
101
|
-
* unrelated tests.
|
|
102
|
-
*
|
|
103
|
-
* @param {Function} fn - Receives the timer controller.
|
|
104
|
-
* @returns {Promise<*>} Whatever `fn` returns.
|
|
105
|
-
*/
|
|
106
|
-
const withFakeTimers = async fn => {
|
|
107
|
-
const timers = installFakeTimers();
|
|
108
|
-
try {
|
|
109
|
-
return await fn(timers);
|
|
110
|
-
} finally {
|
|
111
|
-
timers.restore();
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
module.exports = { installFakeTimers, withFakeTimers };
|