diff --git a/.eslintignore b/.eslintignore index d4d3d2b..9ebfc2d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,3 @@ node_modules/ dist/ coverage/ -test/ - diff --git a/.eslintrc b/.eslintrc index 5cf6aed..8d9c0dd 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,11 +2,8 @@ "env": { "browser": true, "es6": true, - "node": true - }, - "globals": { - "CTX": true, - "console": true + "node": true, + "mocha": true }, "extends": "eslint:recommended", "rules": { @@ -29,10 +26,6 @@ "error", "always" ], - "one-var": [ - "error", - "always" - ], "eol-last": [ "error", "always" @@ -51,8 +44,7 @@ { "max": 2 } - ], - "no-console":0 + ] }, "parserOptions": { "sourceType": "module" diff --git a/package-lock.json b/package-lock.json index a957955..f804cd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "c8": "^9.1.0", - "chai": "^5.1.0", + "chai": "^6.2.1", + "chai-as-promised": "^8.0.2", "documentation": "^14.0.3", "eslint": "^8.57.0", "mocha": "^10.3.0", @@ -990,44 +991,48 @@ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" } }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true, + "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@types/debug": { "version": "4.1.7", @@ -1307,15 +1312,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -1556,19 +1552,26 @@ } }, "node_modules/chai": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.0.tgz", - "integrity": "sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chai-as-promised": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-1GadL+sEJVLzDjcawPM4kjfnL+p/9vrxiEUonowKOAzvVg0PixJUdtuDzdkDeQhK3zfOE76GqGkZIQ7/Adcrqw==", "dev": true, + "license": "MIT", "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.0.0", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" + "check-error": "^2.1.1" }, - "engines": { - "node": ">=12" + "peerDependencies": { + "chai": ">= 2.1.2 < 7" } }, "node_modules/chalk": { @@ -1614,10 +1617,11 @@ } }, "node_modules/check-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz", - "integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 16" } @@ -1840,15 +1844,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/deep-eql": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", - "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2562,15 +2557,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/git-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", @@ -3214,7 +3200,8 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/kleur": { "version": "4.1.5", @@ -3275,12 +3262,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3374,15 +3355,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/loupe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", - "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4610,6 +4582,7 @@ "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0", "@sinonjs/fake-timers": "^11.2.2", @@ -4885,15 +4858,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "dev": true, - "engines": { - "node": ">= 14.16" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -5368,6 +5332,7 @@ "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0", "@sinonjs/fake-timers": "^11.2.2", @@ -5690,6 +5655,7 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -6999,40 +6965,36 @@ } }, "@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", "dev": true, "requires": { - "@sinonjs/commons": "^3.0.0" + "@sinonjs/commons": "^3.0.1" } }, "@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, "requires": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" }, "dependencies": { - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true } } }, "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", "dev": true }, "@types/debug": { @@ -7283,12 +7245,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true - }, "bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -7445,16 +7401,18 @@ "dev": true }, "chai": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.0.tgz", - "integrity": "sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", + "dev": true + }, + "chai-as-promised": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-1GadL+sEJVLzDjcawPM4kjfnL+p/9vrxiEUonowKOAzvVg0PixJUdtuDzdkDeQhK3zfOE76GqGkZIQ7/Adcrqw==", "dev": true, "requires": { - "assertion-error": "^2.0.1", - "check-error": "^2.0.0", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" + "check-error": "^2.1.1" } }, "chalk": { @@ -7482,9 +7440,9 @@ "dev": true }, "check-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz", - "integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true }, "chokidar": { @@ -7652,12 +7610,6 @@ "character-entities": "^2.0.0" } }, - "deep-eql": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", - "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", - "dev": true - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -8185,12 +8137,6 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true - }, "git-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", @@ -8728,12 +8674,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -8801,15 +8741,6 @@ "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "dev": true }, - "loupe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", - "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", - "dev": true, - "requires": { - "get-func-name": "^2.0.1" - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -9840,12 +9771,6 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true }, - "pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/package.json b/package.json index ad6d1f2..09fc10b 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,7 @@ }, "mocha": { "recursive": true, - "timeout": 5000, - "require": [ - "test/init.js" - ] + "timeout": 5000 }, "repository": { "type": "git", @@ -48,7 +45,8 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "c8": "^9.1.0", - "chai": "^5.1.0", + "chai": "^6.2.1", + "chai-as-promised": "^8.0.2", "documentation": "^14.0.3", "eslint": "^8.57.0", "mocha": "^10.3.0", diff --git a/src/client.js b/src/client.js index d374741..52aa530 100644 --- a/src/client.js +++ b/src/client.js @@ -161,7 +161,7 @@ Client.prototype.sendPushNotificationForAuth = function (userId, callback) { self.http.request(reqData, function (err, result) { if (err) { if (result && result.error === "NO_PUSH_TOKEN") { - return callback(new Error("No push token", { cause: err })); + return callback(new Error("No push token", { cause: err }), null); } return callback(err, null); diff --git a/test/config.js b/test/config.js new file mode 100644 index 0000000..99ca4cc --- /dev/null +++ b/test/config.js @@ -0,0 +1,13 @@ +// In memory storage for users +import storage from "./storage.js"; + +// Reusable test data +export default function () { + return { + projectUrl: "https://project.miracl.io", + projectId: "projectID", + seed: "hexSeed", + defaultPinLength: 4, + userStorage: new storage() + }; +} diff --git a/test/init.js b/test/init.js deleted file mode 100644 index 2c85ea1..0000000 --- a/test/init.js +++ /dev/null @@ -1,15 +0,0 @@ -// In memory storage for users -import storage from "./storage.js"; - -// Reusable test data -global.testData = { - init: function () { - return { - projectUrl: "https://project.miracl.io", - projectId: "projectID", - seed: "hexSeed", - defaultPinLength: 4, - userStorage: new storage() - }; - } -}; diff --git a/test/storage.js b/test/storage.js index 72efd8a..d0d9109 100644 --- a/test/storage.js +++ b/test/storage.js @@ -1,10 +1,10 @@ // Mock in-memory user storage export default function UserStorage() { this.storage = {}; -}; +} UserStorage.prototype.setItem = function (key, value) { - this.storage[key] = value || ''; + this.storage[key] = value || ""; }; UserStorage.prototype.getItem = function (key) { @@ -15,6 +15,6 @@ UserStorage.prototype.removeItem = function (key) { delete this.storage[key]; }; -UserStorage.prototype.clear = function (key) { +UserStorage.prototype.clear = function () { this.storage = {}; }; diff --git a/test/test-authentication.js b/test/test-authentication.js index f2aa941..b1463fc 100644 --- a/test/test-authentication.js +++ b/test/test-authentication.js @@ -1,12 +1,13 @@ import Client from "../src/client.js"; import sinon from "sinon"; import { expect } from "chai"; +import testConfig from "./config.js"; describe("Client _getPass1", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("shoud make a request for first pass", function (done) { @@ -39,6 +40,7 @@ describe("Client _getPass1", function () { client._getPass1({}, "1234", ["oidc"], [], [], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Cryptography error: -14"); + expect(data).to.be.null; done(); }); }); @@ -48,6 +50,8 @@ describe("Client _getPass1", function () { sinon.stub(client.crypto, "calculatePass1").returns({U: "", UT: ""}); client._getPass1({}, "1234", ["dvs-auth"], [], [], function (err, data) { + expect(err).to.be.null; + expect(data).to.deep.equal({ success: true }); expect(requestStub.firstCall.args[0].data.scope).to.deep.equal(["dvs-auth"]); done(); }); @@ -63,7 +67,7 @@ describe("Client _getPass2", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("shoud make a request for second pass", function (done) { @@ -96,6 +100,7 @@ describe("Client _getPass2", function () { client._getPass2({}, ["oidc"], "yHex", [], [], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Cryptography error"); + expect(data).to.be.null; done(); }); }); @@ -110,7 +115,7 @@ describe("Client _finishAuthentication", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should call error callback when request fails", function (done) { @@ -118,6 +123,7 @@ describe("Client _finishAuthentication", function () { client._finishAuthentication("test@example.com", 1234, ["oidc"], "authOTT", function (err, data) { expect(err).to.exist; + expect(data).to.deep.equal({ status: 400 }); done(); }); }); @@ -147,7 +153,7 @@ describe("Client _finishAuthentication", function () { it("should return error when _renewSecret fails", function(done) { sinon.stub(client.http, "request").yields(null, { success: true, dvsRegister: { test: 1 } }); - var renewSecretStub = sinon.stub(client, "_renewSecret").yields(new Error("Renew secret error")); + sinon.stub(client, "_renewSecret").yields(new Error("Renew secret error")); client._finishAuthentication("test@example.com", 1234, ["dvs-auth"], "authOTT", function (err) { expect(err).to.exist; @@ -167,7 +173,7 @@ describe("Client _renewSecret", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should renew the identity secret", function (done) { @@ -234,14 +240,14 @@ describe("Client _renewSecret", function () { client._createMPinID.restore && client._createMPinID.restore(); client._getSecret.restore && client._getSecret.restore(); client._createIdentity.restore && client._createIdentity.restore(); - }) + }); }); describe("Client _authentication", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -267,10 +273,11 @@ describe("Client _authentication", function () { it("should go through the authentication flow", function (done) { var getPass1Stub = sinon.stub(client, "_getPass1").yields(null, {}); var getPass2Stub = sinon.stub(client, "_getPass2").yields(null, {}); - var finishAuthenticationStub = sinon.stub(client, "_finishAuthentication").yields(null, true); + var finishAuthenticationStub = sinon.stub(client, "_finishAuthentication").yields(null, { success: true }); - client._authentication("test@example.com", "1234", ['oidc'], function (err, data) { + client._authentication("test@example.com", "1234", ["oidc"], function (err, data) { expect(err).to.be.null; + expect(data).to.deep.equal({ success: true }); expect(getPass1Stub.calledOnce).to.be.true; expect(getPass2Stub.calledOnce).to.be.true; expect(finishAuthenticationStub.calledOnce).to.be.true; @@ -281,8 +288,9 @@ describe("Client _authentication", function () { it("should call callback with error when _getPass1 fails", function (done) { sinon.stub(client, "_getPass1").yields(new Error("Request error"), null); - client._authentication("test@example.com", "1234", ['oidc'], function (err, data) { + client._authentication("test@example.com", "1234", ["oidc"], function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -290,9 +298,10 @@ describe("Client _authentication", function () { it("should call callback with error when MPIN ID has expired", function (done) { sinon.stub(client, "_getPass1").yields(new Error("Request error"), { error: "EXPIRED_MPINID" }); - client._authentication("test@example.com", "1234", ['oidc'], function (err, data) { + client._authentication("test@example.com", "1234", ["oidc"], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Revoked"); + expect(data).to.be.null; done(); }); }); @@ -300,8 +309,9 @@ describe("Client _authentication", function () { it("should call callback with error when _getPass1 fails", function (done) { sinon.stub(client, "_getPass1").yields(new Error("Request error"), null); - client._authentication("test@example.com", "1234", ['oidc'], function (err, data) { + client._authentication("test@example.com", "1234", ["oidc"], function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -310,8 +320,9 @@ describe("Client _authentication", function () { sinon.stub(client, "_getPass1").yields(null, { success: true }); sinon.stub(client, "_getPass2").yields(new Error("Request error"), null); - client._authentication("test@example.com", "1234", ['oidc'], function (err, data) { + client._authentication("test@example.com", "1234", ["oidc"], function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -339,6 +350,7 @@ describe("Client _authentication", function () { client._authentication("test@example.com", "1234", ["jwt"], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Authentication fail"); + expect(data).to.be.null; done(); }); }); @@ -353,6 +365,7 @@ describe("Client _authentication", function () { client._authentication("test@example.com", "1234", ["jwt"], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Unsuccessful authentication"); + expect(data).to.be.null; done(); }); }); @@ -369,6 +382,7 @@ describe("Client _authentication", function () { client._authentication("test@example.com", "1234", ["jwt"], function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Revoked"); + expect(data).to.be.null; expect(userWriteSpy.calledOnce).to.be.true; expect(userWriteSpy.firstCall.args[0]).to.equal("test@example.com"); expect(userWriteSpy.firstCall.args[1].state).to.equal("REVOKED"); @@ -388,7 +402,7 @@ describe("Client authenticate", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -418,7 +432,7 @@ describe("Client authenticateWithQRCode", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -448,7 +462,7 @@ describe("Client authenticateWithAppLink", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -478,7 +492,7 @@ describe("Client authenticateWithNotificationPayload", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -503,6 +517,7 @@ describe("Client authenticateWithNotificationPayload", function () { client.authenticateWithNotificationPayload({qrURL: "https://example.com/mobile/auth#accessID"}, "1234", function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Invalid push notification payload"); + expect(data).to.be.null; done(); }); }); @@ -511,6 +526,7 @@ describe("Client authenticateWithNotificationPayload", function () { client.authenticateWithNotificationPayload({userID: "test@example.com"}, "1234", function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Invalid push notification payload"); + expect(data).to.be.null; done(); }); }); @@ -524,7 +540,7 @@ describe("Client generateQuickCode", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", state: "REGISTERED" @@ -533,7 +549,7 @@ describe("Client generateQuickCode", function () { it("should call _authentication with scope 'reg-code'", function (done) { var authenticationStub = sinon.stub(client, "_authentication").yields(null, {}); - var requestStub = sinon.stub(client.http, "request").yields(null, { code: "123456", ttlSeconds: 60, expireTime: 1737520575 }); + sinon.stub(client.http, "request").yields(null, { code: "123456", ttlSeconds: 60, expireTime: 1737520575 }); client.generateQuickCode("test@example.com", "1234", function (err, data) { expect(err).to.be.null; @@ -548,22 +564,24 @@ describe("Client generateQuickCode", function () { }); it("should fail on _authentication error", function (done) { - var authenticationStub = sinon.stub(client, "_authentication").yields(new Error("Authentication fail"), null); + sinon.stub(client, "_authentication").yields(new Error("Authentication fail"), null); client.generateQuickCode("test@example.com", "1234", function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Authentication fail"); + expect(data).to.be.null; done(); }); }); it("should fail on verification/quickcode request error", function (done) { - var authenticationStub = sinon.stub(client, "_authentication").yields(null, {}); - var requestStub = sinon.stub(client.http, "request").yields(new Error("Request error"), null); + sinon.stub(client, "_authentication").yields(null, {}); + sinon.stub(client.http, "request").yields(new Error("Request error"), null); client.generateQuickCode("test@example.com", "1234", function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Request error"); + expect(data).to.be.null; done(); }); }); diff --git a/test/test-client.js b/test/test-client.js index bbdb6be..b272ff6 100644 --- a/test/test-client.js +++ b/test/test-client.js @@ -1,78 +1,83 @@ import Client from "../src/client.js"; -import pkg from "../package.json" with { type: "json" }; +import { readFileSync } from "fs"; import sinon from "sinon"; import { expect } from "chai"; +import testConfig from "./config.js"; + +const pkg = JSON.parse(readFileSync("./package.json")); describe("Client", function() { it("should throw Error w/o options", function () { expect(function () { - var client = new Client(); + new Client(); }).to.throw("Invalid configuration"); }); it("should throw Error w/o project ID", function () { + var config = testConfig(); + delete config["projectId"]; + expect(function () { - var config = testData.init(); - delete config["projectId"]; - var client = new Client(config); + new Client(config); }).to.throw("Empty project ID"); }); it("should throw Error w/o user storage", function () { + var config = testConfig(); + delete config["userStorage"]; + expect(function () { - var config = testData.init(); - delete config["userStorage"]; - var client = new Client(config); + new Client(config); }).to.throw("Invalid user storage"); }); it("should return client instance", function () { - var client = new Client(testData.init()); + var client = new Client(testConfig()); expect(client).to.be.an.instanceof(Client); }); it("should set default server address if there is no projectUrl", function () { - var config = testData.init(); + var config = testConfig(); delete config["projectUrl"]; var client = new Client(config); expect(client.options.projectUrl).to.equal("https://api.mpin.io"); }); it("should set default PIN length to 4 if there is none", function () { - var config = testData.init(); + var config = testConfig(); delete config["defaultPinLength"]; var client = new Client(config); expect(client.options.defaultPinLength).to.equal(4); }); it("should set default PIN length to 4 if less than 4", function () { - var config = testData.init(); + var config = testConfig(); config.defaultPinLength = 3; var client = new Client(config); expect(client.options.defaultPinLength).to.equal(4); }); it("should set default PIN length to 4 if more than 6", function () { - var config = testData.init(); + var config = testConfig(); config.defaultPinLength = 7; var client = new Client(config); expect(client.options.defaultPinLength).to.equal(4); }); it("should set default PIN length to provided value within range", function () { - var config = testData.init(); + var config = testConfig(); config.defaultPinLength = 5; var client = new Client(config); expect(client.options.defaultPinLength).to.equal(5); }); it("should set clientName", function () { - var client = new Client(testData.init()); + var client = new Client(testConfig()); expect(client.options.clientName).to.equal("MIRACL Client.js/" + pkg.version); }); it("should set clientName with application info", function () { - var config = testData.init(); + var config = testConfig(); config.applicationInfo = "Test Application"; var client = new Client(config); expect(client.options.clientName).to.equal("MIRACL Client.js/" + pkg.version + " Test Application"); @@ -83,7 +88,7 @@ describe("Client setAccessId", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should set access id", function () { @@ -96,7 +101,7 @@ describe("Client fetchAccessId", function () { var client, sessionInfo; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); sessionInfo = { webOTT: 1, @@ -107,7 +112,7 @@ describe("Client fetchAccessId", function () { }); it("should make a request for access ID", function () { - var requestStub = sinon.stub(client.http, "request").yields(null, sessionInfo); + sinon.stub(client.http, "request").yields(null, sessionInfo); client.fetchAccessId("test@example.com", function (err, data) { expect(data).to.deep.equal(sessionInfo); @@ -115,25 +120,30 @@ describe("Client fetchAccessId", function () { }); it("should fail when request fails", function () { - var requestStub = sinon.stub(client.http, "request").yields(new Error("Error"), null); + sinon.stub(client.http, "request").yields(new Error("Error"), null); client.fetchAccessId("test@example.com", function (err, data) { expect(err).to.exist; + expect(data).to.be.null; }); }); it("should store session info", function () { - var requestStub = sinon.stub(client.http, "request").yields(null, sessionInfo); + sinon.stub(client.http, "request").yields(null, sessionInfo); client.fetchAccessId("test@example.com", function (err, data) { + expect(err).to.be.null; + expect(data).to.deep.equal(sessionInfo); expect(client.session).to.deep.equal(sessionInfo); }); }); it("should set the access ID", function () { - var requestStub = sinon.stub(client.http, "request").yields(null, sessionInfo); + sinon.stub(client.http, "request").yields(null, sessionInfo); client.fetchAccessId("test@example.com", function (err, data) { + expect(err).to.be.null; + expect(data).to.deep.equal(sessionInfo); expect(client.session.accessId).to.equal("accessID"); }); }); @@ -147,11 +157,11 @@ describe("Client fetchStatus", function() { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should make a request for session status", function () { - var requestStub = sinon.stub(client.http, "request").yields(null, { status: "new" }); + sinon.stub(client.http, "request").yields(null, { status: "new" }); client.fetchStatus(function (err, data) { expect(data.status).to.equal("new"); @@ -159,10 +169,11 @@ describe("Client fetchStatus", function() { }); it("should fail when request fails", function () { - var requestStub = sinon.stub(client.http, "request").yields(new Error("Error"), null); + sinon.stub(client.http, "request").yields(new Error("Error"), null); client.fetchStatus(function (err, data) { expect(err).to.exist; + expect(data).to.be.null; }); }); @@ -175,7 +186,7 @@ describe("Client sendPushNotificationForAuth", function () { var client; before(function () { - const config = testData.init(); + const config = testConfig(); config.oidc = { client_id: "testClientID" }; @@ -193,25 +204,28 @@ describe("Client sendPushNotificationForAuth", function () { }); it("should fail when the request fails", function () { - var requestStub = sinon.stub(client.http, "request").yields(new Error("Request error"), { status: 400 }); + sinon.stub(client.http, "request").yields(new Error("Request error"), { status: 400 }); client.sendPushNotificationForAuth("test@example.com", function (err, data) { expect(err).to.exist; + expect(data).to.be.null; }); }); it("should fail when the request fails", function () { - var requestStub = sinon.stub(client.http, "request").yields(new Error("Request error"), { status: 400, error: "NO_PUSH_TOKEN" }); + sinon.stub(client.http, "request").yields(new Error("Request error"), { status: 400, error: "NO_PUSH_TOKEN" }); client.sendPushNotificationForAuth("test@example.com", function (err, data) { expect(err).to.exist; expect(err.message).to.equal("No push token"); + expect(data).to.be.null; }); }); it("should return an error without an user ID", function () { client.sendPushNotificationForAuth(null, function (err, data) { expect(err).to.exist; + expect(data).to.be.null; }); }); diff --git a/test/test-crypto.js b/test/test-crypto.js index 618d22f..af264f3 100644 --- a/test/test-crypto.js +++ b/test/test-crypto.js @@ -72,7 +72,7 @@ describe("Crypto extractPin", function () { it("should throw error on crypto failure", function () { sinon.stub(crypto._crypto().MPIN, "EXTRACT_PIN").returns(-1); expect(function () { - crypto.extractPin("0f", "0f", "1234", "hex", "BN254CX") + crypto.extractPin("0f", "0f", "1234", "hex", "BN254CX"); }).to.throw("Could not extract PIN from client secret: -1"); }); diff --git a/test/test-dvs.js b/test/test-dvs.js index b537e9e..d33b01b 100644 --- a/test/test-dvs.js +++ b/test/test-dvs.js @@ -1,12 +1,13 @@ import Client from "../src/client.js"; import sinon from "sinon"; import { expect } from "chai"; +import testConfig from "./config.js"; describe("Client sign", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "exampleMpinId", publicKey: "00", @@ -18,6 +19,7 @@ describe("Client sign", function () { client.sign("", "1234", "message", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("Empty user ID"); + expect(result).to.be.null; done(); }); }); @@ -26,6 +28,7 @@ describe("Client sign", function () { client.sign("test@example.com", "1234", "", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("Empty message"); + expect(result).to.be.null; done(); }); }); @@ -34,6 +37,7 @@ describe("Client sign", function () { client.sign("missing@example.com", "1234", "message", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("User not found"); + expect(result).to.be.null; done(); }); }); @@ -47,6 +51,7 @@ describe("Client sign", function () { client.sign("nopublickey@example.com", "1234", "message", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("Empty public key"); + expect(result).to.be.null; done(); }); }); @@ -71,6 +76,7 @@ describe("Client sign", function () { expect(err).to.exist; expect(err.message).to.equal("Signing fail"); expect(err.cause.message).to.equal("Request error"); + expect(result).to.be.null; done(); }); }); @@ -82,6 +88,7 @@ describe("Client sign", function () { client.sign("test@example.com", "1234", "message", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("Unsuccessful authentication"); + expect(result).to.be.null; done(); }); }); @@ -93,6 +100,7 @@ describe("Client sign", function () { client.sign("test@example.com", "1234", "message", "timestamp", function (err, result) { expect(err).to.exist; expect(err.message).to.equal("Revoked"); + expect(result).to.be.null; done(); }); }); @@ -105,6 +113,7 @@ describe("Client sign", function () { expect(err).to.exist; expect(err.message).to.equal("Signing fail"); expect(err.cause.message).to.equal("Cryptography error"); + expect(result).to.be.null; done(); }); }); diff --git a/test/test-http.js b/test/test-http.js index 303adee..100a91a 100644 --- a/test/test-http.js +++ b/test/test-http.js @@ -3,7 +3,7 @@ import sinon from "sinon"; import { expect } from "chai"; describe("HTTP request", function() { - var client, server, requests; + var client, requests; before(function () { var xhr = global.XMLHttpRequest = sinon.useFakeXMLHttpRequest(); diff --git a/test/test-promise.js b/test/test-promise.js index 81f3db6..2df689f 100644 --- a/test/test-promise.js +++ b/test/test-promise.js @@ -1,223 +1,175 @@ import Client from "../src/promise.js"; import sinon from "sinon"; -import { expect } from "chai"; +import { expect, use } from "chai"; +import chaiAsPromised from "chai-as-promised"; +import testConfig from "./config.js"; + +use(chaiAsPromised); describe("Promises", function() { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); - it("should call fetchAccessId", async function () { + it("should call fetchAccessId", function () { sinon.stub(client.http, "request").yields(null, { accessId: "accessID" }); - expect(await client.fetchAccessId("test@example.com")).to.deep.equal({ accessId: "accessID" }); - }); - it("should fail on fetchAccessId error", async function () { - sinon.stub(client.http, "request").yields(new Error("Request error"), null); + expect(client.fetchAccessId("test@example.com")).to.eventually.deep.equal({ accessId: "accessID" }); + }); - try { - await client.fetchAccessId("test@example.com"); - } catch (err) { - expect(err.message).to.equal("Request error"); - return; - } + it("should fail on fetchAccessId error", function () { + var err = new Error("Request error"); + sinon.stub(client.http, "request").yields(err, null); - throw new Error("Unexpected result"); + expect(client.fetchAccessId("test@example.com")).to.be.rejectedWith(err); }); - it("should call fetchStatus", async function () { + it("should call fetchStatus", function () { sinon.stub(client.http, "request").yields(null, { status: "new" }); - expect(await client.fetchStatus()).to.deep.equal({ status: "new" }); - }); - it("should fail on fetchStatus error", async function () { - sinon.stub(client.http, "request").yields(new Error("Request error"), null); + expect(client.fetchStatus()).to.eventually.deep.equal({ status: "new" }); + }); - try { - await client.fetchStatus(); - } catch (err) { - expect(err.message).to.equal("Request error"); - return; - } + it("should fail on fetchStatus error", function () { + var err = new Error("Request error"); + sinon.stub(client.http, "request").yields(err, null); - throw new Error("Unexpected result"); + expect(client.fetchStatus()).to.be.rejectedWith(err); }); - it("should call sendPushNotificationForAuth", async function () { + it("should call sendPushNotificationForAuth", function () { sinon.stub(client.http, "request").yields(null, { accessId: "accessID" }); - expect(await client.sendPushNotificationForAuth("test@example.com")).to.deep.equal({ accessId: "accessID" }); - }); - it("should fail on sendPushNotificationForAuth error", async function () { - sinon.stub(client.http, "request").yields(new Error("Request error"), null); + expect(client.sendPushNotificationForAuth("test@example.com")).to.eventually.deep.equal({ accessId: "accessID" }); + }); - try { - await client.sendPushNotificationForAuth("test@example.com") - } catch (err) { - expect(err.message).to.equal("Request error"); - return; - } + it("should fail on sendPushNotificationForAuth error", function () { + var err = new Error("Request error"); + sinon.stub(client.http, "request").yields(err, null); - throw new Error("Unexpected result"); + expect(client.sendPushNotificationForAuth("test@example.com")).to.be.rejectedWith(err); }); - it("should call sendVerificationEmail", async function () { + it("should call sendVerificationEmail", function () { sinon.stub(client.http, "request").yields(null, { backoff: 1 }); - expect(await client.sendVerificationEmail("test@example.com")).to.deep.equal({ backoff: 1 }); - }); - it("should fail on sendVerificationEmail error", async function () { - sinon.stub(client.http, "request").yields(new Error("Request error"), null); + expect(client.sendVerificationEmail("test@example.com")).to.eventually.deep.equal({ backoff: 1 }); + }); - try { - await client.sendVerificationEmail("test@example.com") - } catch (err) { - expect(err.message).to.equal("Verification fail"); - return; - } + it("should fail on sendVerificationEmail error", function () { + var err = new Error("Request error"); + sinon.stub(client.http, "request").yields(err, null); - throw new Error("Unexpected result"); + expect(client.sendVerificationEmail("test@example.com")).to.be.rejectedWith(err); }); - it("should call getActivationToken", async function () { + it("should call getActivationToken", function () { sinon.stub(client.http, "request").yields(null, { actToken: "test" }); - expect(await client.getActivationToken("https://example.com/verification/confirmation?user_id=test@example.com&code=test")).to.deep.equal({ userId: "test@example.com", actToken: "test" }); - }); - it("should fail on getActivationToken error", async function () { - sinon.stub(client.http, "request").yields(new Error("Request error"), null); + expect(client.getActivationToken("https://example.com/verification/confirmation?user_id=test@example.com&code=test")).to.eventually.deep.equal({ userId: "test@example.com", actToken: "test" }); + }); - try { - await client.getActivationToken("https://example.com/verification/confirmation?user_id=test@example.com&code=test") - } catch (err) { - expect(err.message).to.equal("Get activation token fail"); - return; - } + it("should fail on getActivationToken error", function () { + var err = new Error("Request error"); + sinon.stub(client.http, "request").yields(err, null); - throw new Error("Unexpected result"); + expect(client.getActivationToken("https://example.com/verification/confirmation?user_id=test@example.com&code=test")).to.be.rejectedWith(err); }); - it("should call register", async function () { + it("should call register", function () { sinon.stub(client, "_createMPinID").yields(null, { pinLength: 4, projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); sinon.stub(client, "_getSecret").yields(null); sinon.stub(client, "_createIdentity").yields(null, { state: "REGISTERED" }); - expect(await client.register("test@example.com", "activationToken", function (passPin) { passPin("1234"); })).to.deep.equal({ state: "REGISTERED" }); + expect(client.register("test@example.com", "activationToken", function (passPin) { + passPin("1234"); + })).to.eventually.deep.equal({ state: "REGISTERED" }); client._createMPinID.restore(); client._getSecret.restore(); client._createIdentity.restore(); }); - it("should fail on register error", async function () { - sinon.stub(client, "_createMPinID").yields(new Error("Request error"), null); + it("should fail on register error", function () { + var err = new Error("Create MPinID error"); + sinon.stub(client, "_createMPinID").yields(err, null); - try { - await client.register("test@example.com", "activationToken", function (passPin) { passPin("1234"); }) - } catch (err) { - expect(err.message).to.equal("Registration fail"); - return; - } + expect(client.register("test@example.com", "activationToken", function (passPin) { + passPin("1234"); + })).to.be.rejectedWith(err); client._createMPinID.restore(); - - throw new Error("Unexpected result"); }); - it("should call authenticate", async function () { + it("should call authenticate", function () { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); - expect(await client.authenticate("test@example.com", "1234")).to.deep.equal({ message: "OK" }); - }); - it("should fail on authenticate error", async function () { - sinon.stub(client, "_authentication").yields(new Error("Authentication error"), null); + expect(client.authenticate("test@example.com", "1234")).to.eventually.deep.equal({ message: "OK" }); + }); - try { - await client.authenticate("test@example.com", "1234") - } catch (err) { - expect(err.message).to.equal("Authentication error"); - return; - } + it("should fail on authenticate error", function () { + var err = new Error("Authentication error"); + sinon.stub(client, "_authentication").yields(err, null); - throw new Error("Unexpected result"); + expect(client.authenticate("test@example.com", "1234")).to.be.rejectedWith(err); }); - it("should call authenticateWithQRCode", async function () { + it("should call authenticateWithQRCode", function () { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); - expect(await client.authenticateWithQRCode("test@example.com", "https://example.com#accessID", "1234")).to.deep.equal({ message: "OK" }); - }); - it("should fail on authenticateWithQRCode error", async function () { - sinon.stub(client, "_authentication").yields(new Error("Authentication error"), null); + expect(client.authenticateWithQRCode("test@example.com", "https://example.com#accessID", "1234")).to.eventually.deep.equal({ message: "OK" }); + }); - try { - await client.authenticateWithQRCode("test@example.com", "https://example.com#accessID", "1234") - } catch (err) { - expect(err.message).to.equal("Authentication error"); - return; - } + it("should fail on authenticateWithQRCode error", function () { + var err = new Error("Authentication error"); + sinon.stub(client, "_authentication").yields(err, null); - throw new Error("Unexpected result"); + expect(client.authenticateWithQRCode("test@example.com", "https://example.com#accessID", "1234")).to.be.rejectedWith(err); }); - it("should call authenticateWithAppLink", async function () { + it("should call authenticateWithAppLink", function () { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); - expect(await client.authenticateWithAppLink("test@example.com", "https://example.com#accessID", "1234")).to.deep.equal({ message: "OK" }); - }); - it("should fail on authenticateWithAppLink error", async function () { - sinon.stub(client, "_authentication").yields(new Error("Authentication error"), null); + expect(client.authenticateWithAppLink("test@example.com", "https://example.com#accessID", "1234")).to.eventually.deep.equal({ message: "OK" }); + }); - try { - await client.authenticateWithAppLink("test@example.com", "https://example.com#accessID", "1234") - } catch (err) { - expect(err.message).to.equal("Authentication error"); - return; - } + it("should fail on authenticateWithAppLink error", function () { + var err = new Error("Authentication error"); + sinon.stub(client, "_authentication").yields(err, null); - throw new Error("Unexpected result"); + expect(client.authenticateWithAppLink("test@example.com", "https://example.com#accessID", "1234")).to.be.rejectedWith(err); }); - it("should call authenticateWithNotificationPayload", async function () { + it("should call authenticateWithNotificationPayload", function () { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); - expect(await client.authenticateWithNotificationPayload({ userID: "test@example.com", qrURL: "https://example.com#accessID" }, "1234")).to.deep.equal({ message: "OK" }); - }); - it("should fail on authenticateWithNotificationPayload error", async function () { - sinon.stub(client, "_authentication").yields(new Error("Authentication error"), null); + expect(client.authenticateWithNotificationPayload({ userID: "test@example.com", qrURL: "https://example.com#accessID" }, "1234")).to.eventually.deep.equal({ message: "OK" }); + }); - try { - await client.authenticateWithNotificationPayload({ userID: "test@example.com", qrURL: "https://example.com#accessID" }, "1234") - } catch (err) { - expect(err.message).to.equal("Authentication error"); - return; - } + it("should fail on authenticateWithNotificationPayload error", function () { + var err = new Error("Authentication error"); + sinon.stub(client, "_authentication").yields(err, null); - throw new Error("Unexpected result"); + expect(client.authenticateWithNotificationPayload({ userID: "test@example.com", qrURL: "https://example.com#accessID" }, "1234")).to.be.rejectedWith(err); }); - it("should call generateQuickCode", async function () { + it("should call generateQuickCode", function () { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); sinon.stub(client.http, "request").yields(null, { code: "123456", ttlSeconds: 60, expireTime: 1737520575 }); - expect(await client.generateQuickCode("test@example.com", "1234")).to.deep.equal({ code: "123456", OTP: "123456", ttlSeconds: 60, expireTime: 1737520575 }); - }); - it("should fail on generateQuickCode error", async function () { - sinon.stub(client, "_authentication").yields(new Error("Authentication error"), null); + expect(client.generateQuickCode("test@example.com", "1234")).to.eventually.deep.equal({ code: "123456", OTP: "123456", ttlSeconds: 60, expireTime: 1737520575 }); + }); - try { - await client.generateQuickCode("test@example.com", "1234") - } catch (err) { - expect(err.message).to.equal("Authentication error"); - return; - } + it("should fail on generateQuickCode error", function () { + var err = new Error("Authentication error"); + sinon.stub(client, "_authentication").yields(err, null); - throw new Error("Unexpected result"); + expect(client.generateQuickCode("test@example.com", "1234")).to.be.rejectedWith(err); }); - it("should call sign", async function () { + it("should call sign", function () { client.users.write("test@example.com", { mpinId: "exampleMpinId", publicKey: "00", @@ -227,23 +179,13 @@ describe("Promises", function() { sinon.stub(client, "_authentication").yields(null, { message: "OK" }); sinon.stub(client.crypto, "sign").returns({U: "1", V: "2"}); - var res = await client.sign("test@example.com", "1234", "0f", "timestamp") - - expect(res.u).to.equal("1"); - expect(res.v).to.equal("2"); + expect(client.sign("test@example.com", "1234", "0f", "timestamp")).to.eventually.deep.equal({u: "1", v: "2"}); client.crypto.sign.restore(); }); - it("should fail on sign error", async function () { - try { - await client.sign("test@example.com", "1234", "0f", "timestamp") - } catch (err) { - expect(err.message).to.equal("Signing fail"); - return; - } - - throw new Error("Unexpected result"); + it("should fail on sign error", function () { + expect(client.sign("test@example.com", "1234", "0f", "timestamp")).to.be.rejectedWith("Signing fail"); }); afterEach(function () { diff --git a/test/test-registration.js b/test/test-registration.js index 5d634d9..5209d5b 100644 --- a/test/test-registration.js +++ b/test/test-registration.js @@ -1,12 +1,13 @@ import Client from "../src/client.js"; import sinon from "sinon"; import { expect } from "chai"; +import testConfig from "./config.js"; describe("Client sendVerificationEmail", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should fail w/o userId", function (done) { @@ -56,7 +57,7 @@ describe("Client getActivationToken", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should fail w/o userId", function (done) { @@ -81,6 +82,7 @@ describe("Client getActivationToken", function () { client.getActivationToken("http://example.com/verification/confirmation?code=test&user_id=test@example.com", function(err, data) { expect(err).to.exist; expect(err.message).to.equal("Get activation token fail"); + expect(data).to.be.null; done(); }); }); @@ -91,6 +93,7 @@ describe("Client getActivationToken", function () { client.getActivationToken("http://example.com/verification/confirmation?code=test&user_id=test@example.com", function(err, data) { expect(err).to.exist; expect(err.message).to.equal("Unsuccessful verification"); + expect(data).to.deep.equal({ error: "UNSUCCESSFUL_VERIFICATION" }); done(); }); }); @@ -115,7 +118,7 @@ describe("Client _createMPinID", function() { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should return error, when register request fail", function(done) { @@ -131,6 +134,8 @@ describe("Client _createMPinID", function() { sinon.stub(client.http, "request").yields(null, { projectId: "projectID" }); client._createMPinID("test@example.com", null, { publicKey: "00" }, function(err, data) { + expect(err).to.be.null; + expect(data).to.deep.equal({ projectId: "projectID" }); expect(client.users.exists("test@example.com")).to.be.true; expect(client.users.get("test@example.com", "state")).to.equal("STARTED"); done(); @@ -146,23 +151,23 @@ describe("Client _getDeviceName", function () { var client; it("should return default device name", function () { - client = new Client(testData.init()); + client = new Client(testConfig()); expect(client._getDeviceName()).to.equal("Browser"); }); it("should return provided device name", function () { - var config = testData.init(); + var config = testConfig(); config.deviceName = "test"; client = new Client(config); expect(client._getDeviceName()).to.equal("test"); - }) + }); }); describe("Client _getSecret", function() { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should return error, when signature request fails", function(done) { @@ -225,7 +230,7 @@ describe("Client _createIdentity", function() { var client; beforeEach(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); client.users.write("test@example.com", { mpinId: "0f", state: "REGISTERED" @@ -234,11 +239,15 @@ describe("Client _createIdentity", function() { it("should call addShares with CS share 1 and 2", function(done) { var addSharesStub = sinon.stub(client.crypto, "addShares"); + sinon.stub(client.crypto, "extractPin"); + var keypair = { privateKey: "privateKey" }; var share1 = { dvsClientSecret: "clientSecretValue1" }; var share2 = { dvsClientSecret: "clientSecretValue2" }; - client._createIdentity("test@example.com", "1234", {}, share1, share2, keypair, function(err) { + client._createIdentity("test@example.com", "1234", {}, share1, share2, keypair, function(err, data) { + expect(err).to.be.null; + expect(data).to.exist; expect(addSharesStub.calledOnce).to.be.true; expect(addSharesStub.firstCall.args[0]).to.equal("privateKey"); expect(addSharesStub.firstCall.args[1]).to.equal("clientSecretValue1"); @@ -251,14 +260,16 @@ describe("Client _createIdentity", function() { var addSharesStub = sinon.stub(client.crypto, "addShares"); var extractPinStub = sinon.stub(client.crypto, "extractPin"); - client._createIdentity("test@example.com", "1234", { mpinId: "0f" }, {}, {}, { publicKey: "0f" }, function (data) { + client._createIdentity("test@example.com", "1234", { mpinId: "0f" }, {}, {}, { publicKey: "0f" }, function (err, data) { + expect(err).to.be.null; + expect(data).to.exist; expect(addSharesStub.calledOnce).to.be.true; expect(extractPinStub.calledOnce).to.be.true; expect(extractPinStub.firstCall.args[0]).to.equal("0f"); expect(extractPinStub.firstCall.args[1]).to.equal("0f"); expect(extractPinStub.firstCall.args[2]).to.equal("1234"); done(); - }, function (err) { + }, function () { throw new Error(); }); }); @@ -266,23 +277,25 @@ describe("Client _createIdentity", function() { it("should call callback with error when addShares fails", function(done) { var addSharesStub = sinon.stub(client.crypto, "addShares").throws(new Error("Cryptography error")); - client._createIdentity("test@example.com", "1234", {}, {}, {}, {}, function(err) { + client._createIdentity("test@example.com", "1234", {}, {}, {}, {}, function(err, data) { expect(addSharesStub.calledOnce).to.be.true; expect(err).to.exist; expect(err.message).to.equal("Cryptography error"); + expect(data).to.be.null; done(); }); }); it("should call callback with error when extractPin fails", function(done) { var thrownError = new Error; - var addSharesStub = sinon.stub(client.crypto, "addShares"); + sinon.stub(client.crypto, "addShares"); var extractPinStub = sinon.stub(client.crypto, "extractPin").throws(thrownError); - client._createIdentity("test@example.com", "1234", {}, {}, {}, {}, function(err) { + client._createIdentity("test@example.com", "1234", {}, {}, {}, {}, function(err, data) { expect(extractPinStub.calledOnce).to.be.true; expect(err).to.exist; expect(err).to.equal(thrownError); + expect(data).to.be.null; done(); }); }); @@ -297,13 +310,14 @@ describe("Client register", function () { var client; before(function () { - client = new Client(testData.init()); + client = new Client(testConfig()); }); it("should return error w/o userId", function () { client.register("", null, function () {}, function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Empty user ID"); + expect(data).to.be.null; }); }); @@ -311,18 +325,20 @@ describe("Client register", function () { client.register("test@example.com", null, function () {}, function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Empty activation token"); + expect(data).to.be.null; }); }); it("should go through the registration flow", function (done) { var registrationStub = sinon.stub(client, "_createMPinID").yields(null, { pinLength: 4, projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); var getSecretStub = sinon.stub(client, "_getSecret").yields(null); - var createIdentityStub = sinon.stub(client, "_createIdentity").yields(null); + var createIdentityStub = sinon.stub(client, "_createIdentity").yields(null, { identityData: true }); client.register("test@example.com", "activationToken", function (passPin) { passPin("1234"); }, function (err, data) { expect(err).to.be.null; + expect(data).to.deep.equal({ identityData: true }); expect(registrationStub.calledOnce).to.be.true; expect(getSecretStub.calledTwice).to.be.true; expect(createIdentityStub.calledOnce).to.be.true; @@ -338,6 +354,7 @@ describe("Client register", function () { passPin("1234"); }, function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -352,6 +369,7 @@ describe("Client register", function () { passPin("1234"); }, function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -363,6 +381,7 @@ describe("Client register", function () { passPin("1234"); }, function (err, data) { expect(err).to.exist; + expect(data).to.be.null; done(); }); }); @@ -389,6 +408,7 @@ describe("Client register", function () { }, function (err, data) { expect(err).to.exist; expect(err.message).to.equal("Invalid activation token"); + expect(data).to.be.null; done(); }); }); @@ -401,35 +421,38 @@ describe("Client register", function () { }, function(err, data) { expect(err).to.exist; expect(err.message).to.equal("Project mismatch"); + expect(data).to.be.null; expect(client.users.exists("test@example.com")).to.be.false; done(); }); }); it("should pass provided PIN length to the PIN callback", function (done) { - var registrationStub = sinon.stub(client, "_createMPinID").yields(null, { pinLength: 5, projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); - var getSecretStub = sinon.stub(client, "_getSecret").yields(null); - var createIdentityStub = sinon.stub(client, "_createIdentity").yields(null, true); + sinon.stub(client, "_createMPinID").yields(null, { pinLength: 5, projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); + sinon.stub(client, "_getSecret").yields(null); + sinon.stub(client, "_createIdentity").yields(null, { identity: true }); client.register("test@example.com", "activationToken", function (passPin, pinLength) { expect(pinLength).to.equal(5); passPin("1234"); }, function (err, data) { expect(err).to.be.null; + expect(data).to.deep.equal({ identity: true }); done(); }); }); it("should pass default PIN length to the PIN callback", function (done) { - var registrationStub = sinon.stub(client, "_createMPinID").yields(null, { projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); - var getSecretStub = sinon.stub(client, "_getSecret").yields(null); - var createIdentityStub = sinon.stub(client, "_createIdentity").yields(null, true); + sinon.stub(client, "_createMPinID").yields(null, { projectId: "projectID", secretUrls: ["http://example.com/secret1", "http://example.com/secret2"] }); + sinon.stub(client, "_getSecret").yields(null); + sinon.stub(client, "_createIdentity").yields(null, { identity: true }); client.register("test@example.com", "activationToken", function (passPin, pinLength) { expect(pinLength).to.equal(4); passPin("1234"); }, function (err, data) { expect(err).to.be.null; + expect(data).to.deep.equal({ identity: true }); done(); }); }); diff --git a/test/test-users.js b/test/test-users.js index b64801e..a6cbbb9 100644 --- a/test/test-users.js +++ b/test/test-users.js @@ -430,7 +430,7 @@ describe("Users remove", function () { afterEach(function () { users.store.restore && users.store.restore(); - }) + }); }); describe("Users get", function () {