diff --git a/package-lock.json b/package-lock.json index 08640a3ea..7a4b66b09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "husky": "^9.1.7", "jest": "^30.2.0", "jest-extended": "^7.0.0", - "jsdom": "^27.2.0", + "jsdom": "^27.3.0", "lerna": "^9.0.3", "lint-staged": "^16.2.7", "prettier": "^3.7.4", @@ -45,9 +45,9 @@ } }, "node_modules/@acemir/cssom": { - "version": "0.9.26", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.26.tgz", - "integrity": "sha512-UMFbL3EnWH/eTvl21dz9s7Td4wYDMtxz/56zD8sL9IZGYyi48RxmdgPMiyT7R6Vn3rjMTwYZ42bqKa7ex74GEQ==", + "version": "0.9.28", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.28.tgz", + "integrity": "sha512-LuS6IVEivI75vKN8S04qRD+YySP0RmU/cV8UNukhQZvprxF+76Z43TNo/a08eCodaGhT1Us8etqS1ZRY9/Or0A==", "dev": true, "license": "MIT" }, @@ -137,6 +137,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1989,6 +1990,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -1997,9 +1999,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.20.tgz", - "integrity": "sha512-8BHsjXfSciZxjmHQOuVdW2b8WLUPts9a+mfL13/PzEviufUEW2xnvQuOlKs9dRBHgRqJ53SF/DUoK9+MZk72oQ==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", + "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", "dev": true, "funding": [ { @@ -2014,6 +2016,9 @@ "license": "MIT-0", "engines": { "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, "node_modules/@csstools/css-tokenizer": { @@ -2032,6 +2037,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -4536,6 +4542,7 @@ "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -5490,6 +5497,7 @@ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -6313,6 +6321,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7032,6 +7041,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -8125,14 +8135,14 @@ } }, "node_modules/cssstyle": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.3.tgz", - "integrity": "sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.4.tgz", + "integrity": "sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^4.0.3", - "@csstools/css-syntax-patches-for-csstree": "^1.0.14", + "@asamuzakjp/css-color": "^4.1.0", + "@csstools/css-syntax-patches-for-csstree": "1.0.14", "css-tree": "^3.1.0" }, "engines": { @@ -8838,6 +8848,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -11743,6 +11754,7 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -12377,15 +12389,15 @@ } }, "node_modules/jsdom": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.2.0.tgz", - "integrity": "sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", + "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", "dev": true, "license": "MIT", "dependencies": { - "@acemir/cssom": "^0.9.23", - "@asamuzakjp/dom-selector": "^6.7.4", - "cssstyle": "^5.3.3", + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "cssstyle": "^5.3.4", "data-urls": "^6.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^4.0.0", @@ -13870,6 +13882,25 @@ "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" } }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -14424,6 +14455,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", "@yarnpkg/lockfile": "^1.1.0", @@ -15581,6 +15613,36 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/postcss-selector-parser": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", @@ -16457,6 +16519,7 @@ "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -18127,6 +18190,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 687943eec..2b0eea771 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "husky": "^9.1.7", "jest": "^30.2.0", "jest-extended": "^7.0.0", - "jsdom": "^27.2.0", + "jsdom": "^27.3.0", "lerna": "^9.0.3", "lint-staged": "^16.2.7", "prettier": "^3.7.4", diff --git a/packages/connection/index.js b/packages/connection/index.js index ebb5654d3..268ef666a 100644 --- a/packages/connection/index.js +++ b/packages/connection/index.js @@ -46,6 +46,10 @@ class Connection extends EventEmitter { } _onData(data) { + // In some case it is possible for the socket to still have buffered data (therefor emit data events) + // even after _detachParser has been called. + // This is intentional so we just drop the data in that case; for example stream restart or stream error. + if (!this.parser) return; const str = data.toString("utf8"); this.parser.write(str); } diff --git a/packages/connection/test/onData.js b/packages/connection/test/onData.js index 84e467486..e72270b4b 100644 --- a/packages/connection/test/onData.js +++ b/packages/connection/test/onData.js @@ -12,3 +12,13 @@ test("#_onData", () => { conn._onData(foo); }); + +test("#_onData does not throw after _detachParser has been called", () => { + expect.assertions(1); + const foo = ""; + const conn = new Connection(); + conn._detachParser(); + expect(() => { + conn._onData(foo); + }).not.toThrow(); +}); diff --git a/test/stream-management.test.js b/test/stream-management.test.js index 196e068c2..6857ed66a 100644 --- a/test/stream-management.test.js +++ b/test/stream-management.test.js @@ -11,15 +11,20 @@ const domain = "localhost"; let xmpp; -afterEach(async () => { +beforeAll(async () => { + await server.enableModules(["smacks"]); +}); + +beforeEach(async () => { + await server.restart(); +}); + +afterAll(async () => { await xmpp?.stop(); await server.reset(); }); test("client ack stanzas", async () => { - await server.enableModules(["smacks"]); - await server.restart(); - xmpp = client({ credentials, service: domain }); debug(xmpp); @@ -36,9 +41,6 @@ test("client ack stanzas", async () => { }); test("client fail stanzas", async () => { - await server.enableModules(["smacks"]); - await server.restart(); - xmpp = client({ credentials, service: domain }); debug(xmpp); @@ -60,9 +62,6 @@ test("client fail stanzas", async () => { }); test("client retry stanzas", async () => { - await server.enableModules(["smacks"]); - await server.restart(); - xmpp = client({ credentials, service: domain }); debug(xmpp); @@ -86,9 +85,6 @@ test("client retry stanzas", async () => { }); test("client reconnects when server fails to ack stanza", async () => { - await server.enableModules(["smacks"]); - await server.restart(); - xmpp = client({ credentials, service: domain }); xmpp.streamManagement.timeout = 10; xmpp.streamManagement.requestAckInterval = 5; @@ -110,39 +106,3 @@ test("client reconnects when server fails to ack stanza", async () => { await promise_resumed; expect().pass(); }); - -test("pings do not prevent timeout", async () => { - await server.enableModules(["smacks"]); - await server.restart(); - - xmpp = client({ credentials, service: domain }); - xmpp.streamManagement.timeout = 10; - xmpp.streamManagement.requestAckInterval = 5; - - // Make sure an ack request is sent right away after a stanza - xmpp.streamManagement.debounceAckRequest = 1; - debug(xmpp); - - let promise_disconnect = new Promise((resolve) => { - xmpp.disconnect = () => { - resolve(); - return Promise.resolve(null); - }; - }); - await xmpp.start(); - - // Send just any stanza to trigger the act request send - xmpp.send( - - - , - ); - - // Pretend we don't receive the ack by removing event listeners - // on the socket, so that the timeout can fire - xmpp._detachSocket(); - - // Timeout fires, and disconnect happens - await promise_disconnect; - expect().pass(); -});