From 5576d42a6015be17eadff29a6137b99f5dc981ac Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 5 Jun 2024 16:48:14 +0800 Subject: [PATCH 01/24] feat: jest env --- babel.config.cjs | 4 + jest.config.js | 28 +- package.json | 14 +- src/command/baseSubCommand.js | 3 +- src/command/config.js | 3 +- src/command/dappServer/socket.js | 3 +- src/command/getBlkInfo.js | 3 +- src/command/getTxResult.js | 3 +- src/index.js | 2 +- test/index.test.js | 15 +- yarn.lock | 815 ++++++++++++++++++++++++++++++- 11 files changed, 842 insertions(+), 51 deletions(-) create mode 100644 babel.config.cjs diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 0000000..301a294 --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,4 @@ +module.exports = { + "presets": ["@babel/preset-env"], + "plugins": [ "babel-plugin-transform-import-meta", "@babel/plugin-syntax-import-attributes"] +} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 9da2199..27a2b24 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,9 @@ // For a detailed explanation regarding each configuration property, visit: // https://jestjs.io/docs/en/configuration.html -const path = require('path'); +import path from 'path'; process.env.RUNTIME_ENV = 'node'; -module.exports = { +export default { // All imported modules in your tests should be mocked automatically // automock: false, @@ -64,9 +64,9 @@ module.exports = { // globals: {}, // An array of directory names to be searched recursively up from the requiring module's location - moduleDirectories: [ - 'node_modules' - ], + // moduleDirectories: [ + // 'node_modules' + // ], // An array of file extensions your modules use // moduleFileExtensions: [ @@ -79,9 +79,9 @@ module.exports = { // ], // A map from regular expressions to module names that allow to stub out resources with a single module - moduleNameMapper: { - '^scryptsy$': path.resolve('src/scrypt-polyfill.js') - }, + // moduleNameMapper: { + // '^scryptsy$': path.resolve('src/scrypt-polyfill.js') + // }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader // modulePathIgnorePatterns: [], @@ -169,14 +169,14 @@ module.exports = { // timers: "real", // A map from regular expressions to paths to transformers - // transform: { - // '^.+\\.js?$': 'babel-jest' - // } + transform: { + '^.+\\.js?$': 'babel-jest' + }, // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/" - // ], + transformIgnorePatterns: [ + // "/node_modules/(?!chalk|update-notifier|configstore|xdg-basedir|unique-string|crypto-random-string|semver-diff|latest-version|package-json|got|@sindresorhus|p-cancelable|@szmarczak/http-timer|cacheable-request|normalize-url|responselike|lowercase-keys|mimic-response|form-data-encoder)" + ], // 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, diff --git a/package.json b/package.json index 667b529..0704db3 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "commit": "git-cz", "lint": "eslint src", "release": "standard-version", - "test": "npx cross-env NODE_ENV=test jest" + "test": "jest --config=jest.config.js", + "test:watch": "jest --config=jest.config.js --watch" }, "preferGlobal": true, "repository": { @@ -38,8 +39,12 @@ }, "engineStrict": true, "dependencies": { + "@babel/core": "^7.24.6", + "@babel/plugin-syntax-import-attributes": "^7.24.6", + "@babel/preset-env": "^7.24.6", "aelf-sdk": "^3.4.12", "async-validator": "^4.2.5", + "babel-plugin-transform-import-meta": "^2.2.1", "boxen": "^7.1.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", @@ -50,14 +55,14 @@ "global": "^4.4.0", "inquirer": "^9.2.22", "inquirer-date-prompt": "^3.0.0", + "inquirer-search-list": "^1.2.6", "mkdirp": "^3.0.1", "moment": "^2.30.1", "ora": "^8.0.1", "prompts": "^2.4.2", "socket.io": "^4.7.5", "update-notifier": "^7.0.0", - "uuid": "^9.0.1", - "inquirer-search-list": "^1.2.6" + "uuid": "^9.0.1" }, "devDependencies": { "commitizen": "^4.3.0", @@ -98,6 +103,9 @@ "collectCoverageFrom": [ "src/**/*.js" ], + "transform": { + "^.+\\.js$": "babel-jest" + }, "testEnvironment": "node" } } diff --git a/src/command/baseSubCommand.js b/src/command/baseSubCommand.js index 4e01227..60ad409 100644 --- a/src/command/baseSubCommand.js +++ b/src/command/baseSubCommand.js @@ -2,8 +2,7 @@ * @file base sub command * @author atom-yang */ -import asyncValidator from 'async-validator'; -const Schema = asyncValidator.default; +import Schema from 'async-validator'; import inquirer from 'inquirer'; import ora from 'ora'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/config.js b/src/command/config.js index 63886ed..54a51bf 100644 --- a/src/command/config.js +++ b/src/command/config.js @@ -2,8 +2,7 @@ * @file get block height * @author atom-yang */ -import asyncValidator from 'async-validator'; -const Schema = asyncValidator.default; +import Schema from 'async-validator'; import BaseSubCommand from './baseSubCommand.js'; import { configCommandParameters, configCommandUsage, commonGlobalOptionValidatorDesc } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/dappServer/socket.js b/src/command/dappServer/socket.js index 2263a7d..049151d 100644 --- a/src/command/dappServer/socket.js +++ b/src/command/dappServer/socket.js @@ -4,8 +4,7 @@ */ import { Server } from 'socket.io'; import AElf from 'aelf-sdk'; -import asyncValidator from 'async-validator'; -const Schema = asyncValidator.default; +import Schema from 'async-validator'; import Sign from './sign.js'; import Encrypt from './encrypt.js'; import { logger } from '../../utils/myLogger.js'; diff --git a/src/command/getBlkInfo.js b/src/command/getBlkInfo.js index 0ab417f..c7b0405 100644 --- a/src/command/getBlkInfo.js +++ b/src/command/getBlkInfo.js @@ -3,8 +3,7 @@ * @author atom-yang */ import AElf from 'aelf-sdk'; -import asyncValidator from 'async-validator'; -const Schema = asyncValidator.default; +import Schema from 'async-validator'; import BaseSubCommand from './baseSubCommand.js'; import { commonGlobalOptionValidatorDesc, blkInfoCommandParameters, blkInfoCommandUsage } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/getTxResult.js b/src/command/getTxResult.js index 20feaee..6c8529e 100644 --- a/src/command/getTxResult.js +++ b/src/command/getTxResult.js @@ -3,8 +3,7 @@ * @author atom-yang */ import AElf from 'aelf-sdk'; -import asyncValidator from 'async-validator'; -const Schema = asyncValidator.default; +import Schema from 'async-validator'; import BaseSubCommand from './baseSubCommand.js'; import { commonGlobalOptionValidatorDesc, txResultCommandParameters, txResultCommandUsage } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/src/index.js b/src/index.js index 5bf767c..4276845 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ import check from 'check-node-version'; import { execSync } from 'child_process'; import commands from './command/index.js'; import RC from './rc/index.js'; -import pkg from '../package.json' assert { type: 'json' }; +import pkg from '../package.json' with { type: 'json' }; import { logger } from './utils/myLogger.js'; import { userHomeDir } from './utils/userHomeDir.js'; diff --git a/test/index.test.js b/test/index.test.js index 433d222..6ae83fe 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,9 +1,6 @@ -/** - * @file test commands - * @author atom-yang - */ -const path = require('path'); -const aelfCommand = require('../src/index'); +import path from 'path'; +import { run as aelfCommandRun } from '../src/index'; + const commandBin = path.resolve(__dirname, '../bin/aelf-command.js'); @@ -12,11 +9,11 @@ process.env.NODE_ENV = 'test'; function execCommand(cmd, args) { process.env.mockArgs = [process.argv[0], commandBin, cmd, ...args]; console.log(process.env.mockArgs); - return aelfCommand.run(); + return aelfCommandRun(); } describe('test index', () => { test('test', async () => { - execCommand('get-chain-status', []); - }, 30000) + await execCommand('get-chain-status', []); + }, 30000); }); diff --git a/yarn.lock b/yarn.lock index ce54924..de789a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -63,12 +63,12 @@ "@babel/highlight" "^7.24.6" picocolors "^1.0.0" -"@babel/compat-data@^7.24.6": +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz#b3600217688cabb26e25f8e467019e66d71b7ae2" integrity sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz#8650e0e4b03589ebe886c4e4a60398db0a7ec787" integrity sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ== @@ -99,7 +99,21 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.24.6": +"@babel/helper-annotate-as-pure@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz#517af93abc77924f9b2514c407bbef527fb8938d" + integrity sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.6.tgz#19e9089ee87b0d0928012c83961a8deef4b0223f" + integrity sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz#4a51d681f7680043d38e212715e2a7b1ad29cb51" integrity sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg== @@ -110,6 +124,41 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz#c50b86fa1c4ca9b7a890dc21884f097b6c4b5286" + integrity sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.6" + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-function-name" "^7.24.6" + "@babel/helper-member-expression-to-functions" "^7.24.6" + "@babel/helper-optimise-call-expression" "^7.24.6" + "@babel/helper-replace-supers" "^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.6" + "@babel/helper-split-export-declaration" "^7.24.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.6.tgz#47d382dec0d49e74ca1b6f7f3b81f5968022a3c8" + integrity sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.6" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + "@babel/helper-environment-visitor@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz#ac7ad5517821641550f6698dd5468f8cef78620d" @@ -130,6 +179,13 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-member-expression-to-functions@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz#86084f3e0e4e2169a134754df3870bc7784db71e" + integrity sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg== + dependencies: + "@babel/types" "^7.24.6" + "@babel/helper-module-imports@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz#65e54ffceed6a268dc4ce11f0433b82cfff57852" @@ -148,11 +204,36 @@ "@babel/helper-split-export-declaration" "^7.24.6" "@babel/helper-validator-identifier" "^7.24.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.6", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-optimise-call-expression@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz#f7836e3ccca3dfa02f15d2bc8b794efe75a5256e" + integrity sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA== + dependencies: + "@babel/types" "^7.24.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz#fa02a32410a15a6e8f8185bcbf608f10528d2a24" integrity sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg== +"@babel/helper-remap-async-to-generator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.6.tgz#c96ceb9846e877d806ce82a1521230ea7e0fc354" + integrity sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.6" + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-wrap-function" "^7.24.6" + +"@babel/helper-replace-supers@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz#3ea87405a2986a49ab052d10e540fe036d747c71" + integrity sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ== + dependencies: + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-member-expression-to-functions" "^7.24.6" + "@babel/helper-optimise-call-expression" "^7.24.6" + "@babel/helper-simple-access@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz#1d6e04d468bba4fc963b4906f6dac6286cfedff1" @@ -160,6 +241,13 @@ dependencies: "@babel/types" "^7.24.6" +"@babel/helper-skip-transparent-expression-wrappers@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz#c47e9b33b7ea50d1073e125ebc26661717cb7040" + integrity sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q== + dependencies: + "@babel/types" "^7.24.6" + "@babel/helper-split-export-declaration@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz#e830068f7ba8861c53b7421c284da30ae656d7a3" @@ -182,6 +270,15 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz#59d8e81c40b7d9109ab7e74457393442177f460a" integrity sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ== +"@babel/helper-wrap-function@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz#c27af1006e310683fdc76b668a0a1f6003e36217" + integrity sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ== + dependencies: + "@babel/helper-function-name" "^7.24.6" + "@babel/template" "^7.24.6" + "@babel/types" "^7.24.6" + "@babel/helpers@^7.24.6": version "7.24.6" resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz#cd124245299e494bd4e00edda0e4ea3545c2c176" @@ -205,6 +302,43 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz#5e030f440c3c6c78d195528c3b688b101a365328" integrity sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q== +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.6.tgz#283a74ef365b1e954cda6b2724c678a978215e88" + integrity sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw== + dependencies: + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.6.tgz#f9f5ae4d6fb72f5950262cb6f0b2482c3bc684ef" + integrity sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.6.tgz#ab9be6edfffa127bd5ec4317c76c5af0f8fc7e6c" + integrity sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.6" + "@babel/plugin-transform-optional-chaining" "^7.24.6" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.6.tgz#0faf879249ec622d7f1c42eaebf7d11197401b2c" + integrity sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ== + dependencies: + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -219,14 +353,49 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.6.tgz#52521c1c1698fc2dd9cf88f7a4dd86d4d041b9e1" + integrity sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-syntax-import-attributes@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.6.tgz#12aba325534129584672920274fefa4dc2d5f68e" + integrity sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -247,7 +416,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.6" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -261,7 +430,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -289,7 +458,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -303,14 +479,510 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.6" -"@babel/runtime@^7.4.5": +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.6.tgz#93607d1ef5b81c70af174aff3532d57216367492" + integrity sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-async-generator-functions@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.6.tgz#fa4a9e5c3a7f60f697ba36587b6c41b04f507d84" + integrity sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA== + dependencies: + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-remap-async-to-generator" "^7.24.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.6.tgz#eb11434b11d73d8c0cf9f71a6f4f1e6ba441df35" + integrity sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g== + dependencies: + "@babel/helper-module-imports" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-remap-async-to-generator" "^7.24.6" + +"@babel/plugin-transform-block-scoped-functions@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.6.tgz#975555b5bfa9870b1218da536d1528735f1f8c56" + integrity sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-block-scoping@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.6.tgz#a03ec8a4591c2b43cf7798bc633e698293fda179" + integrity sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-class-properties@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.6.tgz#d9f394e97e88ef905d5a1e5e7a16238621b7982e" + integrity sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-class-static-block@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.6.tgz#f43f29286f6f0dca33d18fd5033b817d6c3fa816" + integrity sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.6.tgz#0cc198c02720d4eeb091004843477659c6b37977" + integrity sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.6" + "@babel/helper-compilation-targets" "^7.24.6" + "@babel/helper-environment-visitor" "^7.24.6" + "@babel/helper-function-name" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-replace-supers" "^7.24.6" + "@babel/helper-split-export-declaration" "^7.24.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.6.tgz#7a1765c01cdfe59c320d2d0f37a4dc4aecd14df1" + integrity sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/template" "^7.24.6" + +"@babel/plugin-transform-destructuring@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.6.tgz#bdd1a6c90ffb2bfd13b6007b13316eeafc97cb53" + integrity sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-dotall-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.6.tgz#5a6b3148ec5f4f274ff48cebea90565087cad126" + integrity sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-duplicate-keys@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.6.tgz#2716301227cf7cd4fdadcbe4353ce191f8b3dc8a" + integrity sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-dynamic-import@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.6.tgz#b477177761d56b15a4ba42a83be31cf72d757acf" + integrity sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.6.tgz#011e9e1a429f91b024af572530873ca571f9ef06" + integrity sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-export-namespace-from@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.6.tgz#b64ded74d9afb3db5d47d93996c4df69f15ac97c" + integrity sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.6.tgz#7f31780bd0c582b546372c0c0da9d9d56731e0a2" + integrity sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.6" + +"@babel/plugin-transform-function-name@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.6.tgz#60d1de3f6fd816a3e3bf9538578a64527e1b9c97" + integrity sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q== + dependencies: + "@babel/helper-compilation-targets" "^7.24.6" + "@babel/helper-function-name" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-json-strings@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.6.tgz#a84639180ea1f9001bb5e6dc01921235ab05ad8b" + integrity sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.6.tgz#7f44f2871d7a4456030b0540858046f0b7bc6b18" + integrity sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-logical-assignment-operators@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.6.tgz#9cc7baa5629866566562c159dc1eae7569810f33" + integrity sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.6.tgz#5d3681ca201ac6909419cc51ac082a6ba4c5c756" + integrity sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-modules-amd@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.6.tgz#09aeac7acb7913496aaaafdc64f40683e0db7e41" + integrity sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ== + dependencies: + "@babel/helper-module-transforms" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-modules-commonjs@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz#1b8269902f25bd91ca6427230d4735ddd1e1283e" + integrity sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw== + dependencies: + "@babel/helper-module-transforms" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-simple-access" "^7.24.6" + +"@babel/plugin-transform-modules-systemjs@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.6.tgz#c54eb53fe16f9b82d320abd76762d0320e3f9393" + integrity sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w== + dependencies: + "@babel/helper-hoist-variables" "^7.24.6" + "@babel/helper-module-transforms" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-validator-identifier" "^7.24.6" + +"@babel/plugin-transform-modules-umd@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.6.tgz#c4ef8b6d4da230b8dc87e81cd66986728952f89b" + integrity sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg== + dependencies: + "@babel/helper-module-transforms" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.6.tgz#352ee2861ab8705320029f80238cf26a92ba65d5" + integrity sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-new-target@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.6.tgz#fc024294714705113720d5e3dc0f9ad7abdbc289" + integrity sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.6.tgz#12b83b3cdfd1cd2066350e36e4fb912ab194545e" + integrity sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.6.tgz#d9115669cc85aa91fbfb15f88f2226332cf4946a" + integrity sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.6.tgz#68d763f69955f9e599c405c6c876f5be46b47d8a" + integrity sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg== + dependencies: + "@babel/helper-compilation-targets" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.24.6" + +"@babel/plugin-transform-object-super@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.6.tgz#9cbe6f995bed343a7ab8daf0416dac057a9c3e27" + integrity sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-replace-supers" "^7.24.6" + +"@babel/plugin-transform-optional-catch-binding@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.6.tgz#c81e90a971aad898e56f2b75a358e6c4855aeba3" + integrity sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.6.tgz#3d636b3ed8b5a506f93e4d4675fc95754d7594f5" + integrity sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.6" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz#7aee86dfedd2fc0136fecbe6f7649fc02d86ab22" + integrity sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-private-methods@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.6.tgz#258e1f859a52ff7b30ad556598224c192defcda7" + integrity sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-private-property-in-object@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.6.tgz#59ff09a099f62213112cf348e96b6b11957d1f28" + integrity sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.6" + "@babel/helper-create-class-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.6.tgz#243c4faabe811c405e9443059a58e834bf95dfd1" + integrity sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-regenerator@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.6.tgz#ed10cf0c13619365e15459f88d1b915ac57ffc24" + integrity sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-reserved-words@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.6.tgz#9eb16cbf339fcea0a46677716c775afb5ef14245" + integrity sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-shorthand-properties@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.6.tgz#ef734ebccc428d2174c7bb36015d0800faf5381e" + integrity sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-spread@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.6.tgz#a56cecbd8617675531d1b79f5b755b7613aa0822" + integrity sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.6" + +"@babel/plugin-transform-sticky-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.6.tgz#1a78127731fea87d954bed193840986a38f04327" + integrity sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-template-literals@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.6.tgz#aaf2ae157acd0e5c9265dba8ac0a439f8d2a6303" + integrity sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-typeof-symbol@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.6.tgz#3d02da23ebcc8f1982ddcd1f2581cf3ee4e58762" + integrity sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-unicode-escapes@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.6.tgz#c8ddca8fd5bacece837a4e27bd3b7ed64580d1a8" + integrity sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-unicode-property-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.6.tgz#e66297d5d452db0b0be56515e3d0e10b7d33fb32" + integrity sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-unicode-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.6.tgz#2001e7d87ed709eea145e0b65fb5f93c3c0e225b" + integrity sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/plugin-transform-unicode-sets-regex@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.6.tgz#f18b7292222aee85c155258ceb345a146a070a46" + integrity sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + +"@babel/preset-env@^7.24.6": + version "7.24.6" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.6.tgz#a5a55bc70e5ff1ed7f872067e2a9d65ff917ad6f" + integrity sha512-CrxEAvN7VxfjOG8JNF2Y/eMqMJbZPZ185amwGUBp8D9USK90xQmv7dLdFSa+VbD7fdIqcy/Mfv7WtzG8+/qxKg== + dependencies: + "@babel/compat-data" "^7.24.6" + "@babel/helper-compilation-targets" "^7.24.6" + "@babel/helper-plugin-utils" "^7.24.6" + "@babel/helper-validator-option" "^7.24.6" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.6" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.6" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.24.6" + "@babel/plugin-syntax-import-attributes" "^7.24.6" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.24.6" + "@babel/plugin-transform-async-generator-functions" "^7.24.6" + "@babel/plugin-transform-async-to-generator" "^7.24.6" + "@babel/plugin-transform-block-scoped-functions" "^7.24.6" + "@babel/plugin-transform-block-scoping" "^7.24.6" + "@babel/plugin-transform-class-properties" "^7.24.6" + "@babel/plugin-transform-class-static-block" "^7.24.6" + "@babel/plugin-transform-classes" "^7.24.6" + "@babel/plugin-transform-computed-properties" "^7.24.6" + "@babel/plugin-transform-destructuring" "^7.24.6" + "@babel/plugin-transform-dotall-regex" "^7.24.6" + "@babel/plugin-transform-duplicate-keys" "^7.24.6" + "@babel/plugin-transform-dynamic-import" "^7.24.6" + "@babel/plugin-transform-exponentiation-operator" "^7.24.6" + "@babel/plugin-transform-export-namespace-from" "^7.24.6" + "@babel/plugin-transform-for-of" "^7.24.6" + "@babel/plugin-transform-function-name" "^7.24.6" + "@babel/plugin-transform-json-strings" "^7.24.6" + "@babel/plugin-transform-literals" "^7.24.6" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.6" + "@babel/plugin-transform-member-expression-literals" "^7.24.6" + "@babel/plugin-transform-modules-amd" "^7.24.6" + "@babel/plugin-transform-modules-commonjs" "^7.24.6" + "@babel/plugin-transform-modules-systemjs" "^7.24.6" + "@babel/plugin-transform-modules-umd" "^7.24.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.24.6" + "@babel/plugin-transform-new-target" "^7.24.6" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.6" + "@babel/plugin-transform-numeric-separator" "^7.24.6" + "@babel/plugin-transform-object-rest-spread" "^7.24.6" + "@babel/plugin-transform-object-super" "^7.24.6" + "@babel/plugin-transform-optional-catch-binding" "^7.24.6" + "@babel/plugin-transform-optional-chaining" "^7.24.6" + "@babel/plugin-transform-parameters" "^7.24.6" + "@babel/plugin-transform-private-methods" "^7.24.6" + "@babel/plugin-transform-private-property-in-object" "^7.24.6" + "@babel/plugin-transform-property-literals" "^7.24.6" + "@babel/plugin-transform-regenerator" "^7.24.6" + "@babel/plugin-transform-reserved-words" "^7.24.6" + "@babel/plugin-transform-shorthand-properties" "^7.24.6" + "@babel/plugin-transform-spread" "^7.24.6" + "@babel/plugin-transform-sticky-regex" "^7.24.6" + "@babel/plugin-transform-template-literals" "^7.24.6" + "@babel/plugin-transform-typeof-symbol" "^7.24.6" + "@babel/plugin-transform-unicode-escapes" "^7.24.6" + "@babel/plugin-transform-unicode-property-regex" "^7.24.6" + "@babel/plugin-transform-unicode-regex" "^7.24.6" + "@babel/plugin-transform-unicode-sets-regex" "^7.24.6" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.4.5", "@babel/runtime@^7.8.4": version "7.24.6" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz#5b76eb89ad45e2e4a0a8db54c456251469a3358e" integrity sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.24.6", "@babel/template@^7.3.3": +"@babel/template@^7.24.6", "@babel/template@^7.3.3", "@babel/template@^7.4.4": version "7.24.6" resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz#048c347b2787a6072b24c723664c8d02b67a44f9" integrity sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw== @@ -335,7 +1007,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.6", "@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.6", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.24.6" resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz#ba4e1f59870c10dc2fa95a274ac4feec23b21912" integrity sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ== @@ -1354,6 +2026,38 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.11" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.10.4: + version "0.10.4" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" + integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.1" + core-js-compat "^3.36.1" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.2" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + +babel-plugin-transform-import-meta@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz#eb5b79019ff0a9157b94d8280955121189a2964b" + integrity sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw== + dependencies: + "@babel/template" "^7.4.4" + tslib "^2.4.0" + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -1519,7 +2223,7 @@ browserify-des@^1.0.0: inherits "^2.0.1" safe-buffer "^5.1.2" -browserslist@^4.22.2: +browserslist@^4.22.2, browserslist@^4.23.0: version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -2092,6 +2796,13 @@ cookie@~0.4.1: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +core-js-compat@^3.31.0, core-js-compat@^3.36.1: + version "3.37.1" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz#c844310c7852f4bdf49b8d339730b97e17ff09ee" + integrity sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg== + dependencies: + browserslist "^4.23.0" + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -4313,6 +5024,11 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -4489,6 +5205,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" @@ -5373,11 +6094,30 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +regenerate-unicode-properties@^10.1.0: + version "10.1.1" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" @@ -5388,6 +6128,18 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + registry-auth-token@^5.0.1: version "5.0.2" resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756" @@ -5402,6 +6154,13 @@ registry-url@^6.0.0: dependencies: rc "1.2.8" +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5447,7 +6206,7 @@ resolve.exports@^2.0.0: resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.4: +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.4: version "1.22.8" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -6095,6 +6854,11 @@ tslib@^2.1.0, tslib@^2.6.2: resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.4.0: + version "2.6.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -6213,6 +6977,29 @@ undici-types@~5.26.4: resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + unique-string@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a" From 7308f3495189d1970a9c25f1cdde563e9910a8d9 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 5 Jun 2024 17:30:16 +0800 Subject: [PATCH 02/24] feat: with -> assert --- babel.config.cjs | 2 +- src/command/dappServer/socket.js | 2 +- src/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/babel.config.cjs b/babel.config.cjs index 301a294..9465c14 100644 --- a/babel.config.cjs +++ b/babel.config.cjs @@ -1,4 +1,4 @@ module.exports = { "presets": ["@babel/preset-env"], - "plugins": [ "babel-plugin-transform-import-meta", "@babel/plugin-syntax-import-attributes"] + "plugins": [ "babel-plugin-transform-import-meta", ["@babel/plugin-syntax-import-attributes", { "deprecatedAssertSyntax": true }]] } \ No newline at end of file diff --git a/src/command/dappServer/socket.js b/src/command/dappServer/socket.js index 049151d..9252ab6 100644 --- a/src/command/dappServer/socket.js +++ b/src/command/dappServer/socket.js @@ -4,7 +4,7 @@ */ import { Server } from 'socket.io'; import AElf from 'aelf-sdk'; -import Schema from 'async-validator'; +import { default as Schema } from 'async-validator'; import Sign from './sign.js'; import Encrypt from './encrypt.js'; import { logger } from '../../utils/myLogger.js'; diff --git a/src/index.js b/src/index.js index 4276845..5bf767c 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ import check from 'check-node-version'; import { execSync } from 'child_process'; import commands from './command/index.js'; import RC from './rc/index.js'; -import pkg from '../package.json' with { type: 'json' }; +import pkg from '../package.json' assert { type: 'json' }; import { logger } from './utils/myLogger.js'; import { userHomeDir } from './utils/userHomeDir.js'; From 03531537ab805a19c3d9e72d4ac47838443ae896 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 5 Jun 2024 17:45:52 +0800 Subject: [PATCH 03/24] feat: node-cjs-interop --- package.json | 1 + src/command/baseSubCommand.js | 4 +++- src/command/config.js | 4 +++- src/command/dappServer/socket.js | 4 +++- src/command/getBlkInfo.js | 4 +++- src/command/getTxResult.js | 4 +++- yarn.lock | 5 +++++ 7 files changed, 21 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0704db3..03aaad9 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "husky": "^9.0.11", "jest": "^29.7.0", "lint-staged": "^15.2.5", + "node-cjs-interop": "^0.1.6", "standard-version": "^9.5.0" }, "husky": { diff --git a/src/command/baseSubCommand.js b/src/command/baseSubCommand.js index 60ad409..35d2d39 100644 --- a/src/command/baseSubCommand.js +++ b/src/command/baseSubCommand.js @@ -2,7 +2,9 @@ * @file base sub command * @author atom-yang */ -import Schema from 'async-validator'; +import { interopImportCJSDefault } from "node-cjs-interop"; +import asyncValidator from 'async-validator'; +const Schema = interopImportCJSDefault(asyncValidator); import inquirer from 'inquirer'; import ora from 'ora'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/config.js b/src/command/config.js index 54a51bf..ea99ce9 100644 --- a/src/command/config.js +++ b/src/command/config.js @@ -2,7 +2,9 @@ * @file get block height * @author atom-yang */ -import Schema from 'async-validator'; +import { interopImportCJSDefault } from "node-cjs-interop"; +import asyncValidator from 'async-validator'; +const Schema = interopImportCJSDefault(asyncValidator); import BaseSubCommand from './baseSubCommand.js'; import { configCommandParameters, configCommandUsage, commonGlobalOptionValidatorDesc } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/dappServer/socket.js b/src/command/dappServer/socket.js index 9252ab6..16f7357 100644 --- a/src/command/dappServer/socket.js +++ b/src/command/dappServer/socket.js @@ -4,7 +4,9 @@ */ import { Server } from 'socket.io'; import AElf from 'aelf-sdk'; -import { default as Schema } from 'async-validator'; +import { interopImportCJSDefault } from "node-cjs-interop"; +import asyncValidator from 'async-validator'; +const Schema = interopImportCJSDefault(asyncValidator); import Sign from './sign.js'; import Encrypt from './encrypt.js'; import { logger } from '../../utils/myLogger.js'; diff --git a/src/command/getBlkInfo.js b/src/command/getBlkInfo.js index c7b0405..3390fd1 100644 --- a/src/command/getBlkInfo.js +++ b/src/command/getBlkInfo.js @@ -3,7 +3,9 @@ * @author atom-yang */ import AElf from 'aelf-sdk'; -import Schema from 'async-validator'; +import { interopImportCJSDefault } from "node-cjs-interop"; +import asyncValidator from 'async-validator'; +const Schema = interopImportCJSDefault(asyncValidator); import BaseSubCommand from './baseSubCommand.js'; import { commonGlobalOptionValidatorDesc, blkInfoCommandParameters, blkInfoCommandUsage } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/src/command/getTxResult.js b/src/command/getTxResult.js index 6c8529e..a1eff2f 100644 --- a/src/command/getTxResult.js +++ b/src/command/getTxResult.js @@ -3,7 +3,9 @@ * @author atom-yang */ import AElf from 'aelf-sdk'; -import Schema from 'async-validator'; +import { interopImportCJSDefault } from "node-cjs-interop"; +import asyncValidator from 'async-validator'; +const Schema = interopImportCJSDefault(asyncValidator); import BaseSubCommand from './baseSubCommand.js'; import { commonGlobalOptionValidatorDesc, txResultCommandParameters, txResultCommandUsage } from '../utils/constants.js'; import { logger } from '../utils/myLogger.js'; diff --git a/yarn.lock b/yarn.lock index de789a0..840f295 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5531,6 +5531,11 @@ neo-async@^2.6.2: resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +node-cjs-interop@^0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/node-cjs-interop/-/node-cjs-interop-0.1.6.tgz#35839d0e1d66df06ca2b8a62284de50faa7353da" + integrity sha512-apLUa7jj1jRPi8ufDXFE61DtUYOQCfe4m4oj6RPCucJ41mALHLKSLkNInyThjoT302jjKdT6O6L6eQL4f4/CTw== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" From 4ff389ec102b87678c77cf11813eda2661ca4370 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Fri, 7 Jun 2024 16:35:14 +0800 Subject: [PATCH 04/24] feat: index jest --- bin/aelf-command.js | 3 +- package.json | 5 +- src/command/baseSubCommand.js | 7 +- src/index.js | 25 ++++--- test/index.test.js | 128 ++++++++++++++++++++++++++++++---- 5 files changed, 138 insertions(+), 30 deletions(-) diff --git a/bin/aelf-command.js b/bin/aelf-command.js index 41b4a0d..0372f9a 100755 --- a/bin/aelf-command.js +++ b/bin/aelf-command.js @@ -7,5 +7,4 @@ process.on('uncaughtException', err => { logger.fatal(err.message || err); process.exit(1); }); - -run(); +run(process.argv); diff --git a/package.json b/package.json index 06ec89e..17bcfdf 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,9 @@ "commit": "git-cz", "lint": "eslint src", "release": "standard-version", - "test": "jest --config=jest.config.js", - "test:watch": "jest --config=jest.config.js --watch" + "test": "jest --config=jest.config.js --detectOpenHandles", + "test:watch": "jest --config=jest.config.js --watch --detectOpenHandles", + "test:coverage": "jest --config=jest.config.js --coverage --detectOpenHandles" }, "preferGlobal": true, "repository": { diff --git a/src/command/baseSubCommand.js b/src/command/baseSubCommand.js index 35d2d39..79d90d0 100644 --- a/src/command/baseSubCommand.js +++ b/src/command/baseSubCommand.js @@ -97,9 +97,10 @@ class BaseSubCommand { static getUniConfig(commander) { const result = {}; - ['password', 'endpoint', 'account', 'datadir'].forEach(v => { - if (commander[v]) { - result[v] = commander[v]; + ['password','endpoint','account','datadir'].forEach(v => { + const options = commander.opts(); + if (options[v]) { + result[v] = options[v]; } }); return result; diff --git a/src/index.js b/src/index.js index 5bf767c..101e76e 100644 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,6 @@ * @author atom-yang */ import { Command } from 'commander'; -const commander = new Command(); import chalk from 'chalk'; import updateNotifier from 'update-notifier'; import check from 'check-node-version'; @@ -16,7 +15,18 @@ import { userHomeDir } from './utils/userHomeDir.js'; const minVersion = '10.9.0'; -function init() { +function init(options) { + const commander = new Command(); + // Configuration for test + if (options?.exitOverride) { + // throws a JavaScript error instead of the original process exit + commander.exitOverride(); + } + if (options?.suppressOutput) { + commander.configureOutput({ + writeOut: (str) => process.stdout.write(`[OUT] ${str}`), + }); + } commander.version(pkg.version, '-v, --version'); commander.usage('[command] [options]'); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -38,17 +48,12 @@ function init() { logger.info(execSync('aelf-command -h').toString()); }); const isTest = process.env.NODE_ENV === 'test'; - const args = isTest ? process.env.mockArgs.split(',') : process.argv; - commander.parse(args); - if (commander.args.length === 0) commander.help(); - if (!isTest) { const notifier = updateNotifier({ pkg, distTag: 'latest', updateCheckInterval: 1000 * 60 * 60 * 1 // one hours }); - if (notifier.update) { notifier.notify({ message: `Update available ${chalk.dim(pkg.version)} ${chalk.reset('→')} ${chalk.green(notifier.update.latest)} @@ -56,16 +61,18 @@ function init() { }); } } + return commander; } -function run() { +function run(args, options) { check({ node: `>= ${minVersion}` }, (error, results) => { if (error) { logger.error(error); return; } if (results.isSatisfied) { - init(); + const isTest = process.env.NODE_ENV === 'test'; + init({ exitOverride: options?.exitOverride, suppressOutput: options?.suppressOutput }).parse(args, isTest ? { from: "user" } : undefined); } else { logger.error('Your Node.js version is needed to >= %s', minVersion); } diff --git a/test/index.test.js b/test/index.test.js index 6ae83fe..995652a 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,19 +1,119 @@ +import { run as aelfCommandRun } from '../src/index.js'; import path from 'path'; -import { run as aelfCommandRun } from '../src/index'; +import check from 'check-node-version'; +import updateNotifier from 'update-notifier'; +import { logger } from '../src/utils/myLogger.js'; +import pkg from '../package.json' assert { type: 'json' }; +const commandBin = path.resolve(__dirname,'../bin/aelf-command.js'); -const commandBin = path.resolve(__dirname, '../bin/aelf-command.js'); - -process.env.NODE_ENV = 'test'; - -function execCommand(cmd, args) { - process.env.mockArgs = [process.argv[0], commandBin, cmd, ...args]; - console.log(process.env.mockArgs); - return aelfCommandRun(); -} +jest.mock('check-node-version'); +jest.mock('update-notifier'); +jest.mock('child_process',() => { + return { + execSync: (str) => str + } +}); +jest.mock('../src/utils/myLogger.js'); +describe('test index',() => { + afterEach(() => { + // Restore any mocks + jest.restoreAllMocks(); + }); + test('should check node version and run init if satisfied in test environment',() => { + process.env.NODE_ENV = 'test'; + check.mockImplementation((options,callback) => { + callback(null,{ isSatisfied: true }); + }); + try { + aelfCommandRun([process.argv[0],commandBin,'-v'],{ + exitOverride: true, + suppressOutput: true, + }) + } catch (e) { + expect(check).toHaveBeenCalledWith({ node: '>= 10.9.0' },expect.any(Function)); + } + expect(() => aelfCommandRun([process.argv[0],commandBin,'-v'],{ + exitOverride: true, + suppressOutput: true, + })).toThrow(pkg.version) + }); + test('should log error if node version is not satisfied in test environment',() => { + // no notifier + process.env.NODE_ENV = 'test'; + check.mockImplementation((options,callback) => { + callback(null,{ isSatisfied: false }); + }); + aelfCommandRun([process.argv[0],commandBin,'-v'],{ + exitOverride: true, + suppressOutput: true, + }) + expect(check).toHaveBeenCalledWith({ node: '>= 10.9.0' },expect.any(Function)); + expect(logger.error).toHaveBeenCalledWith('Your Node.js version is needed to >= %s','10.9.0'); + }); -describe('test index', () => { - test('test', async () => { - await execCommand('get-chain-status', []); - }, 30000); + test('should notify update if update is available',() => { + // no need in test environment because it will not check if update in this environment + process.env.NODE_ENV = 'development'; + check.mockImplementation((options,callback) => { + callback(null,{ isSatisfied: true }); + }); + const mockNotifier = { + update: { latest: '1.1.0' }, + notify: jest.fn() + }; + updateNotifier.mockReturnValue(mockNotifier); + aelfCommandRun([process.argv[0],commandBin, 'get-chain-status', '-e', 'https://aelf-test-node.aelf.io/'],{ + exitOverride: true, + suppressOutput: true, + }) + expect(updateNotifier).toHaveBeenCalledWith({ + pkg, + distTag: 'latest', + updateCheckInterval: 1000 * 60 * 60 * 1 // one hour + }); + expect(mockNotifier.notify).toHaveBeenCalled(); + }); + test('should notify update if update is unavailable',() => { + // no need in test environment because it will not check if update in this environment + process.env.NODE_ENV = 'development'; + check.mockImplementation((options,callback) => { + callback(null,{ isSatisfied: true }); + }); + const mockNotifier = { + // no update + }; + updateNotifier.mockReturnValue(mockNotifier); + aelfCommandRun([process.argv[0],commandBin, 'get-chain-status', '-e', 'https://aelf-test-node.aelf.io/'],{ + exitOverride: true, + suppressOutput: true, + }) + expect(updateNotifier).toHaveBeenCalledWith({ + pkg, + distTag: 'latest', + updateCheckInterval: 1000 * 60 * 60 * 1 // one hour + }); + }); + test('should log error on check version failure',() => { + process.env.NODE_ENV = 'development'; + const error = new Error('Failed to check version'); + check.mockImplementation((options, callback) => { + callback(error, null); + }); + aelfCommandRun([process.argv[0],commandBin, 'get-chain-status', '-e', 'https://aelf-test-node.aelf.io/'],{ + exitOverride: true, + suppressOutput: true, + }) + expect(logger.error).toHaveBeenCalledWith(error); + }); + test('handle invalid command',() => { + const warnSpy = jest.spyOn(logger, 'warn'); + const infoSpy = jest.spyOn(logger,'info'); + check.mockImplementation((options,callback) => { + callback(null,{ isSatisfied: true }); + }); + aelfCommandRun([process.argv[0],commandBin, 'test-command']); + expect(warnSpy).toHaveBeenCalledWith('not a valid command\n'); + expect(infoSpy).toHaveBeenCalledWith('aelf-command -h'); + }) }); From b7fda86b16593211a7bb2a6c701d5473e7ba401a Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Tue, 11 Jun 2024 19:37:33 +0800 Subject: [PATCH 05/24] feat: baseSubCommand --- src/command/baseSubCommand.js | 4 +- test/command/baseSubCommand.test.js | 255 ++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 test/command/baseSubCommand.test.js diff --git a/src/command/baseSubCommand.js b/src/command/baseSubCommand.js index 79d90d0..5ac308c 100644 --- a/src/command/baseSubCommand.js +++ b/src/command/baseSubCommand.js @@ -141,7 +141,7 @@ class BaseSubCommand { const lastArg = args.slice(this.parameters.length)[0]; const localOptions = {}; this.options.forEach(({ name }) => { - localOptions[name] = lastArg[name] || undefined; + localOptions[name] = lastArg?.[name] || undefined; }); const uniOptions = BaseSubCommand.getUniConfig(commander); // get options from global config and process.argv @@ -152,7 +152,7 @@ class BaseSubCommand { }); // eslint-disable-next-line max-len const globalPrompts = globalOptionsPrompts.filter( - prompt => this.validatorDesc[prompt.name].required && !options[prompt.name] + prompt => this.validatorDesc[prompt.name]?.required && !options[prompt.name] ); const globalPromptsAns = await inquirer.prompt(globalPrompts); options = { diff --git a/test/command/baseSubCommand.test.js b/test/command/baseSubCommand.test.js new file mode 100644 index 0000000..34e8009 --- /dev/null +++ b/test/command/baseSubCommand.test.js @@ -0,0 +1,255 @@ +import inquirer from 'inquirer'; +import path from 'path'; +import ora from 'ora'; +import asyncValidator from 'async-validator'; +import BaseSubCommand from '../../src/command/baseSubCommand.js'; +import { logger } from '../../src/utils/myLogger.js'; +import RC from '../../src/rc/index.js' +import { strictGlobalOptionValidatorDesc } from '../../src/utils/constants.js' +import { Command } from 'commander'; + + +const commandBin = path.resolve(__dirname,'../bin/aelf-command.js'); + +jest.mock('inquirer'); +jest.mock('../../src/utils/myLogger'); +jest.mock('async-validator'); + + +// Sample data for testing +const sampleCommandName = 'get-chain-status'; +const sampleParameters = [{ name: 'param1',required: true }]; +const sampleDescription = 'Get the current chain status'; +const sampleOptions = [{ + flag: '-c, --cipher [cipher]', + name: 'cipher', + description: 'Which cipher algorithm to use, default to be aes-128-ctr' +}]; +const sampleUsage = ['example usage']; +const sampleRc = { getConfigs: jest.fn() }; +const sampleValidatorDesc = { testOption: { required: true } }; +const sampleOraOptions = { text: 'Loading...' }; + +describe('BaseSubCommand',() => { + let baseSubCommand; + beforeEach(() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + sampleParameters, + sampleDescription, + sampleOptions, + sampleUsage, + sampleRc, + sampleValidatorDesc, + sampleOraOptions + ); + inquirer.prompt.mockResolvedValue({}); + }); + test('should initialize with provided parameters',() => { + expect(baseSubCommand.commandName).toBe(sampleCommandName); + expect(baseSubCommand.parameters).toEqual(sampleParameters); + expect(baseSubCommand.description).toBe(sampleDescription); + expect(baseSubCommand.options).toEqual(sampleOptions); + expect(baseSubCommand.usage).toEqual(sampleUsage); + expect(baseSubCommand.rc).toBe(sampleRc); + expect(baseSubCommand.oraInstance.text).toBe(sampleOraOptions.text); + expect(baseSubCommand.validatorDesc).toEqual(sampleValidatorDesc) + }); + test('should set custom prompts flag',() => { + baseSubCommand.setCustomPrompts(true); + expect(baseSubCommand.customPrompts).toBe(true); + }); + + test('should create command with parameters and options',async () => { + const commander = { + command: jest.fn().mockReturnThis(), + description: jest.fn().mockReturnThis(), + option: jest.fn().mockReturnThis(), + action: jest.fn().mockReturnThis(), + on: jest.fn().mockReturnThis() + }; + baseSubCommand.init(commander); + expect(commander.command).toHaveBeenCalledWith(`${sampleCommandName} `); + expect(commander.description).toHaveBeenCalledWith(sampleDescription); + expect(commander.option).toHaveBeenCalledWith("-c, --cipher [cipher]","Which cipher algorithm to use, default to be aes-128-ctr"); + expect(commander.action).toHaveBeenCalled(); + expect(commander.on).toHaveBeenCalledWith('--help',expect.any(Function)); + }); + test('getParameters should return formatted parameter string',() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + [{ name: 'param1',required: true }, + { name: 'param2' }, + { name: 'param3',required: true,extraName: ['alias1','alias2'] },] + ); + const parameters = baseSubCommand.getParameters(); + expect(parameters).toBe(' [param2] '); + }); + test('should handle validation errors',() => { + const error = { errors: [{ message: 'Validation error' }] }; + jest.spyOn(process,'exit').mockImplementation(() => { }); + baseSubCommand.handleUniOptionsError(error); + expect(logger.error).toHaveBeenCalledWith('Validation error\n'); + expect(process.exit).toHaveBeenCalledWith(1); + }); + + test('should exit without errors',() => { + const error = {}; + jest.spyOn(process,'exit').mockImplementation(() => { }); + baseSubCommand.handleUniOptionsError(error); + expect(process.exit).toHaveBeenCalledWith(1); + }); + test('should normalize configuration object',() => { + const config = { 'test-option': 'true','another-option': 'false','nullOption': null }; + const normalizedConfig = BaseSubCommand.normalizeConfig(config); + expect(normalizedConfig).toEqual({ testOption: true,anotherOption: false }); + }); + + test('should parse boolean values correctly',() => { + expect(BaseSubCommand.parseBoolean('true')).toBe(true); + expect(BaseSubCommand.parseBoolean('false')).toBe(false); + expect(BaseSubCommand.parseBoolean('someValue')).toBe('someValue'); + }); + + test('should return unified configuration from commander',() => { + const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const config = BaseSubCommand.getUniConfig(commander); + expect(config).toEqual({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }); + }); + + test('should validate options and return normalized subCommandOptions',async () => { + const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = ['paramValue',{ cipher: 'true' }]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const result = await baseSubCommand.run(commander,...args); + expect(baseSubCommand.rc.getConfigs).toHaveBeenCalled(); + expect(baseSubCommand.validator.validate).toHaveBeenCalled(); + expect(result).toEqual({ + localOptions: { cipher: 'true' }, + options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, + subOptions: { param1: 'paramValue' } + }); + // customPrompts true + baseSubCommand.setCustomPrompts(true); + const result2 = await baseSubCommand.run(commander,...args); + expect(result2).toEqual({ + localOptions: { cipher: 'true' }, + options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, + subOptions: { param1: 'paramValue' } + }); + }); + test('fail to run validate',async () => { + const originalValidate = asyncValidator.prototype.validate; + asyncValidator.prototype.validate = jest.fn().mockRejectedValue(new Error('Validation error')); + baseSubCommand = new BaseSubCommand( + sampleCommandName, + sampleParameters, + sampleDescription, + sampleOptions, + sampleUsage, + sampleRc, + sampleValidatorDesc, + sampleOraOptions + ); + const mockExit = jest.spyOn(process,'exit').mockImplementation(() => { }); + const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = ['paramValue',{ cipher: 'true' }]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + await baseSubCommand.run(commander,...args); + expect(mockExit).toHaveBeenCalledWith(1); + // Clean up + asyncValidator.prototype.validate = originalValidate; // Restore original validate method + // Clean up + mockExit.mockRestore(); + }) + test('run without args',async () => { + const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = [undefined]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const result = await baseSubCommand.run(commander,...args); + expect(result).toEqual({ + localOptions: { cipher: undefined }, + options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, + subOptions: { testOption: true } + }); + }); + test('makeExamples should return formatted examples',() => { + const examples = baseSubCommand.makeExamples(); + expect(examples).toEqual([ + 'aelf-command get-chain-status example usage', + ]); + }); +}); + +describe('BaseSubCommand with default params',() => { + let baseSubCommand; + beforeEach(() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + ); + inquirer.prompt.mockResolvedValue({}); + }); + test('with default params',() => { + expect(baseSubCommand.commandName).toBe(sampleCommandName); + expect(baseSubCommand.parameters).toEqual([]); + expect(baseSubCommand.description).toBe(undefined); + expect(baseSubCommand.options).toEqual([]); + expect(baseSubCommand.usage).toEqual([]); + expect(baseSubCommand.rc).toBe(undefined); + expect(baseSubCommand.oraInstance.text).toBe("AElf loading..."); + expect(baseSubCommand.validatorDesc).toEqual(strictGlobalOptionValidatorDesc) + }) + test('should execute action callback',() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + undefined, + sampleDescription, + ); + + const commander = new Command(); + baseSubCommand.run = jest.fn(); + commander.option('-e, --endpoint ','The URI of an AElf node. Eg: http://127.0.0.1:8000'); + baseSubCommand.init(commander); + commander.parse([process.argv[0],commandBin,'get-chain-status','-e','https://aelf-test-node.aelf.io/']); + // Spy on the run method + jest.spyOn(baseSubCommand,'run').mockResolvedValue('run called'); + // Expect the run method to have been called + expect(baseSubCommand.run).toHaveBeenCalled(); + }); + test('should log examples on --help',() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + undefined, + sampleDescription, + ); + const commander = new Command(); + commander.exitOverride(); + // Setting up the commander help handler + baseSubCommand.init(commander); + expect(() => commander.parse([process.argv[0],commandBin,'get-chain-status','--help'])).toThrow() + }); + test('run with no required validatorDesc',async () => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + undefined, + sampleDescription, + sampleOptions, + sampleUsage, + sampleRc, + { account: { required: true } } + ); + const args = [undefined]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const result = await baseSubCommand.run(commander,...args); + expect(result).toEqual({ + localOptions: { cipher: undefined }, + options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, + subOptions: {} + }); + }); +}) \ No newline at end of file From 638d1a3c5c5e76eff3daac1eb3a16508d4c83105 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Thu, 13 Jun 2024 14:36:09 +0800 Subject: [PATCH 06/24] feat: call & config test --- src/command/config.js | 2 - test/command/call.test.js | 142 +++++++++++++++++ test/command/config.test.js | 145 ++++++++++++++++++ ...D9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json | 23 +++ 4 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 test/command/call.test.js create mode 100644 test/command/config.test.js create mode 100644 test/dataDir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json diff --git a/src/command/config.js b/src/command/config.js index 8f5b90d..08d94d4 100644 --- a/src/command/config.js +++ b/src/command/config.js @@ -99,8 +99,6 @@ class ConfigCommand extends BaseSubCommand { result = this.rc.deleteConfig(key); this.oraInstance.succeed('Succeed!'); break; - default: - throw new Error(`${flag} is not a valid flag, must one of set, get, list, delete`); } } catch (e) { this.oraInstance.fail('Failed!'); diff --git a/test/command/call.test.js b/test/command/call.test.js new file mode 100644 index 0000000..e39ce96 --- /dev/null +++ b/test/command/call.test.js @@ -0,0 +1,142 @@ +import { Command } from 'commander'; +import path from 'path'; +import AElf from 'aelf-sdk'; +import { CallCommand } from '../../src/command'; +import { callCommandUsages, callCommandParameters } from '../../src/utils/constants.js'; +import { getContractInstance } from '../../src/utils/utils.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger.js'; +import inquirer from 'inquirer'; + +const sampleRc = { getConfigs: jest.fn() }; +jest.mock('../../src/utils/myLogger'); + +describe('CallCommand', () => { + let callCommand; + let mockOraInstance; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const aelf = new AElf(new AElf.providers.HttpProvider(endPoint)); + const wallet = AElf.wallet.getWalletByPrivateKey('943df6d39fd1e1cc6ae9813e54f7b9988cf952814f9c31e37744b52594cb4096'); + const address = 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + beforeEach(() => { + backup = inquirer.prompt; + mockOraInstance = { + start: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + callCommand = new CallCommand(sampleRc); + callCommand.oraInstance = mockOraInstance; + }); + test('with default params', async () => { + expect(callCommand.commandName).toBe('call'); + expect(callCommand.parameters).toEqual(callCommandParameters); + expect(callCommand.description).toBe('Call a read-only method on a contract.'); + expect(callCommand.options).toEqual([]); + expect(callCommand.usage).toEqual(callCommandUsages); + expect(callCommand.rc).toEqual(sampleRc); + }); + test('should call method successfully', async () => { + const tokenContract = await aelf.chain.contractAt(address, wallet); + const method = tokenContract.GetTokenInfo; + const params = { + symbol: 'ELF' + }; + const result = await callCommand.callMethod(method, params); + expect(mockOraInstance.start).toHaveBeenCalledWith('Calling method...'); + expect(mockOraInstance.succeed).toHaveBeenCalledWith('Calling method successfully!'); + }, 20000); + test('should process address after prompt', async () => { + const answerInput = { contractAddress: address }; + const result = await callCommand.processAddressAfterPrompt(aelf, wallet, answerInput); + expect(result.address).toBe(address); + }, 20000); + test('should run with valid inputs', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await callCommand.run( + commander, + 'AElf.ContractNames.Token', + 'GetTokenInfo', + JSON.stringify({ + symbol: 'ELF' + }) + ); + expect(logger.info).toHaveBeenCalled(); + }, 20000); + test('should run without contractAddress', async () => { + inquirer.prompt = questions => Promise.resolve(''); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await callCommand.run(commander); + expect(logger.fatal).toHaveBeenCalled(); + }, 5000); + + test('should run without params', async () => { + inquirer.prompt = questions => Promise.resolve({ symbol: 'ELF' }); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await callCommand.run(commander, 'AElf.ContractNames.Token', 'GetTokenInfo'); + expect(logger.info).toHaveBeenCalled(); + }, 20000); + + test('should run with invalid parameters', async () => { + inquirer.prompt = backup; + callCommand = new CallCommand(sampleRc, 'call', 'Call a read-only method on a contract.', [ + ...callCommandParameters, + { + type: 'input', + name: 'fake-prop', + message: 'This is a fake prop', + suffix: ':' + } + ]); + // inquirer.prompt = questions => Promise.resolve({ fakeProp: 'ELF' }); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await callCommand.run( + commander, + 'AElf.ContractNames.Token', + 'GetTokenInfo', + JSON.stringify({ + symbol: 'ELF' + }) + ); + expect(logger.info).toHaveBeenCalled(); + }, 20000); + + afterEach(() => { + inquirer.prompt = backup; + }); +}); diff --git a/test/command/config.test.js b/test/command/config.test.js new file mode 100644 index 0000000..7fcff32 --- /dev/null +++ b/test/command/config.test.js @@ -0,0 +1,145 @@ +import ora from 'ora'; +import path from 'path'; +import { Command } from 'commander'; +import ConfigCommand from '../../src/command/config.js'; +import { logger } from '../../src/utils/myLogger.js'; + +jest.mock('ora'); +jest.mock('inquirer'); +jest.mock('../../src/utils/myLogger.js'); + +describe('ConfigCommand', () => { + let configCommand; + let mockOraInstance; + const sampleRc = { + getConfigs: jest.fn(), + getOption: jest.fn(), + saveOption: jest.fn(), + getFileConfigs: jest.fn(), + deleteConfig: jest.fn() + }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + beforeEach(() => { + mockOraInstance = { + start: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + ora.mockReturnValue(mockOraInstance); + configCommand = new ConfigCommand(sampleRc); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + test('should validate parameters successfully', async () => { + const rule = { + key: { type: 'string', required: true } + }; + const parameters = { key: 'someKey' }; + await expect(configCommand.validateParameters(rule, parameters)).resolves.not.toThrow(); + }); + test('should handle invalid parameters', async () => { + const rule = { + key: { type: 'string', required: true } + }; + const parameters = {}; + jest.spyOn(configCommand, 'handleUniOptionsError').mockImplementation(() => {}); + + await configCommand.validateParameters(rule, parameters); + expect(configCommand.handleUniOptionsError).toHaveBeenCalled(); + }); + it('should handle list correctly', () => { + const content = { + key1: 'value1', + key2: '', + key3: 'value3' + }; + const result = configCommand.handleList(content); + expect(result).toBe('key1=value1\nkey3=value3\n'); + }); + it('should run with flag "get"', async () => { + configCommand.rc.getConfigs.mockReturnValue({ + endpoint: endPoint, + datadir: dataDir + }); + configCommand.rc.getOption.mockReturnValue(endPoint); + const commander = new Command(); + await configCommand.run(commander, 'get', 'endpoint'); + expect(logger.info).toHaveBeenCalledWith(endPoint); + }); + + it('should run with flag "set"', async () => { + configCommand.rc.getConfigs.mockReturnValue({ + endpoint: endPoint, + datadir: dataDir + }); + configCommand.rc.saveOption.mockReturnValue(endPoint); + const commander = new Command(); + await configCommand.run(commander, 'set', 'endpoint', endPoint); + expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + }); + + it('should run with flag "list"', async () => { + configCommand.rc.getConfigs.mockReturnValue({ + endpoint: endPoint, + datadir: dataDir + }); + configCommand.rc.getFileConfigs.mockReturnValue('endpoint=https://tdvw-test-node.aelf.io/'); + const commander = new Command(); + await configCommand.run(commander, 'list'); + expect(configCommand.rc.getFileConfigs).toHaveBeenCalled(); + }); + + it('should run with flag "delete"', async () => { + configCommand.rc.getConfigs.mockReturnValue({ + endpoint: endPoint, + datadir: dataDir + }); + configCommand.rc.deleteConfig.mockReturnValue(endPoint); + const commander = new Command(); + await configCommand.run(commander, 'delete', 'endpoint'); + expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + }); + + // it('should run with flag "list"', async () => { + // const subOptions = { flag: 'list' }; + // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); + // configCommand.rc.getFileConfigs.mockReturnValue({ key1: 'value1' }); + + // await configCommand.run({} /* commander */, subOptions); + + // expect(configCommand.rc.getFileConfigs).toHaveBeenCalled(); + // expect(console.log).toHaveBeenCalledWith('\nkey1=value1\n'); + // }); + + // it('should run with flag "delete"', async () => { + // const subOptions = { flag: 'delete', key: 'testKey' }; + // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); + + // await configCommand.run({} /* commander */, subOptions); + + // expect(configCommand.rc.deleteConfig).toHaveBeenCalledWith('testKey'); + // expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + // }); + + // it('should handle invalid flag', async () => { + // const subOptions = { flag: 'invalid' }; + // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); + + // await expect(configCommand.run({} /* commander */, subOptions)).rejects.toThrow( + // 'invalid is not a valid flag, must one of set, get, list, delete' + // ); + // }); + + // it('should handle validation error', async () => { + // const subOptions = { flag: 'get', key: 'testKey' }; + // const error = new Error('Validation failed'); + // jest.spyOn(configCommand, 'validateParameters').mockRejectedValue(error); + + // await configCommand.run({} /* commander */, subOptions); + + // expect(mockOraInstance.fail).toHaveBeenCalledWith('Failed!'); + // expect(logger.error).toHaveBeenCalledWith(error); + // }); +}); diff --git a/test/dataDir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json b/test/dataDir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json new file mode 100644 index 0000000..040079d --- /dev/null +++ b/test/dataDir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "type": "aelf", + "nickName": "", + "address": "GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk", + "crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "0f6fac1dc5bd410798f34be630c4e639cc272a4f48d59f39789fd20e7c84c133", + "cipherparams": { + "iv": "4fd709e0776b85a0a835a63e87d623cc" + }, + "mnemonicEncrypted": "fc2ebc5f4e7b437ebc83d40a97a309c02df7c9b6c9fab0e3696c3e07631fb0cfcce3cfab92646591f92cd0babba1aa86e715896d2b27643fb520e56fedf667317b266887ec0052c375", + "kdf": "scrypt", + "kdfparams": { + "r": 8, + "n": 8192, + "p": 1, + "dklen": 32, + "salt": "39a7a1fe4c3e7341b4b8e4c25f98c090ca8a908837d07424052c87a64a701875" + }, + "mac": "9eb9bd3a87fc04577642e422053dd82fffc772652f9679d77fdf94f8ee3b482e" + } +} \ No newline at end of file From e73fbb61da16bb3252b9e65acfb9e57574a142b2 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Thu, 13 Jun 2024 16:54:22 +0800 Subject: [PATCH 07/24] feat: console & create --- test/command/console.test.js | 67 ++++++++++++++++++++++ test/command/create.test.js | 106 +++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 test/command/console.test.js create mode 100644 test/command/create.test.js diff --git a/test/command/console.test.js b/test/command/console.test.js new file mode 100644 index 0000000..5a52757 --- /dev/null +++ b/test/command/console.test.js @@ -0,0 +1,67 @@ +import boxen from 'boxen'; +import repl from 'repl'; +import path from 'path'; +import { Command } from 'commander'; +import ConsoleCommand from '../../src/command/console.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger'; + +jest.mock('boxen'); +jest.mock('repl'); +jest.mock('../../src/utils/myLogger'); + +describe('ConsoleCommand', () => { + let consoleCommand; + let oraInstance; + const sampleRc = { + getConfigs: jest.fn() + }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + beforeEach(() => { + oraInstance = { + succeed: jest.fn(), + fail: jest.fn() + }; + consoleCommand = new ConsoleCommand(sampleRc); + consoleCommand.oraInstance = oraInstance; + }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should run the console command successfully', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + boxen.mockReturnValue('mockBoxen'); + repl.start.mockReturnValue({ context: {} }); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await consoleCommand.run(commander); + expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + expect(logger.info).toHaveBeenCalledTimes(2); + }, 20000); + it('should handle errors correctly', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + boxen.mockImplementation(() => { + throw new Error('boxen error'); + }); + await consoleCommand.run(commander); + expect(oraInstance.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.error).toHaveBeenCalled(); + }, 20000); +}); diff --git a/test/command/create.test.js b/test/command/create.test.js new file mode 100644 index 0000000..f4b84ed --- /dev/null +++ b/test/command/create.test.js @@ -0,0 +1,106 @@ +import { Command } from 'commander'; +import path from 'path'; +import CreateCommand from '../../src/command/create.js'; +import { saveKeyStore } from '../../src/utils/wallet'; +import { logger } from '../../src/utils/myLogger'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('../../src/utils/wallet'); +jest.mock('../../src/utils/myLogger'); + +describe('CreateCommand', () => { + let createCommand; + let oraInstance; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + beforeEach(() => { + oraInstance = { + succeed: jest.fn(), + fail: jest.fn() + }; + createCommand = new CreateCommand(sampleRc); + createCommand.oraInstance = oraInstance; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should create a new wallet and log info', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const keyStore = '/path/to/keystore'; + saveKeyStore.mockResolvedValue(keyStore); + await createCommand.run(commander, true); + expect(logger.info).toHaveBeenCalledWith('Your wallet info is :'); + expect(saveKeyStore).toHaveBeenCalled(); + }); + + it('should succeed without saving to file', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const keyStore = '/path/to/keystore'; + saveKeyStore.mockResolvedValue(keyStore); + await createCommand.run(commander, false); + expect(logger.info).toHaveBeenCalledWith('Your wallet info is :'); + expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + }); + + it('should handle saveKeyStore error', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + saveKeyStore.mockImplementation(() => { + throw new Error('saveKeyStore error'); + }); + await createCommand.run(commander, true); + expect(oraInstance.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.error).toHaveBeenCalled(); + }); + + // it('should succeed without saving to file', async () => { + // BaseSubCommand.mockImplementation(() => ({ + // oraInstance, + // run: jest.fn().mockResolvedValue({ + // localOptions: { cipher: 'aes-128-ctr' }, + // options: { datadir: 'testDir' }, + // subOptions: { saveToFile: false } + // }) + // })); + // const mockWallet = { + // mnemonic: 'test mnemonic', + // privateKey: 'test privateKey', + // keyPair: { getPublic: () => ({ encode: () => 'test publicKey' }) }, + // address: 'test address' + // }; + // AElf.wallet.createNewWallet.mockReturnValue(mockWallet); + + // await createCommand.run(); + + // expect(AElf.wallet.createNewWallet).toHaveBeenCalled(); + // expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); + // }); +}); From 444f185b40f11e0f72991d5723afb15c99d62520 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Fri, 14 Jun 2024 16:27:26 +0800 Subject: [PATCH 08/24] feat: until load command --- src/command/getBlkInfo.js | 2 +- src/utils/utils.js | 1 + test/command/config.test.js | 41 --------- test/command/create.test.js | 23 ----- test/command/deploy.test.js | 52 +++++++++++ test/command/event.test.js | 99 ++++++++++++++++++++ test/command/getBlkHeight.test.js | 61 +++++++++++++ test/command/getBlkInfo.test.js | 127 ++++++++++++++++++++++++++ test/command/getChainStatus.test.js | 62 +++++++++++++ test/command/getTxResult.test.js | 61 +++++++++++++ test/command/load.test.js | 134 ++++++++++++++++++++++++++++ 11 files changed, 598 insertions(+), 65 deletions(-) create mode 100644 test/command/deploy.test.js create mode 100644 test/command/event.test.js create mode 100644 test/command/getBlkHeight.test.js create mode 100644 test/command/getBlkInfo.test.js create mode 100644 test/command/getChainStatus.test.js create mode 100644 test/command/getTxResult.test.js create mode 100644 test/command/load.test.js diff --git a/src/command/getBlkInfo.js b/src/command/getBlkInfo.js index 8bbd064..6a5b6a6 100644 --- a/src/command/getBlkInfo.js +++ b/src/command/getBlkInfo.js @@ -49,7 +49,7 @@ class GetBlkInfoCommand extends BaseSubCommand { subOptions ); const aelf = new AElf(new AElf.providers.HttpProvider(options.endpoint)); - const { height, includeTxs = false } = subOptions; + const { height, includeTxs } = subOptions; try { this.oraInstance.start(); let blockInfo; diff --git a/src/utils/utils.js b/src/utils/utils.js index 55d920a..c6eebdb 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -11,6 +11,7 @@ import fs from 'fs'; import _camelCase from 'camelcase'; import inquirer from 'inquirer'; import { plainLogger } from './myLogger.js'; +import * as protobuf from '@aelfqueen/protobufjs'; function promisify(fn, firstData) { return (...args) => diff --git a/test/command/config.test.js b/test/command/config.test.js index 7fcff32..7218757 100644 --- a/test/command/config.test.js +++ b/test/command/config.test.js @@ -101,45 +101,4 @@ describe('ConfigCommand', () => { await configCommand.run(commander, 'delete', 'endpoint'); expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); }); - - // it('should run with flag "list"', async () => { - // const subOptions = { flag: 'list' }; - // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); - // configCommand.rc.getFileConfigs.mockReturnValue({ key1: 'value1' }); - - // await configCommand.run({} /* commander */, subOptions); - - // expect(configCommand.rc.getFileConfigs).toHaveBeenCalled(); - // expect(console.log).toHaveBeenCalledWith('\nkey1=value1\n'); - // }); - - // it('should run with flag "delete"', async () => { - // const subOptions = { flag: 'delete', key: 'testKey' }; - // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); - - // await configCommand.run({} /* commander */, subOptions); - - // expect(configCommand.rc.deleteConfig).toHaveBeenCalledWith('testKey'); - // expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); - // }); - - // it('should handle invalid flag', async () => { - // const subOptions = { flag: 'invalid' }; - // jest.spyOn(configCommand, 'validateParameters').mockResolvedValue(); - - // await expect(configCommand.run({} /* commander */, subOptions)).rejects.toThrow( - // 'invalid is not a valid flag, must one of set, get, list, delete' - // ); - // }); - - // it('should handle validation error', async () => { - // const subOptions = { flag: 'get', key: 'testKey' }; - // const error = new Error('Validation failed'); - // jest.spyOn(configCommand, 'validateParameters').mockRejectedValue(error); - - // await configCommand.run({} /* commander */, subOptions); - - // expect(mockOraInstance.fail).toHaveBeenCalledWith('Failed!'); - // expect(logger.error).toHaveBeenCalledWith(error); - // }); }); diff --git a/test/command/create.test.js b/test/command/create.test.js index f4b84ed..34bc202 100644 --- a/test/command/create.test.js +++ b/test/command/create.test.js @@ -80,27 +80,4 @@ describe('CreateCommand', () => { expect(oraInstance.fail).toHaveBeenCalledWith('Failed!'); expect(logger.error).toHaveBeenCalled(); }); - - // it('should succeed without saving to file', async () => { - // BaseSubCommand.mockImplementation(() => ({ - // oraInstance, - // run: jest.fn().mockResolvedValue({ - // localOptions: { cipher: 'aes-128-ctr' }, - // options: { datadir: 'testDir' }, - // subOptions: { saveToFile: false } - // }) - // })); - // const mockWallet = { - // mnemonic: 'test mnemonic', - // privateKey: 'test privateKey', - // keyPair: { getPublic: () => ({ encode: () => 'test publicKey' }) }, - // address: 'test address' - // }; - // AElf.wallet.createNewWallet.mockReturnValue(mockWallet); - - // await createCommand.run(); - - // expect(AElf.wallet.createNewWallet).toHaveBeenCalled(); - // expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); - // }); }); diff --git a/test/command/deploy.test.js b/test/command/deploy.test.js new file mode 100644 index 0000000..b6b08ad --- /dev/null +++ b/test/command/deploy.test.js @@ -0,0 +1,52 @@ +/* eslint-disable max-len */ +import { Command } from 'commander'; +import path from 'path'; +import chalk from 'chalk'; +import DeployCommand from '../../src/command/deploy.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('chalk', () => { + return { + blue: jest.fn(), + green: jest.fn(), + yellow: jest.fn(), + red: jest.fn(), + hex: jest.fn(), + redBright: jest.fn((...args) => `redBright(${args.join('')})`), + yellowBright: jest.fn(text => `yellowBright(${text})`) + }; +}); + +describe('DeployCommand', () => { + let deployCommand; + let consoleSpy; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + beforeEach(() => { + consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + deployCommand = new DeployCommand(sampleRc); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should log deprecation message when run is called', async () => { + // chalk.redBright.mockReturnValue = text => `redBright(${text})`; + const expectedTips = `redBright(Deprecated! Please use yellowBright(\`aelf-command send\`), check details in aelf-command \`README.md\`)`; + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await deployCommand.run(commander); + expect(consoleSpy).toHaveBeenCalledWith(expectedTips); + }, 20000); +}); diff --git a/test/command/event.test.js b/test/command/event.test.js new file mode 100644 index 0000000..aea40e5 --- /dev/null +++ b/test/command/event.test.js @@ -0,0 +1,99 @@ +import { Command } from 'commander'; +import path from 'path'; +import EventCommand from '../../src/command/event.js'; +import { logger, plainLogger } from '../../src/utils/myLogger'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('../../src/utils/myLogger'); + +describe('EventCommand', () => { + let eventCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + eventCommand = new EventCommand(sampleRc); + eventCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should deserialize logs and succeed', async () => { + const txId = 'ef17ac2078c2b31a702b9edc754bfa56f1c37931f52f9dd8e2b9dc65769966b1'; + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'event', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const logs = [ + { + Address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + Name: 'Transferred', + Indexed: [ + 'CiIKIKl+hAq40lOArRO+3srxpNVRFOaGZtH4WUSLGW7qDyoI', + 'EiIKINhKsag9MOuJ2sbYwzlGfKCeOcGHu4qPWYp6DeqjrOZw', + 'GgNFTEY=' + ], + NonIndexed: 'IICglKWNHQ==', + Result: { + from: '2HeW7S9HZrbRJZeivMppUuUY3djhWdfVnP5zrDsz8wqq6hKMfT', + to: '2eFtDbjWBDPJ6oNtRLjYuS5XrtjSzw4CnrCM79U1HjdvKkGYrF', + symbol: 'ELF', + amount: '1000000000000' + } + } + ]; + await eventCommand.run(commander, txId); + expect(plainLogger.info).toHaveBeenCalledWith( + `\nThe results returned by \nTransaction: ${txId} is: \n${JSON.stringify(logs, null, 2)}` + ); + expect(oraInstanceMock.fail).not.toHaveBeenCalled(); + }, 20000); + + it('should log "not mined" if transaction status is not mined', async () => { + const txId = '3553df418c6ec9a159560440f13a6ae29f786392574737036cf63786321c8a40'; + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'event', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await eventCommand.run(commander, txId); + expect(plainLogger.info).toHaveBeenCalledWith(`Transaction ${txId} is not mined`); + expect(oraInstanceMock.fail).not.toHaveBeenCalled(); + }, 20000); + + it('should log error and fail on exception', async () => { + const txId = 'test'; + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'event', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await eventCommand.run(commander, txId); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + }, 20000); +}); diff --git a/test/command/getBlkHeight.test.js b/test/command/getBlkHeight.test.js new file mode 100644 index 0000000..90920c4 --- /dev/null +++ b/test/command/getBlkHeight.test.js @@ -0,0 +1,61 @@ +import { Command } from 'commander'; +import path from 'path'; +import GetBlkHeightCommand from '../../src/command/getBlkHeight.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('../../src/utils/myLogger'); + +describe('GetBlkHeightCommand', () => { + let getBlkHeightCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + getBlkHeightCommand = new GetBlkHeightCommand(sampleRc); + getBlkHeightCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should get block height and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-blk-height', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getBlkHeightCommand.run(commander); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + }, 20000); + it('should log error and fail on exception', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-blk-height', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + oraInstanceMock.start.mockImplementation(() => { + throw new Error('mock error'); + }); + await getBlkHeightCommand.run(commander); + expect(oraInstanceMock.fail).toHaveBeenCalled(); + }); +}); diff --git a/test/command/getBlkInfo.test.js b/test/command/getBlkInfo.test.js new file mode 100644 index 0000000..cc382b8 --- /dev/null +++ b/test/command/getBlkInfo.test.js @@ -0,0 +1,127 @@ +/* eslint-disable max-len */ +import { Command } from 'commander'; +import path from 'path'; +import GetBlkInfoCommand from '../../src/command/getBlkInfo.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger'; + +jest.mock('../../src/utils/myLogger'); + +describe('GetBlkInfoCommand', () => { + let getBlkInfoCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + getBlkInfoCommand = new GetBlkInfoCommand(sampleRc); + getBlkInfoCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should get block info by height and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-blk-info', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getBlkInfoCommand.run(commander, '123', true); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith({ + BlockHash: '5482f050b51b91496c70b4601fd3049c83f771c9832a370489a6cbad1202a649', + BlockSize: 1393, + Body: { + Transactions: [ + 'e9ed63a9e22931838cd2835ea52eea3083ec0561dedc77fce42067ff88a07fe5', + '491a510eacde8485f5a02c68da42f16fea6ad6795edbcc8b7217804d08d52fda' + ], + TransactionsCount: 2 + }, + Header: { + Bloom: + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', + ChainId: 'tDVW', + Extra: + '{ "CrossChain": "", "Consensus": "CkEE6CtyGYhrpUqwtY7OnCNCLenuCS6JQRgc29PY0tJONpj0smWuvdOwHSmuhU1i7pQnGYpB5/49syK+fJwvZi93zRLxBggEEr4CCoIBMDRlODJiNzIxOTg4NmJhNTRhYjBiNThlY2U5YzIzNDIyZGU5ZWUwOTJlODk0MTE4MWNkYmQzZDhkMmQyNGUzNjk4ZjRiMjY1YWViZGQzYjAxZDI5YWU4NTRkNjJlZTk0MjcxOThhNDFlN2ZlM2RiMzIyYmU3YzljMmY2NjJmNzdjZBK2ATgTSoIBMDRlODJiNzIxOTg4NmJhNTRhYjBiNThlY2U5YzIzNDIyZGU5ZWUwOTJlODk0MTE4MWNkYmQzZDhkMmQyNGUzNjk4ZjRiMjY1YWViZGQzYjAxZDI5YWU4NTRkNjJlZTk0MjcxOThhNDFlN2ZlM2RiMzIyYmU3YzljMmY2NjJmNzdjZGoLCOi94pQGEMiAiW9qDAjoveKUBhCggbzIAWoMCOi94pQGEKzA+PIBgAEDiAF5EocBCoIBMDQzNTdiMWFkOGMwNTc2ZDI2YWEzZDZiMmQwOWIyYWQwM2JmNWRiY2UyMjM3MzA2MzYxNDVjZjQ0M2ZlYjM3ZmIxOTE1NmI5OTE5NGZhNDhhZDkyNTY2Yjk1YzQ1NDkzOWRmMmNhNzFlOWJmNTE3YzI1OTBjMmVlZGRkNzZjZjkxZRIAEocBCoIBMDQyZDIyMTA1YTU3YzEwNjFkZDNjZjZlODhiYjMxOWJmNzU0NTc2MjY5ZGVhZTU4NmVkMTAwYzg0N2NhYjFkM2YxYjU1NzczYzMxZjVlNzM5NjcwZjUzZmQ0ZjBkODU5ZmJiYTZiY2Y4ZDI4MGYxNWRlOGRiYmM0NTExODE1MTdhYhIAEocBCoIBMDQ1Mjc2MmVjMjFmZWQyOWY0Y2I4NmRmM2ZjMDhmMDJhMjM4NWM4NGQ0NWRmZDRlZjU0MDA1OTczYjQxZjVhYjI2NGUyZTVkZTBkNDZlYzQ1ZTY0OTFiOTgxMDUwMzgwYjBhYTE5NzE0YWY0ZjA4Nzg1NjAzMjE4OTNlNjI2MzFlNBIAEocBCoIBMDQ3Nzk0ZTViNDI0MTc3YmYwM2Y5ZDVlNTQxZTdiZGEyODA1NjIwOWQ4MTRjNjhhZWQyNjcwZTQ2ZDk2M2M4NWQwNGRhNWY2OWVmODI0NThlODYxNzQ4OTA3NDM5ODVlMjk3ODQzNDg1YjEwZDAyOTVmYzI4Yjg4NTMzNTVjZmI4YhIAUJy17OceGAQ=", "SystemTransactionCount": "CAI=" }', + Height: 123, + MerkleTreeRootOfTransactionState: '51138bb99d42fb7b7f2ba5691ab5b26c6a1fdf9b0e130baa910bcceeeb86b355', + MerkleTreeRootOfTransactions: '630d56e6f0b1c2678ec5eb41fb45d0d1b3fb67db8afdfe4c40c4a37be31f6039', + MerkleTreeRootOfWorldState: 'c129757cfc5c72b9f2415a380f27e9723b9ca095f4e84ba83415f9a258c34dfb', + PreviousBlockHash: '9ded101527432838273056a0a250b015ad8bf5bc3806391b481974457030d628', + SignerPubkey: + '04e82b7219886ba54ab0b58ece9c23422de9ee092e8941181cdbd3d8d2d24e3698f4b265aebdd3b01d29ae854d62ee9427198a41e7fe3db322be7c9c2f662f77cd', + Time: '2022-06-02T11:28:40.5094851Z' + } + }); + }, 20000); + it('should get block info by hash and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-blk-info', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getBlkInfoCommand.run(commander, '5482f050b51b91496c70b4601fd3049c83f771c9832a370489a6cbad1202a649', true); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith({ + BlockHash: '5482f050b51b91496c70b4601fd3049c83f771c9832a370489a6cbad1202a649', + BlockSize: 1393, + Body: { + Transactions: [ + 'e9ed63a9e22931838cd2835ea52eea3083ec0561dedc77fce42067ff88a07fe5', + '491a510eacde8485f5a02c68da42f16fea6ad6795edbcc8b7217804d08d52fda' + ], + TransactionsCount: 2 + }, + Header: { + Bloom: + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', + ChainId: 'tDVW', + Extra: + '{ "CrossChain": "", "Consensus": "CkEE6CtyGYhrpUqwtY7OnCNCLenuCS6JQRgc29PY0tJONpj0smWuvdOwHSmuhU1i7pQnGYpB5/49syK+fJwvZi93zRLxBggEEr4CCoIBMDRlODJiNzIxOTg4NmJhNTRhYjBiNThlY2U5YzIzNDIyZGU5ZWUwOTJlODk0MTE4MWNkYmQzZDhkMmQyNGUzNjk4ZjRiMjY1YWViZGQzYjAxZDI5YWU4NTRkNjJlZTk0MjcxOThhNDFlN2ZlM2RiMzIyYmU3YzljMmY2NjJmNzdjZBK2ATgTSoIBMDRlODJiNzIxOTg4NmJhNTRhYjBiNThlY2U5YzIzNDIyZGU5ZWUwOTJlODk0MTE4MWNkYmQzZDhkMmQyNGUzNjk4ZjRiMjY1YWViZGQzYjAxZDI5YWU4NTRkNjJlZTk0MjcxOThhNDFlN2ZlM2RiMzIyYmU3YzljMmY2NjJmNzdjZGoLCOi94pQGEMiAiW9qDAjoveKUBhCggbzIAWoMCOi94pQGEKzA+PIBgAEDiAF5EocBCoIBMDQzNTdiMWFkOGMwNTc2ZDI2YWEzZDZiMmQwOWIyYWQwM2JmNWRiY2UyMjM3MzA2MzYxNDVjZjQ0M2ZlYjM3ZmIxOTE1NmI5OTE5NGZhNDhhZDkyNTY2Yjk1YzQ1NDkzOWRmMmNhNzFlOWJmNTE3YzI1OTBjMmVlZGRkNzZjZjkxZRIAEocBCoIBMDQyZDIyMTA1YTU3YzEwNjFkZDNjZjZlODhiYjMxOWJmNzU0NTc2MjY5ZGVhZTU4NmVkMTAwYzg0N2NhYjFkM2YxYjU1NzczYzMxZjVlNzM5NjcwZjUzZmQ0ZjBkODU5ZmJiYTZiY2Y4ZDI4MGYxNWRlOGRiYmM0NTExODE1MTdhYhIAEocBCoIBMDQ1Mjc2MmVjMjFmZWQyOWY0Y2I4NmRmM2ZjMDhmMDJhMjM4NWM4NGQ0NWRmZDRlZjU0MDA1OTczYjQxZjVhYjI2NGUyZTVkZTBkNDZlYzQ1ZTY0OTFiOTgxMDUwMzgwYjBhYTE5NzE0YWY0ZjA4Nzg1NjAzMjE4OTNlNjI2MzFlNBIAEocBCoIBMDQ3Nzk0ZTViNDI0MTc3YmYwM2Y5ZDVlNTQxZTdiZGEyODA1NjIwOWQ4MTRjNjhhZWQyNjcwZTQ2ZDk2M2M4NWQwNGRhNWY2OWVmODI0NThlODYxNzQ4OTA3NDM5ODVlMjk3ODQzNDg1YjEwZDAyOTVmYzI4Yjg4NTMzNTVjZmI4YhIAUJy17OceGAQ=", "SystemTransactionCount": "CAI=" }', + Height: 123, + MerkleTreeRootOfTransactionState: '51138bb99d42fb7b7f2ba5691ab5b26c6a1fdf9b0e130baa910bcceeeb86b355', + MerkleTreeRootOfTransactions: '630d56e6f0b1c2678ec5eb41fb45d0d1b3fb67db8afdfe4c40c4a37be31f6039', + MerkleTreeRootOfWorldState: 'c129757cfc5c72b9f2415a380f27e9723b9ca095f4e84ba83415f9a258c34dfb', + PreviousBlockHash: '9ded101527432838273056a0a250b015ad8bf5bc3806391b481974457030d628', + SignerPubkey: + '04e82b7219886ba54ab0b58ece9c23422de9ee092e8941181cdbd3d8d2d24e3698f4b265aebdd3b01d29ae854d62ee9427198a41e7fe3db322be7c9c2f662f77cd', + Time: '2022-06-02T11:28:40.5094851Z' + } + }); + }, 20000); + it('should log error and fail on exception', async () => { + jest.spyOn(process, 'exit').mockImplementation(() => {}); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-blk-info', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getBlkInfoCommand.run(commander, true, false); + expect(process.exit).toHaveBeenCalledWith(1); + expect(oraInstanceMock.fail).toHaveBeenCalled(); + }, 20000); +}); diff --git a/test/command/getChainStatus.test.js b/test/command/getChainStatus.test.js new file mode 100644 index 0000000..cc40a6d --- /dev/null +++ b/test/command/getChainStatus.test.js @@ -0,0 +1,62 @@ +import { Command } from 'commander'; +import path from 'path'; +import GetChainStatusCommand from '../../src/command/getChainStatus.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('../../src/utils/myLogger'); + +describe('GetChainStatusCommand', () => { + let getChainStatusCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + getChainStatusCommand = new GetChainStatusCommand(sampleRc); + getChainStatusCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should get chain status and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-chain-status', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getChainStatusCommand.run(commander); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + }, 20000); + it('should log error and fail on exception', async () => { + jest.spyOn(process, 'exit').mockImplementation(() => {}); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-chain-status', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + oraInstanceMock.start.mockImplementation(() => { + throw new Error('mock error'); + }); + await getChainStatusCommand.run(commander); + expect(oraInstanceMock.fail).toHaveBeenCalled(); + }, 20000); +}); diff --git a/test/command/getTxResult.test.js b/test/command/getTxResult.test.js new file mode 100644 index 0000000..dab6543 --- /dev/null +++ b/test/command/getTxResult.test.js @@ -0,0 +1,61 @@ +import { Command } from 'commander'; +import path from 'path'; +import GetTxResultCommand from '../../src/command/getTxResult.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; + +jest.mock('../../src/utils/myLogger'); + +describe('GetTxResultCommand', () => { + let getTxResultCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + getTxResultCommand = new GetTxResultCommand(sampleRc); + getTxResultCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should get transaction result and succeed', async () => { + const txId = 'ef17ac2078c2b31a702b9edc754bfa56f1c37931f52f9dd8e2b9dc65769966b1'; + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-tx-result', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getTxResultCommand.run(commander, txId); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + }, 20000); + it('should log error and fail on validation error', async () => { + jest.spyOn(process, 'exit').mockImplementation(() => {}); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'get-tx-result', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await getTxResultCommand.run(commander, true); + expect(process.exit).toHaveBeenCalledWith(1); + expect(oraInstanceMock.fail).toHaveBeenCalled(); + }, 20000); +}); diff --git a/test/command/load.test.js b/test/command/load.test.js new file mode 100644 index 0000000..62f9239 --- /dev/null +++ b/test/command/load.test.js @@ -0,0 +1,134 @@ +/* eslint-disable max-len */ +import { Command } from 'commander'; +import path from 'path'; +import LoadCommand from '../../src/command/load.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger'; +import { saveKeyStore } from '../../src/utils/wallet'; + +jest.mock('../../src/utils/wallet'); +jest.mock('../../src/utils/myLogger'); + +describe('LoadCommand', () => { + let loadCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const privateKey = '9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'; + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + loadCommand = new LoadCommand(sampleRc); + loadCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should load wallet from private key and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const keyStore = '/path/to/keystore'; + saveKeyStore.mockResolvedValue(keyStore); + await loadCommand.run(commander, privateKey, false, true); + expect(logger.info).toHaveBeenCalledWith('Your wallet info is :'); + expect(logger.info).toHaveBeenCalledWith( + 'Private Key : 9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Public Key : 04703bbe95e986c9d901f28edd60975a7a6c3b2dce41dfec2e7983d293c600e8249642a3da379c4194a6d62bd89afe6753e81acfc2b6bbf3b40736ee0949102071' + ); + expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); + expect(saveKeyStore).toHaveBeenCalled(); + }, 20000); + it('should load wallet from Mnemonic and succeed', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const mnemonic = 'orange learn result add snack curtain double state expose bless also clarify'; + await loadCommand.run(commander, mnemonic, false, false); + expect(logger.info).toHaveBeenCalledWith('Your wallet info is :'); + expect(logger.info).toHaveBeenCalledWith( + 'Mnemonic : orange learn result add snack curtain double state expose bless also clarify' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Private Key : cc2895b46707a34eefd3c61bd4a8487266e0398a93309a9910a2b88e587b6582' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Public Key : 04449094b89d0445c920434ea09d87ba8d9bf95d8a3971ee03572a1f666ef2241cc3ada03d47736c005d28bbef8468042e77a084ea11b8aca395ac7686335f4712' + ); + expect(logger.info).toHaveBeenCalledWith('Address : SbWhnq3XU8yeiUTYJmZBSgt7ekgszRXHxh8qNqkFj9g6d3bWh'); + }, 20000); + it('should load wallet from privateKey and succeed without saving to file', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await loadCommand.run(commander, privateKey, false, false); + expect(logger.info).toHaveBeenCalledWith('Your wallet info is :'); + expect(logger.info).toHaveBeenCalledWith( + 'Private Key : 9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Public Key : 04703bbe95e986c9d901f28edd60975a7a6c3b2dce41dfec2e7983d293c600e8249642a3da379c4194a6d62bd89afe6753e81acfc2b6bbf3b40736ee0949102071' + ); + expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); + expect(oraInstanceMock.succeed).toHaveBeenCalledWith('Succeed!'); + }, 20000); + + it('should log error and fail on validation error', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + saveKeyStore.mockImplementation(() => { + throw new Error('saveKeyStore error'); + }); + await loadCommand.run(commander, privateKey, false, true); + expect(oraInstanceMock.fail).toHaveBeenCalled(); + }, 20000); + it('should fail when trying to use old version SDK', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await loadCommand.run(commander, 'xxx xxx', true, false); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Please install older versions of aelf-command before v1.0.0!'); + }, 20000); +}); From afc2fd66610f2e4a4e437f6aab0a4293f4afe04c Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Mon, 17 Jun 2024 12:32:41 +0800 Subject: [PATCH 09/24] feat: until wallet test --- src/utils/wallet.js | 4 +- test/command/baseSubCommand.test.js | 428 +++++++++++++--------------- test/command/call.test.js | 1 - test/command/deploy.test.js | 1 - test/command/proposal.test.js | 35 +++ test/command/send.test.js | 45 +++ test/command/wallet.test.js | 73 +++++ 7 files changed, 360 insertions(+), 227 deletions(-) create mode 100644 test/command/proposal.test.js create mode 100644 test/command/send.test.js create mode 100644 test/command/wallet.test.js diff --git a/src/utils/wallet.js b/src/utils/wallet.js index 56667b3..7ebd37e 100644 --- a/src/utils/wallet.js +++ b/src/utils/wallet.js @@ -18,8 +18,8 @@ function getWallet(commandRoot, address, password) { throw new Error('Make sure you entered the correct account address'); } try { - const { privateKey } = AElf.wallet.keyStore.unlockKeystore(keyStore, password); - return AElf.wallet.getWalletByPrivateKey(privateKey); + const { privateKey, mnemonic } = AElf.wallet.keyStore.unlockKeystore(keyStore, password); + return { ...AElf.wallet.getWalletByPrivateKey(privateKey), mnemonic }; } catch (e) { throw new Error(e.message || 'Make sure you entered the correct password'); } diff --git a/test/command/baseSubCommand.test.js b/test/command/baseSubCommand.test.js index 34e8009..9a14792 100644 --- a/test/command/baseSubCommand.test.js +++ b/test/command/baseSubCommand.test.js @@ -4,252 +4,234 @@ import ora from 'ora'; import asyncValidator from 'async-validator'; import BaseSubCommand from '../../src/command/baseSubCommand.js'; import { logger } from '../../src/utils/myLogger.js'; -import RC from '../../src/rc/index.js' -import { strictGlobalOptionValidatorDesc } from '../../src/utils/constants.js' +import RC from '../../src/rc/index.js'; +import { strictGlobalOptionValidatorDesc } from '../../src/utils/constants.js'; import { Command } from 'commander'; - -const commandBin = path.resolve(__dirname,'../bin/aelf-command.js'); +const commandBin = path.resolve(__dirname, '../bin/aelf-command.js'); jest.mock('inquirer'); jest.mock('../../src/utils/myLogger'); jest.mock('async-validator'); - // Sample data for testing const sampleCommandName = 'get-chain-status'; -const sampleParameters = [{ name: 'param1',required: true }]; +const sampleParameters = [{ name: 'param1', required: true }]; const sampleDescription = 'Get the current chain status'; -const sampleOptions = [{ +const sampleOptions = [ + { flag: '-c, --cipher [cipher]', name: 'cipher', description: 'Which cipher algorithm to use, default to be aes-128-ctr' -}]; + } +]; const sampleUsage = ['example usage']; const sampleRc = { getConfigs: jest.fn() }; const sampleValidatorDesc = { testOption: { required: true } }; const sampleOraOptions = { text: 'Loading...' }; -describe('BaseSubCommand',() => { - let baseSubCommand; - beforeEach(() => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - sampleParameters, - sampleDescription, - sampleOptions, - sampleUsage, - sampleRc, - sampleValidatorDesc, - sampleOraOptions - ); - inquirer.prompt.mockResolvedValue({}); - }); - test('should initialize with provided parameters',() => { - expect(baseSubCommand.commandName).toBe(sampleCommandName); - expect(baseSubCommand.parameters).toEqual(sampleParameters); - expect(baseSubCommand.description).toBe(sampleDescription); - expect(baseSubCommand.options).toEqual(sampleOptions); - expect(baseSubCommand.usage).toEqual(sampleUsage); - expect(baseSubCommand.rc).toBe(sampleRc); - expect(baseSubCommand.oraInstance.text).toBe(sampleOraOptions.text); - expect(baseSubCommand.validatorDesc).toEqual(sampleValidatorDesc) - }); - test('should set custom prompts flag',() => { - baseSubCommand.setCustomPrompts(true); - expect(baseSubCommand.customPrompts).toBe(true); - }); +describe('BaseSubCommand', () => { + let baseSubCommand; + beforeEach(() => { + baseSubCommand = new BaseSubCommand( + sampleCommandName, + sampleParameters, + sampleDescription, + sampleOptions, + sampleUsage, + sampleRc, + sampleValidatorDesc, + sampleOraOptions + ); + inquirer.prompt.mockResolvedValue({}); + }); + test('should initialize with provided parameters', () => { + expect(baseSubCommand.commandName).toBe(sampleCommandName); + expect(baseSubCommand.parameters).toEqual(sampleParameters); + expect(baseSubCommand.description).toBe(sampleDescription); + expect(baseSubCommand.options).toEqual(sampleOptions); + expect(baseSubCommand.usage).toEqual(sampleUsage); + expect(baseSubCommand.rc).toBe(sampleRc); + expect(baseSubCommand.oraInstance.text).toBe(sampleOraOptions.text); + expect(baseSubCommand.validatorDesc).toEqual(sampleValidatorDesc); + }); + test('should set custom prompts flag', () => { + baseSubCommand.setCustomPrompts(true); + expect(baseSubCommand.customPrompts).toBe(true); + }); - test('should create command with parameters and options',async () => { - const commander = { - command: jest.fn().mockReturnThis(), - description: jest.fn().mockReturnThis(), - option: jest.fn().mockReturnThis(), - action: jest.fn().mockReturnThis(), - on: jest.fn().mockReturnThis() - }; - baseSubCommand.init(commander); - expect(commander.command).toHaveBeenCalledWith(`${sampleCommandName} `); - expect(commander.description).toHaveBeenCalledWith(sampleDescription); - expect(commander.option).toHaveBeenCalledWith("-c, --cipher [cipher]","Which cipher algorithm to use, default to be aes-128-ctr"); - expect(commander.action).toHaveBeenCalled(); - expect(commander.on).toHaveBeenCalledWith('--help',expect.any(Function)); - }); - test('getParameters should return formatted parameter string',() => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - [{ name: 'param1',required: true }, - { name: 'param2' }, - { name: 'param3',required: true,extraName: ['alias1','alias2'] },] - ); - const parameters = baseSubCommand.getParameters(); - expect(parameters).toBe(' [param2] '); - }); - test('should handle validation errors',() => { - const error = { errors: [{ message: 'Validation error' }] }; - jest.spyOn(process,'exit').mockImplementation(() => { }); - baseSubCommand.handleUniOptionsError(error); - expect(logger.error).toHaveBeenCalledWith('Validation error\n'); - expect(process.exit).toHaveBeenCalledWith(1); - }); + test('should create command with parameters and options', async () => { + const commander = { + command: jest.fn().mockReturnThis(), + description: jest.fn().mockReturnThis(), + option: jest.fn().mockReturnThis(), + action: jest.fn().mockReturnThis(), + on: jest.fn().mockReturnThis() + }; + baseSubCommand.init(commander); + expect(commander.command).toHaveBeenCalledWith(`${sampleCommandName} `); + expect(commander.description).toHaveBeenCalledWith(sampleDescription); + expect(commander.option).toHaveBeenCalledWith( + '-c, --cipher [cipher]', + 'Which cipher algorithm to use, default to be aes-128-ctr' + ); + expect(commander.action).toHaveBeenCalled(); + expect(commander.on).toHaveBeenCalledWith('--help', expect.any(Function)); + }); + test('getParameters should return formatted parameter string', () => { + baseSubCommand = new BaseSubCommand(sampleCommandName, [ + { name: 'param1', required: true }, + { name: 'param2' }, + { name: 'param3', required: true, extraName: ['alias1', 'alias2'] } + ]); + const parameters = baseSubCommand.getParameters(); + expect(parameters).toBe(' [param2] '); + }); + test('should handle validation errors', () => { + const error = { errors: [{ message: 'Validation error' }] }; + jest.spyOn(process, 'exit').mockImplementation(() => {}); + baseSubCommand.handleUniOptionsError(error); + expect(logger.error).toHaveBeenCalledWith('Validation error\n'); + expect(process.exit).toHaveBeenCalledWith(1); + }); - test('should exit without errors',() => { - const error = {}; - jest.spyOn(process,'exit').mockImplementation(() => { }); - baseSubCommand.handleUniOptionsError(error); - expect(process.exit).toHaveBeenCalledWith(1); - }); - test('should normalize configuration object',() => { - const config = { 'test-option': 'true','another-option': 'false','nullOption': null }; - const normalizedConfig = BaseSubCommand.normalizeConfig(config); - expect(normalizedConfig).toEqual({ testOption: true,anotherOption: false }); - }); + test('should exit without errors', () => { + const error = {}; + jest.spyOn(process, 'exit').mockImplementation(() => {}); + baseSubCommand.handleUniOptionsError(error); + expect(process.exit).toHaveBeenCalledWith(1); + }); + test('should normalize configuration object', () => { + const config = { 'test-option': 'true', 'another-option': 'false', nullOption: null }; + const normalizedConfig = BaseSubCommand.normalizeConfig(config); + expect(normalizedConfig).toEqual({ testOption: true, anotherOption: false }); + }); - test('should parse boolean values correctly',() => { - expect(BaseSubCommand.parseBoolean('true')).toBe(true); - expect(BaseSubCommand.parseBoolean('false')).toBe(false); - expect(BaseSubCommand.parseBoolean('someValue')).toBe('someValue'); - }); + test('should parse boolean values correctly', () => { + expect(BaseSubCommand.parseBoolean('true')).toBe(true); + expect(BaseSubCommand.parseBoolean('false')).toBe(false); + expect(BaseSubCommand.parseBoolean('someValue')).toBe('someValue'); + }); - test('should return unified configuration from commander',() => { - const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; - const config = BaseSubCommand.getUniConfig(commander); - expect(config).toEqual({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }); - }); + test('should return unified configuration from commander', () => { + const commander = { opts: () => ({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const config = BaseSubCommand.getUniConfig(commander); + expect(config).toEqual({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }); + }); - test('should validate options and return normalized subCommandOptions',async () => { - const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; - const args = ['paramValue',{ cipher: 'true' }]; - baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); - inquirer.prompt.mockResolvedValue({ testOption: 'true' }); - const result = await baseSubCommand.run(commander,...args); - expect(baseSubCommand.rc.getConfigs).toHaveBeenCalled(); - expect(baseSubCommand.validator.validate).toHaveBeenCalled(); - expect(result).toEqual({ - localOptions: { cipher: 'true' }, - options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, - subOptions: { param1: 'paramValue' } - }); - // customPrompts true - baseSubCommand.setCustomPrompts(true); - const result2 = await baseSubCommand.run(commander,...args); - expect(result2).toEqual({ - localOptions: { cipher: 'true' }, - options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, - subOptions: { param1: 'paramValue' } - }); - }); - test('fail to run validate',async () => { - const originalValidate = asyncValidator.prototype.validate; - asyncValidator.prototype.validate = jest.fn().mockRejectedValue(new Error('Validation error')); - baseSubCommand = new BaseSubCommand( - sampleCommandName, - sampleParameters, - sampleDescription, - sampleOptions, - sampleUsage, - sampleRc, - sampleValidatorDesc, - sampleOraOptions - ); - const mockExit = jest.spyOn(process,'exit').mockImplementation(() => { }); - const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; - const args = ['paramValue',{ cipher: 'true' }]; - baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); - inquirer.prompt.mockResolvedValue({ testOption: 'true' }); - await baseSubCommand.run(commander,...args); - expect(mockExit).toHaveBeenCalledWith(1); - // Clean up - asyncValidator.prototype.validate = originalValidate; // Restore original validate method - // Clean up - mockExit.mockRestore(); - }) - test('run without args',async () => { - const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; - const args = [undefined]; - baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); - inquirer.prompt.mockResolvedValue({ testOption: 'true' }); - const result = await baseSubCommand.run(commander,...args); - expect(result).toEqual({ - localOptions: { cipher: undefined }, - options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, - subOptions: { testOption: true } - }); - }); - test('makeExamples should return formatted examples',() => { - const examples = baseSubCommand.makeExamples(); - expect(examples).toEqual([ - 'aelf-command get-chain-status example usage', - ]); - }); + test('should validate options and return normalized subCommandOptions', async () => { + const commander = { opts: () => ({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = ['paramValue', { cipher: 'true' }]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const result = await baseSubCommand.run(commander, ...args); + expect(baseSubCommand.rc.getConfigs).toHaveBeenCalled(); + expect(baseSubCommand.validator.validate).toHaveBeenCalled(); + expect(result).toEqual({ + localOptions: { cipher: 'true' }, + options: { globalOption: 'value', testOption: 'true', endpoint: 'https://aelf-test-node.aelf.io/', password: '1234' }, + subOptions: { param1: 'paramValue' } + }); + // customPrompts true + baseSubCommand.setCustomPrompts(true); + const result2 = await baseSubCommand.run(commander, ...args); + expect(result2).toEqual({ + localOptions: { cipher: 'true' }, + options: { globalOption: 'value', testOption: 'true', endpoint: 'https://aelf-test-node.aelf.io/', password: '1234' }, + subOptions: { param1: 'paramValue' } + }); + }); + test('fail to run validate', async () => { + const originalValidate = asyncValidator.prototype.validate; + asyncValidator.prototype.validate = jest.fn().mockRejectedValue(new Error('Validation error')); + baseSubCommand = new BaseSubCommand( + sampleCommandName, + sampleParameters, + sampleDescription, + sampleOptions, + sampleUsage, + sampleRc, + sampleValidatorDesc, + sampleOraOptions + ); + const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); + const commander = { opts: () => ({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = ['paramValue', { cipher: 'true' }]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + await baseSubCommand.run(commander, ...args); + expect(mockExit).toHaveBeenCalledWith(1); + asyncValidator.prototype.validate = originalValidate; + mockExit.mockRestore(); + }); + test('run without args', async () => { + const commander = { opts: () => ({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const args = [undefined]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const result = await baseSubCommand.run(commander, ...args); + expect(result).toEqual({ + localOptions: { cipher: undefined }, + options: { globalOption: 'value', testOption: 'true', endpoint: 'https://aelf-test-node.aelf.io/', password: '1234' }, + subOptions: { testOption: true } + }); + }); + test('makeExamples should return formatted examples', () => { + const examples = baseSubCommand.makeExamples(); + expect(examples).toEqual(['aelf-command get-chain-status example usage']); + }); }); -describe('BaseSubCommand with default params',() => { - let baseSubCommand; - beforeEach(() => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - ); - inquirer.prompt.mockResolvedValue({}); - }); - test('with default params',() => { - expect(baseSubCommand.commandName).toBe(sampleCommandName); - expect(baseSubCommand.parameters).toEqual([]); - expect(baseSubCommand.description).toBe(undefined); - expect(baseSubCommand.options).toEqual([]); - expect(baseSubCommand.usage).toEqual([]); - expect(baseSubCommand.rc).toBe(undefined); - expect(baseSubCommand.oraInstance.text).toBe("AElf loading..."); - expect(baseSubCommand.validatorDesc).toEqual(strictGlobalOptionValidatorDesc) - }) - test('should execute action callback',() => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - undefined, - sampleDescription, - ); +describe('BaseSubCommand with default params', () => { + let baseSubCommand; + beforeEach(() => { + baseSubCommand = new BaseSubCommand(sampleCommandName); + inquirer.prompt.mockResolvedValue({}); + }); + test('with default params', () => { + expect(baseSubCommand.commandName).toBe(sampleCommandName); + expect(baseSubCommand.parameters).toEqual([]); + expect(baseSubCommand.description).toBe(undefined); + expect(baseSubCommand.options).toEqual([]); + expect(baseSubCommand.usage).toEqual([]); + expect(baseSubCommand.rc).toBe(undefined); + expect(baseSubCommand.oraInstance.text).toBe('AElf loading...'); + expect(baseSubCommand.validatorDesc).toEqual(strictGlobalOptionValidatorDesc); + }); + test('should execute action callback', () => { + baseSubCommand = new BaseSubCommand(sampleCommandName, undefined, sampleDescription); - const commander = new Command(); - baseSubCommand.run = jest.fn(); - commander.option('-e, --endpoint ','The URI of an AElf node. Eg: http://127.0.0.1:8000'); - baseSubCommand.init(commander); - commander.parse([process.argv[0],commandBin,'get-chain-status','-e','https://aelf-test-node.aelf.io/']); - // Spy on the run method - jest.spyOn(baseSubCommand,'run').mockResolvedValue('run called'); - // Expect the run method to have been called - expect(baseSubCommand.run).toHaveBeenCalled(); - }); - test('should log examples on --help',() => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - undefined, - sampleDescription, - ); - const commander = new Command(); - commander.exitOverride(); - // Setting up the commander help handler - baseSubCommand.init(commander); - expect(() => commander.parse([process.argv[0],commandBin,'get-chain-status','--help'])).toThrow() - }); - test('run with no required validatorDesc',async () => { - baseSubCommand = new BaseSubCommand( - sampleCommandName, - undefined, - sampleDescription, - sampleOptions, - sampleUsage, - sampleRc, - { account: { required: true } } - ); - const args = [undefined]; - baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); - inquirer.prompt.mockResolvedValue({ testOption: 'true' }); - const commander = { opts: () => ({ password: '1234',endpoint: 'https://aelf-test-node.aelf.io/' }) }; - const result = await baseSubCommand.run(commander,...args); - expect(result).toEqual({ - localOptions: { cipher: undefined }, - options: { globalOption: 'value',testOption: 'true',"endpoint": "https://aelf-test-node.aelf.io/","password": "1234" }, - subOptions: {} - }); - }); -}) \ No newline at end of file + const commander = new Command(); + baseSubCommand.run = jest.fn(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + baseSubCommand.init(commander); + commander.parse([process.argv[0], commandBin, 'get-chain-status', '-e', 'https://aelf-test-node.aelf.io/']); + // Spy on the run method + jest.spyOn(baseSubCommand, 'run').mockResolvedValue('run called'); + // Expect the run method to have been called + expect(baseSubCommand.run).toHaveBeenCalled(); + }); + test('should log examples on --help', () => { + baseSubCommand = new BaseSubCommand(sampleCommandName, undefined, sampleDescription); + const commander = new Command(); + commander.exitOverride(); + // Setting up the commander help handler + baseSubCommand.init(commander); + expect(() => commander.parse([process.argv[0], commandBin, 'get-chain-status', '--help'])).toThrow(); + }); + test('run with no required validatorDesc', async () => { + baseSubCommand = new BaseSubCommand(sampleCommandName, undefined, sampleDescription, sampleOptions, sampleUsage, sampleRc, { + account: { required: true } + }); + const args = [undefined]; + baseSubCommand.rc.getConfigs.mockResolvedValue({ globalOption: 'value' }); + inquirer.prompt.mockResolvedValue({ testOption: 'true' }); + const commander = { opts: () => ({ password: '1234', endpoint: 'https://aelf-test-node.aelf.io/' }) }; + const result = await baseSubCommand.run(commander, ...args); + expect(result).toEqual({ + localOptions: { cipher: undefined }, + options: { globalOption: 'value', testOption: 'true', endpoint: 'https://aelf-test-node.aelf.io/', password: '1234' }, + subOptions: {} + }); + }); +}); diff --git a/test/command/call.test.js b/test/command/call.test.js index e39ce96..d806aeb 100644 --- a/test/command/call.test.js +++ b/test/command/call.test.js @@ -115,7 +115,6 @@ describe('CallCommand', () => { suffix: ':' } ]); - // inquirer.prompt = questions => Promise.resolve({ fakeProp: 'ELF' }); const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/deploy.test.js b/test/command/deploy.test.js index b6b08ad..5e98787 100644 --- a/test/command/deploy.test.js +++ b/test/command/deploy.test.js @@ -35,7 +35,6 @@ describe('DeployCommand', () => { }); test('should log deprecation message when run is called', async () => { - // chalk.redBright.mockReturnValue = text => `redBright(${text})`; const expectedTips = `redBright(Deprecated! Please use yellowBright(\`aelf-command send\`), check details in aelf-command \`README.md\`)`; const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js new file mode 100644 index 0000000..b32b1c6 --- /dev/null +++ b/test/command/proposal.test.js @@ -0,0 +1,35 @@ +/* eslint-disable max-len */ +import { Command } from 'commander'; +import path from 'path'; +import ProposalCommand from '../../src/command/proposal.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger'; + +jest.mock('../../src/utils/myLogger'); + +describe('ProposalCommand', () => { + let getBlkInfoCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + getBlkInfoCommand = new GetBlkInfoCommand(sampleRc); + getBlkInfoCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should run and create a proposal successfully', async () => {}); +}); diff --git a/test/command/send.test.js b/test/command/send.test.js new file mode 100644 index 0000000..6feee24 --- /dev/null +++ b/test/command/send.test.js @@ -0,0 +1,45 @@ +import SendCommand from '../../src/command/send.js'; +import AElf from 'aelf-sdk'; + +describe('SendCommand', () => { + let sendCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + sendCommand = new SendCommand(sampleRc); + sendCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + it('should send the transaction and succeed', async () => { + const wallet = AElf.wallet.getWalletByPrivateKey('9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'); + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const aelf = new AElf(new AElf.providers.HttpProvider(endPoint)); + const contractAddress = '2cVQrFiXNaedBYmUrovmUV2jcF9Hf6AXbh12gWsD4P49NaX99y'; + const contractInstance = await aelf.chain.contractAt(contractAddress, wallet); + const method = contractInstance.CreateOrganization; + const params = { + proposalReleaseThreshold: { + minimalApprovalThreshold: '100000000', + maximalRejectionThreshold: '0', + maximalAbstentionThreshold: '0', + minimalVoteThreshold: '100000000' + }, + tokenSymbol: 'ELF', + proposerWhiteList: { + proposers: ['GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'] + } + }; + const result = await sendCommand.callMethod(method, params); + expect(typeof result.TransactionId).toBe('string'); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + }); +}); diff --git a/test/command/wallet.test.js b/test/command/wallet.test.js new file mode 100644 index 0000000..d85dc10 --- /dev/null +++ b/test/command/wallet.test.js @@ -0,0 +1,73 @@ +/* eslint-disable max-len */ +import { Command } from 'commander'; +import path from 'path'; +import GetTxResultCommand from '../../src/command/wallet.js'; +import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { logger } from '../../src/utils/myLogger.js'; +import { getWallet } from '../../src/utils/wallet.js'; + +jest.mock('../../src/utils/myLogger'); + +describe('WalletCommand', () => { + let walletCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + walletCommand = new GetTxResultCommand(sampleRc); + walletCommand.oraInstance = oraInstanceMock; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should show wallet details', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'wallet', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await walletCommand.run(commander); + expect(oraInstanceMock.succeed).toHaveBeenCalledWith('Succeed!'); + expect(logger.info).toHaveBeenCalledWith( + 'Mnemonic : impact fork bulk museum swap design draw arctic load option ticket across' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Private Key : 9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f' + ); + expect(logger.info).toHaveBeenCalledWith( + 'Public Key : 04703bbe95e986c9d901f28edd60975a7a6c3b2dce41dfec2e7983d293c600e8249642a3da379c4194a6d62bd89afe6753e81acfc2b6bbf3b40736ee0949102071' + ); + expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); + }, 20000); + it('should handle errors and fail', async () => { + jest.spyOn(require('../../src/utils/wallet'), 'getWallet').mockReturnValue(new Error('test error')); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'wallet', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await walletCommand.run(commander); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.error).toHaveBeenCalled(); + }, 20000); +}); From 9ce0d9c21a565ec95ff57ca33e1293a86c8f2beb Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Mon, 17 Jun 2024 18:53:23 +0800 Subject: [PATCH 10/24] feat: proposal --- src/command/proposal.js | 5 +- test/command/proposal.test.js | 254 +++++++++++++++++++++++++++++++++- 2 files changed, 251 insertions(+), 8 deletions(-) diff --git a/src/command/proposal.js b/src/command/proposal.js index ef7718f..9b55777 100644 --- a/src/command/proposal.js +++ b/src/command/proposal.js @@ -64,6 +64,7 @@ class ProposalCommand extends BaseSubCommand { options = [] ) { super(name, parameters, description, options, usage, rc); + this.aelfMock = {}; } async processAddressAfterPrompt(aelf, wallet, answerInput) { @@ -87,7 +88,9 @@ class ProposalCommand extends BaseSubCommand { if (!moment(expiredTime).isValid || moment(expiredTime).isBefore(moment().add(0, 'hours'))) { throw new Error(`Expired Time has to be later than ${moment().add(1, 'hours').format('YYYY/MM/DD HH:mm:ss')}`); } - const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + let aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + // for test mock + aelf = { ...aelf, ...this.aelfMock }; const wallet = getWallet(datadir, account, password); const { GenesisContractAddress } = await aelf.chain.getChainStatus(); const genesisContract = await aelf.chain.contractAt(GenesisContractAddress, wallet); diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js index b32b1c6..fad449c 100644 --- a/test/command/proposal.test.js +++ b/test/command/proposal.test.js @@ -1,21 +1,36 @@ /* eslint-disable max-len */ import { Command } from 'commander'; import path from 'path'; +import inquirer from 'inquirer'; +import AElf from 'aelf-sdk'; +import chalk from 'chalk'; +import moment from 'moment'; import ProposalCommand from '../../src/command/proposal.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger'; +import * as utils from '../../src/utils/utils.js'; +import { getWallet } from '../../src/utils/wallet.js'; jest.mock('../../src/utils/myLogger'); - -describe('ProposalCommand', () => { - let getBlkInfoCommand; +jest.mock('inquirer'); +jest.mock('chalk', () => { + return { + blue: jest.fn(), + green: jest.fn(), + red: jest.fn(), + hex: jest.fn(), + color: jest.fn(), + yellow: jest.fn((...args) => `yellow(${args.join('')})`) + }; +}); +describe('ProposalCommand processAddressAfterPrompt', () => { + let proposalCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; const dataDir = path.resolve(__dirname, '../datadir/aelf'); - beforeEach(() => { oraInstanceMock = { start: jest.fn(), @@ -23,13 +38,238 @@ describe('ProposalCommand', () => { succeed: jest.fn(), fail: jest.fn() }; - getBlkInfoCommand = new GetBlkInfoCommand(sampleRc); - getBlkInfoCommand.oraInstance = oraInstanceMock; + proposalCommand = new ProposalCommand(sampleRc); + proposalCommand.oraInstance = oraInstanceMock; + }); + afterEach(() => { + jest.clearAllMocks(); + }); + test('should process address and return contract address', async () => { + const contractAddress = 'vcv1qewcsFN2tVWqLuu7DJ5wVFA8YEx5FFgCQBb1jMCbAQHxV'; + const aelf = new AElf(new AElf.providers.HttpProvider(endPoint)); + const wallet = getWallet(dataDir, account, password); + const answerInput = { + 'contract-address': 'AElf.ContractNames.Parliament' + }; + const result = await proposalCommand.processAddressAfterPrompt(aelf, wallet, answerInput); + expect(result.address).toBe(contractAddress); + }, 20000); +}); +describe('ProposalCommand run', () => { + let proposalCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + const endPoint = 'https://tdvw-test-node.aelf.io/'; + const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; + const password = '1234*Qwer'; + const dataDir = path.resolve(__dirname, '../datadir/aelf'); + let mockParliamentContract, mockGenesisContract; + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + proposalCommand = new ProposalCommand(sampleRc); + mockGenesisContract = { + GetContractAddressByName: { + call: jest.fn().mockResolvedValue('mockContractAddress') + } + }; + mockParliamentContract = { + CreateProposal: jest.fn().mockResolvedValue({ TransactionId: 'mockTxId' }) + }; + proposalCommand.oraInstance = oraInstanceMock; + proposalCommand.aelfMock = { + chain: { + getChainStatus: jest.fn().mockResolvedValue({ GenesisContractAddress: 'mockGenesisContractAddress' }), + contractAt: jest.fn().mockResolvedValueOnce(mockGenesisContract).mockResolvedValueOnce(mockParliamentContract) + } + }; + inquirer.prompt = jest.fn().mockResolvedValue({ + 'contract-address': 'Z2iqP4tWbbDo7X1EXiMgaAtMEpi43WzvCyzWppgmZ74Mtfvu4', + method: 'GetOwner' + }); + jest.spyOn(utils, 'getContractInstance').mockResolvedValue({ + GetOwner: {} + }); + jest.spyOn(utils, 'getParams').mockResolvedValue({}); + jest.spyOn(utils, 'getMethod').mockReturnValue({ + packInput: params => params + }); }); afterEach(() => { jest.clearAllMocks(); }); - it('should run and create a proposal successfully', async () => {}); + it('should run and create a proposal successfully', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'proposal', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + jest.spyOn(utils, 'getTxResult').mockResolvedValue({ + TransactionId: '3f323bf0d1d67830f55b018bc7ca5b78ccd9dd7676321e613b9052a24a07f118', + Status: 'MINED', + Logs: [ + { + Address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + Name: 'ProposalCreated', + Indexed: ['GiIKIIbldLRadK89uIhfzZsO3Eji1R5Z0tqh4vTZIJEjtinF'], + NonIndexed: 'CgNFTEYQ4oKXhAE=' + } + ], + Bloom: + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', + BlockNumber: 123908526, + BlockHash: 'c1dd1e0fa0fd687eb00e3a7a9d0f1f0a2cb8bba0aede7836ccb99794bd4d1008', + Transaction: { + From: '2nw6SSJEymj72Yzvr6EepTNN5iUFWjukVfxj9g2K8iwdKvF3uf', + To: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + RefBlockNumber: 123908525, + RefBlockPrefix: 'AfUJzw==', + MethodName: 'DonateResourceToken', + Params: '{ "blockHash": "01f509cf3b6372c4567b5dc685be07fab281cedb603b60d889150343d100ce53", "blockHeight": "123908525" }', + Signature: 'NgTp11dCrlVf/Bo8OVAudMPOBmE4gd+tfAAbytm74QspHqoq5OEWGeQY1z+P1qyTLU1oseOgXdfV4C9tF9Hs2gA=' + }, + ReturnValue: '', + Error: null, + TransactionSize: 216 + }); + jest.spyOn(utils, 'deserializeLogs').mockResolvedValue([{ proposalId: 'mockProposal' }]); + await proposalCommand.run( + commander, + 'AElf.ContractNames.Referendum', + '2DcQvtJnVR9gLzuFcvSUxh6UcRc8uHTkSX5uJf3cw9xeb5HRoe', + '2025/06/14 18:47', + 'description' + ); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith({ TransactionId: 'mockTxId' }); + expect(logger.info).toHaveBeenCalledWith('Proposal id: mockProposal.'); + }, 20000); + it('should run and show pending info', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'proposal', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + jest.spyOn(utils, 'getTxResult').mockResolvedValue({ + TransactionId: '3f323bf0d1d67830f55b018bc7ca5b78ccd9dd7676321e613b9052a24a07f118', + Status: 'PENDING', + Logs: [ + { + Address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + Name: 'ProposalCreated', + Indexed: ['GiIKIIbldLRadK89uIhfzZsO3Eji1R5Z0tqh4vTZIJEjtinF'], + NonIndexed: 'CgNFTEYQ4oKXhAE=' + } + ], + Bloom: + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==', + BlockNumber: 123908526, + BlockHash: 'c1dd1e0fa0fd687eb00e3a7a9d0f1f0a2cb8bba0aede7836ccb99794bd4d1008', + Transaction: { + From: '2nw6SSJEymj72Yzvr6EepTNN5iUFWjukVfxj9g2K8iwdKvF3uf', + To: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + RefBlockNumber: 123908525, + RefBlockPrefix: 'AfUJzw==', + MethodName: 'DonateResourceToken', + Params: '{ "blockHash": "01f509cf3b6372c4567b5dc685be07fab281cedb603b60d889150343d100ce53", "blockHeight": "123908525" }', + Signature: 'NgTp11dCrlVf/Bo8OVAudMPOBmE4gd+tfAAbytm74QspHqoq5OEWGeQY1z+P1qyTLU1oseOgXdfV4C9tF9Hs2gA=' + }, + ReturnValue: '', + Error: null, + TransactionSize: 216 + }); + await proposalCommand.run( + commander, + 'AElf.ContractNames.Referendum', + '2DcQvtJnVR9gLzuFcvSUxh6UcRc8uHTkSX5uJf3cw9xeb5HRoe', + '2025/06/14 18:47', + 'description' + ); + expect(oraInstanceMock.succeed).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith({ TransactionId: 'mockTxId' }); + expect(logger.info).toHaveBeenCalledWith( + 'Transaction is still pending, you can get proposal id later by running yellow(aelf-command event mockTxId)' + ); + }, 20000); + + it('should handle failure to create proposal', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'proposal', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + jest.spyOn(utils, 'getTxResult').mockRejectedValue(new Error('mock error')); + await proposalCommand.run( + commander, + 'AElf.ContractNames.Referendum', + '2DcQvtJnVR9gLzuFcvSUxh6UcRc8uHTkSX5uJf3cw9xeb5HRoe', + '2025/06/14 18:47', + 'description' + ); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.fatal).toHaveBeenCalled(); + }); + it('should throw error for invalid proposalContract', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'proposal', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await proposalCommand.run( + commander, + 'TEST', + '2DcQvtJnVR9gLzuFcvSUxh6UcRc8uHTkSX5uJf3cw9xeb5HRoe', + '2025/06/14 18:47', + 'description' + ); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.fatal).toHaveBeenCalledWith( + new Error( + 'TEST is not in the list of proposal contracts, choice one of `AElf.ContractNames.Parliament`, `AElf.ContractNames.Referendum` and `AElf.ContractNames.Association`' + ) + ); + }); + test('should throw error for invalid expiredTime', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'proposal', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + const expiredTime = moment().subtract(1, 'hour'); + await proposalCommand.run( + commander, + 'AElf.ContractNames.Referendum', + '2DcQvtJnVR9gLzuFcvSUxh6UcRc8uHTkSX5uJf3cw9xeb5HRoe', + expiredTime, + 'description' + ); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.fatal).toHaveBeenCalled(); + }); }); From 9e7f457fe266f6fe394ccb1f03ccb594936f06d6 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Tue, 18 Jun 2024 11:10:08 +0800 Subject: [PATCH 11/24] feat: it -> test --- test/command/config.test.js | 10 +++++----- test/command/console.test.js | 4 ++-- test/command/create.test.js | 6 +++--- test/command/event.test.js | 6 +++--- test/command/getBlkHeight.test.js | 4 ++-- test/command/getBlkInfo.test.js | 6 +++--- test/command/getChainStatus.test.js | 4 ++-- test/command/getTxResult.test.js | 4 ++-- test/command/load.test.js | 10 +++++----- test/command/proposal.test.js | 8 ++++---- test/command/send.test.js | 2 +- test/command/wallet.test.js | 4 ++-- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/test/command/config.test.js b/test/command/config.test.js index 7218757..5442cc6 100644 --- a/test/command/config.test.js +++ b/test/command/config.test.js @@ -49,7 +49,7 @@ describe('ConfigCommand', () => { await configCommand.validateParameters(rule, parameters); expect(configCommand.handleUniOptionsError).toHaveBeenCalled(); }); - it('should handle list correctly', () => { + test('should handle list correctly', () => { const content = { key1: 'value1', key2: '', @@ -58,7 +58,7 @@ describe('ConfigCommand', () => { const result = configCommand.handleList(content); expect(result).toBe('key1=value1\nkey3=value3\n'); }); - it('should run with flag "get"', async () => { + test('should run with flag "get"', async () => { configCommand.rc.getConfigs.mockReturnValue({ endpoint: endPoint, datadir: dataDir @@ -69,7 +69,7 @@ describe('ConfigCommand', () => { expect(logger.info).toHaveBeenCalledWith(endPoint); }); - it('should run with flag "set"', async () => { + test('should run with flag "set"', async () => { configCommand.rc.getConfigs.mockReturnValue({ endpoint: endPoint, datadir: dataDir @@ -80,7 +80,7 @@ describe('ConfigCommand', () => { expect(mockOraInstance.succeed).toHaveBeenCalledWith('Succeed!'); }); - it('should run with flag "list"', async () => { + test('should run with flag "list"', async () => { configCommand.rc.getConfigs.mockReturnValue({ endpoint: endPoint, datadir: dataDir @@ -91,7 +91,7 @@ describe('ConfigCommand', () => { expect(configCommand.rc.getFileConfigs).toHaveBeenCalled(); }); - it('should run with flag "delete"', async () => { + test('should run with flag "delete"', async () => { configCommand.rc.getConfigs.mockReturnValue({ endpoint: endPoint, datadir: dataDir diff --git a/test/command/console.test.js b/test/command/console.test.js index 5a52757..cd49775 100644 --- a/test/command/console.test.js +++ b/test/command/console.test.js @@ -31,7 +31,7 @@ describe('ConsoleCommand', () => { afterEach(() => { jest.clearAllMocks(); }); - it('should run the console command successfully', async () => { + test('should run the console command successfully', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -47,7 +47,7 @@ describe('ConsoleCommand', () => { expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); expect(logger.info).toHaveBeenCalledTimes(2); }, 20000); - it('should handle errors correctly', async () => { + test('should handle errors correctly', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/create.test.js b/test/command/create.test.js index 34bc202..d41137d 100644 --- a/test/command/create.test.js +++ b/test/command/create.test.js @@ -29,7 +29,7 @@ describe('CreateCommand', () => { jest.clearAllMocks(); }); - it('should create a new wallet and log info', async () => { + test('should create a new wallet and log info', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -46,7 +46,7 @@ describe('CreateCommand', () => { expect(saveKeyStore).toHaveBeenCalled(); }); - it('should succeed without saving to file', async () => { + test('should succeed without saving to file', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -63,7 +63,7 @@ describe('CreateCommand', () => { expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); }); - it('should handle saveKeyStore error', async () => { + test('should handle saveKeyStore error', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/event.test.js b/test/command/event.test.js index aea40e5..d0a4a37 100644 --- a/test/command/event.test.js +++ b/test/command/event.test.js @@ -30,7 +30,7 @@ describe('EventCommand', () => { jest.clearAllMocks(); }); - it('should deserialize logs and succeed', async () => { + test('should deserialize logs and succeed', async () => { const txId = 'ef17ac2078c2b31a702b9edc754bfa56f1c37931f52f9dd8e2b9dc65769966b1'; const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -66,7 +66,7 @@ describe('EventCommand', () => { expect(oraInstanceMock.fail).not.toHaveBeenCalled(); }, 20000); - it('should log "not mined" if transaction status is not mined', async () => { + test('should log "not mined" if transaction status is not mined', async () => { const txId = '3553df418c6ec9a159560440f13a6ae29f786392574737036cf63786321c8a40'; const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -82,7 +82,7 @@ describe('EventCommand', () => { expect(oraInstanceMock.fail).not.toHaveBeenCalled(); }, 20000); - it('should log error and fail on exception', async () => { + test('should log error and fail on exception', async () => { const txId = 'test'; const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/getBlkHeight.test.js b/test/command/getBlkHeight.test.js index 90920c4..2f922f7 100644 --- a/test/command/getBlkHeight.test.js +++ b/test/command/getBlkHeight.test.js @@ -29,7 +29,7 @@ describe('GetBlkHeightCommand', () => { jest.clearAllMocks(); }); - it('should get block height and succeed', async () => { + test('should get block height and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -42,7 +42,7 @@ describe('GetBlkHeightCommand', () => { await getBlkHeightCommand.run(commander); expect(oraInstanceMock.succeed).toHaveBeenCalled(); }, 20000); - it('should log error and fail on exception', async () => { + test('should log error and fail on exception', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/getBlkInfo.test.js b/test/command/getBlkInfo.test.js index cc382b8..4b0bc78 100644 --- a/test/command/getBlkInfo.test.js +++ b/test/command/getBlkInfo.test.js @@ -31,7 +31,7 @@ describe('GetBlkInfoCommand', () => { jest.clearAllMocks(); }); - it('should get block info by height and succeed', async () => { + test('should get block info by height and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -70,7 +70,7 @@ describe('GetBlkInfoCommand', () => { } }); }, 20000); - it('should get block info by hash and succeed', async () => { + test('should get block info by hash and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -109,7 +109,7 @@ describe('GetBlkInfoCommand', () => { } }); }, 20000); - it('should log error and fail on exception', async () => { + test('should log error and fail on exception', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/getChainStatus.test.js b/test/command/getChainStatus.test.js index cc40a6d..d5bdf53 100644 --- a/test/command/getChainStatus.test.js +++ b/test/command/getChainStatus.test.js @@ -29,7 +29,7 @@ describe('GetChainStatusCommand', () => { jest.clearAllMocks(); }); - it('should get chain status and succeed', async () => { + test('should get chain status and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -42,7 +42,7 @@ describe('GetChainStatusCommand', () => { await getChainStatusCommand.run(commander); expect(oraInstanceMock.succeed).toHaveBeenCalled(); }, 20000); - it('should log error and fail on exception', async () => { + test('should log error and fail on exception', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/getTxResult.test.js b/test/command/getTxResult.test.js index dab6543..c8b2fc4 100644 --- a/test/command/getTxResult.test.js +++ b/test/command/getTxResult.test.js @@ -29,7 +29,7 @@ describe('GetTxResultCommand', () => { jest.clearAllMocks(); }); - it('should get transaction result and succeed', async () => { + test('should get transaction result and succeed', async () => { const txId = 'ef17ac2078c2b31a702b9edc754bfa56f1c37931f52f9dd8e2b9dc65769966b1'; const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -43,7 +43,7 @@ describe('GetTxResultCommand', () => { await getTxResultCommand.run(commander, txId); expect(oraInstanceMock.succeed).toHaveBeenCalled(); }, 20000); - it('should log error and fail on validation error', async () => { + test('should log error and fail on validation error', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/load.test.js b/test/command/load.test.js index 62f9239..fc1a69e 100644 --- a/test/command/load.test.js +++ b/test/command/load.test.js @@ -33,7 +33,7 @@ describe('LoadCommand', () => { jest.clearAllMocks(); }); - it('should load wallet from private key and succeed', async () => { + test('should load wallet from private key and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -56,7 +56,7 @@ describe('LoadCommand', () => { expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); expect(saveKeyStore).toHaveBeenCalled(); }, 20000); - it('should load wallet from Mnemonic and succeed', async () => { + test('should load wallet from Mnemonic and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -80,7 +80,7 @@ describe('LoadCommand', () => { ); expect(logger.info).toHaveBeenCalledWith('Address : SbWhnq3XU8yeiUTYJmZBSgt7ekgszRXHxh8qNqkFj9g6d3bWh'); }, 20000); - it('should load wallet from privateKey and succeed without saving to file', async () => { + test('should load wallet from privateKey and succeed without saving to file', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -102,7 +102,7 @@ describe('LoadCommand', () => { expect(oraInstanceMock.succeed).toHaveBeenCalledWith('Succeed!'); }, 20000); - it('should log error and fail on validation error', async () => { + test('should log error and fail on validation error', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -118,7 +118,7 @@ describe('LoadCommand', () => { await loadCommand.run(commander, privateKey, false, true); expect(oraInstanceMock.fail).toHaveBeenCalled(); }, 20000); - it('should fail when trying to use old version SDK', async () => { + test('should fail when trying to use old version SDK', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js index fad449c..882dc15 100644 --- a/test/command/proposal.test.js +++ b/test/command/proposal.test.js @@ -104,7 +104,7 @@ describe('ProposalCommand run', () => { jest.clearAllMocks(); }); - it('should run and create a proposal successfully', async () => { + test('should run and create a proposal successfully', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -154,7 +154,7 @@ describe('ProposalCommand run', () => { expect(logger.info).toHaveBeenCalledWith({ TransactionId: 'mockTxId' }); expect(logger.info).toHaveBeenCalledWith('Proposal id: mockProposal.'); }, 20000); - it('should run and show pending info', async () => { + test('should run and show pending info', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -206,7 +206,7 @@ describe('ProposalCommand run', () => { ); }, 20000); - it('should handle failure to create proposal', async () => { + test('should handle failure to create proposal', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -227,7 +227,7 @@ describe('ProposalCommand run', () => { expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); expect(logger.fatal).toHaveBeenCalled(); }); - it('should throw error for invalid proposalContract', async () => { + test('should throw error for invalid proposalContract', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); diff --git a/test/command/send.test.js b/test/command/send.test.js index 6feee24..3b0adff 100644 --- a/test/command/send.test.js +++ b/test/command/send.test.js @@ -19,7 +19,7 @@ describe('SendCommand', () => { afterEach(() => { jest.clearAllMocks(); }); - it('should send the transaction and succeed', async () => { + test('should send the transaction and succeed', async () => { const wallet = AElf.wallet.getWalletByPrivateKey('9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'); const endPoint = 'https://tdvw-test-node.aelf.io/'; const aelf = new AElf(new AElf.providers.HttpProvider(endPoint)); diff --git a/test/command/wallet.test.js b/test/command/wallet.test.js index d85dc10..3428b8b 100644 --- a/test/command/wallet.test.js +++ b/test/command/wallet.test.js @@ -32,7 +32,7 @@ describe('WalletCommand', () => { jest.clearAllMocks(); }); - it('should show wallet details', async () => { + test('should show wallet details', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); commander.option('-a, --account ', 'The address of AElf wallet'); @@ -55,7 +55,7 @@ describe('WalletCommand', () => { ); expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); }, 20000); - it('should handle errors and fail', async () => { + test('should handle errors and fail', async () => { jest.spyOn(require('../../src/utils/wallet'), 'getWallet').mockReturnValue(new Error('test error')); const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); From 8a2505b4595044655f2a3529c584948d470ae281 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Fri, 21 Jun 2024 13:15:06 +0800 Subject: [PATCH 12/24] feat: socket test --- package.json | 1 + src/command/dappServer/socket.js | 13 +- test/command/dappServer/index.test.js | 57 ++ test/command/dappServer/socket-sign.test.js | 359 +++++++++++++ test/command/dappServer/socket.test.js | 545 ++++++++++++++++++++ test/constants.js | 6 + yarn.lock | 26 + 7 files changed, 1001 insertions(+), 6 deletions(-) create mode 100644 test/command/dappServer/index.test.js create mode 100644 test/command/dappServer/socket-sign.test.js create mode 100644 test/command/dappServer/socket.test.js create mode 100644 test/constants.js diff --git a/package.json b/package.json index 19c872a..4f5cef9 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "jest": "^29.7.0", "lint-staged": "^15.2.5", "prettier": "^3.3.2", + "socket.io-client": "^4.7.5", "standard-version": "^9.5.0" }, "keywords": [ diff --git a/src/command/dappServer/socket.js b/src/command/dappServer/socket.js index 8254888..cf0d64c 100644 --- a/src/command/dappServer/socket.js +++ b/src/command/dappServer/socket.js @@ -251,10 +251,11 @@ class Socket { } serializeResult(appId, result) { - if (!this.clientConfig[appId]) { - throw new Error(`AppId ${appId} has not connected`); - } - if (this.clientConfig[appId].encryptWay === 'sign') { + // delete next line as function deserializeParams already has the logic + // if (!this.clientConfig[appId]) { + // throw new Error(`AppId ${appId} has not connected`); + // } + if (this.clientConfig[appId]?.encryptWay === 'sign') { const originalResult = serializeMessage(result); const signature = this.clientConfig[appId].encrypt.sign(Buffer.from(originalResult, 'base64')); return { @@ -263,7 +264,7 @@ class Socket { }; } const originalResult = serializeMessage(result); - return this.clientConfig[appId].encrypt.encrypt(originalResult); + return this.clientConfig[appId]?.encrypt.encrypt(originalResult); } async handleConnect(message) { @@ -362,7 +363,7 @@ class Socket { }; } - async handleInvoke(message, isReadOnly = false) { + async handleInvoke(message, isReadOnly) { const params = await this.deserializeParams(message); const { endpoint = this.defaultEndpoint, contractAddress, contractMethod, arguments: contractArgs } = params; logger.info(`${isReadOnly ? 'Calling' : 'Sending'} contract ${contractAddress} method ${contractMethod}...`); diff --git a/test/command/dappServer/index.test.js b/test/command/dappServer/index.test.js new file mode 100644 index 0000000..8af4b9d --- /dev/null +++ b/test/command/dappServer/index.test.js @@ -0,0 +1,57 @@ +import { Command } from 'commander'; +import { userHomeDir } from '../../../src/utils/userHomeDir.js'; +import DeployCommand from '../../../src/command/dappServer/index'; +import Socket from '../../../src/command/dappServer/socket'; +import { logger } from '../../../src/utils/myLogger'; +import { endpoint as endPoint, account, password, dataDir } from '../../constants.js'; + +jest.mock('../../../src/command/dappServer/socket'); +jest.mock('../../../src/utils/myLogger'); +describe('DeployCommand', () => { + let deployCommand; + let oraInstanceMock; + const sampleRc = { getConfigs: jest.fn() }; + beforeEach(() => { + oraInstanceMock = { + start: jest.fn(), + clear: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + deployCommand = new DeployCommand(sampleRc); + deployCommand.oraInstance = oraInstanceMock; + }); + afterEach(() => { + jest.clearAllMocks(); + }); + test('should run and start the server successfully', async () => { + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'wallet', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await deployCommand.run(commander); + expect(logger.info).toHaveBeenCalledWith('DApp server is listening on port 35443'); + }, 20000); + test('should handle errors during server startup', async () => { + Socket.mockImplementation(_ => { + throw new Error('socket error'); + }); + const commander = new Command(); + commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); + commander.option('-a, --account ', 'The address of AElf wallet'); + commander.option('-p, --password ', 'The password of encrypted keyStore'); + commander.option( + '-d, --datadir ', + `The directory that contains the AElf related files. Default to be ${userHomeDir}/aelf` + ); + commander.parse([process.argv[0], '', 'wallet', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); + await deployCommand.run(commander); + expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); + expect(logger.error).toHaveBeenCalled(); + }, 20000); +}); diff --git a/test/command/dappServer/socket-sign.test.js b/test/command/dappServer/socket-sign.test.js new file mode 100644 index 0000000..e2c6f2d --- /dev/null +++ b/test/command/dappServer/socket-sign.test.js @@ -0,0 +1,359 @@ +/* eslint-disable max-len */ +import ioc from 'socket.io-client'; +import AElf from 'aelf-sdk'; +import { getWallet } from '../../../src/utils/wallet'; +import Socket from '../../../src/command/dappServer/socket'; +import { logger } from '../../../src/utils/myLogger'; +import * as utils from '../../../src/command/dappServer/utils'; +import Sign from '../../../src/command/dappServer/sign'; +import { endpoint, account, password, dataDir } from '../../constants.js'; + +jest.mock('../../../src/command/dappServer/sign'); +jest.mock('../../../src/utils/myLogger'); + +const connectData = { + action: 'connect', + params: { + publicKey: + '04b00b9a0c0359a5e0a55b0efa32469929765b30bc5a8b375d2dbffa43322f87df3401845a4cc3841a36c3f14a7481ce1c4e9d920f18ede0f4bcbd29e291a4190a', + timestamp: 1718870995, + encryptAlgorithm: 'secp256k1', + signature: + '33977ec3965229628feb4b95846442d71d20fa9bfd54efe6958daa5fdf369a3ecde738f9a10374dd8b56064618e50746b9c3581ade80abfc3b69decadadec7a200' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '4b62bc590a4d43beb432c1692e1a2234' +}; +let clientSocket, + socketInstance, + port = 35444; +const serverUrl = `http://localhost:${port}`; +const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); +const wallet = getWallet(dataDir, account, password); + +describe('Socket Server with sign', () => { + beforeEach(done => { + socketInstance = new Socket({ + port, + endpoint, + aelf, + wallet, + address: account + }); + clientSocket = ioc(serverUrl, { + transports: ['websocket'], + timeout: 5000, + reconnectionAttempts: 5 + }); + clientSocket.on('connect', async message => { + await new Promise(resolve => setTimeout(resolve, 1000)); + done(); + }); + }); + + afterEach(() => { + clientSocket.close(); + socketInstance.socket.close(); + }); + test('should handle invalid signature', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('Not a valid signature')); + done(); + }); + + Sign.verify = jest.fn().mockReturnValue(false); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + '5a54b642b72af76fdd707fc00f7b48a6166e0816240f1fb5528777c55289e0c7c94eb88e67d9a07f8b5c99777ecbbb99d5482147ef7766888c29c837b023afd101', + getPublicKey: () => + '04e8feb5a19d6de284218083c75b16bdf9bc356e46c2c6da7ec5f9a96ae150d194bfae36782ae54094e4a3be41dd1f92a8eef2e42b0af82511795d25f37a6945c0' + }; + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + clientSocket.emit('bridge', connectData); + }); + + test('should handle invalid Timestamp', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('Timestamp is not valid')); + done(); + }); + + Sign.verify = jest.fn().mockReturnValue(true); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + '5a54b642b72af76fdd707fc00f7b48a6166e0816240f1fb5528777c55289e0c7c94eb88e67d9a07f8b5c99777ecbbb99d5482147ef7766888c29c837b023afd101', + getPublicKey: () => + '04e8feb5a19d6de284218083c75b16bdf9bc356e46c2c6da7ec5f9a96ae150d194bfae36782ae54094e4a3be41dd1f92a8eef2e42b0af82511795d25f37a6945c0' + }; + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(false); + clientSocket.emit('bridge', connectData); + }); + test('should handle not support encrypt method or not enough params', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith(new Error('Not support encrypt method or not enough params')); + expect(logger.error).toHaveBeenCalledWith('error happened'); + done(); + }); + const invalidConnectData = { + action: 'connect', + params: { + publicKey: + '04b00b9a0c0359a5e0a55b0efa32469929765b30bc5a8b375d2dbffa43322f87df3401845a4cc3841a36c3f14a7481ce1c4e9d920f18ede0f4bcbd29e291a4190a', + timestamp: 1718870995, + encryptAlgorithm: 'secp256k1' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '4b62bc590a4d43beb432c1692e1a2234' + }; + clientSocket.emit('bridge', invalidConnectData); + }); +}); + +describe('Socket Server with sign', () => { + // let clientSocket, + // socketInstance, + // port = 35444; + // const serverUrl = `http://localhost:${port}`; + // const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + // const wallet = getWallet(dataDir, account, password); + + beforeEach(done => { + socketInstance = new Socket({ + port, + endpoint, + aelf, + wallet, + address: account + }); + clientSocket = ioc(serverUrl, { + transports: ['websocket'], + timeout: 5000, + reconnectionAttempts: 5 + }); + clientSocket.on('connect', async message => { + await new Promise(resolve => setTimeout(resolve, 1000)); + done(); + }); + // first need to connect + // const connectData = { + // action: 'connect', + // params: { + // publicKey: + // '04b00b9a0c0359a5e0a55b0efa32469929765b30bc5a8b375d2dbffa43322f87df3401845a4cc3841a36c3f14a7481ce1c4e9d920f18ede0f4bcbd29e291a4190a', + // timestamp: 1718870995, + // encryptAlgorithm: 'secp256k1', + // signature: + // '33977ec3965229628feb4b95846442d71d20fa9bfd54efe6958daa5fdf369a3ecde738f9a10374dd8b56064618e50746b9c3581ade80abfc3b69decadadec7a200' + // }, + // appId: '28e653ec-20d4-55e1-b077-a346df57666a', + // id: '4b62bc590a4d43beb432c1692e1a2234' + // }; + Sign.verify = jest.fn().mockReturnValue(true); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + '5a54b642b72af76fdd707fc00f7b48a6166e0816240f1fb5528777c55289e0c7c94eb88e67d9a07f8b5c99777ecbbb99d5482147ef7766888c29c837b023afd101', + getPublicKey: () => + '04e8feb5a19d6de284218083c75b16bdf9bc356e46c2c6da7ec5f9a96ae150d194bfae36782ae54094e4a3be41dd1f92a8eef2e42b0af82511795d25f37a6945c0' + }; + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + clientSocket.emit('bridge', connectData); + }); + + afterEach(() => { + clientSocket.close(); + socketInstance.socket.close(); + }); + + test('should handle account action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith('Querying account information'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + 'd319351e191c8a5f751ed3b3f586af53017dba17f5ec58980ba51ec51f968a3cc8deadb4e9acbb8ddd84b065a8b919d2d32724e87d7df6f412581fa3d375523e01' + }; + }); + const data = { + action: 'account', + params: { + signature: + '8747f44c44d468554fcaeadb64a3cd75444c2bbb91c8e52855679bebc1ca9282a6499911b92da3d627a5b03788c6b5817a61b4183a0e5d7535c2af0abce11a4e01', + originalParams: 'JTdCJTIydGltZXN0YW1wJTIyJTNBMTcxODg3MDk5NiU3RA==' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: 'cd78bea8c031411fb6659939f9070527' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle api action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith('Querying api /api/blockChain/chainStatus...'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + 'd319351e191c8a5f751ed3b3f586af53017dba17f5ec58980ba51ec51f968a3cc8deadb4e9acbb8ddd84b065a8b919d2d32724e87d7df6f412581fa3d375523e01' + }; + }); + const data = { + action: 'api', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhcGlQYXRoJTIyJTNBJTIyJTJGYXBpJTJGYmxvY2tDaGFpbiUyRmNoYWluU3RhdHVzJTIyJTJDJTIybWV0aG9kTmFtZSUyMiUzQSUyMmdldENoYWluU3RhdHVzJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTVEJTJDJTIydGltZXN0YW1wJTIyJTNBMTcxODg3Mjc4MCU3RA==' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: 'e647eda5134a4325a5bf03f429336c03' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invoke action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith( + 'Sending contract ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx method Transfer...' + ); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + 'd319351e191c8a5f751ed3b3f586af53017dba17f5ec58980ba51ec51f968a3cc8deadb4e9acbb8ddd84b065a8b919d2d32724e87d7df6f412581fa3d375523e01' + }; + }); + const data = { + action: 'invoke', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJjb250cmFjdEFkZHJlc3MlMjIlM0ElMjJBU2gyV3Q3blNFbVlxbkd4UFB6cDRwblZEVTR1aGoxWFc5U2U1VmVaY1gyVURkeWp4JTIyJTJDJTIyY29udHJhY3RNZXRob2QlMjIlM0ElMjJUcmFuc2ZlciUyMiUyQyUyMmFyZ3VtZW50cyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJwYXJhbXMlMjIlMkMlMjJ2YWx1ZSUyMiUzQSU3QiUyMnN5bWJvbCUyMiUzQSUyMkVMRiUyMiUyQyUyMmFtb3VudCUyMiUzQTEwMDAwMDAwMCUyQyUyMm1lbW8lMjIlM0ElMjJ5ZWFoJTIyJTJDJTIydG8lMjIlM0ElMjIyUkNMbVpRMjI5MXhEd1NiREVKUjZuTGhGSmNNa3lmclZUcTFpMVl4V0M0U2RZNDlhNiUyMiU3RCU3RCU1RCUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NzMzMDAlN0Q=' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: 'a31b390269ad4caa8da0557c43dea556' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invokeRead action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith( + 'Calling contract 2UKQnHcQvhBT6X6ULtfnuh3b9PVRvVMEroHHkcK4YfcoH1Z1x2 method GetContractAddressByName...' + ); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + 'd319351e191c8a5f751ed3b3f586af53017dba17f5ec58980ba51ec51f968a3cc8deadb4e9acbb8ddd84b065a8b919d2d32724e87d7df6f412581fa3d375523e01' + }; + }); + const data = { + action: 'invokeRead', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJjb250cmFjdEFkZHJlc3MlMjIlM0ElMjIyVUtRbkhjUXZoQlQ2WDZVTHRmbnVoM2I5UFZSdlZNRXJvSEhrY0s0WWZjb0gxWjF4MiUyMiUyQyUyMmNvbnRyYWN0TWV0aG9kJTIyJTNBJTIyR2V0Q29udHJhY3RBZGRyZXNzQnlOYW1lJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTdCJTIybmFtZSUyMiUzQSUyMnBhcmFtcyUyMiUyQyUyMnZhbHVlJTIyJTNBJTIyYTJhMDBmODU4M2MwOGRhYTAwYjgwYjBiYmFjNDY4NDM5NmZlOTY2YjY4M2VhOTU2YTYzYmQ4ODQ1ZWVlNmFlNyUyMiU3RCU1RCUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NzMyMjclN0Q=' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '36055f21b2d6418998dda7eda6526a2a' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle getContractMethods action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Sign.mockImplementation(() => { + return { + verify: () => true, + sign: () => + 'd319351e191c8a5f751ed3b3f586af53017dba17f5ec58980ba51ec51f968a3cc8deadb4e9acbb8ddd84b065a8b919d2d32724e87d7df6f412581fa3d375523e01' + }; + }); + const data = { + action: 'getContractMethods', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhZGRyZXNzJTIyJTNBJTIyQVNoMld0N25TRW1ZcW5HeFBQenA0cG5WRFU0dWhqMVhXOVNlNVZlWmNYMlVEZHlqeCUyMiUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NzMyMjklN0Q=' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '08400d6bac284c40a5984821c2ef4f53' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invalid signature', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith(new Error('Signature is not valid')); + done(); + }); + socketInstance.clientConfig['28e653ec-20d4-55e1-b077-a346df57666a'].encrypt.verify = () => false; + const data = { + action: 'getContractMethods', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhZGRyZXNzJTIyJTNBJTIyQVNoMld0N25TRW1ZcW5HeFBQenA0cG5WRFU0dWhqMVhXOVNlNVZlWmNYMlVEZHlqeCUyMiUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NzMyMjklN0Q=' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '08400d6bac284c40a5984821c2ef4f53' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invalid signature', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith(new Error('Timestamp is not valid')); + done(); + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(false); + const data = { + action: 'getContractMethods', + params: { + signature: + '9f6017bf0c5acee66be32d64edb63471309f7597ef175b64a1329faa3741b875cbec16a46d31a9dd69416cddb6542e3b85a974510869a597d5c099a5d1f6a95501', + originalParams: + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhZGRyZXNzJTIyJTNBJTIyQVNoMld0N25TRW1ZcW5HeFBQenA0cG5WRFU0dWhqMVhXOVNlNVZlWmNYMlVEZHlqeCUyMiUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NzMyMjklN0Q=' + }, + appId: '28e653ec-20d4-55e1-b077-a346df57666a', + id: '08400d6bac284c40a5984821c2ef4f53' + }; + clientSocket.emit('bridge', data); + }, 20000); +}); diff --git a/test/command/dappServer/socket.test.js b/test/command/dappServer/socket.test.js new file mode 100644 index 0000000..5205f81 --- /dev/null +++ b/test/command/dappServer/socket.test.js @@ -0,0 +1,545 @@ +/* eslint-disable max-len */ +import ioc from 'socket.io-client'; +import AElf from 'aelf-sdk'; +import { getWallet } from '../../../src/utils/wallet'; +import Socket from '../../../src/command/dappServer/socket'; +import { logger } from '../../../src/utils/myLogger'; +import * as utils from '../../../src/command/dappServer/utils'; +import Encrypt from '../../../src/command/dappServer/encrypt'; +import { endpoint, account, password, dataDir } from '../../constants.js'; + +jest.mock('../../../src/command/dappServer/encrypt'); +jest.mock('../../../src/utils/myLogger'); + +describe('Socket Server', () => { + let clientSocket, + socketInstance, + port = 35443; + const serverUrl = `http://localhost:${port}`; + const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + const wallet = getWallet(dataDir, account, password); + + beforeEach(done => { + socketInstance = new Socket({ + port, + endpoint, + aelf, + wallet, + address: account + }); + clientSocket = ioc(serverUrl, { + transports: ['websocket'], + timeout: 5000, + reconnectionAttempts: 5 + }); + clientSocket.on('connect', async message => { + await new Promise(resolve => setTimeout(resolve, 1000)); + done(); + }); + // first need to connect + const connectData = { + action: 'connect', + params: { + publicKey: '1cc7d260e79e3b83b4525cba2edd47063f8ad05a2adc229a0ff4a5716aa365e3', + encryptAlgorithm: 'curve25519', + cipher: 'aes-256-cbc' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '47bf3177c41344ca988cfedbba51cf4a' + }; + Encrypt.mockImplementation(() => { + return { + decrypt: () => 'JTdCJTIydGltZXN0YW1wJTIyJTNBMTcxODc5MjM4MCU3RA==', + encrypt: () => { + return { + id: 'a199de9ebed04676a3b0ede012854e26', + result: { + encryptedResult: + 'w7ZqPE5MYtoLVIJPjXsAd6I0sbuHQIA10PbS/d4+Iw6C62avXlcNQSjH36R/3B5+psxKGpps/buCT6yATPwB3TUI1o1NdGBpe59VIdAE6BYySvHOzWnKOiiuc4LOMD0to//YsPy5SYYkYqLVVfjdOSHBmvs7qtI1x3RN57KwDjz9s0/MJlRg9olCwWkCABqqECdE8fP9jeLnWyjyKdPE++qGF4rSnPrEpYTXCjWNjYAX2m1SqV0fcfmLCHqE+NbbTEXLtfort3ZDPAl1nr/kKEp6HkXg8hXKzYHQFv45m78PzEkyUBMS8Jsuy8tw1JPkv+TcwtdhPQemcv8aA1B/nrfVVXGPLM0MVlLOctsisiU50nq21/NhTqUR/85GolfMoDQnMXYa/GilLUiPI1ZqWeV4ZqEgZWcVS3AvEWPgZmQ4sNeaDgXFAWOBZa3bPecqqyKGAu3+LPlchLOHCqV46bH6GodrVkma2n7q92LO2Bx13TZ1v4oF/Kp4N+X1K/5BpbPOsVEyM9DfFj8+vDHY467tBOi2TvLfh46H31Jma5J8hYrghs8G9vkEsYPzVMIYhfEpw0pftrSCK9DV6AVlwJU3Pop2CTlvdBtSLNIL7Iz1SLL27Tonb93VysEAXEw+86fZZCb61+f45JExLMc21AWcdSuDmAMZGBe7mAMU/oyUjkXPC8Hv6VRmLPhcPjLY', + iv: '442e8595ba6345e39a8248993a5ca18f' + } + }; + }, + getPublicKey: () => '5074c544a996ea80d95555fef4da21a3f57673ea949293405cee975aba653b4a' + }; + }); + clientSocket.emit('bridge', connectData); + }); + + afterEach(() => { + clientSocket.close(); + socketInstance.socket.close(); + }); + + test('should handle account action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith('Querying account information'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ timestamp: 1718784774 }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + const data = { + action: 'account', + params: { + encryptedParams: 'yi4N41XoCTSz0ibXKQ2/rIYZz8D0u6vbaRxLPx+cu7AQjv3nsdWA9bqDSeQMr0ye', + iv: '67b83b89bdd44e2f8bcbb02251783825' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '281537101483488da8c12a9b02c4f563' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle api action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith('Querying api /api/blockChain/chainStatus...'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhcGlQYXRoJTIyJTNBJTIyJTJGYXBpJTJGYmxvY2tDaGFpbiUyRmNoYWluU3RhdHVzJTIyJTJDJTIybWV0aG9kTmFtZSUyMiUzQSUyMmdldENoYWluU3RhdHVzJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTVEJTJDJTIydGltZXN0YW1wJTIyJTNBMTcxODc5NDg2NyU3RA====', + encrypt: () => { + return { + id: '45b66a0738ff48a7b06cec79ff673dba', + result: { + encryptedResult: + 'WOsz8XNcMS66yp6qni9+oV9m1pelGe7uLWuICVrc4Urq1gH+XmErWMKZy7vCqPYHfS3kBVwnKMl5WHS6rEUQBZg4mPux3IfozDgNrY7NC9DN81kt/h5tKbSHSx6GMgB9GeVLH5ELj+O+ZZXSszge5k2/xRa0GZYGdX04EXG5OO4XJ+3KxE5YXmO1PhfQenZR19GynQQxymMwByRxZM0GvpKhHM3oQbq7s600wPvulHdIdXY3W4QCPyLTqQD+18aNEVzFYZjr0WGZJKVTv8NsS04gDghVIShmMCTzkvEYPM0kI9JocfSDSI5MqsMGbdpNhKAYCFBgC3ILOpbpGXG53qUUdhFcDIAnj6yeyB8ZG+pkMEBcbn+aZoWjdqS/z7UrIF0RatCKGRzZyOO8La0d+KsHOm11d/cukTsyyz9/Yvds1Equlyk9vz4BUQNkIaM2zXP6AZfE3QwoMf0IhcXdFCEoBybDNEuaxueEBVkHdM+9WF4EwqX2iRHgXa4D6qKfIGgD5zhTASWCEOJj5Q57/eSu2cZ6xT+hJiX95sO1PB0TqatQMhGz2n/fAKf5roKAXxgjAx/eiAzygTVldmMGHQtj++UveilXCeZ9BEInb3K3mRyx5pc/t874dGF44l/VqC18RK0X1xgUDYcV2ru/HJwH0OHKxDJSDlEIzME8U5x6FVGHc33kFgY1LcLEXHd+r0MpSYdtbHiwwPPTSGhgFwnpF+mWZnQepQh4VsNcfJRg8tMG9Jcx4vM9vaT7b7a9LaT333WZ1d6DiXQYZ3MJBewUwqfNlqTaz+O7o51tOXMHzX4FxcUwgsGLSgH9al5hjWb3uZZarXrF/dhB4zyQBmTdPO6k4cowcoWLvEnKiSU2mYKqSvUoqmM1o7cI21VD4reV7XQiFxUEP3CNlkNFm1imImhANZoltx+GkzZRsL9IHMgkEO5ixLR+ouOEZt4RGqmLQnQfdZyZTAOBS95izXjEchWM+W0EEXh+wfvCAphcyfSK0m+KZRsc6z5CN9FvF3nkfVN+pt7G59j0+CbJpGHDqXQm9OcuUqqbHkvUNArrNtHpZSadK6m2TewBuLeujLqG1MQD7P7jzDMvg8vMjOiX7KaqQoKaMlWdM6woEusNT0ddua4ReJ+PJtk7W3AjNIVYGhO47cGjFrb7i4gHPQ==', + iv: '640c59919fa84f7aa6ea9dcaba8c7a0b' + } + }; + } + }; + }); + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + // endpoint: '', + apiPath: '/api/blockChain/chainStatus', + methodName: 'getChainStatus', + arguments: [], + timestamp: 1718794867 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + const data = { + action: 'api', + params: { + encryptedParams: + 'bJiUPLoclvINMQDHJw2Dt4sGCFB5LV65UaIwUuoqs+O+K3H7bhexPNUecHrbqiSxfpoynsh72lrAWcykNPsfL8/XxYqnmJnGACdA+vCRVIdmL91/FzXfZoE8LgfhdELooVk2PCsfVLUuiOfZPVqo05SPvU320hIJbm4jqyCDTnNofLvSwq+bFULdpa1QmLxMiLaiKXXj6ktO3nER75sb3hLk7Lrun3rRvnFrbfC2Qlw4Zia2b0yMIacC0DmomWU0', + iv: '2ef43a6a71ed4aad9811ffba7d39464f' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '45b66a0738ff48a7b06cec79ff673dba' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invoke action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith( + 'Sending contract ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx method Transfer...' + ); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJjb250cmFjdEFkZHJlc3MlMjIlM0ElMjJBU2gyV3Q3blNFbVlxbkd4UFB6cDRwblZEVTR1aGoxWFc5U2U1VmVaY1gyVURkeWp4JTIyJTJDJTIyY29udHJhY3RNZXRob2QlMjIlM0ElMjJUcmFuc2ZlciUyMiUyQyUyMmFyZ3VtZW50cyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJwYXJhbXMlMjIlMkMlMjJ2YWx1ZSUyMiUzQSU3QiUyMnN5bWJvbCUyMiUzQSUyMkVMRiUyMiUyQyUyMmFtb3VudCUyMiUzQTEwMDAwMDAwMCUyQyUyMm1lbW8lMjIlM0ElMjJ5ZWFoJTIyJTJDJTIydG8lMjIlM0ElMjIyUkNMbVpRMjI5MXhEd1NiREVKUjZuTGhGSmNNa3lmclZUcTFpMVl4V0M0U2RZNDlhNiUyMiU3RCU3RCU1RCUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NTI5NzIlN0Q=', + encrypt: () => { + return { + id: 'f84f494d82ce42c5b4018d37d6bd1d34', + result: { + encryptedResult: + 'gE0Mdb25HVglTZdjs26pvgq337LybbfPFZOsL/FWeKi/EBFdT+Vv8J+8xnU5dp/NNy49gTJQI8ggm9QRvpLz2rSb0fT+9fakQcC5REpOIO+WzZ93OCLE2pg/dRyTpyaeZNc7Hk9TGYV5puG2BfLye9ZpdxcUvMzaNqlw6s6frZp2m5djHRskGi+zcsU95JbjEDeqh1s2xtOBbL7JvrT/QTccSPcgTFFLYfoYGhD+SMt/+o049lBGa8c91rQRPbFj', + iv: '9e5d79cb079d49a295e5fa5f795a06c4' + } + }; + } + }; + }); + + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + endpoint: '', + contractAddress: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + contractMethod: 'Transfer', + arguments: [ + { + name: 'params', + value: { + symbol: 'ELF', + amount: 1 * 10 ** 8, + memo: 'yeah', + to: '2RCLmZQ2291xDwSbDEJR6nLhFJcMkyfrVTq1i1YxWC4SdY49a6' + } + } + ], + timestamp: 1718852972 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'invoke', + params: { + encryptedParams: + 'CWI3wEtHiyihMfMerb4UmU5wAOnv2Z652Hho7CltDuKwr8ZD69FNvjeoaxwg14bwxvSHRe5Myjuzp06wGrmRv1i+FaZfNrhBYu3afPqJx4cE6a6HSXwAOoUz3yhHTFU+gTSTeOS3MjkZUcEquu6/RYb0k4g6IwTWgxyRe9hppnbYJO3f0YGqQiP1M2awfWNKgs/OzpqI9FPqLRH/5Rzb1IKNHx8utks02vA2dVna+HgF9H13Pnu7joyuoz/LlKhZJwrAow4Me1c93+KIY1dgVjwgVxyIqxQ9vFe2dBxlPCJWvQB4/NZXVwFKeOlBAEy7o0tpUKnYX5NY7may6fnv1avw2Doi7xnCa4tLrZT4FGzpewxTCvg2WARjEqm/XqQQkXOPTv/wuCUmh6LEkMcccFgR7O87SPLkhLCv5QCrlWwBa4DkxgYO0Uo32X1igdTMwXLvu4yiPT7Od4pfyvMRuMwVEFmqbblbLpT/U1WwzIIcTG3x0CFiw0lJCdZ2zIjy5vIGp/ybxLez3TNn39e8CJTOU95XXsg6xcj2szF4LpE=', + iv: '2fccb196db614d05abc09deaa3798242' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'f84f494d82ce42c5b4018d37d6bd1d34' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invokeRead action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith( + 'Calling contract 2UKQnHcQvhBT6X6ULtfnuh3b9PVRvVMEroHHkcK4YfcoH1Z1x2 method GetContractAddressByName...' + ); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJjb250cmFjdEFkZHJlc3MlMjIlM0ElMjIyVUtRbkhjUXZoQlQ2WDZVTHRmbnVoM2I5UFZSdlZNRXJvSEhrY0s0WWZjb0gxWjF4MiUyMiUyQyUyMmNvbnRyYWN0TWV0aG9kJTIyJTNBJTIyR2V0Q29udHJhY3RBZGRyZXNzQnlOYW1lJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTdCJTIybmFtZSUyMiUzQSUyMnBhcmFtcyUyMiUyQyUyMnZhbHVlJTIyJTNBJTIyYTJhMDBmODU4M2MwOGRhYTAwYjgwYjBiYmFjNDY4NDM5NmZlOTY2YjY4M2VhOTU2YTYzYmQ4ODQ1ZWVlNmFlNyUyMiU3RCU1RCUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NDkwMzElN0Q=', + encrypt: () => { + return { + id: '0dfbd2c9112140f485e6d809b3a70744', + result: { + encryptedResult: + 'e+PS/RjVcXP1fTOzJZQXsaaW/FsDS1cxwjm0/xXwjXHqB4rjc4njsOp4np+qOHCBpLAEqzo181B1/gNRLyFJ2wJwoBpDHJi0d4As4sB4UmCh7SEdHnrMIrbxACewO06xesDYlmKwNKXuGjTAOnYhNyIRcy+FoK9dVOpnpEzK7H344tmZ5lsHN+x9zOH64+L50cek7lPfeNgJQX4xuApqL1le4CgEjH9xFbNVwfN7RkFWt0wW+CiTfH2PqOXk67yHdket1DPmtczMpTb7Kafk0DWfWARxAYgteiem3sKQ7lRrk5A5+CTyxN0DoehSIjDPVaaEc88f18sfqVPvAedkmpkM9NpA8UClSDCIMtoy6byuoapmhdsLPvW6zfF6KH/M34iHcH6RaPSI1EY/oSZLo7mgDfITJH/rDkiriO/sLaIKAtc7vAiE1s0N8BYNd2mzoL+liq0chmFxoyycc8mu2jZuTC8jnOXJIemDQKRk1WGklIfth0ccI1jbU73dxaypNCBFk+E6PkTQaPM7Ml3zBjCJc0Cht0Sa9o3/GajmOfmGVAmp2qvZJvLAlMpn8JdlulpZ0bBLpF04aQw3RVIyuwdBRRR7TkBhvx2TJekVVaON/qUyZw4Th9N4j9XgTSuusPXihhwPcgAJ1d84zZlRMC2Qy5gy6dS5936xN6iiOvtYkvF543Fxtg0Nmdp+dSpuLqzDM0FlJ962CmRdnjf1w/3V599b5Ti5wAFMkE2HjXTN/gSxsnhms4nbmhUGEfgbbk7uAt2l6S1xWljVmD+WA8Y5CJR6h4Na9umZExdCvMfsE3Em/PF6U2NP60D1zzF79FyUEVIN/ZDTj2xn+ekuE3N7i7JlEFF1Qr7+g0r2hlfd5oG6jKHrAJQslS7vpQNsXLGVyL0l0COy8J1gGylJu0875EvIwkYoL51f3GZzp1P2H6e/NyJi5U6cqxGYogViLqaXz3Z+cP9FaPP1/01RpDD4WyIItFXr9qMzgUTCHVbcPXBzeIPVO+XFImdY2u17JRqwdtQ3Est3Pg9SALqBe1Njki3+dhYBdAV7l7GWj8M+7GQnVNEj7GGoEpkCLD8jdqXIcf5iRHrExknTrOzc+9di0lr/VAzflJkIsoP1h/YMVEw7xnulIs/lrs/cvs6Cj4PPUkHpzL+Os034hqrogFHVtXg004fMHBbnHEVNqr02lFd6lOxqHOodpP8/VmI7rbGnHt5Jv26n6MCBUZDOkPh/GxAutivkc3uNPzeFQidWue9UgCb4HW+AVTdcU8yL0EkpnI0T33UQ63NcCaoq3MPDbEe47tBQlNfxgQPdHt+oeJn07CRjnQqZWXKySxR0/1oSdj5NLAfyuja3hWjF5KDyq2ZwolShSTcd4MMTwbZlwSDFSr+viLqYj4WHZWTEWOpI/oAs6Ix2mpJ5WRo9m5PjwhdfVFE9O/d5+SYGlzE4EERLgxiY4LkkiZwybJXnWFktOvK8YEIQ7cI4PIW9KIMrUpHO/KAk2LfUYveWNnf62GQle5+64saU2sOttAD0G0tBd1S812XYYqzWGiD4KSBiaoC0fEy+VManGSSvEk9xYoiXa9HknKvr36PGMTJ4Cl1bDM4Xn9/YOpgI85COPrOy7KZQEp61TA4ubPQVAohE7vN2aAYd21UbDM144ceERQo6NdrLMK6d2B7Gd/u17dAk4rjVMPxQlDb+6P83LVco14y7ycaqFOhlfJa2a2SeXxkw3Ol+9TATcoaXTucaMY5eEMmsjU5URTUfsFn5FJzF16dix/8qb3GZUTIt+yy25aJ36dFuZifzNvqWsPtmDCTvj2npxZlxS2ukVm/MJV64Q9BXxjvm8ryiNJu6/cIIlOXT0hwmH+YkzL0t7EJOEWTGG3rV+0iJYdhRXAb8Bq9nvOH5KaE4pwbG13HIbYjYSIoMq3cdh61v1WvVJA5euW232DEj9z/Qtui81RyjDFdvJg+/XsqJ6LfPNS3uf1GW9BVzUT87z3H25gke6oJM3e3FWbtvj1MXy61IJud6oiScD4+9ONX72yriz2LwNf7Lce6r9pkhnLsBOxr6fAbEt21g9vuxVpIwyBeanjR1aEvZLddJ3OcZOuNQZMmPildZd47rl260Tl2YvQcYIzA6rAJC8GD3orBJyjVh/WaeCc0IeJsqA0GU8Leb7itXoHiOhAFJELgj8fM10Rcw+3oylp2PFATU0KeHelHW+hz5EwOx8blYzjyh5hEMGptq+qxb1hVPHHs9OGSXZOnCU1ZyBpuNlh71J5lMoE762rde15BQbJsrLQ7EI7af3J1DjSbAVLbTtVOYweZujOUr7MvsThqbO9nmxp69qIKjqh4NWV1zNcpyE6PovI0G2+2s2EofYkcvDtkCQPuzod0ddG90B1caY1vvUN4Bl5PkL1kG8GD0Dtgb81HYOKtV52YSGO5Q73qojiFijgxsOkyj7PbtGCF2O9RFwrQVqB1pGLdoCfPcFSp3SyCqIpFbfaOCQs1Asdi7Aosn37hgj/UlbYPeDFj4Ezol2Vh0dyONc5DxaPdDuu5SsyAdx+AFhPWRQ3y6MAFfSf2vQnM7QCqSmtwy1+aNVqJ9UiT4lpSro18GjOiDoxUJBXXyoJLU5t2JvKc7R5va5Nv9kat3WjmgsTSk0vd2jPokc49uownlCVbSWXGyJ5muMfRqIVlUvx8QnOthSWSGOeBQw17RMvJ5Cu5Xdis2ztdWveZp5HN/d5FqGiUktNdw8KL2TCpPuRBliRSeUXyR4mDae3WeS205My8NoLxMCmC6z1WmktYPsu2/8z6XQ11Qv53b/XXNDL0T7rfuc8KPWaQjQgxZQDj0NWcfvyYK8zr5xSUc7mLhj04Qj6bIqzzotBIDdbkWpJwxybxx4MnMS4h59PD8FR4rACb3Jqj7ba8YeZxtEQ5FHMwlAcIw+CXQBfhhbEqOAyTsytKthtYOT3kPdSb/Runm4oitnMdEca1WDPPSmyaDibJBDL/u4m3g/OnHKw+IseIgEBz/ttPXN7hc5cSj2xkgIZbpTLVTymXAkR/6QGuNpoiFnxV3ljpMDIj3WbFrB5vM2KPiOJInKT/wxt+UQe9v9oj7h7KitUdhS8R6wTu1t+wFTPkD03Tessnvo6L6/rqN0F2FwKwiXLypXIQsltQenSMTm2c32AHZuMB3tEfEEIEx4eVjB2B9vyGyfDFiX0N40YFWiz0mQjIMzEqRw6PsS1Zfs81qjKIIL+XBJ4fCetFJoXAMNpkW2iQhIsWkBSJfZ34cuMhAMj8t+nruhGMkG4GC7RtDhCkiTQsa+Rjac2pK39GESE5YzNuJpR2CJHIoT6pLzTA6RRuy77aNSx2zjROZlUe+SOCH1qKIZy1p7CYQNKBzjrhlOBcdxBK5w7Cw3bACvz/aaXbnStInce2HvOBPsFK0mGBPYlVduh6RRz+NN9A5wY65AmZ2cjIUIP24fSQHQs9eStJRimrZ7McfAlm+KRi1uk1dFMAaxbX3ors510hWHuP0PV4Ax7KcLH9eAE+aZp2JNh4LMVHQ7zsjGElxTcFxa7eEIlZtq0ZURT4qRnlXKiJ/VcM4BsgcgzHUzGsmlA26mmHgLqkdzT1Na8jVjXlgCSphHfgfRfmnqFl2u+1bKCk0hwDyPh3B5+6m+QIALCJoEw8I5rE6XAp7xHNzyE2G1T6MITT3dSl2S0ljDfKk/deLIaWzv2yztGvwaCd/fqkXt9YD+7+xEyXVoC53G3i+mHLihKfh14bfFxVvthNF/hbox9XbO1jvxf5gS5Ua5TvpvKse30bzhNDBMyjpa7Fmz5XNpgrDULcqc4+MrpiptoCtAJIFrIs7sEAnsbJT8ZCzADQbQm18xfJyEKbZZ7nOJlbKGwT7ci+T1hhHLvuWcJhMWiC0Xi1UcVG1HdwI4KOpTgzi0B09EVqcedGKwRR68f2KADZ53IAsFJnfbCFW/TtaV0bdH/f3pQaORUqU6jlDsO3GbOSy69nL4/UddShl2K8Ljb/ouBFbvI+caTeiJygyPtXyDqWAjA6RsdVzpVyeIU21m9yCoB7jA3tgRdDlff4lT5piWmIXK/fJ6/0uDxUWrWFmj/ZhdXIY9B3zwr8K0eAcQ/aZsWu1poQAOex5dZOrg3AS818TWMUyN7A=', + iv: '883c926ef17a4c97845c6cad65a030e9' + } + }; + } + }; + }); + + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + // endpoint: '', + contractAddress: '2UKQnHcQvhBT6X6ULtfnuh3b9PVRvVMEroHHkcK4YfcoH1Z1x2', + contractMethod: 'GetContractAddressByName', + arguments: [ + { + name: 'params', + value: 'a2a00f8583c08daa00b80b0bbac4684396fe966b683ea956a63bd8845eee6ae7' + } + ], + timestamp: 1718849031 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'invokeRead', + params: { + encryptedParams: + 'lqmIluuPMyQw/2/LXMEnKYfxp5KsQvwPpAEPCvsUc6Cf0X1K7d1CcCKv+h6W35vV6+d3sOSZLyeX0SIM7375wKsu14A+tO1OiaJ9DdKyJ6LJo+Mj+aA2Qp0N8zaXQmoTZPsKg/VYI3+YFXQU0tkPUCb+/YkPs/aE5T2KItU9WI3hVN6Xkd0vK2dShaTwhngVeXlcXeymcH/C0CevesDY+opYOHfqY/jP0LqDeXjXUP06LKGx+uMObJJvupslRI2HTbfwJWNYbsM3LY6VCbnA4tKnsfdxZZ3PvIoD6LRaMoIGjbsaTKl0hyZ38TPh+15r+OcoJjWka0TYpTFk93pTKnyGnkClGikWu4VNNe9CKKTSksjc5SNsBNNimxd/L4LLw2/yPIG3ZsaQ0AliaWOhO9SuvPKZnWBPdX/I4sPLkX1UZ5p0adUzQfXjnom2vCg/LeN8TcThw/+LlGAct0c4uQ==', + iv: 'da4512e2c1ed4f819d86fb3816b55aca' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '98c8b690fbbe43ca9f6fd1f72c18f2db' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle getContractMethods action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhZGRyZXNzJTIyJTNBJTIyQVNoMld0N25TRW1ZcW5HeFBQenA0cG5WRFU0dWhqMVhXOVNlNVZlWmNYMlVEZHlqeCUyMiUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NTI5NjMlN0Q=', + encrypt: () => { + return { + id: '7c4aafc53b804bb189c77ea95baf70c1', + result: { + encryptedResult: + 'HS0PIR8FNRUr2VTX+FdffkwQS4T4gKSpcLEhQCK1qcqpGqubblMnWJwtGDyWaZOZW7KzAZW4VV4JO7EtSSKk2p+rqAEP0uLxvZtQskHlz9eK/dYOCHiFdyYKnjF8PG+IwBxy5LdQPJ+acJlq7pUfvzyG48iMU3Zy1bOqm4Li5akWoPTVNQIa5Zl9UcniazIw0pDyOrzI0QAL8Tkjy777BNmjb+zLKQ9mPSG3UBUnLZgFB5EsoQ8puKGs9qKbYYWBhs5DrkEbv5ghmhcbUvxBs4jnzJA8Uu+tDzVMVDPFhHEgAoR5eNFNxWpdv/dGBhSWlPn80G8d0ChhM+W+2Me0kHpTQK+N1WILmmxjSro3E2eHVKwFdxayzjRsiXhKn7AEf7hINzghtyALpuu+8aHjdhhb76CIc5KeQhh9TvPMDzlUivnxGF8BxrwP5YEtQ8zwQH0j3EFMwf0oRQAXWnM5tK45A35ifU6hIBKpB4uTJf9GrpxeWTRITDbxquamXwmbzlDHfG6m22m3QBZhWbLcNkNWxK8ronnvFrvACPHCDCh7qUNd8uMM0ONVxCtlxblK8safqRqZAShnAr3lnfPjVV4mwiZAB/ZdC9wWR8jzrU0+OSsoBP4M1SQ+sa+8z2pUsUtTfQdANYVFJK5O02cjpGBGMFW5GgJkmT8JngyBB4vnc3QtCxRqFt2jEAmvgDNIWzvJ6er9ZVOgeSDAuNsx3YuXpEzPDCCtWDRhu/rZVNysplbhwC+0etA+a6ilc690vkBxF670npcNcptaeWbKWXOKky5aqhYw3nQhZwcRQ3wtyTvMZt6lRc9icK/uQbuUpBfw2XwbvHBnEsdpd7ppCtvLnNGzS58DxiIsDf+efisG90nx8NhQgVqhyMEPZdGZ7TGuN2Kg5oqcoVWcUiNxzGuNHvqWw95k7U1uJiSoR4cJfAgeBY+wq44Q8o9nzM9slCGMYM60VsYZRqVL2/iSZ9Tn5bGppsslVBkmCxstpDW/EdPO5jksIKqg6PIX8RygNasG+zZq0eRVn2maQTbL/8oOXxRGGMEwsfe+YHtSJNWlwHnen3Xg4RGJorBM+fm1LOaHzxnU8qf3W0YcsNq2gfYJgCOYfJVL/B2Bsu5UQHEav/F5+fJtkREiNCeTd638msxWktxrFF7h+ivyinSpFrH6etWUx12SlgnBelDOyqBqrYy1O72AjAMzYe0f5F+M5QUdV8FvsvoeGNRfZt4utOW1dAY2jkEohlx9NtQwe3n/f7di8rdg80JpxPRWMweQl+rB9tpKWwG9f0N8FsH0rQ1zQQz++Wy/6t2vQW5Q7s7vKhOOY2nu8girLvQ3D1fsA1Q2H70ZZr8YT4ABiqIOa5YoKjL8VDdt1h7Oj9eUsjqGIP1JrPNnSbkgXaPHan/aWJsEkA4k7t68dmwtKoBEIbNP0vMtohbIJaW/55MVFaBGK/TB6neFz8xTZj5ns+iMJa1fznZw4F+BjD3yQWqc/5A8oi9qx+LZuJReGqSbmzWOspL5XKgO1odD8c4KypFr/RsjR8tJzhu97bF+0tf6l9BWs8l1vS4eSnqyhFZfGCUtomK/1VNHh9iYYBqTj576hjfEVaGr2cvI4UnlNhcq80cfCOSxpYUQBqqLE90WcdERr3UbBevrS6+V27vQ47OA5cViDO9wRcQ8WngDyOyUiHRzX+DqSOI5oYKrlinIMS5abQ9ZfGodkeWWX2YAclPPnTZuV2n5BSFKdsbQ3afTILhalW2H5pmAa5oa8C3eLE6w8rgaH/L3CUzxooKGf3SgONltUvn0iFEkmM57ASMofl+C0Q/vAA+kfMifH5ojStxyWVCyK0RkTWWY1l6oaY2lexeT2orAQUGLPrwDlDmAj//N1Y+htFfvAT77N46Gvp/HFEQv+u4FaC5OEmSJOKtcOtvlxXbwOZrW3YQ9IGg8utNAQ4rIA6z68JQ5CXRlzK41le9IJ48NdFgH4sNaQI69qCIcpoC3DjIPwNKJ5QV37ofyVyqijOADPRAWi51tSI64Et++hBdyBqQ29KiKI/M1IddknQnL0K/futBdXTyTgR7o4zdhtewxbxKjJyrURrtlcmTCRBggYACZsIJNJ9N2siBdDYvmgs4NNbrcHd4+v6IpdMf0KO9ZsXJ1r8kV3h5eURnUcisd3+0JtnezxHvhgaGycZzqLjNqtKSiyua7YvojySd9da4E3hKVqhX9hnNzgOTaeWdTBiiJ8q8rghLobsjpIiErXUtRU0FLPmKHI99lZjRuAXV+Q9fGf1uTjqldWgALn3+U3+TdeQtt3aFPox9eoIls2uVbkn/OEe5AIHy/CgL3aLNmhfY+hPqRw1CBOy/jO4mpPfgTFaVwobmu3i8OQ13awvlLa0z7NPq0ReNak6JeAvydR/KPAhphqcdZLQHapcvisYBavf7tVt4IPVSYEitzU2OI/QdyE7O4IQH7t+WU+WZrPpVioyOdEXHaFOaybxAsQLRvcsDi9PQathfs9vno9uFmWP+QhEkDRyJ5Yk5bvsRkWwVGaWQaMTCe+U7daNB2Vq1gCwnCikIn5h0+g6W2NbhR7STmkhslc/O7SP1i8HTYfjwAUCBEV8ga1CwhgoZPsuAKDo1aSO0VEW08LjQV33BcbxZi+/daqVQ7z1aFyL8m7oza/qDY+g3HYET3JmkbxT2Pjl0/bdxzZTj3r4mIaNbjOo/NHIEAszgl5nFTwk7WASLEoNlt1Z45mMxcmXz9e9rpo8w/LaagSwEe3OoGQMp3NNMQJVWSQP6W6nbaFFV4T1DIbhXssIcHL4WPVTyBa++ONJ8sUyc2hp+k43i+sektswCm4+JR8movJvueeHlGoBDIgKDEvIu/tcvDbXJVC9sfjNonEP6aeOkMchoamW+kWr7sfQ636drMvuYRJ5bdF+l9PoDt7udvcrMb6T4Sg0/l3ALygvTiOvjzWCAwEcYX7tqebXqOpwJqVXUhy1qTEFw0pQCIjjVck6tvhaZ0goIjDmo4V6lVXh5YePtZQ2oOjk7BnRaOUXuxbnmx7kWEAAYPilK4JdqzU3kRaErEAiABi41XUR+pamxUMR0X/A9XmbLqsYRbyK1FpfSK0pXNa2UgakxKECvKTzOs8qTp+gIAqhPQooXtZwEto/ZxzL99rSFc5mCMIopIY4hxjsDATqgaKnvv+W2rrO9/MREeQqh8T2Cd7ioOCFRfVAH8D1sjHCjyOmerO8mxFigzUzpFkNbGt7VSEF1l4C5mE1AD/36+QJJii+mCNxpriPBCo/wEaEF6bf2khyg5FPG4XWRswlQ5dJo8wTr8Yl0vvf+zc/n6TQaxfYjqAqA+33OhbOfsgwuQADY38DvCdaSVFOHLhIJsLWwhibsno5I2sG6GHn/Buk9/uvLo+4w/LsBogMfMI3BTqCiAB1y7KB/l1Tno7gse1U2HWYsk+4OqZwvAbeY3xhYSZ5Dyq3FlcShizDiCYFvlSdmmlZaZYHxH0R1jg7F6B2BaPiSQfFkzETnuVVWHpBoosnMzWh4thsB5lcfnHRgK1QQPJ2ynoK/Ow4BGJbbk8XcG5DZ982nVpHFgEnaBqx8zeEIhTEJgPR1vdHCMJMMh5KrSz5CpOZ3s1SInNmeaDeLw8R0u1jed2zRrSa76MTBM/jjgcn0NIwF0HRhg2zCY71z/qc/5Su/Tv8/iAtfdO78wD1QlTQAUmW32uGVmccUhrAtvxRI3J5Q+nqCL84bVO/MIq1jzjSDqqPaoHQZFctgzSB+0lujG3PgHvVs+cwlLa3gcwB6ip7GfrdjMuSgaaCIt9d75akcfczi8exeMV2BjzfsYHv473EEmbCu8R+FFPldS0cxe08oN26uBomHc4HdcDvWOVJBWpHWwiWdABOdYhAFQWi9nZmL4tHwLyCRtmamkCGe5YvEAjMFsDf+vNaWbD3p1SigrGsDOqFgv4usn0DnI+y/Bix3/jwbH8i25QQ5c0s24YqyKF4gP9GhnAm27G+/Ut5y+Pw8GnUB5mG+lc5tOWLcyndps+ilexaYuguuyBytjoSDXYZcD7Mqem5cL1ueAdfFtD+WFBrSs7vO+DG/PuA67zI60I+cm6Gi1wUWg1EkDHrnmizY2/MHp10x2TI1rKv+SUFshBZ7lJbm/P672908UK1ElFw6mxb0op4HY9fFE3P14bgrEuHU5JmJxf+aVHVfKDBMZobp8n4u4Enuc0gSywpbfs9agHB9VilO/2l5yyYktkayR1dL6ggFQXJxzMlpSmVRur36i6d58o8L75VkNyyDO0zuqoFv/Rl+MZxuVKC99A+RUon/ffV4fmA==', + iv: '9038ab6200ac48c0a0ffef278f5afbb8' + } + }; + } + }; + }); + + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + endpoint: '', + address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + timestamp: 1718852963 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'getContractMethods', + params: { + encryptedParams: + 'bY89mIBq4wRbI0LWkDN52aFFgbgJbusedG+A54+sOTOnlSk9PxQ93Nw92D8Hc2zBL9DDROudC75dlqxCP8nGD3NKZyeAPQXM1BFTpc/8+OoD8AVpp+XAkO2SFFjHzS35JqspnaeJuJHKGvvnySFUkR/0OOq6ES8pj0nsogPl8wupWHlcDp0+mUo2hrYPddBZ', + iv: 'ea22631f45b34416ae01d95f095cba49' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '7c4aafc53b804bb189c77ea95baf70c1' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle disconnect action', done => { + clientSocket.on('bridge', message => { + expect(logger.info).toHaveBeenCalledWith('Message received'); + expect(logger.info).toHaveBeenCalledWith('App 8a430b69-31df-5ea9-8a55-695faf0623d9 disconnected'); + expect(logger.error).not.toHaveBeenCalled(); + done(); + }); + + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyY29kZSUyMiUzQTAlMkMlMjJtc2clMjIlM0ElMjJzdWNjZXNzJTIyJTJDJTIyZXJyb3IlMjIlM0ElNUIlNUQlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTdE', + encrypt: () => { + return { + id: 'ded9643a0095440a9a5684c4b4c10e35', + result: { + encryptedResult: + 'BytgmULgGg7yEJ9EOvqipB+8uwBjAD4Dv44X7nba6j+ISTnx4QCFtjNpCAbDw9DloC/FMfl/4q+QbORXbtE1DqbGsae0bsAUQ03jLFU40Aui9Dq/AZLrcJ7/usU+2pbk', + iv: 'b08cbd888f8a400e8c0ded10826f4c03' + } + }; + } + }; + }); + + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + endpoint: '', + address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx', + timestamp: 1718852963 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'disconnect', + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + test('should handle null action', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('You should set a action name')); + done(); + }); + + const data = { + action: null, + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + test('should handle undefined action', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('You should set a action name')); + done(); + }); + + const data = { + action: undefined, + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + test('should handle empty string action', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('You should set a action name')); + done(); + }); + + const data = { + action: '', + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle not supported action', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('test is not supported')); + done(); + }); + + const data = { + action: 'test', + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle not connected appId', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error('AppId test-id has not connected')); + done(); + }); + + const data = { + action: 'account', + params: { + encryptedParams: 'K/ZzGwmGdGBvypMkYEFkKNj8BiGnqndWwPPar1vejw/FOFptyhGTBe27NCRObzoR', + iv: 'f009bd251db14d13b1e87273b8b828b5' + }, + appId: 'test-id', + id: 'ded9643a0095440a9a5684c4b4c10e35' + }; + clientSocket.emit('bridge', data); + }, 20000); + test('should handle Timestamp is not valid', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith(new Error('Timestamp is not valid')); + done(); + }); + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ timestamp: 1718784774 }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(false); + + const data = { + action: 'account', + params: { + encryptedParams: 'yi4N41XoCTSz0ibXKQ2/rIYZz8D0u6vbaRxLPx+cu7AQjv3nsdWA9bqDSeQMr0ye', + iv: '67b83b89bdd44e2f8bcbb02251783825' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '281537101483488da8c12a9b02c4f563' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle not supported api', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error(`Not support api /test`)); + done(); + }); + + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJhcGlQYXRoJTIyJTNBJTIyJTJGYXBpJTJGYmxvY2tDaGFpbiUyRmNoYWluU3RhdHVzJTIyJTJDJTIybWV0aG9kTmFtZSUyMiUzQSUyMmdldENoYWluU3RhdHVzJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTVEJTJDJTIydGltZXN0YW1wJTIyJTNBMTcxODc5NDg2NyU3RA====', + encrypt: () => { + return { + id: '45b66a0738ff48a7b06cec79ff673dba', + result: { + encryptedResult: + 'WOsz8XNcMS66yp6qni9+oV9m1pelGe7uLWuICVrc4Urq1gH+XmErWMKZy7vCqPYHfS3kBVwnKMl5WHS6rEUQBZg4mPux3IfozDgNrY7NC9DN81kt/h5tKbSHSx6GMgB9GeVLH5ELj+O+ZZXSszge5k2/xRa0GZYGdX04EXG5OO4XJ+3KxE5YXmO1PhfQenZR19GynQQxymMwByRxZM0GvpKhHM3oQbq7s600wPvulHdIdXY3W4QCPyLTqQD+18aNEVzFYZjr0WGZJKVTv8NsS04gDghVIShmMCTzkvEYPM0kI9JocfSDSI5MqsMGbdpNhKAYCFBgC3ILOpbpGXG53qUUdhFcDIAnj6yeyB8ZG+pkMEBcbn+aZoWjdqS/z7UrIF0RatCKGRzZyOO8La0d+KsHOm11d/cukTsyyz9/Yvds1Equlyk9vz4BUQNkIaM2zXP6AZfE3QwoMf0IhcXdFCEoBybDNEuaxueEBVkHdM+9WF4EwqX2iRHgXa4D6qKfIGgD5zhTASWCEOJj5Q57/eSu2cZ6xT+hJiX95sO1PB0TqatQMhGz2n/fAKf5roKAXxgjAx/eiAzygTVldmMGHQtj++UveilXCeZ9BEInb3K3mRyx5pc/t874dGF44l/VqC18RK0X1xgUDYcV2ru/HJwH0OHKxDJSDlEIzME8U5x6FVGHc33kFgY1LcLEXHd+r0MpSYdtbHiwwPPTSGhgFwnpF+mWZnQepQh4VsNcfJRg8tMG9Jcx4vM9vaT7b7a9LaT333WZ1d6DiXQYZ3MJBewUwqfNlqTaz+O7o51tOXMHzX4FxcUwgsGLSgH9al5hjWb3uZZarXrF/dhB4zyQBmTdPO6k4cowcoWLvEnKiSU2mYKqSvUoqmM1o7cI21VD4reV7XQiFxUEP3CNlkNFm1imImhANZoltx+GkzZRsL9IHMgkEO5ixLR+ouOEZt4RGqmLQnQfdZyZTAOBS95izXjEchWM+W0EEXh+wfvCAphcyfSK0m+KZRsc6z5CN9FvF3nkfVN+pt7G59j0+CbJpGHDqXQm9OcuUqqbHkvUNArrNtHpZSadK6m2TewBuLeujLqG1MQD7P7jzDMvg8vMjOiX7KaqQoKaMlWdM6woEusNT0ddua4ReJ+PJtk7W3AjNIVYGhO47cGjFrb7i4gHPQ==', + iv: '640c59919fa84f7aa6ea9dcaba8c7a0b' + } + }; + } + }; + }); + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + endpoint: '', + apiPath: '/test', + methodName: 'getChainStatus', + arguments: [], + timestamp: 1718794867 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'api', + params: { + encryptedParams: + 'bJiUPLoclvINMQDHJw2Dt4sGCFB5LV65UaIwUuoqs+O+K3H7bhexPNUecHrbqiSxfpoynsh72lrAWcykNPsfL8/XxYqnmJnGACdA+vCRVIdmL91/FzXfZoE8LgfhdELooVk2PCsfVLUuiOfZPVqo05SPvU320hIJbm4jqyCDTnNofLvSwq+bFULdpa1QmLxMiLaiKXXj6ktO3nER75sb3hLk7Lrun3rRvnFrbfC2Qlw4Zia2b0yMIacC0DmomWU0', + iv: '2ef43a6a71ed4aad9811ffba7d39464f' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '45b66a0738ff48a7b06cec79ff673dba' + }; + clientSocket.emit('bridge', data); + }, 20000); + + test('should handle invoke with not supported method', done => { + clientSocket.on('bridge', message => { + expect(logger.error).toHaveBeenCalledWith('error happened'); + expect(logger.error).toHaveBeenCalledWith(new Error(`No such method Test`)); + done(); + }); + + Encrypt.mockImplementation(() => { + return { + decrypt: () => + 'JTdCJTIyZW5kcG9pbnQlMjIlM0ElMjIlMjIlMkMlMjJjb250cmFjdEFkZHJlc3MlMjIlM0ElMjIyVUtRbkhjUXZoQlQ2WDZVTHRmbnVoM2I5UFZSdlZNRXJvSEhrY0s0WWZjb0gxWjF4MiUyMiUyQyUyMmNvbnRyYWN0TWV0aG9kJTIyJTNBJTIyR2V0Q29udHJhY3RBZGRyZXNzQnlOYW1lJTIyJTJDJTIyYXJndW1lbnRzJTIyJTNBJTVCJTdCJTIybmFtZSUyMiUzQSUyMnBhcmFtcyUyMiUyQyUyMnZhbHVlJTIyJTNBJTIyYTJhMDBmODU4M2MwOGRhYTAwYjgwYjBiYmFjNDY4NDM5NmZlOTY2YjY4M2VhOTU2YTYzYmQ4ODQ1ZWVlNmFlNyUyMiU3RCU1RCUyQyUyMnRpbWVzdGFtcCUyMiUzQTE3MTg4NDkwMzElN0Q=', + encrypt: () => { + return { + id: '0dfbd2c9112140f485e6d809b3a70744', + result: { + encryptedResult: + 'e+PS/RjVcXP1fTOzJZQXsaaW/FsDS1cxwjm0/xXwjXHqB4rjc4njsOp4np+qOHCBpLAEqzo181B1/gNRLyFJ2wJwoBpDHJi0d4As4sB4UmCh7SEdHnrMIrbxACewO06xesDYlmKwNKXuGjTAOnYhNyIRcy+FoK9dVOpnpEzK7H344tmZ5lsHN+x9zOH64+L50cek7lPfeNgJQX4xuApqL1le4CgEjH9xFbNVwfN7RkFWt0wW+CiTfH2PqOXk67yHdket1DPmtczMpTb7Kafk0DWfWARxAYgteiem3sKQ7lRrk5A5+CTyxN0DoehSIjDPVaaEc88f18sfqVPvAedkmpkM9NpA8UClSDCIMtoy6byuoapmhdsLPvW6zfF6KH/M34iHcH6RaPSI1EY/oSZLo7mgDfITJH/rDkiriO/sLaIKAtc7vAiE1s0N8BYNd2mzoL+liq0chmFxoyycc8mu2jZuTC8jnOXJIemDQKRk1WGklIfth0ccI1jbU73dxaypNCBFk+E6PkTQaPM7Ml3zBjCJc0Cht0Sa9o3/GajmOfmGVAmp2qvZJvLAlMpn8JdlulpZ0bBLpF04aQw3RVIyuwdBRRR7TkBhvx2TJekVVaON/qUyZw4Th9N4j9XgTSuusPXihhwPcgAJ1d84zZlRMC2Qy5gy6dS5936xN6iiOvtYkvF543Fxtg0Nmdp+dSpuLqzDM0FlJ962CmRdnjf1w/3V599b5Ti5wAFMkE2HjXTN/gSxsnhms4nbmhUGEfgbbk7uAt2l6S1xWljVmD+WA8Y5CJR6h4Na9umZExdCvMfsE3Em/PF6U2NP60D1zzF79FyUEVIN/ZDTj2xn+ekuE3N7i7JlEFF1Qr7+g0r2hlfd5oG6jKHrAJQslS7vpQNsXLGVyL0l0COy8J1gGylJu0875EvIwkYoL51f3GZzp1P2H6e/NyJi5U6cqxGYogViLqaXz3Z+cP9FaPP1/01RpDD4WyIItFXr9qMzgUTCHVbcPXBzeIPVO+XFImdY2u17JRqwdtQ3Est3Pg9SALqBe1Njki3+dhYBdAV7l7GWj8M+7GQnVNEj7GGoEpkCLD8jdqXIcf5iRHrExknTrOzc+9di0lr/VAzflJkIsoP1h/YMVEw7xnulIs/lrs/cvs6Cj4PPUkHpzL+Os034hqrogFHVtXg004fMHBbnHEVNqr02lFd6lOxqHOodpP8/VmI7rbGnHt5Jv26n6MCBUZDOkPh/GxAutivkc3uNPzeFQidWue9UgCb4HW+AVTdcU8yL0EkpnI0T33UQ63NcCaoq3MPDbEe47tBQlNfxgQPdHt+oeJn07CRjnQqZWXKySxR0/1oSdj5NLAfyuja3hWjF5KDyq2ZwolShSTcd4MMTwbZlwSDFSr+viLqYj4WHZWTEWOpI/oAs6Ix2mpJ5WRo9m5PjwhdfVFE9O/d5+SYGlzE4EERLgxiY4LkkiZwybJXnWFktOvK8YEIQ7cI4PIW9KIMrUpHO/KAk2LfUYveWNnf62GQle5+64saU2sOttAD0G0tBd1S812XYYqzWGiD4KSBiaoC0fEy+VManGSSvEk9xYoiXa9HknKvr36PGMTJ4Cl1bDM4Xn9/YOpgI85COPrOy7KZQEp61TA4ubPQVAohE7vN2aAYd21UbDM144ceERQo6NdrLMK6d2B7Gd/u17dAk4rjVMPxQlDb+6P83LVco14y7ycaqFOhlfJa2a2SeXxkw3Ol+9TATcoaXTucaMY5eEMmsjU5URTUfsFn5FJzF16dix/8qb3GZUTIt+yy25aJ36dFuZifzNvqWsPtmDCTvj2npxZlxS2ukVm/MJV64Q9BXxjvm8ryiNJu6/cIIlOXT0hwmH+YkzL0t7EJOEWTGG3rV+0iJYdhRXAb8Bq9nvOH5KaE4pwbG13HIbYjYSIoMq3cdh61v1WvVJA5euW232DEj9z/Qtui81RyjDFdvJg+/XsqJ6LfPNS3uf1GW9BVzUT87z3H25gke6oJM3e3FWbtvj1MXy61IJud6oiScD4+9ONX72yriz2LwNf7Lce6r9pkhnLsBOxr6fAbEt21g9vuxVpIwyBeanjR1aEvZLddJ3OcZOuNQZMmPildZd47rl260Tl2YvQcYIzA6rAJC8GD3orBJyjVh/WaeCc0IeJsqA0GU8Leb7itXoHiOhAFJELgj8fM10Rcw+3oylp2PFATU0KeHelHW+hz5EwOx8blYzjyh5hEMGptq+qxb1hVPHHs9OGSXZOnCU1ZyBpuNlh71J5lMoE762rde15BQbJsrLQ7EI7af3J1DjSbAVLbTtVOYweZujOUr7MvsThqbO9nmxp69qIKjqh4NWV1zNcpyE6PovI0G2+2s2EofYkcvDtkCQPuzod0ddG90B1caY1vvUN4Bl5PkL1kG8GD0Dtgb81HYOKtV52YSGO5Q73qojiFijgxsOkyj7PbtGCF2O9RFwrQVqB1pGLdoCfPcFSp3SyCqIpFbfaOCQs1Asdi7Aosn37hgj/UlbYPeDFj4Ezol2Vh0dyONc5DxaPdDuu5SsyAdx+AFhPWRQ3y6MAFfSf2vQnM7QCqSmtwy1+aNVqJ9UiT4lpSro18GjOiDoxUJBXXyoJLU5t2JvKc7R5va5Nv9kat3WjmgsTSk0vd2jPokc49uownlCVbSWXGyJ5muMfRqIVlUvx8QnOthSWSGOeBQw17RMvJ5Cu5Xdis2ztdWveZp5HN/d5FqGiUktNdw8KL2TCpPuRBliRSeUXyR4mDae3WeS205My8NoLxMCmC6z1WmktYPsu2/8z6XQ11Qv53b/XXNDL0T7rfuc8KPWaQjQgxZQDj0NWcfvyYK8zr5xSUc7mLhj04Qj6bIqzzotBIDdbkWpJwxybxx4MnMS4h59PD8FR4rACb3Jqj7ba8YeZxtEQ5FHMwlAcIw+CXQBfhhbEqOAyTsytKthtYOT3kPdSb/Runm4oitnMdEca1WDPPSmyaDibJBDL/u4m3g/OnHKw+IseIgEBz/ttPXN7hc5cSj2xkgIZbpTLVTymXAkR/6QGuNpoiFnxV3ljpMDIj3WbFrB5vM2KPiOJInKT/wxt+UQe9v9oj7h7KitUdhS8R6wTu1t+wFTPkD03Tessnvo6L6/rqN0F2FwKwiXLypXIQsltQenSMTm2c32AHZuMB3tEfEEIEx4eVjB2B9vyGyfDFiX0N40YFWiz0mQjIMzEqRw6PsS1Zfs81qjKIIL+XBJ4fCetFJoXAMNpkW2iQhIsWkBSJfZ34cuMhAMj8t+nruhGMkG4GC7RtDhCkiTQsa+Rjac2pK39GESE5YzNuJpR2CJHIoT6pLzTA6RRuy77aNSx2zjROZlUe+SOCH1qKIZy1p7CYQNKBzjrhlOBcdxBK5w7Cw3bACvz/aaXbnStInce2HvOBPsFK0mGBPYlVduh6RRz+NN9A5wY65AmZ2cjIUIP24fSQHQs9eStJRimrZ7McfAlm+KRi1uk1dFMAaxbX3ors510hWHuP0PV4Ax7KcLH9eAE+aZp2JNh4LMVHQ7zsjGElxTcFxa7eEIlZtq0ZURT4qRnlXKiJ/VcM4BsgcgzHUzGsmlA26mmHgLqkdzT1Na8jVjXlgCSphHfgfRfmnqFl2u+1bKCk0hwDyPh3B5+6m+QIALCJoEw8I5rE6XAp7xHNzyE2G1T6MITT3dSl2S0ljDfKk/deLIaWzv2yztGvwaCd/fqkXt9YD+7+xEyXVoC53G3i+mHLihKfh14bfFxVvthNF/hbox9XbO1jvxf5gS5Ua5TvpvKse30bzhNDBMyjpa7Fmz5XNpgrDULcqc4+MrpiptoCtAJIFrIs7sEAnsbJT8ZCzADQbQm18xfJyEKbZZ7nOJlbKGwT7ci+T1hhHLvuWcJhMWiC0Xi1UcVG1HdwI4KOpTgzi0B09EVqcedGKwRR68f2KADZ53IAsFJnfbCFW/TtaV0bdH/f3pQaORUqU6jlDsO3GbOSy69nL4/UddShl2K8Ljb/ouBFbvI+caTeiJygyPtXyDqWAjA6RsdVzpVyeIU21m9yCoB7jA3tgRdDlff4lT5piWmIXK/fJ6/0uDxUWrWFmj/ZhdXIY9B3zwr8K0eAcQ/aZsWu1poQAOex5dZOrg3AS818TWMUyN7A=', + iv: '883c926ef17a4c97845c6cad65a030e9' + } + }; + } + }; + }); + + jest.spyOn(utils, 'deserializeMessage').mockReturnValue({ + endpoint: '', + contractAddress: '2UKQnHcQvhBT6X6ULtfnuh3b9PVRvVMEroHHkcK4YfcoH1Z1x2', + contractMethod: 'Test', + arguments: [ + { + name: 'params', + value: 'a2a00f8583c08daa00b80b0bbac4684396fe966b683ea956a63bd8845eee6ae7' + } + ], + timestamp: 1718849031 + }); + jest.spyOn(utils, 'checkTimestamp').mockReturnValue(true); + + const data = { + action: 'invokeRead', + params: { + encryptedParams: + 'lqmIluuPMyQw/2/LXMEnKYfxp5KsQvwPpAEPCvsUc6Cf0X1K7d1CcCKv+h6W35vV6+d3sOSZLyeX0SIM7375wKsu14A+tO1OiaJ9DdKyJ6LJo+Mj+aA2Qp0N8zaXQmoTZPsKg/VYI3+YFXQU0tkPUCb+/YkPs/aE5T2KItU9WI3hVN6Xkd0vK2dShaTwhngVeXlcXeymcH/C0CevesDY+opYOHfqY/jP0LqDeXjXUP06LKGx+uMObJJvupslRI2HTbfwJWNYbsM3LY6VCbnA4tKnsfdxZZ3PvIoD6LRaMoIGjbsaTKl0hyZ38TPh+15r+OcoJjWka0TYpTFk93pTKnyGnkClGikWu4VNNe9CKKTSksjc5SNsBNNimxd/L4LLw2/yPIG3ZsaQ0AliaWOhO9SuvPKZnWBPdX/I4sPLkX1UZ5p0adUzQfXjnom2vCg/LeN8TcThw/+LlGAct0c4uQ==', + iv: 'da4512e2c1ed4f819d86fb3816b55aca' + }, + appId: '8a430b69-31df-5ea9-8a55-695faf0623d9', + id: '98c8b690fbbe43ca9f6fd1f72c18f2db' + }; + clientSocket.emit('bridge', data); + }, 20000); +}); diff --git a/test/constants.js b/test/constants.js new file mode 100644 index 0000000..f538560 --- /dev/null +++ b/test/constants.js @@ -0,0 +1,6 @@ +import path from 'path'; + +export const endpoint = 'https://tdvw-test-node.aelf.io/'; +export const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; +export const password = '1234*Qwer'; +export const dataDir = path.resolve(__dirname, './datadir/aelf'); diff --git a/yarn.lock b/yarn.lock index 9aec3fc..86388a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3343,6 +3343,17 @@ emoji-regex@^9.2.2: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +engine.io-client@~6.5.2: + version "6.5.3" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz#4cf6fa24845029b238f83c628916d9149c399bc5" + integrity sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.11.0" + xmlhttprequest-ssl "~2.0.0" + engine.io-parser@~5.2.1: version "5.2.2" resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz#37b48e2d23116919a3453738c5720455e64e1c49" @@ -6765,6 +6776,16 @@ socket.io-adapter@~2.5.2: debug "~4.3.4" ws "~8.11.0" +socket.io-client@^4.7.5: + version "4.7.5" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" + integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.5.2" + socket.io-parser "~4.2.4" + socket.io-parser@~4.2.4: version "4.2.4" resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" @@ -7536,6 +7557,11 @@ xdg-basedir@^5.0.1, xdg-basedir@^5.1.0: resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + xmlhttprequest@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" From f4de27baa7c08e9ac92a59a23a0010c73c428301 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Mon, 24 Jun 2024 10:02:36 +0800 Subject: [PATCH 13/24] feat: dappServer test --- test/command/dappServer/HKDF.test.js | 29 ++++++++++ test/command/dappServer/encrypt.test.js | 65 +++++++++++++++++++++ test/command/dappServer/sign.test.js | 48 ++++++++++++++++ test/command/dappServer/utils.test.js | 76 +++++++++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 test/command/dappServer/HKDF.test.js create mode 100644 test/command/dappServer/encrypt.test.js create mode 100644 test/command/dappServer/sign.test.js create mode 100644 test/command/dappServer/utils.test.js diff --git a/test/command/dappServer/HKDF.test.js b/test/command/dappServer/HKDF.test.js new file mode 100644 index 0000000..a993c6c --- /dev/null +++ b/test/command/dappServer/HKDF.test.js @@ -0,0 +1,29 @@ +import HKDF from '../../../src/command/dappServer/HKDF'; + +describe('HKDF', () => { + const hash = 'sha256'; + const random = '52695e07c0c545e8a279a71b1f47b9b7'; + const salt = Buffer.from(random, 'hex'); + console.log(salt, 'salt'); + const initialKey = '667a8937f4da939b93e716211e83f787741be3fe0c938bea9e333d37c779b5'; + afterEach(() => { + jest.clearAllMocks(); + }); + test('should initialize with correct values', () => { + const hkdf = new HKDF(hash, salt, initialKey); + expect(hkdf.hashMethod).toBe(hash); + expect(hkdf.hashLength).toBe(32); + expect(hkdf.salt).toBe(salt); + expect(hkdf.initialKey).toBe(initialKey); + console.log(hkdf.prk, 'hkdf.prk'); + expect(hkdf.prk.toString('hex')).toEqual('6269eb093d3ed47cd698158c8f404b6380cd3222f3889323ea7814ea341456f2'); + }); + test('should throw an error for unsupported hash method', () => { + expect(() => new HKDF('sha1', Buffer.from('salt'), 'initialKey')).toThrow('not supported hash method'); + }); + test('should expand correctly', () => { + const hkdf = new HKDF(hash, salt, initialKey); + const result = hkdf.expand(); + expect(result.toString('hex')).toBe('50649277a8ec2090de2c15af4aab197a7baa3c09accb755d3fafa829c370ba62'); + }); +}); diff --git a/test/command/dappServer/encrypt.test.js b/test/command/dappServer/encrypt.test.js new file mode 100644 index 0000000..663ff92 --- /dev/null +++ b/test/command/dappServer/encrypt.test.js @@ -0,0 +1,65 @@ +/* eslint-disable max-len */ +import elliptic from 'elliptic'; +import Encrypt from '../../../src/command/dappServer/encrypt'; +import { randomId } from '../../../src/utils/utils.js'; + +jest.mock('../../../src/utils/utils.js', () => { + return { + randomId: () => '1ef39a09ce4f415da335dcb408989116' + }; +}); + +describe('Encrypt', () => { + const algorithm = 'curve25519'; + const remotePublicKey = '75d5e81323eecc4e887ef0934a52d8de1a2785ca04f4a4e9a39359c4bfd8cc9d'; + const random = 'e44ab14618724a80be03f4565e7ed668'; + const ecInstance = new Encrypt(algorithm, remotePublicKey, random); + const data = + 'JTdCJTIyY29kZSUyMiUzQTAlMkMlMjJtc2clMjIlM0ElMjJzdWNjZXNzJTIyJTJDJTIyZXJyb3IlMjIlM0ElNUIlNUQlMkMlMjJkYXRhJTIyJTNBJTdCJTIyYWNjb3VudHMlMjIlM0ElNUIlN0IlMjJuYW1lJTIyJTNBJTIyYWVsZi1jb21tYW5kJTIyJTJDJTIyYWRkcmVzcyUyMiUzQSUyMkd5UVg2dDE4a3B3YUQ5WEhYZTFUb0t4Zm92OG1TZVRMRTlxOU53VUFlVEU4dFVMWmslMjIlMkMlMjJwdWJsaWNLZXklMjIlM0ElMjIwNDcwM2JiZTk1ZTk4NmM5ZDkwMWYyOGVkZDYwOTc1YTdhNmMzYjJkY2U0MWRmZWMyZTc5ODNkMjkzYzYwMGU4MjQ5NjQyYTNkYTM3OWM0MTk0YTZkNjJiZDg5YWZlNjc1M2U4MWFjZmMyYjZiYmYzYjQwNzM2ZWUwOTQ5MTAyMDcxJTIyJTdEJTVEJTJDJTIyY2hhaW5zJTIyJTNBJTVCJTdCJTIydXJsJTIyJTNBJTIyaHR0cHMlM0ElMkYlMkZ0ZHZ3LXRlc3Qtbm9kZS5hZWxmLmlvJTJGJTIyJTJDJTIyaXNNYWluQ2hhaW4lMjIlM0F0cnVlJTJDJTIyY2hhaW5JZCUyMiUzQSUyMkFFTEYlMjIlN0QlNUQlN0QlN0Q='; + const encrypted = + 'U5E3LMWOVAintuE4zJf+8O4XSHgAtZTeQX831sc53r9yZJGnh6fiwNR3tF8zCORnwtVUaYh+pnzPgxeQz8b1tKEUhc/VYoy2dtqMubMDq+WUeF5tFnFhv6kuhHkMSDYQnpwOpwSvzJ4kWr+cxdHGOg+qoWe1nPujQlc/gQ/7Z4MeEHWXDagtKXzKGfE/rYJhnlAN+K1xHhq//tS4g4izEuHe2J2RK5xYa91e5p1qzLTEQyqax2q1pyYFPbaRyrP/6yAlUPOkdyuIGdMXwEp7BdfPXF3xPemaj6w+WgOkmAUcKk35blQvNLuJAWux6ZhLl+P+w6sfinT3Mk1ymrz2SEdThjB/LEPbbBlx+in80y0S8bSgUpsXbW1mfMPX3svDks0cK3Thjf/o+sGed5Ej4cFMFbgeCI4JdDnKeG7RWPWN9lL77kzPq0q60zXr/70jyRElktzSWzGfcOEr+TQiEx3MfiRHgAoqz5glc/ml7VlUP9ouLvRQfmrWcYIsbkf9WnBac/G68rSGOEqR/qbugsQCclO+V6yJt3o4NL94Nbn8V/+gQo430zdefkljGum84c0e2vVYxXyRbrFIAROJeO4IRiVWAaLrnFc0h/Shtt8EupaWGYJps+aYODUpfulJjDm6pZoDE+bp5h02XV0C/akhIUclLveNJc14qYc7tGpSRBDNXC/z6PfZgPlV3OL+'; + const iv = '1ef39a09ce4f415da335dcb408989116'; + afterEach(() => { + jest.clearAllMocks(); + }); + test('should initialize correctly', () => { + expect(ecInstance).toHaveProperty('keyPair'); + expect(ecInstance).toHaveProperty('cipher'); + expect(ecInstance).toHaveProperty('remoteKeyPair'); + expect(ecInstance).toHaveProperty('sharedKey'); + expect(ecInstance).toHaveProperty('derivedKey'); + }); + + test('should ecInstance data correctly', () => { + // mock + ecInstance.sharedKey = Buffer.from('7f8e6db3591d76846d8b6ffefe5e0a19f85feee2cb5d41131dac2b9a668b41ca', 'hex'); + ecInstance.derivedKey = Buffer.from('0369788fa050c720131722efb25281f444857db4b833ea89ede08a8fdf6117c0', 'hex'); + const result = ecInstance.encrypt(data); + expect(result).toEqual({ + encryptedResult: encrypted, + iv + }); + }); + test('should decrypt data correctly', () => { + const decrypt = ecInstance.decrypt(encrypted, iv); + expect(decrypt).toBe(data); + }); + test('should return correct public key', () => { + const result = ecInstance.getPublicKey(); + expect(result.length).toBe(64); + }); + + test(`should initialize with not default algorithm`, () => { + // another algorithm + const ecInstanceNotDefault = new Encrypt( + 'secp256k1', + '04695fb2e8ce837d5b9e79df046dd1947a558b884165c8f83a9e9b01e47a37135fc4ff42256e4a79f25f740a840b58f47f79a3bf934857c7397e545163cddf663e', + 'beae60451b554891bb8967d0c2bdaa4e' + ); + expect(ecInstance).toHaveProperty('keyPair'); + expect(ecInstance).toHaveProperty('cipher'); + expect(ecInstance).toHaveProperty('remoteKeyPair'); + expect(ecInstance).toHaveProperty('sharedKey'); + expect(ecInstance).toHaveProperty('derivedKey'); + }); +}); diff --git a/test/command/dappServer/sign.test.js b/test/command/dappServer/sign.test.js new file mode 100644 index 0000000..668a34c --- /dev/null +++ b/test/command/dappServer/sign.test.js @@ -0,0 +1,48 @@ +/* eslint-disable max-len */ +import elliptic from 'elliptic'; +import Sign from '../../../src/command/dappServer/sign'; + +describe('Sign', () => { + const algorithm = 'secp256k1'; + const remotePublicKey = + '04a6eba849ac6cbd7f61df41fee59f46540b3d969da6f859d6ccbac9cdc9af94e10045b52074ba4c154dd3cc395c45b757e3e515740d67fc5e7b6215ec7cd281fb'; + const msg = Buffer.from('31373138393634323633', 'hex'); + const signature = + 'b8b201b3599ea04b196c836697d6fa42a5841cf42a6b4a22394022afed0fd41274f25b0f5520efbcc98834640abf7f83508a3a8904e992a8324ad8cc59ff3da200'; + const signInstance = new Sign(algorithm, remotePublicKey); + afterEach(() => { + jest.clearAllMocks(); + }); + test('should initialize correctly', () => { + expect(signInstance).toHaveProperty('keyPair'); + expect(signInstance).toHaveProperty('remoteKeyPair'); + }); + + test('should verify data correctly', () => { + const result = Sign.verify(algorithm, remotePublicKey, msg, signature); + expect(result).toEqual(true); + }); + test('should sign msg correctly', () => { + const data = Buffer.from('4811b3d9e39b4214af728436159f7387', 'hex'); + const result = signInstance.sign(data); + expect(result.length).toBe(130); + }); + test('should verify msg in fixed algorithm and publicKey', () => { + const msg = Buffer.from('25374225323274696d657374616d7025323225334131373138393635333132253744', 'hex'); + const signature = + '8904880db5ecb7bc4b5b09046cb359dbc78c9cf507f5445244b24bdcec7def1599393bf98ad27178c6052a6e2b95d4393dceac7420e776544797f5e2f74d7ac800'; + const result = signInstance.verify(msg, signature); + expect(result).toBe(true); + }); + test('should return correct public key', () => { + const result = signInstance.getPublicKey(); + expect(result.length).toBe(130); + }); + + test(`should initialize with not default algorithm`, () => { + // another algorithm + const signInstanceNotDefault = new Sign('curve25519', '75d5e81323eecc4e887ef0934a52d8de1a2785ca04f4a4e9a39359c4bfd8cc9d'); + expect(signInstance).toHaveProperty('keyPair'); + expect(signInstance).toHaveProperty('remoteKeyPair'); + }); +}); diff --git a/test/command/dappServer/utils.test.js b/test/command/dappServer/utils.test.js new file mode 100644 index 0000000..ab6d95f --- /dev/null +++ b/test/command/dappServer/utils.test.js @@ -0,0 +1,76 @@ +import { serializeMessage, deserializeMessage, checkTimestamp } from '../../../src/command/dappServer/utils'; + +describe('Utils module', () => { + describe('serializeMessage', () => { + test('should serialize a valid JSON object', () => { + const data = { key: 'value' }; + const serialized = serializeMessage(data); + const expected = Buffer.from(encodeURIComponent(JSON.stringify(data))).toString('base64'); + expect(serialized).toBe(expected); + }); + + test('should return an empty string for null input', () => { + const serialized = serializeMessage(null); + expect(serialized).toBe(''); + }); + + test('should return an empty string for undefined input', () => { + const serialized = serializeMessage(undefined); + expect(serialized).toBe(''); + }); + + test('should serialize an empty object', () => { + const data = {}; + const serialized = serializeMessage(data); + const expected = Buffer.from(encodeURIComponent(JSON.stringify(data))).toString('base64'); + expect(serialized).toBe(expected); + }); + }); + + describe('deserializeMessage', () => { + test('should deserialize a valid base64-encoded string', () => { + const data = { key: 'value' }; + const serialized = Buffer.from(encodeURIComponent(JSON.stringify(data))).toString('base64'); + const deserialized = deserializeMessage(serialized); + expect(deserialized).toEqual(data); + }); + + test('should return an empty object for an invalid JSON string', () => { + const invalidSerialized = Buffer.from('invalid json').toString('base64'); + const deserialized = deserializeMessage(invalidSerialized); + expect(deserialized).toBe('invalid json'); + }); + + test('should return an empty string for an empty input string', () => { + const deserialized = deserializeMessage(''); + expect(deserialized).toBe(''); + }); + }); + + describe('checkTimestamp', () => { + test('should return true for a valid timestamp within the buffer', () => { + const time = Math.ceil(new Date().getTime() / 1000); + const isValid = checkTimestamp(time); + expect(isValid).toBe(true); + }); + + test('should return false for a timestamp outside the buffer', () => { + // 5 minutes ago + const time = Math.ceil(new Date().getTime() / 1000) - 5 * 60; + const isValid = checkTimestamp(time, 4 * 60); + expect(isValid).toBe(false); + }); + + test('should return false for an invalid timestamp', () => { + const isValid = checkTimestamp('invalid timestamp'); + expect(isValid).toBe(false); + }); + + test('should return false for a future timestamp', () => { + // 1 minute in the future + const time = Math.ceil(new Date().getTime() / 1000) + 60; + const isValid = checkTimestamp(time); + expect(isValid).toBe(false); + }); + }); +}); From 8a2913a40cb222e66256f43e0965ff99c780555b Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Tue, 25 Jun 2024 22:54:23 +0800 Subject: [PATCH 14/24] feat: utils test --- jest.config.js | 12 +- src/utils/utils.js | 3 +- test/dataDir/aelf/.aelfrc | 5 + test/rc/index.test.js | 79 +++++++ test/utils/Logger.test.js | 52 +++++ test/utils/fs.test.js | 51 +++++ test/utils/userHomeDir.test.js | 111 ++++++++++ test/utils/utils.test.js | 391 +++++++++++++++++++++++++++++++++ test/utils/wallet.test.js | 81 +++++++ 9 files changed, 778 insertions(+), 7 deletions(-) create mode 100644 test/dataDir/aelf/.aelfrc create mode 100644 test/rc/index.test.js create mode 100644 test/utils/Logger.test.js create mode 100644 test/utils/fs.test.js create mode 100644 test/utils/userHomeDir.test.js create mode 100644 test/utils/utils.test.js create mode 100644 test/utils/wallet.test.js diff --git a/jest.config.js b/jest.config.js index 27a2b24..ddc6320 100644 --- a/jest.config.js +++ b/jest.config.js @@ -143,10 +143,12 @@ export default { // testLocationInResults: false, // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], + testMatch: [ + '**/test/command/dappServer/socket-sign.test.js', + '**/test/**/*.[jt]s?(x)' + // "**/?(*.)+(spec|test).[tj]s?(x)" + ], + testTimeout: 5000, // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped // testPathIgnorePatterns: [ @@ -176,7 +178,7 @@ export default { // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation transformIgnorePatterns: [ // "/node_modules/(?!chalk|update-notifier|configstore|xdg-basedir|unique-string|crypto-random-string|semver-diff|latest-version|package-json|got|@sindresorhus|p-cancelable|@szmarczak/http-timer|cacheable-request|normalize-url|responselike|lowercase-keys|mimic-response|form-data-encoder)" - ], + ] // 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, diff --git a/src/utils/utils.js b/src/utils/utils.js index c6eebdb..028c76d 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -289,7 +289,6 @@ async function getParams(method) { } catch (e) {} let paramValue; // todo: use recursion - if ( rule !== 'repeated' && innerType && @@ -366,7 +365,7 @@ async function deserializeLogs(aelf, logs = []) { let results = await Promise.all(logs.map(v => getProto(aelf, v.Address))); results = results.map((proto, index) => { const { Name, NonIndexed, Indexed = [] } = logs[index]; - const serializedData = [...(Indexed || [])]; + const serializedData = [...Indexed]; if (NonIndexed) { serializedData.push(NonIndexed); } diff --git a/test/dataDir/aelf/.aelfrc b/test/dataDir/aelf/.aelfrc new file mode 100644 index 0000000..0706a85 --- /dev/null +++ b/test/dataDir/aelf/.aelfrc @@ -0,0 +1,5 @@ +# THIS IS AN AUTOGENERATED FILE FOR AELF-COMMAND OPTIONS. DO NOT EDIT THIS FILE DIRECTLY. + + + +endpoint https://tdvw-test-node.aelf.io/ diff --git a/test/rc/index.test.js b/test/rc/index.test.js new file mode 100644 index 0000000..c851f14 --- /dev/null +++ b/test/rc/index.test.js @@ -0,0 +1,79 @@ +import fs from 'fs'; +import path from 'path'; +import Registry from '../../src/rc/index'; +import { userHomeDir } from '../../src/utils/userHomeDir'; +import { endpoint, account, password, dataDir } from '../constants.js'; + +jest.mock('../../src/utils/userHomeDir', () => { + const path = require('path'); + return { + userHomeDir: path.resolve(__dirname) + }; +}); + +describe('Registry', () => { + afterEach(() => { + jest.clearAllMocks(); + delete process.env.AELF_CLI_ENDPOINT; + }); + afterAll(() => { + fs.unlinkSync(path.resolve(userHomeDir, 'aelf/.aelfrc')); + fs.rmdirSync(path.resolve(userHomeDir, 'aelf')); + }); + test('should get file or not', () => { + const result = Registry.getFileOrNot(path.resolve(__dirname, '../datadir/aelf/.aelfrc')); + expect(result).toBe(`# THIS IS AN AUTOGENERATED FILE FOR AELF-COMMAND OPTIONS. DO NOT EDIT THIS FILE DIRECTLY. + + + +endpoint https://tdvw-test-node.aelf.io/ +`); + }); + test('should load config', () => { + const result = Registry.loadConfig(); + expect(result).toEqual({}); + }); + test('should get config from env', () => { + // mock + process.env.AELF_CLI_ENDPOINT = 'http://localhost:1234'; + const result = Registry.getConfigFromEnv(); + expect(result).toEqual({ endpoint: 'http://localhost:1234' }); + }); + test('should stringify', () => { + const result = Registry.stringify(); + expect(result).toEqual([ + '# THIS IS AN AUTOGENERATED FILE FOR AELF-COMMAND OPTIONS. DO NOT EDIT THIS FILE DIRECTLY.', + '', + '', + '' + ]); + }); + test('should get and set options correctly', () => { + const registry = new Registry(); + registry.setOption('endpoint', endpoint); + expect(registry.getOption('endpoint')).toBe(endpoint); + }); + test('should save options to file', () => { + const registry = new Registry(); + registry.saveOption('endpoint', endpoint); + expect(fs.readFileSync(registry.globalConfigLoc).toString()).toContain(`endpoint ${endpoint}`); + }); + test('should delete config key from file', () => { + const registry = new Registry(); + registry.saveOption('endpoint', endpoint); + registry.deleteConfig('endpoint'); + expect(fs.readFileSync(registry.globalConfigLoc).toString()).not.toContain(`endpoint ${endpoint}`); + }); + test('should get file configs correctly', () => { + const registry = new Registry(); + registry.saveOption('endpoint', endpoint); + const fileConfigs = registry.getFileConfigs(); + expect(fileConfigs.endpoint).toBe(endpoint); + }); + test('should get configs correctly', () => { + const registry = new Registry(); + registry.saveOption('endpoint', endpoint); + const configs = registry.getConfigs(); + expect(configs.endpoint).toBe(endpoint); + }); +}); diff --git a/test/utils/Logger.test.js b/test/utils/Logger.test.js new file mode 100644 index 0000000..dcba056 --- /dev/null +++ b/test/utils/Logger.test.js @@ -0,0 +1,52 @@ +import chalk from 'chalk'; +import Logger from '../../src/utils/Logger'; + +describe('Logger', () => { + let consoleLogSpy; + const fnName = 'trace', + level = 'Trace'; + beforeEach(() => { + consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); + }); + + afterEach(() => { + consoleLogSpy.mockRestore(); + }); + + test(`should log correctly formatted message`, () => { + const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); + const message = 'Test message'; + logger[fnName](message); + const expectedPrefix = `[${level}]: `; + const expectedLog = chalk.gray(`TestLogger ${expectedPrefix}${message}`); + // second params: add spaces + expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, ''); + }); + test(`should return correctly formatted chalk message`, () => { + const logger = new Logger({ log: false, onlyWords: false, name: 'TestLogger' }); + const message = 'Test message'; + const result = logger[fnName](message); + const expectedPrefix = `TestLogger [${level}]: `; + const expectedChalk = chalk(chalk.gray(`${expectedPrefix}${message}`)); + expect(result.trim()).toEqual(expectedChalk); + }); + test(`should log correctly formatted object message`, () => { + const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); + const message = { key: 'value' }; + logger[fnName](message); + const expectedPrefix = `TestLogger [${level}]: \n`; + const expectedLog = chalk.gray(`${expectedPrefix}`).trim(); + expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, message); + }); + test(`should log correctly formatted object message (onlyWords: true)`, () => { + const logger = new Logger({ onlyWords: true, name: 'TestLogger' }); + logger.symbol = '*'; + const message = { key: 'value' }; + logger[fnName](message); + + const expectedPrefix = `* [${level}]: \n`; + const expectedLog = chalk.gray(`${expectedPrefix}`).trim(); + + expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, message); + }); +}); diff --git a/test/utils/fs.test.js b/test/utils/fs.test.js new file mode 100644 index 0000000..0851867 --- /dev/null +++ b/test/utils/fs.test.js @@ -0,0 +1,51 @@ +import fs from 'fs'; +import os from 'os'; +import { writeFilePreservingEol } from '../../src/utils/fs.js'; +import { promisify } from '../../src/utils/utils'; + +jest.mock('fs'); +jest.mock('../../src/utils/utils', () => { + return { + promisify: fn => fn + }; +}); + +describe('File System Operators', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('writeFilePreservingEol', () => { + // cannot test /r/n because it depends on Windows + test('should write data with preserved EOL', async () => { + const path = '/path/to/existing/file.txt'; + const existingData = 'Line 1\nLine 2\nLine 3\n'; + const newData = 'New Line 1\nNew Line 2\nNew Line 3\n'; + const expectedData = 'New Line 1\nNew Line 2\nNew Line 3\n'; + + const mockBuffer = Buffer.from(existingData, 'utf-8'); + fs.existsSync.mockReturnValue(true); + fs.readFile.mockReturnValue(mockBuffer); + + let writtenData = ''; + fs.writeFile.mockImplementation((filePath, data) => { + writtenData = data.toString(); + }); + + await writeFilePreservingEol(path, newData); + expect(writtenData).toBe(expectedData); + }); + + test('should write data with default EOL if file does not exist', async () => { + const path = '/path/to/nonexistent/file.txt'; + const newData = 'Line 1\nLine 2\nLine 3\n'; + fs.existsSync.mockReturnValue(false); + let writtenData = ''; + fs.writeFile.mockImplementation((filePath, data) => { + writtenData = data.toString(); + }); + await writeFilePreservingEol(path, newData); + expect(writtenData).toBe(newData); + }); + }); +}); diff --git a/test/utils/userHomeDir.test.js b/test/utils/userHomeDir.test.js new file mode 100644 index 0000000..0fda4ac --- /dev/null +++ b/test/utils/userHomeDir.test.js @@ -0,0 +1,111 @@ +import path from 'path'; +import { homedir } from 'os'; +import { userHomeDir, home, isFakeRoot, isRootUser, ROOT_USER } from '../../src/utils/userHomeDir'; + +jest.mock('os', () => ({ + homedir: jest.fn(() => { + const mockHomeDir = '/mock/home'; + return mockHomeDir; + }) +})); +describe('userHomeDir', () => { + let originalPlatform; + let originalEnv; + const mockHomeDir = '/mock/home'; + beforeAll(() => { + originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform'); + originalEnv = { ...process.env }; + }); + + afterAll(() => { + Object.defineProperty(process, 'platform', originalPlatform); + process.env = originalEnv; + }); + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + }); + + test('home should be the user home directory', () => { + expect(home).toBe(mockHomeDir); + }); + + test('isFakeRoot should return true if FAKEROOTKEY is set', () => { + process.env.FAKEROOTKEY = 'true'; + expect(isFakeRoot()).toBe(true); + }); + + test('isFakeRoot should return false if FAKEROOTKEY is not set', () => { + delete process.env.FAKEROOTKEY; + expect(isFakeRoot()).toBe(false); + }); + + test('isRootUser should return true if uid is 0', () => { + expect(isRootUser(0)).toBe(true); + }); + + test('isRootUser should return false if uid is not 0', () => { + expect(isRootUser(1000)).toBe(false); + }); + + test('isWindows should return true if platform is win32', () => { + Object.defineProperty(process, 'platform', { + value: 'win32' + }); + expect(process.platform).toBe('win32'); + }); + + test('isWindows should return false if platform is not win32', () => { + Object.defineProperty(process, 'platform', { + value: 'linux' + }); + expect(process.platform).toBe('linux'); + }); + + test('userHomeDir should be correct for Windows platform', () => { + Object.defineProperty(process, 'platform', { + value: 'win32' + }); + + jest.resetModules(); + const { userHomeDir } = require('../../src/utils/userHomeDir'); + expect(userHomeDir).toBe(path.resolve(mockHomeDir, './AppData/Local')); + }); + + test('userHomeDir should be correct for non-Windows platform', () => { + Object.defineProperty(process, 'platform', { + value: 'linux' + }); + + jest.resetModules(); + const { userHomeDir } = require('../../src/utils/userHomeDir'); + expect(userHomeDir).toBe(path.resolve(mockHomeDir, './.local/share')); + }); + + test('ROOT_USER should be true if user is root and not fake root', () => { + jest.spyOn(process, 'getuid').mockReturnValue(0); + delete process.env.FAKEROOTKEY; + + jest.resetModules(); + const { ROOT_USER } = require('../../src/utils/userHomeDir'); + expect(ROOT_USER).toBe(true); + }); + + test('ROOT_USER should be false if user is not root', () => { + jest.spyOn(process, 'getuid').mockReturnValue(1000); + + jest.resetModules(); + const { ROOT_USER } = require('../../src/utils/userHomeDir'); + expect(ROOT_USER).toBe(false); + }); + + test('ROOT_USER should be false if user is root but is fake root', () => { + jest.spyOn(process, 'getuid').mockReturnValue(0); + process.env.FAKEROOTKEY = 'true'; + + jest.resetModules(); + const { ROOT_USER } = require('../../src/utils/userHomeDir'); + expect(ROOT_USER).toBe(false); + }); +}); diff --git a/test/utils/utils.test.js b/test/utils/utils.test.js new file mode 100644 index 0000000..b3e66d6 --- /dev/null +++ b/test/utils/utils.test.js @@ -0,0 +1,391 @@ +import path from 'path'; +import inquirer from 'inquirer'; +import moment from 'moment'; +import { v4 as uuid } from 'uuid'; +import AElf from 'aelf-sdk'; +import { + promisify, + camelCase, + getContractMethods, + getContractInstance, + getMethod, + promptTolerateSeveralTimes, + isAElfContract, + getTxResult, + parseJSON, + randomId, + getParams, + deserializeLogs +} from '../../src/utils/utils'; +import { plainLogger } from '../../src/utils/myLogger'; +import { endpoint, account, password, dataDir } from '../constants.js'; + +jest.mock('inquirer'); + +describe('utils', () => { + afterEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + }); + + describe('promisify', () => { + test('should resolve with result when no error', async () => { + const mockFn = jest.fn((arg1, cb) => cb(null, arg1 + 1)); + const promiseFn = promisify(mockFn); + const result = await promiseFn(5); + expect(result).toBe(6); + }); + test('should reject with error when callback has error', async () => { + const mockFn = jest.fn((_, cb) => cb(new Error('Callback error'))); + const promiseFn = promisify(mockFn); + await expect(promiseFn(5)).rejects.toThrow('Callback error'); + }); + test('should handle firstData parameter correctly', async () => { + const mockFn = jest.fn((_, cb) => cb('result')); + const promiseFn = promisify(mockFn, true); + const result = await promiseFn(5); + expect(result).toBe('result'); + }); + }); + + describe('camelCase', () => { + test('should convert string to camelCase', () => { + expect(camelCase('hello_world')).toBe('helloWorld'); + }); + }); + + describe('isAElfContract', () => { + test('should return true for valid AElf contract name', () => { + expect(isAElfContract('aelf.contract')).toBe(true); + }); + + test('should return false for non-AElf contract name', () => { + expect(isAElfContract('not.aelf.contract')).toBe(false); + }); + }); + + describe('getContractMethods', () => { + test('should return methods starting with uppercase letters', () => { + const contract = { + Transfer: () => {}, + approve: () => {} + }; + const methods = getContractMethods(contract); + expect(methods).toEqual(['Transfer']); + }); + + test('should call plainLogger.fatal and exit process if no contract provided', () => { + const spyFatal = jest.spyOn(plainLogger, 'fatal').mockReturnValue(); + const spyExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); + getContractMethods(''); + expect(spyFatal).toHaveBeenCalled(); + expect(spyExit).toHaveBeenCalledWith(1); + }); + }); + + describe('getContractInstance', () => { + let oraInstance; + const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + const contractAddress = '2cVQrFiXNaedBYmUrovmUV2jcF9Hf6AXbh12gWsD4P49NaX99y'; + const wallet = AElf.wallet.getWalletByPrivateKey('9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'); + + beforeEach(() => { + oraInstance = { + start: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + }); + + test('should fetch contract by address if not AElf contract', async () => { + const contractInstance = await getContractInstance(contractAddress, aelf, wallet, oraInstance); + expect(oraInstance.start).toHaveBeenCalledWith('Fetching contract'); + expect(oraInstance.succeed).toHaveBeenCalledWith('Fetching contract successfully!'); + expect(contractInstance).toMatchObject({ address: contractAddress }); + }); + + test('should fetch AElf contract by name', async () => { + // contract Token + const contractInstance = await getContractInstance('AElf.ContractNames.Token', aelf, wallet, oraInstance); + expect(oraInstance.start).toHaveBeenCalledWith('Fetching contract'); + expect(oraInstance.succeed).toHaveBeenCalledWith('Fetching contract successfully!'); + expect(contractInstance).toMatchObject({ address: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx' }); + }); + + test('should fail and exit process if contract retrieval fails', async () => { + const spyFail = jest.spyOn(oraInstance, 'fail').mockReturnValue(); + const spyError = jest.spyOn(plainLogger, 'error').mockReturnValue('Error message'); + const spyExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); + await expect(getContractInstance('invalidAddress', aelf, wallet, oraInstance)); + expect(spyFail).toHaveBeenCalled(); + expect(spyError).toHaveBeenCalled(); + expect(spyExit).toHaveBeenCalledWith(1); + }); + + test('should handle contract address which is not string', async () => { + // contract Token + const contractInstance = await getContractInstance({}, aelf, wallet, oraInstance); + expect(contractInstance).toEqual({}); + }); + }); + + describe('getMethod', () => { + test('should return method if exists in contract', () => { + const contract = { method: jest.fn() }; + const method = getMethod('method', contract); + expect(method).toBe(contract.method); + }); + + test('should throw error if method does not exist in contract', () => { + const contract = {}; + expect(() => getMethod('nonexistentMethod', contract)).toThrow('Not exist method nonexistentMethod'); + }); + + test('should return method directly if not a string', () => { + const contract = {}; + const method = getMethod(null, contract); + expect(method).toBeNull(); + }); + }); + + describe('promptTolerateSeveralTimes', () => { + let oraInstance; + + beforeEach(() => { + oraInstance = { + start: jest.fn(), + fail: jest.fn() + }; + }); + + test('should return valid input according to pattern', async () => { + inquirer.prompt.mockResolvedValueOnce({ input: 'validInput' }); + const processAfterPrompt = jest.fn().mockResolvedValue('processedInput'); + const input = await promptTolerateSeveralTimes( + { + processAfterPrompt, + pattern: /valid/, + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ); + expect(input).toBe('processedInput'); + expect(processAfterPrompt).toHaveBeenCalledWith({ input: 'validInput' }); + }); + + test('should retry prompt if input does not match pattern', async () => { + inquirer.prompt.mockResolvedValue({ input: 'invalidInput' }); + const processAfterPrompt = jest.fn().mockResolvedValue('processedInput'); + await promptTolerateSeveralTimes( + { + processAfterPrompt, + pattern: /valid/, + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ); + expect(inquirer.prompt).toHaveBeenCalledTimes(3); + }); + + test('should exit process if maximum attempts exceeded', async () => { + inquirer.prompt.mockResolvedValue({ input: null }); + const spyFail = jest.spyOn(oraInstance, 'fail').mockReturnValue(); + const spyFatal = jest.spyOn(plainLogger, 'fatal').mockReturnValue(); + const spyExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); + const processAfterPrompt = jest.fn().mockResolvedValue(null); + await promptTolerateSeveralTimes( + { + processAfterPrompt, + pattern: /valid/, + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ); + expect(spyFail).toHaveBeenCalled(); + expect(spyFatal).toHaveBeenCalled(); + expect(spyExit).toHaveBeenCalledWith(1); + }); + test('should handle error pattern', async () => { + await expect( + promptTolerateSeveralTimes( + { + pattern: {}, + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ) + ).rejects.toThrow("param 'pattern' must be a regular expression!"); + }); + + test('should handle error processAfterPrompt', async () => { + await expect( + promptTolerateSeveralTimes( + { + processAfterPrompt: {}, + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ) + ).rejects.toThrow("Param 'processAfterPrompt' must be a function!"); + }); + + test('should handle no pattern', async () => { + await promptTolerateSeveralTimes( + { + times: 3, + prompt: [{ name: 'input', message: 'Enter input' }] + }, + oraInstance + ); + const spyFail = jest.spyOn(oraInstance, 'fail').mockReturnValue(); + expect(spyFail).toHaveBeenCalledWith('Failed'); + }); + }); + + describe('getTxResult', () => { + let aelf; + + beforeEach(() => { + aelf = { chain: { getTxResult: jest.fn() } }; + }); + + test('should return tx result when Status is MINED', async () => { + aelf.chain.getTxResult.mockResolvedValueOnce({ Status: 'MINED' }); + const tx = await getTxResult(aelf, 'txId'); + expect(tx).toEqual({ Status: 'MINED' }); + }); + + test('should throw error if Status is not MINED after retries', async () => { + aelf.chain.getTxResult.mockResolvedValue({ Status: 'PENDING' }); + const tx = await getTxResult(aelf, 'txId'); + expect(tx).toEqual({ Status: 'PENDING' }); + }); + + test('should retry if Status is PENDING', async () => { + aelf.chain.getTxResult.mockResolvedValueOnce({ Status: 'PENDING' }).mockResolvedValueOnce({ Status: 'MINED' }); + const tx = await getTxResult(aelf, 'txId'); + expect(tx).toEqual({ Status: 'MINED' }); + }); + + test('should retry if Status is FAILED', async () => { + aelf.chain.getTxResult.mockResolvedValueOnce({ Status: 'FAILED' }); + await expect(getTxResult(aelf, 'txId')).toThrow({ Status: 'FAILED' }); + }); + }); + + describe('parseJSON', () => { + test('should correctly parse JSON', function () { + expect(parseJSON('{"key": "value"}')).toEqual({ key: 'value' }); + expect(parseJSON('invalid')).toBe('invalid'); + expect(parseJSON('')).toBe(''); + }); + }); + + describe('randomId', () => { + it('should generate a random UUID without dashes', function () { + const uuid = randomId(); + expect(typeof uuid).toBe('string'); + expect(uuid.length).toBe(32); + }); + }); + + describe('getParams', () => { + let oraInstance; + const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + const contractAddress = '2cVQrFiXNaedBYmUrovmUV2jcF9Hf6AXbh12gWsD4P49NaX99y'; + const wallet = AElf.wallet.getWalletByPrivateKey('9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'); + beforeEach(() => { + oraInstance = { + start: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + }); + test('should get parameters by method', async () => { + const contractInstance = await getContractInstance(contractAddress, aelf, wallet, oraInstance); + const method = getMethod('GetProposal', contractInstance); + inquirer.prompt.mockResolvedValue({ value: 'proposal' }); + const params = await getParams(method); + expect(params).toBe('proposal'); + }); + + test('should get parameters by method with not special params', async () => { + const contractInstance = await getContractInstance(contractAddress, aelf, wallet, oraInstance); + // console.log(Object.keys(contractInstance)); + const method = getMethod('GetMethodFee', contractInstance); + inquirer.prompt.mockResolvedValue({ value: 'method fee' }); + const params = await getParams(method); + expect(params).toEqual({ value: 'method fee' }); + }); + }); + + describe('deserializeLogs', () => { + let oraInstance; + const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); + beforeEach(() => { + oraInstance = { + start: jest.fn(), + succeed: jest.fn(), + fail: jest.fn() + }; + }); + test('test deserialize log', async () => { + const logs = [ + { + Address: 'ELF_2sGZFRtqQ57F55Z2KvhmoozKrf7ik2htNVQawEAo3Vyvcx9Qwr_tDVW', + Name: '.aelf.Hash', + NonIndexed: 'CgNFTEYQoI/hGQ==' + } + ]; + const result = await deserializeLogs(aelf, logs); + expect(result).toEqual(['454c46']); + }); + test('test deserialize log with VirtualTransactionCreated', async () => { + const logs = [ + { + Address: '238X6iw1j8YKcHvkDYVtYVbuYk2gJnK8UoNpVCtssynSpVC8hb', + Name: 'VirtualTransactionCreated', + Indexed: [ + 'CiIKIA8J04pLJGNHl4y2KWuBJipdXjtJ2ForrSRRuRx9w2LY', + 'EiIKIAR/b9iJa/+kT2+h9XAdQE0UX9wFZogfPtn9YvtlCnB2', + 'GiIKICeR6ZKlfyjnWhHxOvLArsiw6zXS8EjULrqJAckuA3jc', + 'IghUcmFuc2Zlcg==', + 'MiIKICWmXUMWhKDuXFdYz8/uF7ze4kC5r3i7boxM5Dj+RE4G' + ], + NonIndexed: 'KjAKIgogIKCTibOwFJNFp0zUNEXymkyazYKz8LLwLqOZxEqKRF0SA09NSRiA0NvD9AI=' + } + ]; + const result = await deserializeLogs(aelf, logs); + expect(result).toEqual([ + { + from: '2ytdtA2PDX7VLYWkqf36MQQ8wUtcXWRdpovX7Wxy8tJZXumaY', + methodName: 'Transfer', + params: 'CiIKICCgk4mzsBSTRadM1DRF8ppMms2Cs/Cy8C6jmcRKikRdEgNPTUkYgNDbw/QC', + signatory: 'HaiUnezHpBieiVZNuyQV4uLFspYDGxsEwt8wSFYqGSpXY3CzJ', + to: 'JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE', + virtualHash: '0f09d38a4b246347978cb6296b81262a5d5e3b49d85a2bad2451b91c7dc362d8' + } + ]); + }); + test('test deserialize log with empty NonIndexed', async () => { + const logs = [ + { + Indexed: ['CiIKIPoq3y6L7T71F5BynCBXISeMFKrCt4QayljkLE4U8St4', 'EiIKIKt0P1P3+jKuU4Y5rSGOfzleHFw0YXn5eNM88jWfUWYR'], + Name: '.aelf.Hash', + Address: 'ELF_2sGZFRtqQ57F55Z2KvhmoozKrf7ik2htNVQawEAo3Vyvcx9Qwr_tDVW' + } + ]; + const result = await deserializeLogs(aelf, logs); + expect(result).toEqual(['0a20fa2adf2e8bed3ef51790729c205721278c14aac2b7841aca58e42c4e14f12b78']); + }); + test('test deserialize log with empty logs', async () => { + const result = await deserializeLogs(aelf); + expect(result).toEqual(null); + }); + }); +}); diff --git a/test/utils/wallet.test.js b/test/utils/wallet.test.js new file mode 100644 index 0000000..6abbb04 --- /dev/null +++ b/test/utils/wallet.test.js @@ -0,0 +1,81 @@ +import inquirer from 'inquirer'; +import fs from 'fs'; +import { mkdirpSync } from 'mkdirp'; +import { getWallet, saveKeyStore } from '../../src/utils/wallet'; +import { endpoint, account, password, dataDir } from '../constants.js'; +import keyJSON from '../datadir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json'; + +jest.mock('inquirer'); +jest.mock('mkdirp'); + +describe('wallet', () => { + describe('getWallet', () => { + test('should get wallet', () => { + const result = getWallet(dataDir, account, password); + expect(result.privateKey).toBe('9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'); + expect(result.mnemonic).toBe('impact fork bulk museum swap design draw arctic load option ticket across'); + }); + test('should handle error', () => { + expect(() => getWallet(dataDir, 'test', password)).toThrow('Make sure you entered the correct account address'); + expect(() => getWallet(dataDir, account, 'test')).toThrow('Make sure you entered the correct password'); + }); + }); + describe('saveKeyStore', () => { + let existsSyncMock; + let writeFileSyncMock; + const wallet = getWallet(dataDir, account, password); + const keyStorePath = `${dataDir}/keys/${wallet.address}.json`; + + beforeEach(() => { + jest.clearAllMocks(); + inquirer.prompt.mockResolvedValue({ + password: '1234*Qwer', + confirmPassword: '1234*Qwer' + }); + }); + + beforeAll(() => { + // Mock fs methods + existsSyncMock = jest.spyOn(fs, 'existsSync').mockImplementation(() => true); + writeFileSyncMock = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); + }); + + afterAll(() => { + // Restore fs methods + existsSyncMock.mockRestore(); + writeFileSyncMock.mockRestore(); + }); + + test('should save keystore file and return its path', async () => { + existsSyncMock.mockReturnValueOnce(false); + const result = await saveKeyStore(wallet, dataDir); + expect(mkdirpSync).toHaveBeenCalled(); + expect(writeFileSyncMock).toHaveBeenCalled(); + expect(result).toBe(keyStorePath); + }); + + test('should throw error if passwords do not match', async () => { + inquirer.prompt.mockResolvedValueOnce({ + password: 'test-password', + confirmPassword: 'wrong-password' + }); + await expect(saveKeyStore(wallet, dataDir)).rejects.toThrow('Passwords are different'); + }); + + test('should throw error if password is too short', async () => { + inquirer.prompt.mockResolvedValueOnce({ + password: 'short', + confirmPassword: 'short' + }); + await expect(saveKeyStore(wallet, dataDir)).rejects.toThrow('password is too short'); + }); + + test('should not create directory if it already exists', async () => { + existsSyncMock.mockReturnValueOnce(true); + const result = await saveKeyStore(wallet, dataDir); + expect(mkdirpSync).not.toHaveBeenCalled(); + expect(writeFileSyncMock).toHaveBeenCalled(); + expect(result).toBe(keyStorePath); + }); + }); +}); From a32becee70cfd397c83a7c49f6c733bbd6481f4e Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 09:49:04 +0800 Subject: [PATCH 15/24] feat: add Coverage Diff --- .github/workflows/test.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a1c75e2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: Coverage Diff + +on: + push: + branches: + - master + pull_request: {} + +jobs: + test: + name: Coverage Diff + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + cache: yarn + - run: yarn install + - run: yarn run test:coverage + - name: Coverage Diff + uses: greatwizard/coverage-diff-action@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From 6232b74c163b1c5522bf92c83d2f5b295097558f Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 09:50:53 +0800 Subject: [PATCH 16/24] feat: node version --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1c75e2..1fc2e1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 16 + node-version: 20 cache: yarn - run: yarn install - run: yarn run test:coverage From c91f530967063eee0419f95a8727ee5107e74ca3 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 11:36:13 +0800 Subject: [PATCH 17/24] feat: add timeout and fix error --- jest.config.js | 5 +-- src/utils/utils.js | 1 + test/command/call.test.js | 12 +++---- test/command/console.test.js | 4 +-- test/command/dappServer/index.test.js | 4 +-- test/command/dappServer/socket-sign.test.js | 35 +++++---------------- test/command/dappServer/socket.test.js | 28 ++++++++--------- test/command/deploy.test.js | 2 +- test/command/event.test.js | 11 +++---- test/command/getBlkHeight.test.js | 2 +- test/command/getBlkInfo.test.js | 4 +-- test/command/getChainStatus.test.js | 4 +-- test/command/getTxResult.test.js | 4 +-- test/command/load.test.js | 10 +++--- test/command/proposal.test.js | 6 ++-- test/command/wallet.test.js | 4 +-- test/utils/fs.test.js | 1 - test/utils/utils.test.js | 9 ++++-- 18 files changed, 63 insertions(+), 83 deletions(-) diff --git a/jest.config.js b/jest.config.js index ddc6320..201adca 100644 --- a/jest.config.js +++ b/jest.config.js @@ -144,11 +144,12 @@ export default { // The glob patterns Jest uses to detect test files testMatch: [ + // '**/test/utils/utils.test.js' '**/test/command/dappServer/socket-sign.test.js', - '**/test/**/*.[jt]s?(x)' + '**/test/**/?(*.)+(spec|test).[jt]s?(x)' // "**/?(*.)+(spec|test).[tj]s?(x)" ], - testTimeout: 5000, + testTimeout: 20000, // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped // testPathIgnorePatterns: [ diff --git a/src/utils/utils.js b/src/utils/utils.js index 028c76d..969aaf9 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -138,6 +138,7 @@ async function promptTolerateSeveralTimes({ processAfterPrompt = () => {}, patte askTimes++; } catch (e) { oraInstance.fail('Failed'); + break; } } if (askTimes >= times && answerInput === null) { diff --git a/test/command/call.test.js b/test/command/call.test.js index d806aeb..f91cf1f 100644 --- a/test/command/call.test.js +++ b/test/command/call.test.js @@ -48,12 +48,12 @@ describe('CallCommand', () => { const result = await callCommand.callMethod(method, params); expect(mockOraInstance.start).toHaveBeenCalledWith('Calling method...'); expect(mockOraInstance.succeed).toHaveBeenCalledWith('Calling method successfully!'); - }, 20000); + }); test('should process address after prompt', async () => { const answerInput = { contractAddress: address }; const result = await callCommand.processAddressAfterPrompt(aelf, wallet, answerInput); expect(result.address).toBe(address); - }, 20000); + }); test('should run with valid inputs', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -73,7 +73,7 @@ describe('CallCommand', () => { }) ); expect(logger.info).toHaveBeenCalled(); - }, 20000); + }); test('should run without contractAddress', async () => { inquirer.prompt = questions => Promise.resolve(''); const commander = new Command(); @@ -87,7 +87,7 @@ describe('CallCommand', () => { commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await callCommand.run(commander); expect(logger.fatal).toHaveBeenCalled(); - }, 5000); + }); test('should run without params', async () => { inquirer.prompt = questions => Promise.resolve({ symbol: 'ELF' }); @@ -102,7 +102,7 @@ describe('CallCommand', () => { commander.parse([process.argv[0], '', 'call', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await callCommand.run(commander, 'AElf.ContractNames.Token', 'GetTokenInfo'); expect(logger.info).toHaveBeenCalled(); - }, 20000); + }); test('should run with invalid parameters', async () => { inquirer.prompt = backup; @@ -133,7 +133,7 @@ describe('CallCommand', () => { }) ); expect(logger.info).toHaveBeenCalled(); - }, 20000); + }); afterEach(() => { inquirer.prompt = backup; diff --git a/test/command/console.test.js b/test/command/console.test.js index cd49775..0cad0a9 100644 --- a/test/command/console.test.js +++ b/test/command/console.test.js @@ -46,7 +46,7 @@ describe('ConsoleCommand', () => { await consoleCommand.run(commander); expect(oraInstance.succeed).toHaveBeenCalledWith('Succeed!'); expect(logger.info).toHaveBeenCalledTimes(2); - }, 20000); + }); test('should handle errors correctly', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -63,5 +63,5 @@ describe('ConsoleCommand', () => { await consoleCommand.run(commander); expect(oraInstance.fail).toHaveBeenCalledWith('Failed!'); expect(logger.error).toHaveBeenCalled(); - }, 20000); + }); }); diff --git a/test/command/dappServer/index.test.js b/test/command/dappServer/index.test.js index 8af4b9d..ee63e48 100644 --- a/test/command/dappServer/index.test.js +++ b/test/command/dappServer/index.test.js @@ -36,7 +36,7 @@ describe('DeployCommand', () => { commander.parse([process.argv[0], '', 'wallet', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await deployCommand.run(commander); expect(logger.info).toHaveBeenCalledWith('DApp server is listening on port 35443'); - }, 20000); + }); test('should handle errors during server startup', async () => { Socket.mockImplementation(_ => { throw new Error('socket error'); @@ -53,5 +53,5 @@ describe('DeployCommand', () => { await deployCommand.run(commander); expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); expect(logger.error).toHaveBeenCalled(); - }, 20000); + }); }); diff --git a/test/command/dappServer/socket-sign.test.js b/test/command/dappServer/socket-sign.test.js index e2c6f2d..2e782e8 100644 --- a/test/command/dappServer/socket-sign.test.js +++ b/test/command/dappServer/socket-sign.test.js @@ -118,13 +118,6 @@ describe('Socket Server with sign', () => { }); describe('Socket Server with sign', () => { - // let clientSocket, - // socketInstance, - // port = 35444; - // const serverUrl = `http://localhost:${port}`; - // const aelf = new AElf(new AElf.providers.HttpProvider(endpoint)); - // const wallet = getWallet(dataDir, account, password); - beforeEach(done => { socketInstance = new Socket({ port, @@ -142,20 +135,6 @@ describe('Socket Server with sign', () => { await new Promise(resolve => setTimeout(resolve, 1000)); done(); }); - // first need to connect - // const connectData = { - // action: 'connect', - // params: { - // publicKey: - // '04b00b9a0c0359a5e0a55b0efa32469929765b30bc5a8b375d2dbffa43322f87df3401845a4cc3841a36c3f14a7481ce1c4e9d920f18ede0f4bcbd29e291a4190a', - // timestamp: 1718870995, - // encryptAlgorithm: 'secp256k1', - // signature: - // '33977ec3965229628feb4b95846442d71d20fa9bfd54efe6958daa5fdf369a3ecde738f9a10374dd8b56064618e50746b9c3581ade80abfc3b69decadadec7a200' - // }, - // appId: '28e653ec-20d4-55e1-b077-a346df57666a', - // id: '4b62bc590a4d43beb432c1692e1a2234' - // }; Sign.verify = jest.fn().mockReturnValue(true); Sign.mockImplementation(() => { return { @@ -200,7 +179,7 @@ describe('Socket Server with sign', () => { id: 'cd78bea8c031411fb6659939f9070527' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle api action', done => { clientSocket.on('bridge', message => { @@ -228,7 +207,7 @@ describe('Socket Server with sign', () => { id: 'e647eda5134a4325a5bf03f429336c03' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invoke action', done => { clientSocket.on('bridge', message => { @@ -258,7 +237,7 @@ describe('Socket Server with sign', () => { id: 'a31b390269ad4caa8da0557c43dea556' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invokeRead action', done => { clientSocket.on('bridge', message => { @@ -288,7 +267,7 @@ describe('Socket Server with sign', () => { id: '36055f21b2d6418998dda7eda6526a2a' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle getContractMethods action', done => { clientSocket.on('bridge', message => { @@ -315,7 +294,7 @@ describe('Socket Server with sign', () => { id: '08400d6bac284c40a5984821c2ef4f53' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invalid signature', done => { clientSocket.on('bridge', message => { @@ -335,7 +314,7 @@ describe('Socket Server with sign', () => { id: '08400d6bac284c40a5984821c2ef4f53' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invalid signature', done => { clientSocket.on('bridge', message => { @@ -355,5 +334,5 @@ describe('Socket Server with sign', () => { id: '08400d6bac284c40a5984821c2ef4f53' }; clientSocket.emit('bridge', data); - }, 20000); + }); }); diff --git a/test/command/dappServer/socket.test.js b/test/command/dappServer/socket.test.js index 5205f81..90cb3ba 100644 --- a/test/command/dappServer/socket.test.js +++ b/test/command/dappServer/socket.test.js @@ -90,7 +90,7 @@ describe('Socket Server', () => { id: '281537101483488da8c12a9b02c4f563' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle api action', done => { clientSocket.on('bridge', message => { @@ -134,7 +134,7 @@ describe('Socket Server', () => { id: '45b66a0738ff48a7b06cec79ff673dba' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invoke action', done => { clientSocket.on('bridge', message => { @@ -192,7 +192,7 @@ describe('Socket Server', () => { id: 'f84f494d82ce42c5b4018d37d6bd1d34' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invokeRead action', done => { clientSocket.on('bridge', message => { @@ -246,7 +246,7 @@ describe('Socket Server', () => { id: '98c8b690fbbe43ca9f6fd1f72c18f2db' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle getContractMethods action', done => { clientSocket.on('bridge', message => { @@ -290,7 +290,7 @@ describe('Socket Server', () => { id: '7c4aafc53b804bb189c77ea95baf70c1' }; clientSocket.emit('bridge', data); - }, 20000); + }, 40000); test('should handle disconnect action', done => { clientSocket.on('bridge', message => { @@ -334,7 +334,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle null action', done => { clientSocket.on('bridge', message => { expect(logger.error).toHaveBeenCalledWith('error happened'); @@ -352,7 +352,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle undefined action', done => { clientSocket.on('bridge', message => { expect(logger.error).toHaveBeenCalledWith('error happened'); @@ -370,7 +370,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle empty string action', done => { clientSocket.on('bridge', message => { expect(logger.error).toHaveBeenCalledWith('error happened'); @@ -388,7 +388,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle not supported action', done => { clientSocket.on('bridge', message => { @@ -407,7 +407,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle not connected appId', done => { clientSocket.on('bridge', message => { @@ -426,7 +426,7 @@ describe('Socket Server', () => { id: 'ded9643a0095440a9a5684c4b4c10e35' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle Timestamp is not valid', done => { clientSocket.on('bridge', message => { expect(logger.error).toHaveBeenCalledWith(new Error('Timestamp is not valid')); @@ -445,7 +445,7 @@ describe('Socket Server', () => { id: '281537101483488da8c12a9b02c4f563' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle not supported api', done => { clientSocket.on('bridge', message => { @@ -490,7 +490,7 @@ describe('Socket Server', () => { id: '45b66a0738ff48a7b06cec79ff673dba' }; clientSocket.emit('bridge', data); - }, 20000); + }); test('should handle invoke with not supported method', done => { clientSocket.on('bridge', message => { @@ -541,5 +541,5 @@ describe('Socket Server', () => { id: '98c8b690fbbe43ca9f6fd1f72c18f2db' }; clientSocket.emit('bridge', data); - }, 20000); + }); }); diff --git a/test/command/deploy.test.js b/test/command/deploy.test.js index 5e98787..990dd9e 100644 --- a/test/command/deploy.test.js +++ b/test/command/deploy.test.js @@ -47,5 +47,5 @@ describe('DeployCommand', () => { commander.parse([process.argv[0], '', 'console', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await deployCommand.run(commander); expect(consoleSpy).toHaveBeenCalledWith(expectedTips); - }, 20000); + }); }); diff --git a/test/command/event.test.js b/test/command/event.test.js index d0a4a37..f8ae259 100644 --- a/test/command/event.test.js +++ b/test/command/event.test.js @@ -3,6 +3,7 @@ import path from 'path'; import EventCommand from '../../src/command/event.js'; import { logger, plainLogger } from '../../src/utils/myLogger'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -10,10 +11,6 @@ describe('EventCommand', () => { let eventCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); beforeEach(() => { oraInstanceMock = { @@ -64,7 +61,7 @@ describe('EventCommand', () => { `\nThe results returned by \nTransaction: ${txId} is: \n${JSON.stringify(logs, null, 2)}` ); expect(oraInstanceMock.fail).not.toHaveBeenCalled(); - }, 20000); + }); test('should log "not mined" if transaction status is not mined', async () => { const txId = '3553df418c6ec9a159560440f13a6ae29f786392574737036cf63786321c8a40'; @@ -80,7 +77,7 @@ describe('EventCommand', () => { await eventCommand.run(commander, txId); expect(plainLogger.info).toHaveBeenCalledWith(`Transaction ${txId} is not mined`); expect(oraInstanceMock.fail).not.toHaveBeenCalled(); - }, 20000); + }); test('should log error and fail on exception', async () => { const txId = 'test'; @@ -95,5 +92,5 @@ describe('EventCommand', () => { commander.parse([process.argv[0], '', 'event', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await eventCommand.run(commander, txId); expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); - }, 20000); + }); }); diff --git a/test/command/getBlkHeight.test.js b/test/command/getBlkHeight.test.js index 2f922f7..00a4bf8 100644 --- a/test/command/getBlkHeight.test.js +++ b/test/command/getBlkHeight.test.js @@ -41,7 +41,7 @@ describe('GetBlkHeightCommand', () => { commander.parse([process.argv[0], '', 'get-blk-height', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await getBlkHeightCommand.run(commander); expect(oraInstanceMock.succeed).toHaveBeenCalled(); - }, 20000); + }); test('should log error and fail on exception', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); diff --git a/test/command/getBlkInfo.test.js b/test/command/getBlkInfo.test.js index 4b0bc78..52483dc 100644 --- a/test/command/getBlkInfo.test.js +++ b/test/command/getBlkInfo.test.js @@ -69,7 +69,7 @@ describe('GetBlkInfoCommand', () => { Time: '2022-06-02T11:28:40.5094851Z' } }); - }, 20000); + }); test('should get block info by hash and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -108,7 +108,7 @@ describe('GetBlkInfoCommand', () => { Time: '2022-06-02T11:28:40.5094851Z' } }); - }, 20000); + }); test('should log error and fail on exception', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); diff --git a/test/command/getChainStatus.test.js b/test/command/getChainStatus.test.js index d5bdf53..7a7a63a 100644 --- a/test/command/getChainStatus.test.js +++ b/test/command/getChainStatus.test.js @@ -41,7 +41,7 @@ describe('GetChainStatusCommand', () => { commander.parse([process.argv[0], '', 'get-chain-status', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await getChainStatusCommand.run(commander); expect(oraInstanceMock.succeed).toHaveBeenCalled(); - }, 20000); + }); test('should log error and fail on exception', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); @@ -58,5 +58,5 @@ describe('GetChainStatusCommand', () => { }); await getChainStatusCommand.run(commander); expect(oraInstanceMock.fail).toHaveBeenCalled(); - }, 20000); + }); }); diff --git a/test/command/getTxResult.test.js b/test/command/getTxResult.test.js index c8b2fc4..7bba77a 100644 --- a/test/command/getTxResult.test.js +++ b/test/command/getTxResult.test.js @@ -42,7 +42,7 @@ describe('GetTxResultCommand', () => { commander.parse([process.argv[0], '', 'get-tx-result', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await getTxResultCommand.run(commander, txId); expect(oraInstanceMock.succeed).toHaveBeenCalled(); - }, 20000); + }); test('should log error and fail on validation error', async () => { jest.spyOn(process, 'exit').mockImplementation(() => {}); const commander = new Command(); @@ -57,5 +57,5 @@ describe('GetTxResultCommand', () => { await getTxResultCommand.run(commander, true); expect(process.exit).toHaveBeenCalledWith(1); expect(oraInstanceMock.fail).toHaveBeenCalled(); - }, 20000); + }); }); diff --git a/test/command/load.test.js b/test/command/load.test.js index fc1a69e..36469f5 100644 --- a/test/command/load.test.js +++ b/test/command/load.test.js @@ -55,7 +55,7 @@ describe('LoadCommand', () => { ); expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); expect(saveKeyStore).toHaveBeenCalled(); - }, 20000); + }); test('should load wallet from Mnemonic and succeed', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -79,7 +79,7 @@ describe('LoadCommand', () => { 'Public Key : 04449094b89d0445c920434ea09d87ba8d9bf95d8a3971ee03572a1f666ef2241cc3ada03d47736c005d28bbef8468042e77a084ea11b8aca395ac7686335f4712' ); expect(logger.info).toHaveBeenCalledWith('Address : SbWhnq3XU8yeiUTYJmZBSgt7ekgszRXHxh8qNqkFj9g6d3bWh'); - }, 20000); + }); test('should load wallet from privateKey and succeed without saving to file', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -100,7 +100,7 @@ describe('LoadCommand', () => { ); expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); expect(oraInstanceMock.succeed).toHaveBeenCalledWith('Succeed!'); - }, 20000); + }); test('should log error and fail on validation error', async () => { const commander = new Command(); @@ -117,7 +117,7 @@ describe('LoadCommand', () => { }); await loadCommand.run(commander, privateKey, false, true); expect(oraInstanceMock.fail).toHaveBeenCalled(); - }, 20000); + }); test('should fail when trying to use old version SDK', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -130,5 +130,5 @@ describe('LoadCommand', () => { commander.parse([process.argv[0], '', 'load', '-e', endPoint, '-a', account, '-p', password, '-d', dataDir]); await loadCommand.run(commander, 'xxx xxx', true, false); expect(oraInstanceMock.fail).toHaveBeenCalledWith('Please install older versions of aelf-command before v1.0.0!'); - }, 20000); + }); }); diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js index 882dc15..7d0900c 100644 --- a/test/command/proposal.test.js +++ b/test/command/proposal.test.js @@ -53,7 +53,7 @@ describe('ProposalCommand processAddressAfterPrompt', () => { }; const result = await proposalCommand.processAddressAfterPrompt(aelf, wallet, answerInput); expect(result.address).toBe(contractAddress); - }, 20000); + }); }); describe('ProposalCommand run', () => { let proposalCommand; @@ -153,7 +153,7 @@ describe('ProposalCommand run', () => { expect(oraInstanceMock.succeed).toHaveBeenCalled(); expect(logger.info).toHaveBeenCalledWith({ TransactionId: 'mockTxId' }); expect(logger.info).toHaveBeenCalledWith('Proposal id: mockProposal.'); - }, 20000); + }); test('should run and show pending info', async () => { const commander = new Command(); commander.option('-e, --endpoint ', 'The URI of an AElf node. Eg: http://127.0.0.1:8000'); @@ -204,7 +204,7 @@ describe('ProposalCommand run', () => { expect(logger.info).toHaveBeenCalledWith( 'Transaction is still pending, you can get proposal id later by running yellow(aelf-command event mockTxId)' ); - }, 20000); + }); test('should handle failure to create proposal', async () => { const commander = new Command(); diff --git a/test/command/wallet.test.js b/test/command/wallet.test.js index 3428b8b..d49eed7 100644 --- a/test/command/wallet.test.js +++ b/test/command/wallet.test.js @@ -54,7 +54,7 @@ describe('WalletCommand', () => { 'Public Key : 04703bbe95e986c9d901f28edd60975a7a6c3b2dce41dfec2e7983d293c600e8249642a3da379c4194a6d62bd89afe6753e81acfc2b6bbf3b40736ee0949102071' ); expect(logger.info).toHaveBeenCalledWith('Address : GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'); - }, 20000); + }); test('should handle errors and fail', async () => { jest.spyOn(require('../../src/utils/wallet'), 'getWallet').mockReturnValue(new Error('test error')); const commander = new Command(); @@ -69,5 +69,5 @@ describe('WalletCommand', () => { await walletCommand.run(commander); expect(oraInstanceMock.fail).toHaveBeenCalledWith('Failed!'); expect(logger.error).toHaveBeenCalled(); - }, 20000); + }); }); diff --git a/test/utils/fs.test.js b/test/utils/fs.test.js index 0851867..f9296cf 100644 --- a/test/utils/fs.test.js +++ b/test/utils/fs.test.js @@ -16,7 +16,6 @@ describe('File System Operators', () => { }); describe('writeFilePreservingEol', () => { - // cannot test /r/n because it depends on Windows test('should write data with preserved EOL', async () => { const path = '/path/to/existing/file.txt'; const existingData = 'Line 1\nLine 2\nLine 3\n'; diff --git a/test/utils/utils.test.js b/test/utils/utils.test.js index b3e66d6..d6301e4 100644 --- a/test/utils/utils.test.js +++ b/test/utils/utils.test.js @@ -235,6 +235,9 @@ describe('utils', () => { }); test('should handle no pattern', async () => { + inquirer.prompt.mockImplementation(() => { + throw new Error(); + }); await promptTolerateSeveralTimes( { times: 3, @@ -242,7 +245,7 @@ describe('utils', () => { }, oraInstance ); - const spyFail = jest.spyOn(oraInstance, 'fail').mockReturnValue(); + const spyFail = jest.spyOn(oraInstance, 'fail'); expect(spyFail).toHaveBeenCalledWith('Failed'); }); }); @@ -274,7 +277,7 @@ describe('utils', () => { test('should retry if Status is FAILED', async () => { aelf.chain.getTxResult.mockResolvedValueOnce({ Status: 'FAILED' }); - await expect(getTxResult(aelf, 'txId')).toThrow({ Status: 'FAILED' }); + await expect(getTxResult(aelf, 'txId')).rejects.toEqual({ Status: 'FAILED' }); }); }); @@ -344,7 +347,7 @@ describe('utils', () => { ]; const result = await deserializeLogs(aelf, logs); expect(result).toEqual(['454c46']); - }); + }, 40000); test('test deserialize log with VirtualTransactionCreated', async () => { const logs = [ { From 8581c5dc13a0f8ba34972ab6939e3f7615eb3a77 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 12:18:38 +0800 Subject: [PATCH 18/24] feat: change to Upper --- jest.config.js | 2 +- test/command/call.test.js | 2 +- test/command/config.test.js | 2 +- test/command/console.test.js | 2 +- test/command/create.test.js | 2 +- test/command/deploy.test.js | 2 +- test/command/getBlkHeight.test.js | 2 +- test/command/getBlkInfo.test.js | 2 +- test/command/getChainStatus.test.js | 2 +- test/command/getTxResult.test.js | 2 +- test/command/load.test.js | 2 +- test/command/proposal.test.js | 4 ++-- test/command/wallet.test.js | 2 +- test/constants.js | 2 +- test/rc/index.test.js | 2 +- test/utils/wallet.test.js | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/jest.config.js b/jest.config.js index 201adca..47a51ed 100644 --- a/jest.config.js +++ b/jest.config.js @@ -144,7 +144,7 @@ export default { // The glob patterns Jest uses to detect test files testMatch: [ - // '**/test/utils/utils.test.js' + // '**/test/utils/wallet.test.js' '**/test/command/dappServer/socket-sign.test.js', '**/test/**/?(*.)+(spec|test).[jt]s?(x)' // "**/?(*.)+(spec|test).[tj]s?(x)" diff --git a/test/command/call.test.js b/test/command/call.test.js index f91cf1f..15be62c 100644 --- a/test/command/call.test.js +++ b/test/command/call.test.js @@ -20,7 +20,7 @@ describe('CallCommand', () => { const address = 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { backup = inquirer.prompt; mockOraInstance = { diff --git a/test/command/config.test.js b/test/command/config.test.js index 5442cc6..7ac7740 100644 --- a/test/command/config.test.js +++ b/test/command/config.test.js @@ -19,7 +19,7 @@ describe('ConfigCommand', () => { deleteConfig: jest.fn() }; const endPoint = 'https://tdvw-test-node.aelf.io/'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { mockOraInstance = { start: jest.fn(), diff --git a/test/command/console.test.js b/test/command/console.test.js index 0cad0a9..dd480f9 100644 --- a/test/command/console.test.js +++ b/test/command/console.test.js @@ -19,7 +19,7 @@ describe('ConsoleCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstance = { succeed: jest.fn(), diff --git a/test/command/create.test.js b/test/command/create.test.js index d41137d..e8b1ad3 100644 --- a/test/command/create.test.js +++ b/test/command/create.test.js @@ -15,7 +15,7 @@ describe('CreateCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstance = { succeed: jest.fn(), diff --git a/test/command/deploy.test.js b/test/command/deploy.test.js index 990dd9e..23ff970 100644 --- a/test/command/deploy.test.js +++ b/test/command/deploy.test.js @@ -24,7 +24,7 @@ describe('DeployCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); deployCommand = new DeployCommand(sampleRc); diff --git a/test/command/getBlkHeight.test.js b/test/command/getBlkHeight.test.js index 00a4bf8..820620b 100644 --- a/test/command/getBlkHeight.test.js +++ b/test/command/getBlkHeight.test.js @@ -12,7 +12,7 @@ describe('GetBlkHeightCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getBlkInfo.test.js b/test/command/getBlkInfo.test.js index 52483dc..0d80cde 100644 --- a/test/command/getBlkInfo.test.js +++ b/test/command/getBlkInfo.test.js @@ -14,7 +14,7 @@ describe('GetBlkInfoCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getChainStatus.test.js b/test/command/getChainStatus.test.js index 7a7a63a..b22bb0c 100644 --- a/test/command/getChainStatus.test.js +++ b/test/command/getChainStatus.test.js @@ -12,7 +12,7 @@ describe('GetChainStatusCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getTxResult.test.js b/test/command/getTxResult.test.js index 7bba77a..470ca92 100644 --- a/test/command/getTxResult.test.js +++ b/test/command/getTxResult.test.js @@ -12,7 +12,7 @@ describe('GetTxResultCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/load.test.js b/test/command/load.test.js index 36469f5..d5bef8f 100644 --- a/test/command/load.test.js +++ b/test/command/load.test.js @@ -16,7 +16,7 @@ describe('LoadCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); const privateKey = '9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'; beforeEach(() => { oraInstanceMock = { diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js index 7d0900c..8b44169 100644 --- a/test/command/proposal.test.js +++ b/test/command/proposal.test.js @@ -30,7 +30,7 @@ describe('ProposalCommand processAddressAfterPrompt', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { start: jest.fn(), @@ -62,7 +62,7 @@ describe('ProposalCommand run', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); let mockParliamentContract, mockGenesisContract; beforeEach(() => { oraInstanceMock = { diff --git a/test/command/wallet.test.js b/test/command/wallet.test.js index d49eed7..540b92f 100644 --- a/test/command/wallet.test.js +++ b/test/command/wallet.test.js @@ -15,7 +15,7 @@ describe('WalletCommand', () => { const endPoint = 'https://tdvw-test-node.aelf.io/'; const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../datadir/aelf'); + const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/constants.js b/test/constants.js index f538560..943dc4e 100644 --- a/test/constants.js +++ b/test/constants.js @@ -3,4 +3,4 @@ import path from 'path'; export const endpoint = 'https://tdvw-test-node.aelf.io/'; export const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; export const password = '1234*Qwer'; -export const dataDir = path.resolve(__dirname, './datadir/aelf'); +export const dataDir = path.resolve(__dirname, './dataDir/aelf'); diff --git a/test/rc/index.test.js b/test/rc/index.test.js index c851f14..7fdc4be 100644 --- a/test/rc/index.test.js +++ b/test/rc/index.test.js @@ -21,7 +21,7 @@ describe('Registry', () => { fs.rmdirSync(path.resolve(userHomeDir, 'aelf')); }); test('should get file or not', () => { - const result = Registry.getFileOrNot(path.resolve(__dirname, '../datadir/aelf/.aelfrc')); + const result = Registry.getFileOrNot(path.resolve(__dirname, '../dataDir/aelf/.aelfrc')); expect(result).toBe(`# THIS IS AN AUTOGENERATED FILE FOR AELF-COMMAND OPTIONS. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/test/utils/wallet.test.js b/test/utils/wallet.test.js index 6abbb04..c08ea56 100644 --- a/test/utils/wallet.test.js +++ b/test/utils/wallet.test.js @@ -3,7 +3,7 @@ import fs from 'fs'; import { mkdirpSync } from 'mkdirp'; import { getWallet, saveKeyStore } from '../../src/utils/wallet'; import { endpoint, account, password, dataDir } from '../constants.js'; -import keyJSON from '../datadir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json'; +import keyJSON from '../dataDir/aelf/keys/GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk.json'; jest.mock('inquirer'); jest.mock('mkdirp'); From 7d8c4f23a56735cc19652be4f9d175346f4a1baf Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 12:36:34 +0800 Subject: [PATCH 19/24] feat: coveragePathIgnorePatterns --- jest.config.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jest.config.js b/jest.config.js index 47a51ed..9003436 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,9 +30,7 @@ export default { coverageDirectory: 'coverage', // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], + coveragePathIgnorePatterns: ['/node_modules/', '/src/utils/constants.js', '/src/command/index.js'], // A list of reporter names that Jest uses when writing coverage reports // coverageReporters: [ From 36bcf5bfbe844397aae5c292389e1fa0a0cee7d4 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 14:42:12 +0800 Subject: [PATCH 20/24] feat: logger test --- jest.config.js | 6 +++--- test/utils/Logger.test.js | 38 +++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/jest.config.js b/jest.config.js index 9003436..f9c8fef 100644 --- a/jest.config.js +++ b/jest.config.js @@ -142,9 +142,9 @@ export default { // The glob patterns Jest uses to detect test files testMatch: [ - // '**/test/utils/wallet.test.js' - '**/test/command/dappServer/socket-sign.test.js', - '**/test/**/?(*.)+(spec|test).[jt]s?(x)' + '**/test/utils/Logger.test.js' + // '**/test/command/dappServer/socket-sign.test.js', + // '**/test/**/?(*.)+(spec|test).[jt]s?(x)' // "**/?(*.)+(spec|test).[tj]s?(x)" ], testTimeout: 20000, diff --git a/test/utils/Logger.test.js b/test/utils/Logger.test.js index dcba056..f2fabd3 100644 --- a/test/utils/Logger.test.js +++ b/test/utils/Logger.test.js @@ -13,29 +13,29 @@ describe('Logger', () => { consoleLogSpy.mockRestore(); }); - test(`should log correctly formatted message`, () => { - const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); - const message = 'Test message'; - logger[fnName](message); - const expectedPrefix = `[${level}]: `; - const expectedLog = chalk.gray(`TestLogger ${expectedPrefix}${message}`); - // second params: add spaces - expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, ''); - }); - test(`should return correctly formatted chalk message`, () => { - const logger = new Logger({ log: false, onlyWords: false, name: 'TestLogger' }); - const message = 'Test message'; - const result = logger[fnName](message); - const expectedPrefix = `TestLogger [${level}]: `; - const expectedChalk = chalk(chalk.gray(`${expectedPrefix}${message}`)); - expect(result.trim()).toEqual(expectedChalk); - }); + // test(`should log correctly formatted message`, () => { + // const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); + // const message = 'Test message'; + // logger[fnName](message); + // const expectedPrefix = `[${level}]: `; + // const expectedLog = chalk.gray(`TestLogger ${expectedPrefix}${message}`); + // // second params: add spaces + // expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, ''); + // }); + // test(`should return correctly formatted chalk message`, () => { + // const logger = new Logger({ log: false, onlyWords: false, name: 'TestLogger' }); + // const message = 'Test message'; + // const result = logger[fnName](message); + // const expectedPrefix = `TestLogger [${level}]: `; + // const expectedChalk = chalk(chalk.gray(`${expectedPrefix}${message}`)); + // expect(result.trim()).toEqual(expectedChalk); + // }); test(`should log correctly formatted object message`, () => { const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); const message = { key: 'value' }; logger[fnName](message); const expectedPrefix = `TestLogger [${level}]: \n`; - const expectedLog = chalk.gray(`${expectedPrefix}`).trim(); + const expectedLog = chalk.gray(`${expectedPrefix}`); expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, message); }); test(`should log correctly formatted object message (onlyWords: true)`, () => { @@ -45,7 +45,7 @@ describe('Logger', () => { logger[fnName](message); const expectedPrefix = `* [${level}]: \n`; - const expectedLog = chalk.gray(`${expectedPrefix}`).trim(); + const expectedLog = chalk.gray(`${expectedPrefix}`); expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, message); }); From fdbd422d2a114cd57cb56a064119c2d3623b1f2d Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 14:56:40 +0800 Subject: [PATCH 21/24] feat: logger --- jest.config.js | 6 +++--- test/utils/Logger.test.js | 34 +++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/jest.config.js b/jest.config.js index f9c8fef..bfb233b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -142,9 +142,9 @@ export default { // The glob patterns Jest uses to detect test files testMatch: [ - '**/test/utils/Logger.test.js' - // '**/test/command/dappServer/socket-sign.test.js', - // '**/test/**/?(*.)+(spec|test).[jt]s?(x)' + // '**/test/utils/Logger.test.js' + '**/test/command/dappServer/socket-sign.test.js', + '**/test/**/?(*.)+(spec|test).[jt]s?(x)' // "**/?(*.)+(spec|test).[tj]s?(x)" ], testTimeout: 20000, diff --git a/test/utils/Logger.test.js b/test/utils/Logger.test.js index f2fabd3..c439d6c 100644 --- a/test/utils/Logger.test.js +++ b/test/utils/Logger.test.js @@ -13,23 +13,23 @@ describe('Logger', () => { consoleLogSpy.mockRestore(); }); - // test(`should log correctly formatted message`, () => { - // const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); - // const message = 'Test message'; - // logger[fnName](message); - // const expectedPrefix = `[${level}]: `; - // const expectedLog = chalk.gray(`TestLogger ${expectedPrefix}${message}`); - // // second params: add spaces - // expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, ''); - // }); - // test(`should return correctly formatted chalk message`, () => { - // const logger = new Logger({ log: false, onlyWords: false, name: 'TestLogger' }); - // const message = 'Test message'; - // const result = logger[fnName](message); - // const expectedPrefix = `TestLogger [${level}]: `; - // const expectedChalk = chalk(chalk.gray(`${expectedPrefix}${message}`)); - // expect(result.trim()).toEqual(expectedChalk); - // }); + test(`should log correctly formatted message`, () => { + const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); + const message = 'Test message'; + logger[fnName](message); + const expectedPrefix = `[${level}]: `; + const expectedLog = chalk.gray(`TestLogger ${expectedPrefix}${message}`); + // second params: add spaces + expect(consoleLogSpy).toHaveBeenCalledWith(expectedLog, ''); + }); + test(`should return correctly formatted chalk message`, () => { + const logger = new Logger({ log: false, onlyWords: false, name: 'TestLogger' }); + const message = 'Test message'; + const result = logger[fnName](message); + const expectedPrefix = `TestLogger [${level}]: `; + const expectedChalk = chalk(chalk.gray(`${expectedPrefix}${message}`)); + expect(result.trim()).toEqual(expectedChalk); + }); test(`should log correctly formatted object message`, () => { const logger = new Logger({ log: true, onlyWords: false, name: 'TestLogger' }); const message = { key: 'value' }; From 4ea8708f60d0e929886e59bf59219226f0d65c40 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 15:05:50 +0800 Subject: [PATCH 22/24] feat: coverageReporters --- jest.config.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jest.config.js b/jest.config.js index bfb233b..53e59ea 100644 --- a/jest.config.js +++ b/jest.config.js @@ -33,12 +33,7 @@ export default { coveragePathIgnorePatterns: ['/node_modules/', '/src/utils/constants.js', '/src/command/index.js'], // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], + coverageReporters: ['text', 'json-summary'], // An object that configures minimum threshold enforcement for coverage results // coverageThreshold: null, From 55c08a6314d47c277cfe7e4088a02bd0381dd7f1 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 15:26:03 +0800 Subject: [PATCH 23/24] feat: add constants --- test/command/call.test.js | 8 +++----- test/command/console.test.js | 5 +---- test/command/create.test.js | 5 +---- test/command/deploy.test.js | 5 +---- test/command/getBlkHeight.test.js | 5 +---- test/command/getBlkInfo.test.js | 5 +---- test/command/getChainStatus.test.js | 5 +---- test/command/getTxResult.test.js | 5 +---- test/command/load.test.js | 5 +---- test/command/proposal.test.js | 9 +-------- test/command/wallet.test.js | 5 +---- 11 files changed, 13 insertions(+), 49 deletions(-) diff --git a/test/command/call.test.js b/test/command/call.test.js index 15be62c..e4e52af 100644 --- a/test/command/call.test.js +++ b/test/command/call.test.js @@ -1,12 +1,13 @@ import { Command } from 'commander'; import path from 'path'; import AElf from 'aelf-sdk'; +import inquirer from 'inquirer'; import { CallCommand } from '../../src/command'; import { callCommandUsages, callCommandParameters } from '../../src/utils/constants.js'; import { getContractInstance } from '../../src/utils/utils.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger.js'; -import inquirer from 'inquirer'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; const sampleRc = { getConfigs: jest.fn() }; jest.mock('../../src/utils/myLogger'); @@ -14,13 +15,10 @@ jest.mock('../../src/utils/myLogger'); describe('CallCommand', () => { let callCommand; let mockOraInstance; - const endPoint = 'https://tdvw-test-node.aelf.io/'; const aelf = new AElf(new AElf.providers.HttpProvider(endPoint)); const wallet = AElf.wallet.getWalletByPrivateKey('943df6d39fd1e1cc6ae9813e54f7b9988cf952814f9c31e37744b52594cb4096'); const address = 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); + beforeEach(() => { backup = inquirer.prompt; mockOraInstance = { diff --git a/test/command/console.test.js b/test/command/console.test.js index dd480f9..7cb01e2 100644 --- a/test/command/console.test.js +++ b/test/command/console.test.js @@ -5,6 +5,7 @@ import { Command } from 'commander'; import ConsoleCommand from '../../src/command/console.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('boxen'); jest.mock('repl'); @@ -16,10 +17,6 @@ describe('ConsoleCommand', () => { const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstance = { succeed: jest.fn(), diff --git a/test/command/create.test.js b/test/command/create.test.js index e8b1ad3..96e7f52 100644 --- a/test/command/create.test.js +++ b/test/command/create.test.js @@ -4,6 +4,7 @@ import CreateCommand from '../../src/command/create.js'; import { saveKeyStore } from '../../src/utils/wallet'; import { logger } from '../../src/utils/myLogger'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/wallet'); jest.mock('../../src/utils/myLogger'); @@ -12,10 +13,6 @@ describe('CreateCommand', () => { let createCommand; let oraInstance; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstance = { succeed: jest.fn(), diff --git a/test/command/deploy.test.js b/test/command/deploy.test.js index 23ff970..3d18ba6 100644 --- a/test/command/deploy.test.js +++ b/test/command/deploy.test.js @@ -4,6 +4,7 @@ import path from 'path'; import chalk from 'chalk'; import DeployCommand from '../../src/command/deploy.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('chalk', () => { return { @@ -21,10 +22,6 @@ describe('DeployCommand', () => { let deployCommand; let consoleSpy; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); deployCommand = new DeployCommand(sampleRc); diff --git a/test/command/getBlkHeight.test.js b/test/command/getBlkHeight.test.js index 820620b..270a48e 100644 --- a/test/command/getBlkHeight.test.js +++ b/test/command/getBlkHeight.test.js @@ -2,6 +2,7 @@ import { Command } from 'commander'; import path from 'path'; import GetBlkHeightCommand from '../../src/command/getBlkHeight.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -9,10 +10,6 @@ describe('GetBlkHeightCommand', () => { let getBlkHeightCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getBlkInfo.test.js b/test/command/getBlkInfo.test.js index 0d80cde..53ed52f 100644 --- a/test/command/getBlkInfo.test.js +++ b/test/command/getBlkInfo.test.js @@ -4,6 +4,7 @@ import path from 'path'; import GetBlkInfoCommand from '../../src/command/getBlkInfo.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -11,10 +12,6 @@ describe('GetBlkInfoCommand', () => { let getBlkInfoCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getChainStatus.test.js b/test/command/getChainStatus.test.js index b22bb0c..7347c86 100644 --- a/test/command/getChainStatus.test.js +++ b/test/command/getChainStatus.test.js @@ -2,6 +2,7 @@ import { Command } from 'commander'; import path from 'path'; import GetChainStatusCommand from '../../src/command/getChainStatus.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -9,10 +10,6 @@ describe('GetChainStatusCommand', () => { let getChainStatusCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/getTxResult.test.js b/test/command/getTxResult.test.js index 470ca92..fd5d8a3 100644 --- a/test/command/getTxResult.test.js +++ b/test/command/getTxResult.test.js @@ -2,6 +2,7 @@ import { Command } from 'commander'; import path from 'path'; import GetTxResultCommand from '../../src/command/getTxResult.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -9,10 +10,6 @@ describe('GetTxResultCommand', () => { let getTxResultCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { diff --git a/test/command/load.test.js b/test/command/load.test.js index d5bef8f..95ef3bd 100644 --- a/test/command/load.test.js +++ b/test/command/load.test.js @@ -5,6 +5,7 @@ import LoadCommand from '../../src/command/load.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger'; import { saveKeyStore } from '../../src/utils/wallet'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/wallet'); jest.mock('../../src/utils/myLogger'); @@ -13,10 +14,6 @@ describe('LoadCommand', () => { let loadCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); const privateKey = '9a2c6023e8b2221f4b02f4ccc5128392c1bd968ae45a42fa62848d793fff148f'; beforeEach(() => { oraInstanceMock = { diff --git a/test/command/proposal.test.js b/test/command/proposal.test.js index 8b44169..e1bf002 100644 --- a/test/command/proposal.test.js +++ b/test/command/proposal.test.js @@ -10,6 +10,7 @@ import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger'; import * as utils from '../../src/utils/utils.js'; import { getWallet } from '../../src/utils/wallet.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); jest.mock('inquirer'); @@ -27,10 +28,6 @@ describe('ProposalCommand processAddressAfterPrompt', () => { let proposalCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { start: jest.fn(), @@ -59,10 +56,6 @@ describe('ProposalCommand run', () => { let proposalCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); let mockParliamentContract, mockGenesisContract; beforeEach(() => { oraInstanceMock = { diff --git a/test/command/wallet.test.js b/test/command/wallet.test.js index 540b92f..9b32c43 100644 --- a/test/command/wallet.test.js +++ b/test/command/wallet.test.js @@ -5,6 +5,7 @@ import GetTxResultCommand from '../../src/command/wallet.js'; import { userHomeDir } from '../../src/utils/userHomeDir.js'; import { logger } from '../../src/utils/myLogger.js'; import { getWallet } from '../../src/utils/wallet.js'; +import { endpoint as endPoint, account, password, dataDir } from '../constants.js'; jest.mock('../../src/utils/myLogger'); @@ -12,10 +13,6 @@ describe('WalletCommand', () => { let walletCommand; let oraInstanceMock; const sampleRc = { getConfigs: jest.fn() }; - const endPoint = 'https://tdvw-test-node.aelf.io/'; - const account = 'GyQX6t18kpwaD9XHXe1ToKxfov8mSeTLE9q9NwUAeTE8tULZk'; - const password = '1234*Qwer'; - const dataDir = path.resolve(__dirname, '../dataDir/aelf'); beforeEach(() => { oraInstanceMock = { From 95dbbd206858a5233098dd9ed4d22af13a30326d Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Wed, 26 Jun 2024 17:03:12 +0800 Subject: [PATCH 24/24] feat: version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f5cef9..ed3e9e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aelf-command", - "version": "0.1.47-beta.3", + "version": "0.1.47-beta.4", "description": "A CLI tools for AElf", "main": "src/index.js", "type": "module",