diff --git a/.github/workflows/flow-build-application.yaml b/.github/workflows/flow-build-application.yaml new file mode 100644 index 00000000..9b0f7c3d --- /dev/null +++ b/.github/workflows/flow-build-application.yaml @@ -0,0 +1,91 @@ +## +# Copyright (C) 2022-2023 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: 'Build Application' +on: + workflow_dispatch: + inputs: + enable-unit-tests: + description: 'Unit Testing Enabled' + type: boolean + required: false + default: true + enable-e2e-tests: + description: 'E2E Testing Enabled' + type: boolean + required: false + default: false + enable-snyk-scan: + description: 'Snyk Scan Enabled' + type: boolean + required: false + default: false + push: + branches: + - main + - 'release/*' + +defaults: + run: + shell: bash + +jobs: + code: + name: Code + uses: ./.github/workflows/zxc-compile-code.yaml + + code-style: + name: Code Style + uses: ./.github/workflows/zxc-compile-code.yaml + needs: + - code + with: + custom-job-label: Check + enable-code-style-check: true + + unit-tests: + name: Unit Tests + uses: ./.github/workflows/zxc-compile-code.yaml + if: ${{ github.event_name == 'push' || github.event.inputs.enable-unit-tests == 'true' }} + with: + custom-job-label: Standard + enable-unit-tests: true + + e2e-tests: + name: E2E Tests + uses: ./.github/workflows/zxc-compile-code.yaml + if: ${{ github.event_name == 'push' || github.event.inputs.enable-e2e-tests == 'true' }} + with: + custom-job-label: Standard + enable-e2e-tests: true + + analyze: + name: Analyze + uses: ./.github/workflows/zxc-code-analysis.yaml + needs: + - unit-tests + - e2e-tests + if: ${{ (github.event_name == 'push' || github.event.inputs.enable-unit-tests == 'true' || github.event.inputs.enable-e2e-tests == 'true') && !failure() && !cancelled() }} + with: + custom-job-label: Source Code + #enable-snyk-scan: ${{ github.event_name == 'push' || github.event.inputs.enable-snyk-scan == 'true' }} + enable-codecov-analysis: true + enable-codacy-coverage: true + enable-e2e-coverage-report: ${{ github.event_name == 'push' || github.event.inputs.enable-e2e-tests == 'true' }} + secrets: + snyk-token: ${{ secrets.SNYK_TOKEN }} + codecov-token: ${{ secrets.CODECOV_TOKEN }} + codacy-project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} diff --git a/.github/workflows/flow-pull-request-checks.yaml b/.github/workflows/flow-pull-request-checks.yaml new file mode 100644 index 00000000..12739af9 --- /dev/null +++ b/.github/workflows/flow-pull-request-checks.yaml @@ -0,0 +1,105 @@ +## +# Copyright (C) 2023-2024 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: 'PR Checks' +on: + workflow_dispatch: + pull_request: + types: + - opened + - reopened + - synchronize + +defaults: + run: + shell: bash + +concurrency: + group: pr-checks-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + build: + name: Code + uses: ./.github/workflows/zxc-compile-code.yaml + + code-style: + name: Code Style + uses: ./.github/workflows/zxc-compile-code.yaml + needs: + - build + with: + custom-job-label: Check + enable-code-style-check: true + + unit-tests: + name: Unit Tests + uses: ./.github/workflows/zxc-compile-code.yaml + needs: + - code-style + with: + custom-job-label: Standard + enable-unit-tests: true + + e2e-tests: + name: E2E Tests + uses: ./.github/workflows/zxc-compile-code.yaml + needs: + - code-style + with: + custom-job-label: Standard + enable-e2e-tests: true + + codecov: + name: CodeCov + uses: ./.github/workflows/zxc-code-analysis.yaml + needs: + - unit-tests + - e2e-tests + if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name && github.actor != 'dependabot[bot]' }} + with: + custom-job-label: Standard + enable-codecov-analysis: true + enable-e2e-coverage-report: true + secrets: + codecov-token: ${{ secrets.CODECOV_TOKEN }} + + codacy-coverage: + name: Codacy + uses: ./.github/workflows/zxc-code-analysis.yaml + needs: + - unit-tests + - e2e-tests + if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name && github.actor != 'dependabot[bot]' }} + with: + custom-job-label: Coverage + enable-codacy-coverage: true + enable-e2e-coverage-report: true + secrets: + codacy-project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + +# snyk: +# name: Snyk Scan +# uses: ./.github/workflows/zxc-code-analysis.yaml +# needs: +# - unit-tests +# - e2e-tests +# if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name && github.actor != 'dependabot[bot]' }} +# with: +# custom-job-label: Standard +# enable-snyk-scan: true +# secrets: +# snyk-token: ${{ secrets.SNYK_TOKEN }} diff --git a/.github/workflows/flow-pull-request-formatting.yaml b/.github/workflows/flow-pull-request-formatting.yaml new file mode 100644 index 00000000..c3b9fe7e --- /dev/null +++ b/.github/workflows/flow-pull-request-formatting.yaml @@ -0,0 +1,47 @@ +## +# Copyright (C) 2023 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: 'PR Formatting' +on: + workflow_dispatch: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + +defaults: + run: + shell: bash + +permissions: + contents: read + statuses: write + +concurrency: + group: pr-formatting-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + title-check: + name: Title Check + runs-on: [self-hosted, Linux, medium, ephemeral] + steps: + - name: Check PR Title + uses: aslafy-z/conventional-pr-title-action@a0b851005a0f82ac983a56ead5a8111c0d8e044a # v3.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/zxc-code-analysis.yaml b/.github/workflows/zxc-code-analysis.yaml new file mode 100644 index 00000000..2cd95286 --- /dev/null +++ b/.github/workflows/zxc-code-analysis.yaml @@ -0,0 +1,183 @@ +## +# Copyright (C) 2023-2024 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: 'ZXC: Code Analysis' +# The purpose of this reusable workflow is to perform static code analysis and code coverage reporting. +# This reusable component is called by the following workflows: +# - .github/workflows/flow-pull-request-checks.yaml +# - .github/workflows/flow-build-application.yaml +# +# This workflow is only run if the pull request is coming from the original repository and not a fork. + +on: + workflow_call: + inputs: + enable-codecov-analysis: + description: 'CodeCov Analysis Enabled' + type: boolean + required: false + default: false + enable-codacy-coverage: + description: 'Codacy Coverage Enabled' + type: boolean + required: false + default: false + enable-e2e-coverage-report: + description: 'E2E Coverage Report Enabled' + type: boolean + required: false + default: false + enable-snyk-scan: + description: 'Snyk Scan Enabled' + type: boolean + required: false + default: false + node-version: + description: 'NodeJS Version:' + type: string + required: false + default: '20' + custom-job-label: + description: 'Custom Job Label:' + type: string + required: false + default: 'Analyze' + secrets: + snyk-token: + description: 'The Snyk access token is used by Snyk to analyze the code for vulnerabilities ' + required: false + codecov-token: + description: 'The CodeCov access token is used by CodeCov.io to analyze the code coverage ' + required: false + codacy-project-token: + description: 'The Codacy project token used to report code coverage.' + required: false + +defaults: + run: + shell: bash + +permissions: + contents: read + actions: read + pull-requests: write + checks: write + statuses: write + +jobs: + analyze: + name: ${{ inputs.custom-job-label || 'Analyze' }} + runs-on: [self-hosted, Linux, medium, ephemeral] + steps: + - name: Checkout Code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.workflow_run.head_branch }} + fetch-depth: ${{ inputs.enable-sonar-analysis && '0' || '' }} + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: ${{ inputs.node-version }} + + - name: Download Unit Test Coverage Report + uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 + if: ${{ (inputs.enable-codecov-analysis || inputs.enable-codacy-coverage) && !cancelled() && !failure() }} + with: + name: Unit Test Coverage Report + path: 'coverage/unit' + + - name: Download E2E Coverage Report + uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 + if: ${{ (inputs.enable-codecov-analysis || inputs.enable-codacy-coverage) && inputs.enable-e2e-coverage-report && !cancelled() && !failure() }} + with: + name: E2E Coverage Report + path: 'coverage/e2e' + + - name: Publish To Codecov + uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0 + if: ${{ inputs.enable-codecov-analysis && !cancelled() && !failure() }} + env: + CODECOV_TOKEN: ${{ secrets.codecov-token }} + with: + verbose: true + directory: 'coverage' + + - name: Publish to Codacy + env: + CODACY_PROJECT_TOKEN: ${{ secrets.codacy-project-token }} + if: ${{ inputs.enable-codacy-coverage && !cancelled() && !failure() }} + run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Javascript $(find . -name 'lcov.info' -printf '-r %p ') + + - name: Setup Snyk + env: + SNYK_TOKEN: ${{ secrets.snyk-token }} + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + run: npm install -g snyk snyk-to-html @wcj/html-to-markdown-cli + + - name: Snyk Scan + id: snyk + env: + SNYK_TOKEN: ${{ secrets.snyk-token }} + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + run: snyk test --org=release-engineering-N6EoZVZn3jw4qNuVkiG5Qs --all-projects --severity-threshold=high --json-file-output=snyk-test.json + + - name: Snyk Code + id: snyk-code + env: + SNYK_TOKEN: ${{ secrets.snyk-token }} + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + run: snyk code test --org=release-engineering-N6EoZVZn3jw4qNuVkiG5Qs --severity-threshold=high --json-file-output=snyk-code.json + + - name: Publish Snyk Results + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + run: | + if [[ -f "snyk-test.json" && -n "$(cat snyk-test.json | tr -d '[:space:]')" ]]; then + snyk-to-html -i snyk-test.json -o snyk-test.html --summary + html-to-markdown snyk-test.html -o snyk + cat snyk/snyk-test.html.md >> $GITHUB_STEP_SUMMARY + fi + + - name: Publish Snyk Code Results + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + run: | + if [[ -f "snyk-code.json" && -n "$(cat snyk-code.json | tr -d '[:space:]')" ]]; then + snyk-to-html -i snyk-code.json -o snyk-code.html --summary + html-to-markdown snyk-code.html -o snyk + cat snyk/snyk-code.html.md >> $GITHUB_STEP_SUMMARY + fi + + - name: Check Snyk Files + if: ${{ always() }} + run: | + echo "::group::Snyk File List" + ls -lah snyk* || true + echo "::endgroup::" + echo "::group::Snyk Test Contents" + cat snyk-test.json || true + echo "::endgroup::" + echo "::group::Snyk Code Contents" + cat snyk-code.json || true + echo "::endgroup::" + + - name: Publish Snyk Reports + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: ${{ inputs.enable-snyk-scan && !cancelled() && !failure() }} + with: + name: Snyk Reports + path: | + snyk-*.html + snyk-*.json diff --git a/.github/workflows/zxc-compile-code.yaml b/.github/workflows/zxc-compile-code.yaml new file mode 100644 index 00000000..8cb00648 --- /dev/null +++ b/.github/workflows/zxc-compile-code.yaml @@ -0,0 +1,161 @@ +## +# Copyright (C) 2023-2024 Hedera Hashgraph, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +name: 'ZXC: Compile Code' +# The purpose of this reusable workflow is to compile the code and run the unit tests on every PR and commit. +# This reusable component is called by the following workflows: +# - .github/workflows/flow-pull-request-checks.yaml +# - .github/workflows/flow-build-application.yaml + +on: + workflow_call: + inputs: + enable-unit-tests: + description: 'Unit Testing Enabled' + type: boolean + required: false + default: false + enable-code-style-check: + description: 'Code Style Check Enabled' + type: boolean + required: false + default: false + enable-e2e-tests: + description: 'E2E Testing Enabled' + type: boolean + required: false + default: false + node-version: + description: 'NodeJS Version:' + type: string + required: false + default: '20' + custom-job-label: + description: 'Custom Job Label:' + type: string + required: false + default: 'Compiles' + +defaults: + run: + shell: bash + +permissions: + id-token: write + contents: read + actions: read + pull-requests: write + checks: write + statuses: write + +jobs: + compile: + name: ${{ inputs.custom-job-label || 'Compiles' }} + runs-on: [self-hosted, Linux, medium, ephemeral] + steps: + - name: Checkout Code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: ${{ inputs.node-version }} + cache: npm + + - name: Install Dependencies + id: npm-deps + run: npm ci + + - name: Compile Code + id: compile + run: npm run build + + - name: Check Code Style + if: ${{ inputs.enable-code-style-check && !cancelled() && !failure() }} + run: npm run lint + + - name: Run Unit Tests + if: ${{ inputs.enable-unit-tests && !cancelled() && !failure() }} + run: npm run unit-test + + - name: Publish Unit Test Report + uses: EnricoMi/publish-unit-test-result-action@f355d34d53ad4e7f506f699478db2dd71da9de5f # v2.15.1 + if: ${{ inputs.enable-unit-tests && steps.npm-deps.conclusion == 'success' && !cancelled() }} + with: + check_name: 'Unit Test Results' + files: 'junit.xml' + + - name: Publish Unit Test Coverage Report + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: ${{ inputs.enable-unit-tests && !cancelled() }} + with: + name: Unit Test Coverage Report + path: 'coverage/unit' + + - name: Install Local Node (E2E Tests) + if: ${{ inputs.enable-e2e-tests && !cancelled() && !failure() }} + run: npm install -g @hashgraph/hedera-local + + - name: Setup Local Node (E2E Tests) + id: setup-local-node + if: ${{ inputs.enable-e2e-tests && !cancelled() && !failure() }} + run: hedera start --verbose --detached --full + + - name: Configure E2E Tests + if: ${{ inputs.enable-e2e-tests && !cancelled() && !failure() }} + run: | + mkdir -p "${HOME}/.hedera" + touch "${HOME}/.hedera/.env" + echo "LOCALNET_OPERATOR_ID=0.0.2" >> "${HOME}/.hedera/.env" + echo "LOCALNET_OPERATOR_KEY=302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137" >> "${HOME}/.hedera/.env" + echo "PREVIEWNET_OPERATOR_ID=" >> "${HOME}/.hedera/.env" + echo "PREVIEWNET_OPERATOR_KEY=" >> "${HOME}/.hedera/.env" + echo "TESTNET_OPERATOR_ID=" >> "${HOME}/.hedera/.env" + echo "TESTNET_OPERATOR_KEY=" >> "${HOME}/.hedera/.env" + echo "MAINNET_OPERATOR_ID=" >> "${HOME}/.hedera/.env" + echo "MAINNET_OPERATOR_KEY=" >> "${HOME}/.hedera/.env" + + npm run copy-test-state + npm run rename-test-state + + - name: Run E2E Tests + if: ${{ inputs.enable-e2e-tests && !cancelled() && !failure() }} + run: npm run e2e-test + + - name: Teardown Local Node (E2E Tests) + if: ${{ inputs.enable-e2e-tests && steps.setup-local-node.conclusion == 'success' }} + run: hedera stop + + - name: Publish E2E Test Report + uses: EnricoMi/publish-unit-test-result-action@f355d34d53ad4e7f506f699478db2dd71da9de5f # v2.15.1 + if: ${{ inputs.enable-e2e-tests && steps.npm-deps.conclusion == 'success' && !cancelled() }} + with: + check_name: 'E2E Test Results' + files: 'junit-e2e.xml' + + - name: Publish E2E Coverage Report + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: ${{ inputs.enable-e2e-tests && !cancelled() }} + with: + name: E2E Coverage Report + path: 'coverage/e2e' + + - name: Publish Test Reports + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + if: ${{ inputs.enable-unit-tests && steps.npm-deps.conclusion == 'success' && !cancelled() }} + with: + name: Test Reports + path: 'junit*.xml' diff --git a/.gitignore b/.gitignore index 08c15a9d..b5d692b3 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,9 @@ dist # Visual Studio Code files .vscode/ + +# JUnit test result output +junit*.xml + +# Exclude E2E/Unit test generated state files +src/state/state.json diff --git a/__tests__/commands/network/use.test.ts b/__tests__/commands/network/use.test.ts index b9c21e53..50cd9cfd 100644 --- a/__tests__/commands/network/use.test.ts +++ b/__tests__/commands/network/use.test.ts @@ -1,33 +1,44 @@ -import { baseState } from "../../helpers/state"; -import { Command } from "commander"; -import commands from "../../../src/commands"; -import stateController from "../../../src/state/stateController"; +import { baseState } from '../../helpers/state'; +import { Command } from 'commander'; +import commands from '../../../src/commands'; +import stateController from '../../../src/state/stateController'; -jest.mock("../../../src/state/state"); // Mock the original module -> looks for __mocks__/state.ts in same directory +jest.mock('../../../src/state/state'); // Mock the original module -> looks for __mocks__/state.ts in same directory -describe("network use command", () => { +describe('network use command', () => { const stateControllerSpy = jest.spyOn(stateController, 'saveKey'); beforeEach(() => { - stateController.saveState(baseState); + const stateCopy = { + ...baseState, + // Provide a bogus mainnet operator ID and key + mainnetOperatorId: '0.0.1001', + mainnetOperatorKey: + '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', + }; + + stateController.saveState(stateCopy); }); - describe("network use - success path", () => { + describe('network use - success path', () => { afterEach(() => { // Spy cleanup stateControllerSpy.mockClear(); }); - test("✅ switch to mainnet", async () => { - // Arrange - const program = new Command(); - commands.networkCommands(program); - - // Act - await program.parse(["node", "hedera-cli.ts", "network", "use", "mainnet"]); - - // Assert - expect(stateControllerSpy).toHaveBeenCalledWith('network', 'mainnet'); - }); + test('✅ switch to mainnet', async () => { + // Assert + expect(stateController.get('network')).toEqual('localnet'); + + // Arrange + const program = new Command(); + commands.networkCommands(program); + + // Act + program.parse(['node', 'hedera-cli.ts', 'network', 'use', 'mainnet']); + + // Assert + expect(stateControllerSpy).toHaveBeenCalledWith('network', 'mainnet'); + }); }); }); diff --git a/__tests__/commands/token/create.test.ts b/__tests__/commands/token/create.test.ts index c9828ba5..f77ff88d 100644 --- a/__tests__/commands/token/create.test.ts +++ b/__tests__/commands/token/create.test.ts @@ -110,7 +110,7 @@ describe('token create command', () => { pauseKey: '', feeScheduleKey: '', }, - network: 'testnet', + network: 'localnet', customFees: [], } as Token); expect(saveKeyStateControllerSpy).toHaveBeenCalledWith( diff --git a/__tests__/e2e.test.ts b/__tests__/e2e.test.ts index 5355ebe1..fce45b17 100644 --- a/__tests__/e2e.test.ts +++ b/__tests__/e2e.test.ts @@ -8,8 +8,8 @@ import stateController from '../src/state/stateController'; import api from '../src/api'; import { Logger } from '../src/utils/logger'; - import { Token } from '../types'; +import stateUtils from '../src/utils/state'; const logger = Logger.getInstance(); @@ -44,7 +44,7 @@ describe('End to end tests', () => { /** * E2E testing flow: * - Setup init - * - Switch to testnet + * - Switch to localnet * - Create a new account with specific balance, type, and network and verify it is created * - Transfer part of the balance back to the operator account and verify the balance is correct * - Create a backup of the state file and verify it is created @@ -60,17 +60,17 @@ describe('End to end tests', () => { // Assert const accounts = stateController.get('accounts'); - expect(accounts['testnet-operator']).toBeDefined(); + expect(accounts['localnet-operator']).toBeDefined(); - // Arrange: Change network to testnet + // Arrange: Change network to localnet commands.networkCommands(program); // Act - program.parse(['node', 'hedera-cli.ts', 'network', 'use', 'testnet']); + program.parse(['node', 'hedera-cli.ts', 'network', 'use', 'localnet']); // Assert const network = stateController.get('network'); - expect(network).toEqual('testnet'); + expect(network).toEqual('localnet'); // Arrange: Create a new account with specific balance, type, and network and verify it is created commands.accountCommands(program); @@ -115,7 +115,7 @@ describe('End to end tests', () => { '-f', accountAlias, '-t', - 'testnet-operator', + 'localnet-operator', ]); await new Promise((resolve) => setTimeout(resolve, 7000)); @@ -183,7 +183,7 @@ describe('End to end tests', () => { for (const backup of backups) { fs.unlinkSync(path.join(__dirname, '..', 'src', 'state', backup)); } - }); + }, 60000); /** * E2E testing flow for scripts: @@ -192,20 +192,10 @@ describe('End to end tests', () => { * - Delete script and verify it is deleted in state file */ test('✅ Script features', async () => { - // Arrange: Setup init - commands.setupCommands(program); - - // Act - await program.parseAsync(['node', 'hedera-cli.ts', 'setup', 'init']); - - // Assert - let accounts = stateController.get('accounts'); - expect(accounts['testnet-operator']).toBeDefined(); - // Arrange: Download a script from the internet commands.stateCommands(program); const scriptURL = - 'https://raw.githubusercontent.com/hashgraph/hedera-cli/main/src/commands/script/examples.json'; + 'https://raw.githubusercontent.com/hashgraph/hedera-cli/0e724e64f3c95c41ec4a8765e3a58733891328ea/src/commands/script/examples.json'; // Act await program.parseAsync([ @@ -279,16 +269,6 @@ describe('End to end tests', () => { * - Verify balance by looking up the token balance of account 3 via API */ test('✅ Token features', async () => { - // Arrange: Setup init - commands.setupCommands(program); - - // Act - await program.parseAsync(['node', 'hedera-cli.ts', 'setup', 'init']); - - // Assert - let accounts = stateController.get('accounts'); - expect(accounts['testnet-operator']).toBeDefined(); - // Arrange: Create 3 accounts commands.accountCommands(program); const accountAliasTreasury = 'treasury'; @@ -328,7 +308,7 @@ describe('End to end tests', () => { ]); // Assert - accounts = stateController.get('accounts'); + const accounts = stateController.get('accounts'); expect(accounts[accountAliasTreasury]).toBeDefined(); expect(accounts[accountAliasAdmin]).toBeDefined(); expect(accounts[accountAliasUser]).toBeDefined(); @@ -426,7 +406,11 @@ describe('End to end tests', () => { accounts[accountAliasUser].accountId, ); expect(data.data.balances).toEqual([ - { account: accounts[accountAliasUser].accountId, balance: 1 }, + { + account: accounts[accountAliasUser].accountId, + balance: 1, + decimals: 2, + }, ]); }); @@ -445,7 +429,17 @@ describe('End to end tests', () => { // Assert let accounts = stateController.get('accounts'); - expect(accounts['testnet-operator']).toBeDefined(); + expect(accounts['localnet-operator']).toBeDefined(); + + // Arrange: Change network to localnet + commands.networkCommands(program); + + // Act + program.parse(['node', 'hedera-cli.ts', 'network', 'use', 'localnet']); + + // Assert + const network = stateController.get('network'); + expect(network).toEqual('localnet'); // Arrange: Create 2 accounts commands.accountCommands(program); @@ -521,10 +515,9 @@ describe('End to end tests', () => { // Assert const response = await api.topic.findMessage(Object.keys(topics)[0], 1); // first message - expect(Buffer.from( - response.data.message, - 'base64', - ).toString('ascii')).toEqual(message); // decode buffer + expect( + Buffer.from(response.data.message, 'base64').toString('ascii'), + ).toEqual(message); // decode buffer // Arrange: Find the message and verify it is correct // Act @@ -542,10 +535,9 @@ describe('End to end tests', () => { // Assert expect(logSpy).toHaveBeenCalledWith( - `Message found: "${Buffer.from( - response.data.message, - 'base64', - ).toString('ascii')}"` + `Message found: "${Buffer.from(response.data.message, 'base64').toString( + 'ascii', + )}"`, ); }); }); diff --git a/__tests__/helpers/state.ts b/__tests__/helpers/state.ts index cc4e81e6..d2ed7bb2 100644 --- a/__tests__/helpers/state.ts +++ b/__tests__/helpers/state.ts @@ -1,105 +1,113 @@ -import { Account, State, Script, Topic, Token, DownloadState } from "../../types"; +import { + Account, + State, + Script, + Topic, + Token, + DownloadState, +} from '../../types'; export const baseState: State = { - network: "testnet", - mirrorNodeLocalnet: "http://localhost:5551/api/v1", - mirrorNodePreviewnet: "https://previewnet.mirrornode.hedera.com/api/v1", - mirrorNodeTestnet: "https://testnet.mirrornode.hedera.com/api/v1", - mirrorNodeMainnet: "https://mainnet.mirrornode.hedera.com/api/v1", + network: 'localnet', + mirrorNodeLocalnet: 'http://localhost:5551/api/v1', + mirrorNodePreviewnet: 'https://previewnet.mirrornode.hedera.com/api/v1', + mirrorNodeTestnet: 'https://testnet.mirrornode.hedera.com/api/v1', + mirrorNodeMainnet: 'https://mainnet.mirrornode.hedera.com/api/v1', recording: 0, - recordingScriptName: "", + recordingScriptName: '', scriptExecution: 0, - scriptExecutionName: "", + scriptExecutionName: '', accounts: {}, scripts: {}, tokens: {}, topics: {}, - testnetOperatorKey: "", - testnetOperatorId: "", - mainnetOperatorKey: "", - mainnetOperatorId: "", - previewnetOperatorKey: "", - previewnetOperatorId: "", - localnetOperatorKey: '', - localnetOperatorId: '', - localNodeAddress: '', - localNodeAccountId: '', - localNodeMirrorAddressGRPC: '', + testnetOperatorKey: '', + testnetOperatorId: '', + mainnetOperatorKey: '', + mainnetOperatorId: '', + previewnetOperatorKey: '', + previewnetOperatorId: '', + localnetOperatorKey: + '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', + localnetOperatorId: '0.0.2', + localNodeAddress: '127.0.0.1:50211', + localNodeAccountId: '0.0.3', + localNodeMirrorAddressGRPC: '127.0.0.1:5600', }; /* accounts */ export const alice: Account = { - network: "testnet", - alias: "alice", - accountId: "0.0.6025067", - type: "ED25519", + network: 'localnet', + alias: 'alice', + accountId: '0.0.6025067', + type: 'ED25519', publicKey: - "302a300506032b6570032100052ff6e06c1610e33c1c631fa44c259ab62c7becb7a97932b3d60094d0a2f8ba", - evmAddress: "", - solidityAddress: "00000000000000000000000000000000005bef6b", - solidityAddressFull: "0x00000000000000000000000000000000005bef6b", + '302a300506032b6570032100052ff6e06c1610e33c1c631fa44c259ab62c7becb7a97932b3d60094d0a2f8ba', + evmAddress: '', + solidityAddress: '00000000000000000000000000000000005bef6b', + solidityAddressFull: '0x00000000000000000000000000000000005bef6b', privateKey: - "302e020100300506032b657004220420ece0b15b20e555f66d5f4cd83187567af9613276629d7e15161b0c929ea07697", + '302e020100300506032b657004220420ece0b15b20e555f66d5f4cd83187567af9613276629d7e15161b0c929ea07697', }; export const bob: Account = { - network: "testnet", - alias: "bob", - accountId: "0.0.6025066", - type: "ED25519", + network: 'localnet', + alias: 'bob', + accountId: '0.0.6025066', + type: 'ED25519', publicKey: - "302a300506032b65700321009c7c0a15424226860552f0fd859f3995c55ebf64088214b692f87528f2e3d7e6", - evmAddress: "", - solidityAddress: "00000000000000000000000000000000005bef6a", - solidityAddressFull: "0x00000000000000000000000000000000005bef6a", + '302a300506032b65700321009c7c0a15424226860552f0fd859f3995c55ebf64088214b692f87528f2e3d7e6', + evmAddress: '', + solidityAddress: '00000000000000000000000000000000005bef6a', + solidityAddressFull: '0x00000000000000000000000000000000005bef6a', privateKey: - "302e020100300506032b657004220420b4a0c427a47602aad6ad447dd3a0dc1cd482da23511e08a960c20bcaa77748fa", + '302e020100300506032b657004220420b4a0c427a47602aad6ad447dd3a0dc1cd482da23511e08a960c20bcaa77748fa', }; export const script_basic: Script = { - name: "basic", + name: 'basic', creation: 1697103669402, commands: [ - "network use testnet", - "account create -a random", - "token create-ft -n m -s mm -d 2 -i 1000 -a 302e020100300506032b6570042204202a6568253a539643468dda3128a734c9fcb07a927b3f742719a869db731f9f50 -t 0.0.4536940 -k 302e020100300506032b6570042204202a6568253a539643468dda3128a734c9fcb07a927b3f742719a869db731f9f50", + 'network use testnet', + 'account create -a random', + 'token create-ft -n m -s mm -d 2 -i 1000 -a 302e020100300506032b6570042204202a6568253a539643468dda3128a734c9fcb07a927b3f742719a869db731f9f50 -t 0.0.4536940 -k 302e020100300506032b6570042204202a6568253a539643468dda3128a734c9fcb07a927b3f742719a869db731f9f50', ], - args: {} + args: {}, }; export const token: Token = { - network: "testnet", + network: 'localnet', associations: [], - tokenId: "0.0.6025124", - name: "myToken", - symbol: "MTK", - treasuryId: "0.0.6025067", + tokenId: '0.0.6025124', + name: 'myToken', + symbol: 'MTK', + treasuryId: '0.0.6025067', decimals: 2, initialSupply: 1000, - supplyType: "finite", + supplyType: 'finite', maxSupply: 1000000, keys: { adminKey: - "3030020100300706052b8104000a0422042056ba50eb37387c7d523587652ddd5f1783965277ba781dbddeeb28f1d1a0d946", - pauseKey: "", - kycKey: "", - wipeKey: "", - freezeKey: "", + '3030020100300706052b8104000a0422042056ba50eb37387c7d523587652ddd5f1783965277ba781dbddeeb28f1d1a0d946', + pauseKey: '', + kycKey: '', + wipeKey: '', + freezeKey: '', supplyKey: - "302e020100300506032b657004220420b4a0c427a47602aad6ad447dd3a0dc1cd482da23511e08a960c20bcaa77748fa", - feeScheduleKey: "", + '302e020100300506032b657004220420b4a0c427a47602aad6ad447dd3a0dc1cd482da23511e08a960c20bcaa77748fa', + feeScheduleKey: '', treasuryKey: - "302e020100300506032b657004220420ece0b15b20e555f66d5f4cd83187567af9613276629d7e15161b0c929ea07697", + '302e020100300506032b657004220420ece0b15b20e555f66d5f4cd83187567af9613276629d7e15161b0c929ea07697', }, customFees: [], }; export const topic: Topic = { - network: "testnet", - topicId: "0.0.123", - memo: "test", - adminKey: "", - submitKey: "", + network: 'localnet', + topicId: '0.0.123', + memo: 'test', + adminKey: '', + submitKey: '', }; export const accountState: State = { @@ -162,21 +170,24 @@ export const downloadState: DownloadState = { topics: { [topic.topicId]: topic, }, -} +}; -export const testnetOperatorKey = '302e020100300506032b6570042204202ef1cb430150535aa15bdcc6609ff2ef4ec843eb35f1d0cc655a4cad2130b796'; // dummy account +export const testnetOperatorKey = + '302e020100300506032b6570042204202ef1cb430150535aa15bdcc6609ff2ef4ec843eb35f1d0cc655a4cad2130b796'; // dummy account export const testnetOperatorId = '0.0.7699836'; export const testnetOperatorAccount: Record = { - "testnet-operator": { - accountId: "0.0.7699836", - alias: "testnet-operator", - evmAddress: "", - network: "testnet", - privateKey: "302e020100300506032b6570042204202ef1cb430150535aa15bdcc6609ff2ef4ec843eb35f1d0cc655a4cad2130b796", - publicKey: "302a300506032b6570032100b5416f8c0c2836904c58082e4e4a4e923db30bcf85aa189b41fa91062eb8e98b", - solidityAddress: "0000000000000000000000000000000000757d7c", - solidityAddressFull: "0x0000000000000000000000000000000000757d7c", - type: "ed25519", - } + 'testnet-operator': { + accountId: '0.0.7699836', + alias: 'testnet-operator', + evmAddress: '', + network: 'testnet', + privateKey: + '302e020100300506032b6570042204202ef1cb430150535aa15bdcc6609ff2ef4ec843eb35f1d0cc655a4cad2130b796', + publicKey: + '302a300506032b6570032100b5416f8c0c2836904c58082e4e4a4e923db30bcf85aa189b41fa91062eb8e98b', + solidityAddress: '0000000000000000000000000000000000757d7c', + solidityAddressFull: '0x0000000000000000000000000000000000757d7c', + type: 'ed25519', + }, }; diff --git a/jest.config.js b/jest.config.js index c205ee96..1da2f9c3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,5 +5,6 @@ module.exports = { testTimeout: 40000, testPathIgnorePatterns: [ "/__tests__/helpers/" - ] -}; \ No newline at end of file + ], + reporters: ['default', 'jest-junit'] +}; diff --git a/package-lock.json b/package-lock.json index 61bbebe3..9cd07f11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", "jest": "^29.7.0", + "jest-junit": "^16.0.0", "prettier": "^3.1.1", "rimraf": "^5.0.5", "ts-jest": "^29.1.1", @@ -5484,6 +5485,21 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", @@ -7933,6 +7949,15 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", @@ -8058,6 +8083,12 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -11997,6 +12028,18 @@ "walker": "^1.0.8" } }, + "jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + } + }, "jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", @@ -13826,6 +13869,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, "v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", @@ -13917,6 +13966,12 @@ "signal-exit": "^3.0.7" } }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index eef75287..7b741f4b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "module": "esnext", "scripts": { "build": "npm run format && rimraf --glob 'dist/' && tsc && npm run copy-state && npm run rename-base-state && npm run copy-input", + "clean": "rm -rf dist/ && rm -rf coverage/ && rm -rf junit.xml && rm -rf junit-e2e.xml", "dev-build": "rm -rf dist/ && tsc && npm run copy-test-state && npm run copy-input && npm run rename-test-state && npm run watch", "watch": "tsc --watch", "copy-test-state": "copyfiles -u 2 src/state/test_state.json dist/state/", @@ -16,8 +17,8 @@ "copy-input": "copyfiles -u 2 src/input/*.json dist/input/", "lint": "eslint 'src/**/*.{js,ts,tsx}' --quiet", "format": "prettier --write 'src/**/*.{js,ts,tsx}'", - "unit-test": "jest -- __tests__/commands/**/*.test.ts", - "e2e-test": "jest -- __tests__/e2e.test.ts --runInBand", + "unit-test": "JEST_SUITE_NAME='Unit Tests' JEST_JUNIT_OUTPUT_NAME='junit.xml' jest --coverage --coverageDirectory='coverage/unit' -- __tests__/commands/**/*.test.ts", + "e2e-test": "JEST_SUITE_NAME='E2E Tests' JEST_JUNIT_OUTPUT_NAME='junit-e2e.xml' jest --coverage --coverageDirectory='coverage/e2e' -- __tests__/e2e.test.ts --runInBand", "test": "npm run unit-test && npm run e2e-test", "single-test": "jest" }, @@ -47,6 +48,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", "jest": "^29.7.0", + "jest-junit": "^16.0.0", "prettier": "^3.1.1", "rimraf": "^5.0.5", "ts-jest": "^29.1.1", diff --git a/src/commands/script/examples.json b/src/commands/script/examples.json index f7fc51d1..a56dde2f 100644 --- a/src/commands/script/examples.json +++ b/src/commands/script/examples.json @@ -1,49 +1,45 @@ { - "scripts": { - "script-token": { - "name": "token", - "commands": [ - "network use testnet", - "account create -a random --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", - "account create -a random --args privateKey,privKeyAcc2 --args alias,aliasAcc2 --args accountId,idAcc2", - "account create -a random --args privateKey,privKeyAcc3 --args alias,aliasAcc3 --args accountId,idAcc3", - "token create -n mytoken -s MTK -d 2 -i 1000 --supply-type infinite -a {{privKeyAcc1}} -t {{idAcc2}} -k {{privKeyAcc2}} --args tokenId,tokenId", - "token associate --account-id {{idAcc3}} --token-id {{tokenId}}", - "token transfer -t {{tokenId}} -b 1 --from {{aliasAcc2}} --to {{aliasAcc3}}", - "wait 3", - "account balance --account-id-or-alias {{aliasAcc3}} --token-id {{tokenId}}", - "state view --token-id {{tokenId}}" - ] - }, - "script-account-create": { - "name": "account-create", - "commands": [ - "network use testnet", - "account create -a random -b 10000000 --type ecdsa --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", - "wait 5", - "account balance --account-id-or-alias {{idAcc1}} --only-hbar" - ] - }, - "script-account-create-simple": { - "name": "account-create-simple", - "creation": 1706620441200, - "commands": [ - "network use testnet", - "account create -a random -b 10000000 --type ecdsa --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", - "wait 5" - ], - "args": {} - }, - "script-topic-create": { - "name": "topic-create", - "creation": 1697103669402, - "commands": [ - "network use testnet", - "account create -a random --args privateKey,privKeyAdmin", - "account create -a random --args privateKey,privKeySubmit", - "topic create --admin-key {{privKeyAdmin}} --submit-key {{privKeySubmit}} --args topicId,topicId" - ], - "args": {} - } + "scripts": { + "script-token": { + "name": "token", + "commands": [ + "account create -a random --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", + "account create -a random --args privateKey,privKeyAcc2 --args alias,aliasAcc2 --args accountId,idAcc2", + "account create -a random --args privateKey,privKeyAcc3 --args alias,aliasAcc3 --args accountId,idAcc3", + "token create -n mytoken -s MTK -d 2 -i 1000 --supply-type infinite -a {{privKeyAcc1}} -t {{idAcc2}} -k {{privKeyAcc2}} --args tokenId,tokenId", + "token associate --account-id {{idAcc3}} --token-id {{tokenId}}", + "token transfer -t {{tokenId}} -b 1 --from {{aliasAcc2}} --to {{aliasAcc3}}", + "wait 3", + "account balance --account-id-or-alias {{aliasAcc3}} --token-id {{tokenId}}", + "state view --token-id {{tokenId}}" + ] + }, + "script-account-create": { + "name": "account-create", + "commands": [ + "account create -a random -b 10000000 --type ecdsa --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", + "wait 5", + "account balance --account-id-or-alias {{idAcc1}} --only-hbar" + ] + }, + "script-account-create-simple": { + "name": "account-create-simple", + "creation": 1706620441200, + "commands": [ + "account create -a random -b 10000000 --type ecdsa --args privateKey,privKeyAcc1 --args alias,aliasAcc1 --args accountId,idAcc1", + "wait 5" + ], + "args": {} + }, + "script-topic-create": { + "name": "topic-create", + "creation": 1697103669402, + "commands": [ + "account create -a random --args privateKey,privKeyAdmin", + "account create -a random --args privateKey,privKeySubmit", + "topic create --admin-key {{privKeyAdmin}} --submit-key {{privKeySubmit}} --args topicId,topicId" + ], + "args": {} } - } \ No newline at end of file + } +} diff --git a/src/state/base_state.json b/src/state/base_state.json index 14bcfa68..db3bc6ec 100644 --- a/src/state/base_state.json +++ b/src/state/base_state.json @@ -22,13 +22,7 @@ "scripts": { "script-init": { "name": "init", - "commands": [ - "network use testnet", - "account create -a alice -b 1000000000 --type ecdsa", - "account create -a bob -b 1000000000 --type ecdsa", - "account create -a clarice -b 1000000000 --type ecdsa", - "state download --url https://raw.githubusercontent.com/hashgraph/hedera-cli/main/src/commands/script/examples.json --merge" - ] + "commands": [] } }, "localNodeAddress": "127.0.0.1:50211", diff --git a/src/state/config.ts b/src/state/config.ts index a7d86117..394927da 100644 --- a/src/state/config.ts +++ b/src/state/config.ts @@ -1,5 +1,5 @@ export default { - network: 'testnet', + network: 'localnet', mirrorNodeLocalnet: 'http://localhost:5551/api/v1', mirrorNodePreviewnet: 'https://previewnet.mirrornode.hedera.com/api/v1', mirrorNodeTestnet: 'https://testnet.mirrornode.hedera.com/api/v1', @@ -18,8 +18,9 @@ export default { testnetOperatorId: '', mainnetOperatorKey: '', mainnetOperatorId: '', - localnetOperatorKey: '', - localnetOperatorId: '', + localnetOperatorKey: + '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', + localnetOperatorId: '0.0.2', localNodeAddress: '127.0.0.1:50211', localNodeAccountId: '0.0.3', localNodeMirrorAddressGRPC: '127.0.0.1:5600', diff --git a/src/state/state.json b/src/state/state.json index 14bcfa68..d994fb91 100644 --- a/src/state/state.json +++ b/src/state/state.json @@ -1,36 +1,25 @@ { - "network": "testnet", + "network": "localnet", "mirrorNodeLocalnet": "http://localhost:5551/api/v1", "mirrorNodePreviewnet": "https://previewnet.mirrornode.hedera.com/api/v1", "mirrorNodeTestnet": "https://testnet.mirrornode.hedera.com/api/v1", "mirrorNodeMainnet": "https://mainnet.mirrornode.hedera.com/api/v1", - "testnetOperatorKey": "", - "testnetOperatorId": "", - "mainnetOperatorKey": "", - "mainnetOperatorId": "", - "previewnetOperatorId": "", - "previewnetOperatorKey": "", - "localnetOperatorKey": "", - "localnetOperatorId": "", "recording": 0, "recordingScriptName": "", "scriptExecution": 0, "scriptExecutionName": "", "accounts": {}, + "scripts": {}, "tokens": {}, "topics": {}, - "scripts": { - "script-init": { - "name": "init", - "commands": [ - "network use testnet", - "account create -a alice -b 1000000000 --type ecdsa", - "account create -a bob -b 1000000000 --type ecdsa", - "account create -a clarice -b 1000000000 --type ecdsa", - "state download --url https://raw.githubusercontent.com/hashgraph/hedera-cli/main/src/commands/script/examples.json --merge" - ] - } - }, + "testnetOperatorKey": "", + "testnetOperatorId": "", + "mainnetOperatorKey": "", + "mainnetOperatorId": "", + "previewnetOperatorKey": "", + "previewnetOperatorId": "", + "localnetOperatorKey": "302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137", + "localnetOperatorId": "0.0.2", "localNodeAddress": "127.0.0.1:50211", "localNodeAccountId": "0.0.3", "localNodeMirrorAddressGRPC": "127.0.0.1:5600" diff --git a/src/state/test_state.json b/src/state/test_state.json new file mode 100644 index 00000000..55f9f6e5 --- /dev/null +++ b/src/state/test_state.json @@ -0,0 +1,32 @@ +{ + "network": "localnet", + "mirrorNodeLocalnet": "http://localhost:5551/api/v1", + "mirrorNodePreviewnet": "https://previewnet.mirrornode.hedera.com/api/v1", + "mirrorNodeTestnet": "https://testnet.mirrornode.hedera.com/api/v1", + "mirrorNodeMainnet": "https://mainnet.mirrornode.hedera.com/api/v1", + "testnetOperatorKey": "", + "testnetOperatorId": "", + "mainnetOperatorKey": "", + "mainnetOperatorId": "", + "previewnetOperatorId": "", + "previewnetOperatorKey": "", + "localnetOperatorKey": "302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137", + "localnetOperatorId": "0.0.2", + "recording": 0, + "recordingScriptName": "", + "scriptExecution": 0, + "scriptExecutionName": "", + "accounts": {}, + "tokens": {}, + "topics": {}, + "scripts": { + "script-init": { + "name": "init", + "commands": [ + ] + } + }, + "localNodeAddress": "127.0.0.1:50211", + "localNodeAccountId": "0.0.3", + "localNodeMirrorAddressGRPC": "127.0.0.1:5600" +} diff --git a/src/utils/state.ts b/src/utils/state.ts index 0c42ebe7..f7e02596 100644 --- a/src/utils/state.ts +++ b/src/utils/state.ts @@ -147,7 +147,7 @@ function switchNetwork(name: string) { const state = stateController.getAll(); let operatorId, operatorKey; - switch (state.network) { + switch (name) { case 'mainnet': operatorId = state.mainnetOperatorId; operatorKey = state.mainnetOperatorKey; @@ -167,7 +167,7 @@ function switchNetwork(name: string) { } if (operatorId === '' || operatorKey === '') { - logger.error(`operator key and ID not set for ${state.network}`); + logger.error(`operator key and ID not set for ${name}`); process.exit(1); }