From: Chris Duncan Date: Thu, 5 Dec 2024 23:51:10 +0000 (-0800) Subject: Create our own testing framework. Needs some double-checking on accuracy. X-Git-Url: https://zoso.dev/?a=commitdiff_plain;h=a1989a950b794af253a57897f97d02264cd7b25a;p=libnemo.git Create our own testing framework. Needs some double-checking on accuracy. --- diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..024ed21 Binary files /dev/null and b/favicon.ico differ diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..3013080 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,199 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import type { Config } from 'jest' + +const config: Config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rs", + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + coveragePathIgnorePatterns: [ + "/node_modules/" + ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + moduleDirectories: [ + "node_modules" + ], + + // An array of file extensions your modules use + moduleFileExtensions: [ + "js", + "mjs", + "cjs", + "jsx", + "ts", + "tsx", + "json", + "node" + ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "jsdom", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: [ + "**/__tests__/**/*.m[jt]s?(x)", + "**/?(*.)+(spec|test).m[tj]s?(x)" + ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + transform: {}, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +} + +export default config diff --git a/package-lock.json b/package-lock.json index 4bd52d2..149f0bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "@types/web-bluetooth": "^0.0.20", "esbuild": "^0.24.0", "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "ts-node": "^10.9.2", "typescript": "^5.6.3" }, "funding": { @@ -548,6 +550,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", @@ -1044,6 +1070,44 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1126,6 +1190,18 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, "node_modules/@types/node": { "version": "22.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", @@ -1143,6 +1219,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/w3c-web-hid": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/w3c-web-hid/-/w3c-web-hid-1.0.6.tgz", @@ -1181,6 +1264,64 @@ "dev": true, "license": "MIT" }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1237,6 +1378,13 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1247,6 +1395,13 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -1598,6 +1753,19 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1634,6 +1802,13 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1649,6 +1824,48 @@ "node": ">= 8" } }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -1667,6 +1884,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, + "license": "MIT" + }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -1692,6 +1916,16 @@ "node": ">=0.10.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -1702,6 +1936,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -1712,6 +1956,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.70", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.70.tgz", @@ -1739,6 +1997,19 @@ "dev": true, "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1809,6 +2080,28 @@ "node": ">=8" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1823,6 +2116,26 @@ "node": ">=4" } }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -1927,6 +2240,21 @@ "node": ">=8" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2064,6 +2392,19 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -2071,6 +2412,35 @@ "dev": true, "license": "MIT" }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -2081,6 +2451,19 @@ "node": ">=10.17.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", @@ -2183,6 +2566,13 @@ "node": ">=0.12.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -2474,6 +2864,34 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/jest-environment-node": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", @@ -2878,6 +3296,52 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -2977,6 +3441,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -3008,6 +3479,29 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -3082,6 +3576,13 @@ "node": ">=8" } }, + "node_modules/nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3182,6 +3683,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3304,6 +3818,29 @@ "node": ">= 6" } }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -3321,6 +3858,13 @@ ], "license": "MIT" }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -3338,6 +3882,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -3399,6 +3950,26 @@ "tslib": "^2.1.0" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -3601,6 +4172,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -3636,6 +4214,79 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -3687,6 +4338,16 @@ "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -3718,6 +4379,24 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -3733,6 +4412,19 @@ "node": ">=10.12.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -3743,6 +4435,53 @@ "makeerror": "1.0.12" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3798,6 +4537,45 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -3844,6 +4622,16 @@ "node": ">=12" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index f54178a..106a743 100644 --- a/package.json +++ b/package.json @@ -43,11 +43,11 @@ }, "scripts": { "build": "rm -rf dist && tsc && esbuild main.min=dist/main.js global.min=dist/global.js --outdir=dist --target=esnext --format=esm --platform=browser --bundle --sourcemap", - "test": "npm run build && jest", + "test": "npm run build && esbuild test.min=test/main.mjs --outdir=dist --target=esnext --format=esm --platform=browser --bundle --sourcemap", "test:node": "npm run build -- --platform=node && node --test --test-force-exit --env-file .env", "test:coverage": "npm run test:node -- --experimental-test-coverage", "test:coverage:report": "npm run test:coverage -- --test-reporter=lcov --test-reporter-destination=coverage.info && genhtml coverage.info --output-directory test/coverage && rm coverage.info && xdg-open test/coverage/index.html", - "test:performance": "npm run test perf/*" + "test:performance": "npm run build && npm run jest -- ./perf/*" }, "imports": { "#*": "./*" @@ -65,6 +65,8 @@ "@types/web-bluetooth": "^0.0.20", "esbuild": "^0.24.0", "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "ts-node": "^10.9.2", "typescript": "^5.6.3" }, "type": "module", diff --git a/src/lib/rpc.ts b/src/lib/rpc.ts index 0e28d59..d43f237 100644 --- a/src/lib/rpc.ts +++ b/src/lib/rpc.ts @@ -25,10 +25,11 @@ export class Rpc { * @returns {Promise} JSON-formatted RPC results from the node */ async call (action: string, data?: { [key: string]: any }): Promise { + var process: any = process || null this.#validate(action) const headers: { [key: string]: string } = {} headers['Content-Type'] = 'application/json' - if (this.#n && process.env.LIBNEMO_RPC_API_KEY) { + if (this.#n && process?.env?.LIBNEMO_RPC_API_KEY) { headers[this.#n] = process.env.LIBNEMO_RPC_API_KEY } diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts index 142f2b9..2c3ae3b 100644 --- a/src/lib/wallet.ts +++ b/src/lib/wallet.ts @@ -272,9 +272,9 @@ export class Bip44Wallet extends Wallet { if (!Bip44Wallet.#isInternal) { throw new Error(`Bip44Wallet cannot be instantiated directly. Use 'await Bip44Wallet.create()' instead.`) } + Bip44Wallet.#isInternal = false super(seed, mnemonic, id) this.#pool = new Pool(Bip44Ckd) - Bip44Wallet.#isInternal = false } /** @@ -296,7 +296,6 @@ export class Bip44Wallet extends Wallet { */ static async create (key: CryptoKey, salt?: string): Promise static async create (passkey: string | CryptoKey, salt: string = ''): Promise { - Bip44Wallet.#isInternal = true try { const e = new Entropy() return await Bip44Wallet.fromEntropy(passkey as string, e.hex, salt) @@ -326,11 +325,11 @@ export class Bip44Wallet extends Wallet { */ static async fromEntropy (key: CryptoKey, entropy: string, salt?: string): Promise static async fromEntropy (passkey: string | CryptoKey, entropy: string, salt: string = ''): Promise { - Bip44Wallet.#isInternal = true try { const e = new Entropy(entropy) const m = await Bip39Mnemonic.fromEntropy(e.hex) const s = await m.toBip39Seed(salt) + Bip44Wallet.#isInternal = true const wallet = new this(s, m) await wallet.lock(passkey as string) return wallet @@ -358,10 +357,10 @@ export class Bip44Wallet extends Wallet { */ static async fromMnemonic (key: CryptoKey, mnemonic: string, salt?: string): Promise static async fromMnemonic (passkey: string | CryptoKey, mnemonic: string, salt: string = ''): Promise { - Bip44Wallet.#isInternal = true try { const m = await Bip39Mnemonic.fromPhrase(mnemonic) const s = await m.toBip39Seed(salt) + Bip44Wallet.#isInternal = true const wallet = new this(s, m) await wallet.lock(passkey as string) return wallet @@ -391,13 +390,13 @@ export class Bip44Wallet extends Wallet { */ static async fromSeed (key: CryptoKey, seed: string): Promise static async fromSeed (passkey: string | CryptoKey, seed: string): Promise { - Bip44Wallet.#isInternal = true if (seed.length !== SEED_LENGTH_BIP44) { throw new Error(`Expected a ${SEED_LENGTH_BIP44}-character seed, but received ${seed.length}-character string.`) } if (!/^[0-9a-fA-F]+$/i.test(seed)) { throw new Error('Seed contains invalid hexadecimal characters.') } + Bip44Wallet.#isInternal = true const wallet = new this(seed) await wallet.lock(passkey as string) return wallet @@ -410,12 +409,11 @@ export class Bip44Wallet extends Wallet { * @returns {Bip44Wallet} Restored locked Bip44Wallet */ static async restore (id: string): Promise { - Bip44Wallet.#isInternal = true if (typeof id !== 'string' || id === '') { throw new TypeError('Wallet ID is required to restore') } - const wallet = new this('', undefined, id) - return wallet + Bip44Wallet.#isInternal = true + return new this('', undefined, id) } /** @@ -455,8 +453,8 @@ export class Blake2bWallet extends Wallet { if (!Blake2bWallet.#isInternal) { throw new Error(`Blake2bWallet cannot be instantiated directly. Use 'await Blake2bWallet.create()' instead.`) } - super(seed, mnemonic, id) Blake2bWallet.#isInternal = false + super(seed, mnemonic, id) } /** @@ -476,7 +474,6 @@ export class Blake2bWallet extends Wallet { */ static async create (key: CryptoKey): Promise static async create (passkey: string | CryptoKey): Promise { - Blake2bWallet.#isInternal = true try { const seed = new Entropy() return await Blake2bWallet.fromSeed(passkey as string, seed.hex) @@ -504,7 +501,6 @@ export class Blake2bWallet extends Wallet { */ static async fromSeed (key: CryptoKey, seed: string): Promise static async fromSeed (passkey: string | CryptoKey, seed: string): Promise { - Blake2bWallet.#isInternal = true if (seed.length !== SEED_LENGTH_BLAKE2B) { throw new Error(`Expected a ${SEED_LENGTH_BLAKE2B}-character seed, but received ${seed.length}-character string.`) } @@ -513,6 +509,7 @@ export class Blake2bWallet extends Wallet { } const s = seed const m = await Bip39Mnemonic.fromEntropy(seed) + Blake2bWallet.#isInternal = true const wallet = new this(s, m) await wallet.lock(passkey as string) return wallet @@ -535,10 +532,10 @@ export class Blake2bWallet extends Wallet { */ static async fromMnemonic (key: CryptoKey, mnemonic: string): Promise static async fromMnemonic (passkey: string | CryptoKey, mnemonic: string): Promise { - Blake2bWallet.#isInternal = true try { const m = await Bip39Mnemonic.fromPhrase(mnemonic) const s = await m.toBlake2bSeed() + Blake2bWallet.#isInternal = true const wallet = new this(s, m) await wallet.lock(passkey as string) return wallet @@ -554,12 +551,11 @@ export class Blake2bWallet extends Wallet { * @returns {Blake2bWallet} Restored locked Blake2bWallet */ static async restore (id: string): Promise { - Blake2bWallet.#isInternal = true if (typeof id !== 'string' || id === '') { throw new TypeError('Wallet ID is required to restore') } - const wallet = new this('', undefined, id) - return wallet + Blake2bWallet.#isInternal = true + return new this('', undefined, id) } /** @@ -602,9 +598,9 @@ export class LedgerWallet extends Wallet { if (!LedgerWallet.#isInternal) { throw new Error(`LedgerWallet cannot be instantiated directly. Use 'await LedgerWallet.create()' instead.`) } + LedgerWallet.#isInternal = false super(undefined, undefined, id) this.#ledger = ledger - LedgerWallet.#isInternal = false } /** @@ -614,9 +610,9 @@ export class LedgerWallet extends Wallet { * @returns {LedgerWallet} A wallet containing accounts and a Ledger device communication object */ static async create (): Promise { - LedgerWallet.#isInternal = true const { Ledger } = await import('./ledger.js') const l = await Ledger.init() + LedgerWallet.#isInternal = true return new this(l) } @@ -627,12 +623,12 @@ export class LedgerWallet extends Wallet { * @returns {LedgerWallet} Restored LedgerWallet */ static async restore (id: string): Promise { - LedgerWallet.#isInternal = true if (typeof id !== 'string' || id === '') { throw new TypeError('Wallet ID is required to restore') } const { Ledger } = await import('./ledger.js') const l = await Ledger.init() + LedgerWallet.#isInternal = true return new this(l, id) } diff --git a/test.html b/test.html index 92bc8b0..f3aa38b 100644 --- a/test.html +++ b/test.html @@ -1,8 +1,10 @@ + - + diff --git a/test/GLOBALS.mjs b/test/GLOBALS.mjs index 1c780fd..410d2ae 100644 --- a/test/GLOBALS.mjs +++ b/test/GLOBALS.mjs @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: 2024 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { EventEmitter } from 'node:events' -EventEmitter.defaultMaxListeners = navigator.hardwareConcurrency * 2 - if (globalThis.sessionStorage == null) { let _sessionStorage = {} Object.defineProperty(globalThis, 'sessionStorage', { @@ -18,3 +15,74 @@ if (globalThis.sessionStorage == null) { enumerable: true }) } + +export function skip (name, ...args) { + console.log(`SKIP: ${name}`) +} + +export function test (name, fn) { + if (fn instanceof Promise) { + try { + fn.then(() => console.log(`PASS: ${name}`)) + .catch((err) => console.error(`FAIL: ${name}`)) + } catch (err) { + console.error(`FAIL: ${name}`) + console.error(err) + } + } else { + try { + fn() + console.log(`PASS: ${name}`) + } catch (err) { + console.error(`FAIL: ${name}`) + console.error(err) + } + } +} + +export const assert = { + ok: (bool) => { + if (typeof bool !== 'boolean') throw new Error('Invalid assertion') + if (!bool) throw new Error(`test result falsy`) + return true + }, + exists: (a) => { + let b = a || null + if (b == null) throw new Error(`argument is ${typeof a}`) + return b != null + }, + equals: (a, b) => { + return a === b + }, + notEqual: (a, b) => { + return a !== b + }, + rejects: (fn, msg) => { + try { + if (!(fn instanceof Promise)) throw new Error(msg ?? 'expected async function') + fn.then(() => { throw new Error(msg ?? 'expected async function to reject') }) + .catch((err) => { return true }) + } catch (err) { + return true + } + }, + resolves: (fn, msg) => { + try { + if (!(fn instanceof Promise)) throw new Error('expected async function') + fn.then(() => { return true }) + .catch((err) => { throw new Error(msg ?? 'expected async function to resolve') }) + return true + } catch (err) { + throw new Error(msg ?? 'expected async function to resolve') + } + }, + throws: (fn, msg) => { + try { + const r = fn() + if (r instanceof Promise) throw new Error('expected synchronous function') + throw new Error(msg ?? `expected function to throw an exception`) + } catch (err) { + return true + } + } +} diff --git a/test/create-wallet.test.mjs b/test/create-wallet.test.mjs index 80ff375..ec7c448 100644 --- a/test/create-wallet.test.mjs +++ b/test/create-wallet.test.mjs @@ -3,62 +3,59 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet, LedgerWallet } from '#dist/main.js' -describe('creating a new wallet', async () => { - test('BIP-44 wallet with random entropy', async () => { - const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) +test('BIP-44 wallet with random entropy', async () => { + const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - expect('id' in wallet).toBeTruthy() - expect(/[A-Fa-f0-9]{32,64}/.test(wallet.id)).toBeTruthy() - expect('mnemonic' in wallet).toBeTruthy() - expect(/^(?:[a-z]{3,} ){11,23}[a-z]{3,}$/.test(wallet.mnemonic)).toBeTruthy() - expect('seed' in wallet).toBeTruthy() - expect(/[A-Fa-f0-9]{32,64}/.test(wallet.seed)).toBeTruthy() - }) - - test('BLAKE2b wallet with random entropy', async () => { - const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + assert.ok('id' in wallet) + assert.ok(/[A-Fa-f0-9]{32,64}/.test(wallet.id)) + assert.ok('mnemonic' in wallet) + assert.ok(/^(?:[a-z]{3,} ){11,23}[a-z]{3,}$/.test(wallet.mnemonic)) + assert.ok('seed' in wallet) + assert.ok(/[A-Fa-f0-9]{32,64}/.test(wallet.seed)) +}) - expect('id' in wallet).toBeTruthy() - expect(/[A-Fa-f0-9]{32,64}/.test(wallet.id)).toBeTruthy() - expect('mnemonic' in wallet).toBeTruthy() - expect(/^(?:[a-z]{3,} ){11,23}[a-z]{3,}$/.test(wallet.mnemonic)).toBeTruthy() - expect('seed' in wallet).toBeTruthy() - expect(/[A-Fa-f0-9]{32,64}/.test(wallet.seed)).toBeTruthy() - }) +test('BLAKE2b wallet with random entropy', async () => { + const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - test('BIP-44 replace invalid salt with empty string', async () => { - const invalidArgs = [null, true, false, 0, 1, 2, { "foo": "bar" }] - for (const arg of invalidArgs) { - //@ts-expect-error - await assert.doesNotReject(Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD, arg), `Rejected ${arg}`) - } - }) + assert.ok('id' in wallet) + assert.ok(/[A-Fa-f0-9]{32,64}/.test(wallet.id)) + assert.ok('mnemonic' in wallet) + assert.ok(/^(?:[a-z]{3,} ){11,23}[a-z]{3,}$/.test(wallet.mnemonic)) + assert.ok('seed' in wallet) + assert.ok(/[A-Fa-f0-9]{32,64}/.test(wallet.seed)) +}) - test('fail when using new', async () => { +test('BIP-44 replace invalid salt with empty string', async () => { + const invalidArgs = [null, true, false, 0, 1, 2, { "foo": "bar" }] + for (const arg of invalidArgs) { //@ts-expect-error - expect(() => new Bip44Wallet()).toThrow() - //@ts-expect-error - expect(() => new Blake2bWallet()).toThrow() - //@ts-expect-error - expect(() => new LedgerWallet()).toThrow() - }) + assert.resolves(Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD, arg)) + } +}) - test('fail without a password', async () => { - //@ts-expect-error - expect(async () => await Bip44Wallet.create()).rejects() - //@ts-expect-error - expect(async () => await Blake2bWallet.create()).rejects() - }) +test('fail when using new', () => { + //@ts-expect-error + assert.throws(() => new Bip44Wallet()) + //@ts-expect-error + assert.throws(() => new Blake2bWallet()) + //@ts-expect-error + assert.throws(() => new LedgerWallet()) +}) + +test('fail without a password', async () => { + //@ts-expect-error + assert.rejects(Bip44Wallet.create()) + //@ts-expect-error + assert.rejects(Blake2bWallet.create()) +}) - test.skip('connect to ledger', async () => { - const wallet = await LedgerWallet.create() - expect(wallet).toBeDefined() - }) +skip('connect to ledger', async () => { + const wallet = await LedgerWallet.create() + assert.ok(wallet) }) diff --git a/test/derive-accounts.test.mjs b/test/derive-accounts.test.mjs index 9dc9513..44ecd26 100644 --- a/test/derive-accounts.test.mjs +++ b/test/derive-accounts.test.mjs @@ -3,46 +3,45 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet, LedgerWallet } from '#dist/main.js' -describe('derive child accounts from the same seed', async () => { +test('derive child accounts from the same seed', async () => { const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) test('should derive the first account from the given BIP-44 seed', async () => { const accounts = await wallet.accounts() - assert.equal(accounts.length, 1) - assert.equal(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) - assert.equal(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) - assert.equal(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(accounts.length, 1) + assert.equals(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) + assert.equals(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) + assert.equals(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) }) test('should derive low indexed accounts from the given BIP-44 seed', async () => { const accounts = await wallet.accounts(1, 2) - assert.equal(accounts.length, 2) - assert.equal(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_1) - assert.equal(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_1) - assert.equal(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(accounts[1].privateKey, NANO_TEST_VECTORS.PRIVATE_2) - assert.equal(accounts[1].publicKey, NANO_TEST_VECTORS.PUBLIC_2) - assert.equal(accounts[1].address, NANO_TEST_VECTORS.ADDRESS_2) + assert.equals(accounts.length, 2) + assert.equals(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_1) + assert.equals(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_1) + assert.equals(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(accounts[1].privateKey, NANO_TEST_VECTORS.PRIVATE_2) + assert.equals(accounts[1].publicKey, NANO_TEST_VECTORS.PUBLIC_2) + assert.equals(accounts[1].address, NANO_TEST_VECTORS.ADDRESS_2) }) test('should derive high indexed accounts from the given seed', async () => { const accounts = await wallet.accounts(0x70000000, 0x700000ff) - assert.equal(accounts.length, 0x100) + assert.equals(accounts.length, 0x100) for (const a of accounts) { - assert.ok(a) - assert.ok(a.address) - assert.ok(a.publicKey) - assert.ok(a.privateKey) - assert.ok(a.index != null) + assert.exists(a) + assert.exists(a.address) + assert.exists(a.publicKey) + assert.exists(a.privateKey) + assert.exists(a.index) } }) @@ -51,36 +50,36 @@ describe('derive child accounts from the same seed', async () => { await bwallet.unlock(NANO_TEST_VECTORS.PASSWORD) const lowAccounts = await bwallet.accounts(0, 2) - assert.equal(lowAccounts.length, 3) + assert.equals(lowAccounts.length, 3) for (const a of lowAccounts) { - assert.ok(a) - assert.ok(a.address) - assert.ok(a.publicKey) - assert.ok(a.privateKey) - assert.ok(a.index != null) + assert.exists(a) + assert.exists(a.address) + assert.exists(a.publicKey) + assert.exists(a.privateKey) + assert.exists(a.index) } const highAccounts = await bwallet.accounts(0x70000000, 0x700000ff) - assert.equal(highAccounts.length, 0x100) + assert.equals(highAccounts.length, 0x100) for (const a of highAccounts) { - assert.ok(a) - assert.ok(a.address) - assert.ok(a.publicKey) - assert.ok(a.privateKey) - assert.ok(a.index != null) + assert.exists(a) + assert.exists(a.address) + assert.exists(a.publicKey) + assert.exists(a.privateKey) + assert.exists(a.index) } }) }) -describe.skip('Ledger device accounts', async () => { +skip('Ledger device accounts', async () => { const wallet = await LedgerWallet.create() test('should fetch the first account from a Ledger device', async () => { const accounts = await wallet.accounts() - assert.equal(accounts.length, 1) - assert.ok(accounts[0].publicKey) - assert.ok(accounts[0].address) + assert.equals(accounts.length, 1) + assert.exists(accounts[0].publicKey) + assert.exists(accounts[0].address) }) }) diff --git a/test/import-wallet.test.mjs b/test/import-wallet.test.mjs index 56d913a..1585620 100644 --- a/test/import-wallet.test.mjs +++ b/test/import-wallet.test.mjs @@ -3,12 +3,11 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, test } from '#test/GLOBALS.mjs' import { BIP32_TEST_VECTORS, CUSTOM_TEST_VECTORS, NANO_TEST_VECTORS, TREZOR_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Account, Bip44Wallet, Blake2bWallet } from '#dist/main.js' -describe('import wallet with test vectors test', () => { +test('import wallet with test vectors test', () => { test('should successfully import a wallet with the official Nano test vectors mnemonic', async () => { const wallet = await Bip44Wallet.fromMnemonic(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.MNEMONIC, NANO_TEST_VECTORS.PASSWORD) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) @@ -17,17 +16,17 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.ok(accounts[0] instanceof Account) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) - assert.equal(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) - assert.equal(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) - assert.equal(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) + assert.equals(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) + assert.equals(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) }) test('should successfully import a wallet with the checksum starting with a zero', async () => { const wallet = await Bip44Wallet.fromMnemonic(NANO_TEST_VECTORS.PASSWORD, 'food define cancel major spoon trash cigar basic aim bless wolf win ability seek paddle bench seed century group they mercy address monkey cake') await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - assert.equal(wallet.seed, 'F665F804E5907985455D1E5A7AD344843A2ED4179A7E06EEF263DE925FF6F4C0991B0A9344FCEE939FE0F1B1841B8C9B20FEACF6B954B74B2D26A01906B758E2') + assert.equals(wallet.seed, 'F665F804E5907985455D1E5A7AD344843A2ED4179A7E06EEF263DE925FF6F4C0991B0A9344FCEE939FE0F1B1841B8C9B20FEACF6B954B74B2D26A01906B758E2') }) test('should successfully import a wallet with a 12-word phrase', async () => { @@ -36,11 +35,11 @@ describe('import wallet with test vectors test', () => { const accounts = await wallet.accounts() const account = accounts[0] - assert.equal(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_0) - assert.equal(wallet.seed, CUSTOM_TEST_VECTORS.SEED_0) - assert.equal(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_0) - assert.equal(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_0) - assert.equal(account.address, CUSTOM_TEST_VECTORS.ADDRESS_0) + assert.equals(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_0) + assert.equals(wallet.seed, CUSTOM_TEST_VECTORS.SEED_0) + assert.equals(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_0) + assert.equals(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_0) + assert.equals(account.address, CUSTOM_TEST_VECTORS.ADDRESS_0) }) test('should successfully import a wallet with a 15-word phrase', async () => { @@ -49,11 +48,11 @@ describe('import wallet with test vectors test', () => { const accounts = await wallet.accounts() const account = accounts[0] - assert.equal(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_1) - assert.equal(wallet.seed, CUSTOM_TEST_VECTORS.SEED_1) - assert.equal(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_1) - assert.equal(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_1) - assert.equal(account.address, CUSTOM_TEST_VECTORS.ADDRESS_1) + assert.equals(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_1) + assert.equals(wallet.seed, CUSTOM_TEST_VECTORS.SEED_1) + assert.equals(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_1) + assert.equals(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_1) + assert.equals(account.address, CUSTOM_TEST_VECTORS.ADDRESS_1) }) test('should successfully import a wallet with a 18-word phrase', async () => { @@ -62,11 +61,11 @@ describe('import wallet with test vectors test', () => { const accounts = await wallet.accounts() const account = accounts[0] - assert.equal(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_2) - assert.equal(wallet.seed, CUSTOM_TEST_VECTORS.SEED_2) - assert.equal(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_2) - assert.equal(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_2) - assert.equal(account.address, CUSTOM_TEST_VECTORS.ADDRESS_2) + assert.equals(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_2) + assert.equals(wallet.seed, CUSTOM_TEST_VECTORS.SEED_2) + assert.equals(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_2) + assert.equals(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_2) + assert.equals(account.address, CUSTOM_TEST_VECTORS.ADDRESS_2) }) test('should successfully import a wallet with a 21-word phrase', async () => { @@ -75,11 +74,11 @@ describe('import wallet with test vectors test', () => { const accounts = await wallet.accounts() const account = accounts[0] - assert.equal(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_3) - assert.equal(wallet.seed, CUSTOM_TEST_VECTORS.SEED_3) - assert.equal(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_3) - assert.equal(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_3) - assert.equal(account.address, CUSTOM_TEST_VECTORS.ADDRESS_3) + assert.equals(wallet.mnemonic, CUSTOM_TEST_VECTORS.MNEMONIC_3) + assert.equals(wallet.seed, CUSTOM_TEST_VECTORS.SEED_3) + assert.equals(account.privateKey, CUSTOM_TEST_VECTORS.PRIVATE_3) + assert.equals(account.publicKey, CUSTOM_TEST_VECTORS.PUBLIC_3) + assert.equals(account.address, CUSTOM_TEST_VECTORS.ADDRESS_3) }) test('should successfully import a wallet with the official Nano test vectors seed', async () => { @@ -90,11 +89,11 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.ok(accounts[0] instanceof Account) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) - assert.equal(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) - assert.equal(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) - assert.equal(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(accounts[0].privateKey, NANO_TEST_VECTORS.PRIVATE_0) + assert.equals(accounts[0].publicKey, NANO_TEST_VECTORS.PUBLIC_0) + assert.equals(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0) }) test('should successfully import a BIP-44 wallet with the zero seed', async () => { @@ -104,15 +103,15 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.SEED_0.toUpperCase()) - assert.equal(accounts.length, 4) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.SEED_0.toUpperCase()) + assert.equals(accounts.length, 4) for (let i = 0; i < accounts.length; i++) { assert.ok(accounts[i]) assert.ok(accounts[i].address) assert.ok(accounts[i].publicKey) assert.ok(accounts[i].privateKey) - assert.equal(accounts[i].index, i) + assert.equals(accounts[i].index, i) } }) @@ -123,15 +122,15 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) - assert.equal(accounts.length, 4) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) + assert.equals(accounts.length, 4) for (let i = 0; i < accounts.length; i++) { assert.ok(accounts[i]) assert.ok(accounts[i].address) assert.ok(accounts[i].publicKey) assert.ok(accounts[i].privateKey) - assert.equal(accounts[i].index, i) + assert.equals(accounts[i].index, i) } }) @@ -142,18 +141,18 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) assert.ok(accounts[0] instanceof Account) - assert.equal(accounts[0].index, 0) - assert.equal(accounts[0].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PRIVATE_0) - assert.equal(accounts[0].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PUBLIC_0) - assert.equal(accounts[0].address, TREZOR_TEST_VECTORS.BLAKE2B_1_ADDRESS_0) + assert.equals(accounts[0].index, 0) + assert.equals(accounts[0].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PRIVATE_0) + assert.equals(accounts[0].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PUBLIC_0) + assert.equals(accounts[0].address, TREZOR_TEST_VECTORS.BLAKE2B_1_ADDRESS_0) assert.ok(accounts[1] instanceof Account) - assert.equal(accounts[1].index, 1) - assert.equal(accounts[1].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PRIVATE_1) - assert.equal(accounts[1].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PUBLIC_1) - assert.equal(accounts[1].address, TREZOR_TEST_VECTORS.BLAKE2B_1_ADDRESS_1) + assert.equals(accounts[1].index, 1) + assert.equals(accounts[1].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PRIVATE_1) + assert.equals(accounts[1].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_1_PUBLIC_1) + assert.equals(accounts[1].address, TREZOR_TEST_VECTORS.BLAKE2B_1_ADDRESS_1) }) test('should get identical BLAKE2b wallets when created with a seed versus with its derived mnemonic', async () => { @@ -165,17 +164,17 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.ok(walletAccount) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_2) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_2) const imported = await Blake2bWallet.fromMnemonic(TREZOR_TEST_VECTORS.PASSWORD, TREZOR_TEST_VECTORS.MNEMONIC_2) await imported.unlock(TREZOR_TEST_VECTORS.PASSWORD) const importedAccounts = await imported.accounts() const importedAccount = importedAccounts[0] - assert.equal(imported.mnemonic, wallet.mnemonic) - assert.equal(imported.seed, wallet.seed) - assert.equal(importedAccount.privateKey, walletAccount.privateKey) - assert.equal(importedAccount.publicKey, walletAccount.publicKey) + assert.equals(imported.mnemonic, wallet.mnemonic) + assert.equals(imported.seed, wallet.seed) + assert.equals(importedAccount.privateKey, walletAccount.privateKey) + assert.equals(importedAccount.publicKey, walletAccount.publicKey) }) test('should get identical BLAKE2b wallets when created with max entropy value', async () => { @@ -186,16 +185,16 @@ describe('import wallet with test vectors test', () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.ok(accounts[0] instanceof Account) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_3) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_3) - assert.equal(accounts[0].index, 0) - assert.equal(accounts[0].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_3_PRIVATE_0) - assert.equal(accounts[0].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_3_PUBLIC_0) - assert.equal(accounts[0].address, TREZOR_TEST_VECTORS.BLAKE2B_3_ADDRESS_0) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_3) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_3) + assert.equals(accounts[0].index, 0) + assert.equals(accounts[0].privateKey, TREZOR_TEST_VECTORS.BLAKE2B_3_PRIVATE_0) + assert.equals(accounts[0].publicKey, TREZOR_TEST_VECTORS.BLAKE2B_3_PUBLIC_0) + assert.equals(accounts[0].address, TREZOR_TEST_VECTORS.BLAKE2B_3_ADDRESS_0) }) }) -describe('invalid wallet', async () => { +test('invalid wallet', async () => { test('throw when given invalid entropy', async () => { assert.rejects(async () => await Bip44Wallet.fromEntropy(NANO_TEST_VECTORS.PASSWORD, '6CAF5A42BB8074314AAE20295975ECE663BE7AAD945A73613D193B0CC41C797')) assert.rejects(async () => await Bip44Wallet.fromEntropy(NANO_TEST_VECTORS.PASSWORD, '6CAF5A42BB8074314AAE20295975ECE663BE7AAD945A73613D193B0CC41C79701')) @@ -204,36 +203,36 @@ describe('invalid wallet', async () => { test('should throw when given a seed with an invalid length', async () => { await assert.rejects(Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED + 'f'), - { message: `Expected a ${NANO_TEST_VECTORS.BIP39_SEED.length}-character seed, but received ${NANO_TEST_VECTORS.BIP39_SEED.length + 1}-character string.` }) + `Expected a ${NANO_TEST_VECTORS.BIP39_SEED.length}-character seed, but received ${NANO_TEST_VECTORS.BIP39_SEED.length + 1}-character string.`) await assert.rejects(Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED.slice(0, -1)), - { message: `Expected a ${NANO_TEST_VECTORS.BIP39_SEED.length}-character seed, but received ${NANO_TEST_VECTORS.BIP39_SEED.length - 1}-character string.` }) + `Expected a ${NANO_TEST_VECTORS.BIP39_SEED.length}-character seed, but received ${NANO_TEST_VECTORS.BIP39_SEED.length - 1}-character string.`) }) test('should throw when given a seed containing non-hex characters', async () => { await assert.rejects(Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, TREZOR_TEST_VECTORS.SEED_0.replace(/./, 'g')), - { message: 'Seed contains invalid hexadecimal characters.' }) + 'Seed contains invalid hexadecimal characters.') await assert.rejects(Blake2bWallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, TREZOR_TEST_VECTORS.ENTROPY_1.replace(/./, 'g')), - { message: 'Seed contains invalid hexadecimal characters.' }) + 'Seed contains invalid hexadecimal characters.') }) }) -describe('import from storage', async () => { +test('import from storage', async () => { test('should retrieve a Bip44Wallet from storage using an ID', async () => { const id = (await Bip44Wallet.fromMnemonic(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.MNEMONIC, NANO_TEST_VECTORS.PASSWORD)).id const wallet = await Bip44Wallet.restore(id) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - assert.equal(unlockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) }) test('should retrieve a Blake2bWallet from storage using an ID', async () => { @@ -242,15 +241,15 @@ describe('import from storage', async () => { assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - assert.equal(unlockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) }) }) diff --git a/test/lock-unlock-wallet.mjs b/test/lock-unlock-wallet.mjs index 3c271e5..b583555 100644 --- a/test/lock-unlock-wallet.mjs +++ b/test/lock-unlock-wallet.mjs @@ -3,27 +3,26 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS, TREZOR_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '#dist/main.js' -describe('locking and unlocking a Bip44Wallet', async () => { +test('locking and unlocking a Bip44Wallet', async () => { test('should succeed with a password', async () => { const wallet = await Bip44Wallet.fromMnemonic(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.MNEMONIC, NANO_TEST_VECTORS.PASSWORD) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - assert.equal(unlockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) }) test('should succeed with a random CryptoKey', async () => { @@ -35,16 +34,16 @@ describe('locking and unlocking a Bip44Wallet', async () => { assert.ok(lockResult) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(key) - assert.equal(unlockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) }) test('should fail to unlock with different passwords', async () => { @@ -53,7 +52,7 @@ describe('locking and unlocking a Bip44Wallet', async () => { const lockResult = await wallet.lock(TREZOR_TEST_VECTORS.PASSWORD) await assert.rejects(wallet.unlock(NANO_TEST_VECTORS.PASSWORD), { message: 'Failed to unlock wallet' }) - assert.equal(lockResult, true) + assert.equals(lockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.notEqual(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) @@ -68,7 +67,7 @@ describe('locking and unlocking a Bip44Wallet', async () => { const lockResult = await wallet.lock(rightKey) await assert.rejects(wallet.unlock(wrongKey), { message: 'Failed to unlock wallet' }) - assert.equal(lockResult, true) + assert.equals(lockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.notEqual(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) @@ -94,8 +93,8 @@ describe('locking and unlocking a Bip44Wallet', async () => { await assert.rejects(wallet.lock(), { message: 'Failed to lock wallet' }) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) await wallet.lock('password') @@ -115,8 +114,8 @@ describe('locking and unlocking a Bip44Wallet', async () => { await assert.rejects(wallet.lock(1), { message: 'Failed to lock wallet' }) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) - assert.equal(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) + assert.equals(wallet.mnemonic, NANO_TEST_VECTORS.MNEMONIC) + assert.equals(wallet.seed, NANO_TEST_VECTORS.BIP39_SEED) await wallet.lock(NANO_TEST_VECTORS.PASSWORD) @@ -129,22 +128,22 @@ describe('locking and unlocking a Bip44Wallet', async () => { }) }) -describe('locking and unlocking a Blake2bWallet', async () => { +test('locking and unlocking a Blake2bWallet', async () => { test('should succeed with a password', async () => { const wallet = await Blake2bWallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, TREZOR_TEST_VECTORS.ENTROPY_0) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - assert.equal(unlockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_0) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_0) }) test('should succeed with a random CryptoKey', async () => { @@ -153,20 +152,20 @@ describe('locking and unlocking a Blake2bWallet', async () => { const key = await globalThis.crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']) const lockResult = await wallet.lock(key) - assert.equal(lockResult, true) + assert.equals(lockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, '') - assert.equal(wallet.seed, '') + assert.equals(wallet.mnemonic, '') + assert.equals(wallet.seed, '') const unlockResult = await wallet.unlock(key) - assert.equal(lockResult, true) - assert.equal(unlockResult, true) + assert.equals(lockResult, true) + assert.equals(unlockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) }) test('should fail to unlock with different passwords', async () => { @@ -187,7 +186,7 @@ describe('locking and unlocking a Blake2bWallet', async () => { const lockResult = await wallet.lock(rightKey) await assert.rejects(wallet.unlock(wrongKey), { message: 'Failed to unlock wallet' }) - assert.equal(lockResult, true) + assert.equals(lockResult, true) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) assert.notEqual(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) @@ -213,8 +212,8 @@ describe('locking and unlocking a Blake2bWallet', async () => { await assert.rejects(wallet.lock(), { message: 'Failed to lock wallet' }) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) await wallet.lock(NANO_TEST_VECTORS.PASSWORD) @@ -234,8 +233,8 @@ describe('locking and unlocking a Blake2bWallet', async () => { await assert.rejects(wallet.lock(1), { message: 'Failed to lock wallet' }) assert.ok('mnemonic' in wallet) assert.ok('seed' in wallet) - assert.equal(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) - assert.equal(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) + assert.equals(wallet.mnemonic, TREZOR_TEST_VECTORS.MNEMONIC_1) + assert.equals(wallet.seed, TREZOR_TEST_VECTORS.ENTROPY_1) await wallet.lock(NANO_TEST_VECTORS.PASSWORD) diff --git a/test/main.mjs b/test/main.mjs new file mode 100644 index 0000000..f7a990f --- /dev/null +++ b/test/main.mjs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2024 Chris Duncan +// SPDX-License-Identifier: GPL-3.0-or-later + +import './create-wallet.test.mjs' +import './derive-accounts.test.mjs' +import './import-wallet.test.mjs' +import './lock-unlock-wallet.mjs' +import './manage-rolodex.mjs' +import './refresh-accounts.test.mjs' +import './sign-blocks.test.mjs' +import './tools.test.mjs' + +import './perf/account.perf.js' +import './perf/wallet.perf.js' + +console.log('> TESTING COMPLETE <') diff --git a/test/manage-rolodex.mjs b/test/manage-rolodex.mjs index e15d22d..53c0d27 100644 --- a/test/manage-rolodex.mjs +++ b/test/manage-rolodex.mjs @@ -3,31 +3,30 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Rolodex, Tools } from '#dist/main.js' -describe('rolodex valid contact management', async () => { +test('rolodex valid contact management', async () => { test('should create a rolodex and add two contacts', async () => { const rolodex = new Rolodex() - assert.equal(rolodex.constructor, Rolodex) + assert.equals(rolodex.constructor, Rolodex) await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) await rolodex.add('JaneSmith', NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(rolodex.getAllNames().length, 2) - assert.equal(rolodex.getAllNames()[0], 'JohnDoe') - assert.equal(rolodex.getAllNames()[1], 'JaneSmith') - assert.equal(rolodex.getAddresses('JohnDoe').length, 1) - assert.equal(rolodex.getAddresses('JohnDoe')[0], NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(rolodex.getAddresses('JaneSmith').length, 1) - assert.equal(rolodex.getAddresses('JaneSmith')[0], NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(rolodex.getAllNames().length, 2) + assert.equals(rolodex.getAllNames()[0], 'JohnDoe') + assert.equals(rolodex.getAllNames()[1], 'JaneSmith') + assert.equals(rolodex.getAddresses('JohnDoe').length, 1) + assert.equals(rolodex.getAddresses('JohnDoe')[0], NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(rolodex.getAddresses('JaneSmith').length, 1) + assert.equals(rolodex.getAddresses('JaneSmith')[0], NANO_TEST_VECTORS.ADDRESS_1) }) test('should get a name from an address', async () => { const rolodex = new Rolodex() await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(rolodex.getName(NANO_TEST_VECTORS.ADDRESS_0), 'JohnDoe') + assert.equals(rolodex.getName(NANO_TEST_VECTORS.ADDRESS_0), 'JohnDoe') }) test('should add three addresses to the same contact', async () => { @@ -35,46 +34,46 @@ describe('rolodex valid contact management', async () => { await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_1) await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_2) await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(rolodex.getAddresses('JohnDoe').length, 3) - assert.equal(rolodex.getAddresses('JohnDoe')[0], NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(rolodex.getAddresses('JohnDoe')[1], NANO_TEST_VECTORS.ADDRESS_2) - assert.equal(rolodex.getAddresses('JohnDoe')[2], NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(rolodex.getAddresses('JohnDoe').length, 3) + assert.equals(rolodex.getAddresses('JohnDoe')[0], NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(rolodex.getAddresses('JohnDoe')[1], NANO_TEST_VECTORS.ADDRESS_2) + assert.equals(rolodex.getAddresses('JohnDoe')[2], NANO_TEST_VECTORS.ADDRESS_0) }) test('should update the name on an existing entry', async () => { const rolodex = new Rolodex() await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) await rolodex.add('JaneSmith', NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(rolodex.getAddresses('JohnDoe').length, 0) - assert.equal(rolodex.getAddresses('JaneSmith').length, 1) - assert.equal(rolodex.getAddresses('JaneSmith')[0], NANO_TEST_VECTORS.ADDRESS_0) + assert.equals(rolodex.getAddresses('JohnDoe').length, 0) + assert.equals(rolodex.getAddresses('JaneSmith').length, 1) + assert.equals(rolodex.getAddresses('JaneSmith')[0], NANO_TEST_VECTORS.ADDRESS_0) }) test('should return empty address array for an unknown contact', async () => { const rolodex = new Rolodex() await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(Array.isArray(rolodex.getAddresses('JaneSmith')), true) - assert.equal(rolodex.getAddresses('JaneSmith').length, 0) + assert.equals(Array.isArray(rolodex.getAddresses('JaneSmith')), true) + assert.equals(rolodex.getAddresses('JaneSmith').length, 0) }) test('should return empty address array for blank contact names', () => { const rolodex = new Rolodex() //@ts-expect-error - assert.equal(Array.isArray(rolodex.getAddresses(undefined)), true) + assert.equals(Array.isArray(rolodex.getAddresses(undefined)), true) //@ts-expect-error - assert.equal(rolodex.getAddresses(undefined).length, 0) + assert.equals(rolodex.getAddresses(undefined).length, 0) //@ts-expect-error - assert.equal(Array.isArray(rolodex.getAddresses(null)), true) + assert.equals(Array.isArray(rolodex.getAddresses(null)), true) //@ts-expect-error - assert.equal(rolodex.getAddresses(null).length, 0) - assert.equal(Array.isArray(rolodex.getAddresses('')), true) - assert.equal(rolodex.getAddresses('').length, 0) + assert.equals(rolodex.getAddresses(null).length, 0) + assert.equals(Array.isArray(rolodex.getAddresses('')), true) + assert.equals(rolodex.getAddresses('').length, 0) }) test('should return null for an unknown address', async () => { const rolodex = new Rolodex() await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) - assert.equal(rolodex.getName(NANO_TEST_VECTORS.ADDRESS_1), null) + assert.equals(rolodex.getName(NANO_TEST_VECTORS.ADDRESS_1), null) assert.notEqual(rolodex.getName(NANO_TEST_VECTORS.ADDRESS_1), undefined) }) @@ -82,19 +81,19 @@ describe('rolodex valid contact management', async () => { const rolodex = new Rolodex() await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) //@ts-expect-error - assert.equal(rolodex.getName(undefined), null) + assert.equals(rolodex.getName(undefined), null) //@ts-expect-error assert.notEqual(rolodex.getName(undefined), undefined) //@ts-expect-error - assert.equal(rolodex.getName(null), null) + assert.equals(rolodex.getName(null), null) //@ts-expect-error assert.notEqual(rolodex.getName(null), undefined) - assert.equal(rolodex.getName(''), null) + assert.equals(rolodex.getName(''), null) assert.notEqual(rolodex.getName(''), undefined) }) }) -describe('rolodex exceptions', async () => { +test('rolodex exceptions', async () => { test('should throw if adding no data', async () => { const rolodex = new Rolodex() //@ts-expect-error @@ -122,7 +121,7 @@ describe('rolodex exceptions', async () => { }) }) -describe('rolodex data signature verification', async () => { +test('rolodex data signature verification', async () => { const data = 'Test data' const signature = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0, data) const rolodex = new Rolodex() @@ -130,12 +129,12 @@ describe('rolodex data signature verification', async () => { test('should verify valid data and signature', async () => { await rolodex.add('JohnDoe', NANO_TEST_VECTORS.ADDRESS_0) const result = await rolodex.verify('JohnDoe', signature, data) - assert.equal(result, true) + assert.equals(result, true) }) test('should reject incorrect contact for signature', async () => { await rolodex.add('JaneSmith', NANO_TEST_VECTORS.ADDRESS_1) const result = await rolodex.verify('JaneSmith', signature, data) - assert.equal(result, false) + assert.equals(result, false) }) }) diff --git a/perf/account.perf.js b/test/perf/account.perf.js similarity index 67% rename from perf/account.perf.js rename to test/perf/account.perf.js index 831f275..e4d796a 100644 --- a/perf/account.perf.js +++ b/test/perf/account.perf.js @@ -3,27 +3,25 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '#dist/main.js' -console.log('child key derivation performance test') - -test('BIP-44 ckd', async () => { +test('BIP-44 ckd performance test', async () => { const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + console.log(`HERE`) const accounts = await wallet.accounts(0, 0x7fff) - expect(accounts.length).toEqual(0x8000) + assert.equals(accounts.length, 0x8000) }) -test('BLAKE2b ckd', async () => { +test('BLAKE2b ckd performance test', async () => { const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) const accounts = await wallet.accounts(0, 0x7fff) - expect(accounts.length).toEqual(0x8000) + assert.equals(accounts.length, 0x8000) }) diff --git a/perf/wallet.perf.js b/test/perf/wallet.perf.js similarity index 62% rename from perf/wallet.perf.js rename to test/perf/wallet.perf.js index 51cb4a8..7c65a68 100644 --- a/perf/wallet.perf.js +++ b/test/perf/wallet.perf.js @@ -3,25 +3,22 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '#dist/main.js' -console.log('wallet performance test') - -test.skip('creating BIP-44 wallets', async () => { +test('creating BIP-44 wallets performance test', async () => { const wallets = [] for (let i = 0x80; i > 0; i--) { wallets.push(await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD)) } - expect(wallets.length).toEqual(0x80) + assert.equals(wallets.length, 0x80) }) -test.skip('creating BLAKE2b wallets', async () => { +test('creating BLAKE2b wallets performance test', async () => { const wallets = [] for (let i = 0x80; i > 0; i--) { wallets.push(await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD)) } - expect(wallets.length).toEqual(0x80) + assert.equals(wallets.length, 0x80) }) diff --git a/test/refresh-accounts.test.mjs b/test/refresh-accounts.test.mjs index 23010d9..00e76fa 100644 --- a/test/refresh-accounts.test.mjs +++ b/test/refresh-accounts.test.mjs @@ -3,34 +3,39 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Account, Bip44Wallet, Rpc } from '#dist/main.js' const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) -const node = new Rpc(process.env.NODE_URL ?? '', process.env.API_KEY_NAME) - -describe.skip('refreshing account info', async () => { +let rpc +//@ts-expect-error +var process = process || null +if (process) { + //@ts-expect-error + rpc = new Rpc(process?.env?.NODE_URL ?? '', process?.env?.API_KEY_NAME) +} + +skip('refreshing account info', async () => { test('should fetch balance, frontier, and representative', async () => { const accounts = await wallet.accounts() const account = accounts[0] - await account.refresh(node) + await account.refresh(rpc) - assert.equal(typeof account.balance, 'bigint') + assert.equals(typeof account.balance, 'bigint') assert.notEqual(account.balance, undefined) assert.notEqual(account.balance, null) assert.notEqual(account.balance, '') assert.notEqual(account.balance && account.balance < 0, true) - assert.equal(typeof account.frontier, 'string') + assert.equals(typeof account.frontier, 'string') assert.notEqual(account.frontier, undefined) assert.notEqual(account.frontier, null) assert.notEqual(account.frontier, '') assert.match(account.frontier ?? '', /^[0-9A-F]{64}$/i) - assert.equal(account.representative && account.representative.constructor, Account) + assert.equals(account.representative && account.representative.constructor, Account) assert.notEqual(account.representative, undefined) assert.notEqual(account.representative, null) assert.notEqual(account.representative, '') @@ -42,7 +47,7 @@ describe.skip('refreshing account info', async () => { test('should throw when refreshing unopened account', async () => { const accounts = await wallet.accounts(0x7fffffff) const account = accounts[0] - await assert.rejects(account.refresh(node), + await assert.rejects(account.refresh(rpc), { message: 'Account not found' }) }) @@ -60,26 +65,26 @@ describe.skip('refreshing account info', async () => { }) }) -describe.skip('finding next unopened account', async () => { +skip('finding next unopened account', async () => { test('should return correct account from test vector', async () => { - const account = await wallet.getNextNewAccount(node) + const account = await wallet.getNextNewAccount(rpc) assert.ok(account) - assert.equal(account.address, NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) + assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) }) test('should return successfully for small batch size', async () => { - const account = await wallet.getNextNewAccount(node, 1) + const account = await wallet.getNextNewAccount(rpc, 1) assert.ok(account) - assert.equal(account.address, NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) + assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) }) test('should return successfully for large batch size', async () => { - const account = await wallet.getNextNewAccount(node, 100) + const account = await wallet.getNextNewAccount(rpc, 100) assert.ok(account) - assert.equal(account.address, NANO_TEST_VECTORS.ADDRESS_1) - assert.equal(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) + assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1) + assert.equals(account.publicKey, NANO_TEST_VECTORS.PUBLIC_1) }) test('should throw on invalid node URL', async () => { @@ -97,35 +102,35 @@ describe.skip('finding next unopened account', async () => { test('should throw on invalid batch size', async () => { //@ts-expect-error - await assert.rejects(wallet.getNextNewAccount(node, null)) - await assert.rejects(wallet.getNextNewAccount(node, -1)) + await assert.rejects(wallet.getNextNewAccount(rpc, null)) + await assert.rejects(wallet.getNextNewAccount(rpc, -1)) //@ts-expect-error - await assert.rejects(wallet.getNextNewAccount(node, '')) + await assert.rejects(wallet.getNextNewAccount(rpc, '')) //@ts-expect-error - await assert.rejects(wallet.getNextNewAccount(node, 'foo')) + await assert.rejects(wallet.getNextNewAccount(rpc, 'foo')) //@ts-expect-error - await assert.rejects(wallet.getNextNewAccount(node, { 'foo': 'bar' })) + await assert.rejects(wallet.getNextNewAccount(rpc, { 'foo': 'bar' })) }) }) -describe.skip('refreshing wallet accounts', async () => { +skip('refreshing wallet accounts', async () => { test('should get balance, frontier, and representative for one account', async () => { - const accounts = await wallet.refresh(node) + const accounts = await wallet.refresh(rpc) const account = accounts[0] assert.ok(account instanceof Account) - assert.equal(typeof account.balance, 'bigint') + assert.equals(typeof account.balance, 'bigint') assert.notEqual(account.frontier, undefined) assert.notEqual(account.frontier, null) - assert.equal(typeof account.frontier, 'string') + assert.equals(typeof account.frontier, 'string') }) test('should get balance, frontier, and representative for multiple accounts', async () => { - const accounts = await wallet.refresh(node, 0, 2) - assert.equal(accounts.length, 1) + const accounts = await wallet.refresh(rpc, 0, 2) + assert.equals(accounts.length, 1) assert.ok(accounts[0] instanceof Account) }) test('should handle failure gracefully', async () => { - await assert.doesNotReject(wallet.refresh(node, 0, 20)) + await assert.doesNotReject(wallet.refresh(rpc, 0, 20)) }) }) diff --git a/test/sign-blocks.test.mjs b/test/sign-blocks.test.mjs index d37439c..0415a97 100644 --- a/test/sign-blocks.test.mjs +++ b/test/sign-blocks.test.mjs @@ -3,12 +3,11 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, test } from '#test/GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { SendBlock, ReceiveBlock, ChangeBlock } from '#dist/main.js' -describe('valid blocks', async () => { +test('valid blocks', async () => { test('should not allow negative balances', async () => { assert.throws(() => { const block = new SendBlock( @@ -32,7 +31,7 @@ describe('valid blocks', async () => { '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D' ) assert.notEqual(block.balance, 0) - assert.equal(block.balance, BigInt(0)) + assert.equals(block.balance, BigInt(0)) }) test('should subtract balance from SendBlock correctly', async () => { @@ -44,7 +43,7 @@ describe('valid blocks', async () => { NANO_TEST_VECTORS.ADDRESS_2, '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D' ) - assert.equal(block.balance, 1000000000000000000000000000000n) + assert.equals(block.balance, 1000000000000000000000000000000n) }) test('should add balance from ReceiveBlock correctly', async () => { @@ -56,11 +55,11 @@ describe('valid blocks', async () => { NANO_TEST_VECTORS.ADDRESS_2, '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D' ) - assert.equal(block.balance, 3000000000000000000000000000000n) + assert.equals(block.balance, 3000000000000000000000000000000n) }) }) -describe('block signing tests using official test vectors', async () => { +test('block signing tests using official test vectors', async () => { test('should create a valid signature for an open block', async () => { const block = new ReceiveBlock( NANO_TEST_VECTORS.OPEN_BLOCK.account, @@ -72,8 +71,8 @@ describe('block signing tests using official test vectors', async () => { NANO_TEST_VECTORS.OPEN_BLOCK.work ) await block.sign(NANO_TEST_VECTORS.OPEN_BLOCK.key) - assert.equal(await block.hash(), NANO_TEST_VECTORS.OPEN_BLOCK.hash) - assert.equal(block.signature, NANO_TEST_VECTORS.OPEN_BLOCK.signature) + assert.equals(await block.hash(), NANO_TEST_VECTORS.OPEN_BLOCK.hash) + assert.equals(block.signature, NANO_TEST_VECTORS.OPEN_BLOCK.signature) }) test('should create a valid signature for a receive block', async () => { @@ -87,8 +86,8 @@ describe('block signing tests using official test vectors', async () => { NANO_TEST_VECTORS.RECEIVE_BLOCK.work ) await block.sign(NANO_TEST_VECTORS.RECEIVE_BLOCK.key) - assert.equal(await block.hash(), NANO_TEST_VECTORS.RECEIVE_BLOCK.hash) - assert.equal(block.signature, NANO_TEST_VECTORS.RECEIVE_BLOCK.signature) + assert.equals(await block.hash(), NANO_TEST_VECTORS.RECEIVE_BLOCK.hash) + assert.equals(block.signature, NANO_TEST_VECTORS.RECEIVE_BLOCK.signature) }) test('should create a valid signature for a receive block without work', async () => { @@ -101,9 +100,9 @@ describe('block signing tests using official test vectors', async () => { NANO_TEST_VECTORS.RECEIVE_BLOCK.previous ) await block.sign(NANO_TEST_VECTORS.RECEIVE_BLOCK.key) - assert.equal(await block.hash(), NANO_TEST_VECTORS.RECEIVE_BLOCK.hash) - assert.equal(block.signature, NANO_TEST_VECTORS.RECEIVE_BLOCK.signature) - assert.equal(block.work, '') + assert.equals(await block.hash(), NANO_TEST_VECTORS.RECEIVE_BLOCK.hash) + assert.equals(block.signature, NANO_TEST_VECTORS.RECEIVE_BLOCK.signature) + assert.equals(block.work, '') }) test('should create a valid signature for a send block', async () => { @@ -117,8 +116,8 @@ describe('block signing tests using official test vectors', async () => { NANO_TEST_VECTORS.SEND_BLOCK.work ) await block.sign(NANO_TEST_VECTORS.SEND_BLOCK.key) - assert.equal(await block.hash(), NANO_TEST_VECTORS.SEND_BLOCK.hash) - assert.equal(block.signature, NANO_TEST_VECTORS.SEND_BLOCK.signature) + assert.equals(await block.hash(), NANO_TEST_VECTORS.SEND_BLOCK.hash) + assert.equals(block.signature, NANO_TEST_VECTORS.SEND_BLOCK.signature) }) test('should create a valid signature for a send block without work', async () => { @@ -131,9 +130,9 @@ describe('block signing tests using official test vectors', async () => { NANO_TEST_VECTORS.SEND_BLOCK.previous ) await block.sign(NANO_TEST_VECTORS.SEND_BLOCK.key) - assert.equal(await block.hash(), NANO_TEST_VECTORS.SEND_BLOCK.hash) - assert.equal(block.signature, NANO_TEST_VECTORS.SEND_BLOCK.signature) - assert.equal(block.work, '') + assert.equals(await block.hash(), NANO_TEST_VECTORS.SEND_BLOCK.hash) + assert.equals(block.signature, NANO_TEST_VECTORS.SEND_BLOCK.signature) + assert.equals(block.work, '') }) test('should create a valid signature for a change rep block', async () => { @@ -146,8 +145,8 @@ describe('block signing tests using official test vectors', async () => { work, ) await block.sign('781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3') // Did not find a private key at nano docs for this address - assert.equal(block.signature?.toUpperCase(), 'A3C3C66D6519CBC0A198E56855942DEACC6EF741021A1B11279269ADC587DE1DA53CD478B8A47553231104CF24D742E1BB852B0546B87038C19BAE20F9082B0D') - assert.equal(block.work, work) + assert.equals(block.signature?.toUpperCase(), 'A3C3C66D6519CBC0A198E56855942DEACC6EF741021A1B11279269ADC587DE1DA53CD478B8A47553231104CF24D742E1BB852B0546B87038C19BAE20F9082B0D') + assert.equals(block.work, work) }) test('should create a valid signature for a change rep block without work', async () => { @@ -158,7 +157,7 @@ describe('block signing tests using official test vectors', async () => { 'F3C1D7B6EE97DA09D4C00538CEA93CBA5F74D78FD3FBE71347D2DFE7E53DF327' ) await block.sign(NANO_TEST_VECTORS.PRIVATE_0) - assert.equal(block.signature?.toUpperCase(), '2BD2F905E74B5BEE3E2277CED1D1E3F7535E5286B6E22F7B08A814AA9E5C4E1FEA69B61D60B435ADC2CE756E6EE5F5BE7EC691FE87E024A0B22A3D980CA5B305') - assert.equal(block.work, '') + assert.equals(block.signature?.toUpperCase(), '2BD2F905E74B5BEE3E2277CED1D1E3F7535E5286B6E22F7B08A814AA9E5C4E1FEA69B61D60B435ADC2CE756E6EE5F5BE7EC691FE87E024A0B22A3D980CA5B305') + assert.equals(block.work, '') }) }) diff --git a/test/tools.test.mjs b/test/tools.test.mjs index 165c9ed..04be748 100644 --- a/test/tools.test.mjs +++ b/test/tools.test.mjs @@ -3,54 +3,59 @@ 'use strict' -import '#test/GLOBALS.mjs' -import { describe, expect, test } from '@jest/globals' +import { assert, skip, test } from '#test/GLOBALS.mjs' import { RAW_MAX, NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Account, SendBlock, Rpc, Tools } from '#dist/main.js' const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED) await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) -const rpc = new Rpc(process.env.NODE_URL ?? '', process.env.API_KEY_NAME) - -describe('unit conversion tests', async () => { +let rpc +//@ts-expect-error +var process = process || null +if (process) { + //@ts-expect-error + rpc = new Rpc(process?.env?.NODE_URL ?? '', process?.env?.API_KEY_NAME) +} + +test('unit conversion tests', async () => { test('should convert nano to raw', async () => { const result = await Tools.convert('1', 'NANO', 'RAW') - assert.equal(result, '1000000000000000000000000000000') + assert.equals(result, '1000000000000000000000000000000') }) test('should convert raw to nano', async () => { const result = await Tools.convert('1000000000000000000000000000000', 'RAW', 'NANO') - assert.equal(result, '1') + assert.equals(result, '1') }) test('should convert 1 raw to 10^-29 nano', async () => { const result = await Tools.convert('1', 'RAW', 'NANO') - assert.equal(result, '.000000000000000000000000000001') + assert.equals(result, '.000000000000000000000000000001') }) test('should ignore leading and trailing zeros', async () => { const result = await Tools.convert('0011002200.0033004400', 'nano', 'nano') - assert.equal(result, '11002200.00330044') + assert.equals(result, '11002200.00330044') }) test('should convert raw to nyano', async () => { const result = await Tools.convert(RAW_MAX, 'RAW', 'NYANO') - assert.equal(result, '340282366920938.463463374607431768211455') + assert.equals(result, '340282366920938.463463374607431768211455') }) test('should convert case-insensitive nyano to raw', async () => { const result = await Tools.convert('0.000000000000000123456789', 'nYaNo', 'rAw') - assert.equal(result, '123456789') + assert.equals(result, '123456789') }) test('should convert nano to pico', async () => { const result = await Tools.convert('123.456', 'nano', 'pico') - assert.equal(result, '123456') + assert.equals(result, '123456') }) test('should convert knano to pico', async () => { const result = await Tools.convert('123.456', 'nano', 'pico') - assert.equal(result, '123456') + assert.equals(result, '123456') }) test('should throw if amount exceeds raw max', async () => { @@ -74,26 +79,26 @@ describe('unit conversion tests', async () => { }) }) -describe('signature tests', async () => { +test('signature tests', async () => { test('should sign data with a single parameter', async () => { const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0, 'miro@metsanheimo.fi') - assert.equal(result, 'FECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C') + assert.equals(result, 'FECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C') }) test('should sign data with multiple parameters', async () => { const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0, 'miro@metsanheimo.fi', 'somePassword') - assert.equal(result, 'BB534F9B469AF451B1941FFEF8EE461FC5D284B5D393140900C6E13A65EF08D0AE2BC77131EE182922F66C250C7237A83878160457D5C39A70E55F7FCE925804') + assert.equals(result, 'BB534F9B469AF451B1941FFEF8EE461FC5D284B5D393140900C6E13A65EF08D0AE2BC77131EE182922F66C250C7237A83878160457D5C39A70E55F7FCE925804') }) test('should verify a signature using the public key', async () => { const result = await Tools.verify(NANO_TEST_VECTORS.PUBLIC_0, 'FECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C', 'miro@metsanheimo.fi') - assert.equal(result, true) + assert.equals(result, true) const result2 = await Tools.verify(NANO_TEST_VECTORS.PUBLIC_0, 'FECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C', 'mir@metsanheimo.fi') - assert.equal(result2, false) + assert.equals(result2, false) const result3 = await Tools.verify(NANO_TEST_VECTORS.PUBLIC_0, 'AECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C', 'miro@metsanheimo.fi') - assert.equal(result3, false) + assert.equals(result3, false) }) test('should verify a block using the public key', async () => { @@ -109,7 +114,7 @@ describe('signature tests', async () => { ) await sendBlock.sign(account.privateKey ?? '') const valid = await sendBlock.verify(account.publicKey) - assert.equal(valid, true) + assert.equals(valid, true) }) test('should reject a block using the wrong public key', async () => { @@ -127,20 +132,20 @@ describe('signature tests', async () => { sendBlock.account = Account.fromAddress('nano_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p') const valid = await sendBlock.verify(account.publicKey) - assert.equal(valid, false) + assert.equals(valid, false) }) }) -describe('sweeper', async () => { +test('sweeper', async () => { test('throws without required parameters', async () => { //@ts-expect-error await assert.rejects(Tools.sweep(), - { message: 'Missing required sweep arguments' }) + 'Missing required sweep arguments') }) - test.skip('fails gracefully for ineligible accounts', async () => { + skip('fails gracefully for ineligible accounts', async () => { const results = await Tools.sweep(rpc, wallet, NANO_TEST_VECTORS.ADDRESS_1) assert.ok(results) - assert.equal(results.length, 1) + assert.equals(results.length, 1) }) })