From ae26254423e8f36bfb00e900aa7e5e783909c074 Mon Sep 17 00:00:00 2001 From: Yaro Shkvorets Date: Wed, 11 Dec 2024 17:06:47 -0500 Subject: [PATCH] refactor tests to use snapshots (#1824) --- .../codegen/__snapshots__/abi.test.ts.snap | 961 ++++++++++++++++++ .../protocols/ethereum/codegen/abi.test.ts | 155 +-- .../__snapshots__/cosmos.test.ts.snap | 69 ++ .../__snapshots__/ethereum.test.ts.snap | 438 ++++++++ .../scaffold/__snapshots__/near.test.ts.snap | 71 ++ packages/cli/src/scaffold/cosmos.test.ts | 67 +- packages/cli/src/scaffold/ethereum.test.ts | 429 +------- packages/cli/src/scaffold/near.test.ts | 69 +- 8 files changed, 1562 insertions(+), 697 deletions(-) create mode 100644 packages/cli/src/protocols/ethereum/codegen/__snapshots__/abi.test.ts.snap create mode 100644 packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap create mode 100644 packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap create mode 100644 packages/cli/src/scaffold/__snapshots__/near.test.ts.snap diff --git a/packages/cli/src/protocols/ethereum/codegen/__snapshots__/abi.test.ts.snap b/packages/cli/src/protocols/ethereum/codegen/__snapshots__/abi.test.ts.snap new file mode 100644 index 00000000..7da206be --- /dev/null +++ b/packages/cli/src/protocols/ethereum/codegen/__snapshots__/abi.test.ts.snap @@ -0,0 +1,961 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ABI code generation > Generated types > Type generated 1`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toI32() + ", + "name": "get result", + "params": [], + "returnType": "i32", + }, + Method { + "body": " + return this[1].toAddress() + ", + "name": "get target", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[2].toBytes() + ", + "name": "get data", + "params": [], + "returnType": "Bytes", + }, + Method { + "body": " + return this[3].toAddress() + ", + "name": "get proposer", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[4].toAddress() + ", + "name": "get feeRecipient", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[5].toBigInt() + ", + "name": "get fee", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[6].toBigInt() + ", + "name": "get startTime", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[7].toBigInt() + ", + "name": "get yesCount", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[8].toBigInt() + ", + "name": "get noCount", + "params": [], + "returnType": "BigInt", + }, + ], + "name": "Contract__getProposalResultValue0Struct", +} +`; + +exports[`ABI code generation > Generated types > Type generated 2`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toI32() + ", + "name": "get foo", + "params": [], + "returnType": "i32", + }, + Method { + "body": " + return changetype(this[1].toTuple()) + ", + "name": "get bar", + "params": [], + "returnType": "Contract__getProposalInputParam1BarStruct", + }, + ], + "name": "Contract__getProposalInputParam1Struct", +} +`; + +exports[`ABI code generation > Generated types > Type generated 3`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toAddress() + ", + "name": "get baz", + "params": [], + "returnType": "Address", + }, + ], + "name": "Contract__getProposalInputParam1BarStruct", +} +`; + +exports[`ABI code generation > Generated types > Type generated 4`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toBigInt() + ", + "name": "get first", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[1].toString() + ", + "name": "get second", + "params": [], + "returnType": "string", + }, + ], + "name": "Contract__getProposalsResultValue1Struct", +} +`; + +exports[`ABI code generation > Generated types > Type generated 5`] = ` +Class { + "export": true, + "extends": undefined, + "members": [ + ClassMember { + "name": "value0", + "type": "BigInt", + }, + ClassMember { + "name": "value1", + "type": "Array", + }, + ], + "methods": [ + Method { + "body": "this.value0 = value0 +this.value1 = value1", + "name": "constructor", + "params": Immutable.List [ + Param { + "name": "value0", + "type": "BigInt", + }, + Param { + "name": "value1", + "type": "Array", + }, + ], + "returnType": null, + }, + Method { + "body": " + let map = new TypedMap(); + map.set('value0', ethereum.Value.fromUnsignedBigInt(this.value0));map.set('value1', ethereum.Value.fromTupleArray(this.value1)) + return map; + ", + "name": "toMap", + "params": [], + "returnType": NamedType { + "name": "TypedMap", + }, + }, + Method { + "body": "return this.value0;", + "name": "getSize", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": "return this.value1;", + "name": "getValue1", + "params": [], + "returnType": "Array", + }, + ], + "name": "Contract__getProposalsResult", +} +`; + +exports[`ABI code generation > Generated types > Type generated 6`] = ` +Class { + "export": true, + "extends": "ethereum.SmartContract", + "members": [], + "methods": [ + StaticMethod { + "body": " + return new Contract('Contract', address); + ", + "name": "bind", + "params": Immutable.List [ + Param { + "name": "address", + "type": "Address", + }, + ], + "returnType": NamedType { + "name": "Contract", + }, + }, + Method { + "body": " + + let result = super.call( + 'read', + 'read():(bytes32)', + []) + + return ( result[0].toBytes())", + "name": "read", + "params": Immutable.List [], + "returnType": NamedType { + "name": "Bytes", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'read', + 'read():(bytes32)', + []) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toBytes())", + "name": "try_read", + "params": Immutable.List [], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'getProposal', + 'getProposal(uint256,(uint8,(address))):((uint8,address,bytes,address,address,uint256,uint256,uint256,uint256))', + [ethereum.Value.fromUnsignedBigInt(proposalId), ethereum.Value.fromTuple(param1)]) + + return ( changetype(result[0].toTuple()))", + "name": "getProposal", + "params": Immutable.List [ + Param { + "name": "proposalId", + "type": "BigInt", + }, + Param { + "name": "param1", + "type": "Contract__getProposalInputParam1Struct", + }, + ], + "returnType": NamedType { + "name": "Contract__getProposalResultValue0Struct", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'getProposal', + 'getProposal(uint256,(uint8,(address))):((uint8,address,bytes,address,address,uint256,uint256,uint256,uint256))', + [ethereum.Value.fromUnsignedBigInt(proposalId), ethereum.Value.fromTuple(param1)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( changetype(value[0].toTuple()))", + "name": "try_getProposal", + "params": Immutable.List [ + Param { + "name": "proposalId", + "type": "BigInt", + }, + Param { + "name": "param1", + "type": "Contract__getProposalInputParam1Struct", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'getProposals', + 'getProposals():(uint256,(uint256,string)[])', + []) + + return ( new Contract__getProposalsResult( + result[0].toBigInt(), result[1].toTupleArray() + ))", + "name": "getProposals", + "params": Immutable.List [], + "returnType": NamedType { + "name": "Contract__getProposalsResult", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'getProposals', + 'getProposals():(uint256,(uint256,string)[])', + []) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( new Contract__getProposalsResult( + value[0].toBigInt(), value[1].toTupleArray() + ))", + "name": "try_getProposals", + "params": Immutable.List [], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(string):(string)', + [ethereum.Value.fromString(param0)]) + + return ( result[0].toString())", + "name": "overloaded", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "string", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(string):(string)', + [ethereum.Value.fromString(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "string", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(uint256):(string)', + [ethereum.Value.fromUnsignedBigInt(param0)]) + + return ( result[0].toString())", + "name": "overloaded1", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "BigInt", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(uint256):(string)', + [ethereum.Value.fromUnsignedBigInt(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded1", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "BigInt", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(bytes32):(string)', + [ethereum.Value.fromFixedBytes(param0)]) + + return ( result[0].toString())", + "name": "overloaded2", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "Bytes", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(bytes32):(string)', + [ethereum.Value.fromFixedBytes(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded2", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "Bytes", + }, + ], + "returnType": "ethereum.CallResult", + }, + ], + "name": "Contract", +} +`; + +exports[`ABI code generation > Generated types > Type test 1`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toI32() + ", + "name": "get result", + "params": [], + "returnType": "i32", + }, + Method { + "body": " + return this[1].toAddress() + ", + "name": "get target", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[2].toBytes() + ", + "name": "get data", + "params": [], + "returnType": "Bytes", + }, + Method { + "body": " + return this[3].toAddress() + ", + "name": "get proposer", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[4].toAddress() + ", + "name": "get feeRecipient", + "params": [], + "returnType": "Address", + }, + Method { + "body": " + return this[5].toBigInt() + ", + "name": "get fee", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[6].toBigInt() + ", + "name": "get startTime", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[7].toBigInt() + ", + "name": "get yesCount", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[8].toBigInt() + ", + "name": "get noCount", + "params": [], + "returnType": "BigInt", + }, + ], + "name": "Contract__getProposalResultValue0Struct", +} +`; + +exports[`ABI code generation > Generated types > Type test 2`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toI32() + ", + "name": "get foo", + "params": [], + "returnType": "i32", + }, + Method { + "body": " + return changetype(this[1].toTuple()) + ", + "name": "get bar", + "params": [], + "returnType": "Contract__getProposalInputParam1BarStruct", + }, + ], + "name": "Contract__getProposalInputParam1Struct", +} +`; + +exports[`ABI code generation > Generated types > Type test 3`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toAddress() + ", + "name": "get baz", + "params": [], + "returnType": "Address", + }, + ], + "name": "Contract__getProposalInputParam1BarStruct", +} +`; + +exports[`ABI code generation > Generated types > Type test 4`] = ` +Class { + "export": true, + "extends": "ethereum.Tuple", + "members": [], + "methods": [ + Method { + "body": " + return this[0].toBigInt() + ", + "name": "get first", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": " + return this[1].toString() + ", + "name": "get second", + "params": [], + "returnType": "string", + }, + ], + "name": "Contract__getProposalsResultValue1Struct", +} +`; + +exports[`ABI code generation > Generated types > Type test 5`] = ` +Class { + "export": true, + "extends": undefined, + "members": [ + ClassMember { + "name": "value0", + "type": "BigInt", + }, + ClassMember { + "name": "value1", + "type": "Array", + }, + ], + "methods": [ + Method { + "body": "this.value0 = value0 +this.value1 = value1", + "name": "constructor", + "params": Immutable.List [ + Param { + "name": "value0", + "type": "BigInt", + }, + Param { + "name": "value1", + "type": "Array", + }, + ], + "returnType": null, + }, + Method { + "body": " + let map = new TypedMap(); + map.set('value0', ethereum.Value.fromUnsignedBigInt(this.value0));map.set('value1', ethereum.Value.fromTupleArray(this.value1)) + return map; + ", + "name": "toMap", + "params": [], + "returnType": NamedType { + "name": "TypedMap", + }, + }, + Method { + "body": "return this.value0;", + "name": "getSize", + "params": [], + "returnType": "BigInt", + }, + Method { + "body": "return this.value1;", + "name": "getValue1", + "params": [], + "returnType": "Array", + }, + ], + "name": "Contract__getProposalsResult", +} +`; + +exports[`ABI code generation > Generated types > Type test 6`] = ` +Class { + "export": true, + "extends": "ethereum.SmartContract", + "members": [], + "methods": [ + StaticMethod { + "body": " + return new Contract('Contract', address); + ", + "name": "bind", + "params": Immutable.List [ + Param { + "name": "address", + "type": "Address", + }, + ], + "returnType": NamedType { + "name": "Contract", + }, + }, + Method { + "body": " + + let result = super.call( + 'read', + 'read():(bytes32)', + []) + + return ( result[0].toBytes())", + "name": "read", + "params": Immutable.List [], + "returnType": NamedType { + "name": "Bytes", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'read', + 'read():(bytes32)', + []) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toBytes())", + "name": "try_read", + "params": Immutable.List [], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'getProposal', + 'getProposal(uint256,(uint8,(address))):((uint8,address,bytes,address,address,uint256,uint256,uint256,uint256))', + [ethereum.Value.fromUnsignedBigInt(proposalId), ethereum.Value.fromTuple(param1)]) + + return ( changetype(result[0].toTuple()))", + "name": "getProposal", + "params": Immutable.List [ + Param { + "name": "proposalId", + "type": "BigInt", + }, + Param { + "name": "param1", + "type": "Contract__getProposalInputParam1Struct", + }, + ], + "returnType": NamedType { + "name": "Contract__getProposalResultValue0Struct", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'getProposal', + 'getProposal(uint256,(uint8,(address))):((uint8,address,bytes,address,address,uint256,uint256,uint256,uint256))', + [ethereum.Value.fromUnsignedBigInt(proposalId), ethereum.Value.fromTuple(param1)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( changetype(value[0].toTuple()))", + "name": "try_getProposal", + "params": Immutable.List [ + Param { + "name": "proposalId", + "type": "BigInt", + }, + Param { + "name": "param1", + "type": "Contract__getProposalInputParam1Struct", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'getProposals', + 'getProposals():(uint256,(uint256,string)[])', + []) + + return ( new Contract__getProposalsResult( + result[0].toBigInt(), result[1].toTupleArray() + ))", + "name": "getProposals", + "params": Immutable.List [], + "returnType": NamedType { + "name": "Contract__getProposalsResult", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'getProposals', + 'getProposals():(uint256,(uint256,string)[])', + []) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( new Contract__getProposalsResult( + value[0].toBigInt(), value[1].toTupleArray() + ))", + "name": "try_getProposals", + "params": Immutable.List [], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(string):(string)', + [ethereum.Value.fromString(param0)]) + + return ( result[0].toString())", + "name": "overloaded", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "string", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(string):(string)', + [ethereum.Value.fromString(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "string", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(uint256):(string)', + [ethereum.Value.fromUnsignedBigInt(param0)]) + + return ( result[0].toString())", + "name": "overloaded1", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "BigInt", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(uint256):(string)', + [ethereum.Value.fromUnsignedBigInt(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded1", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "BigInt", + }, + ], + "returnType": "ethereum.CallResult", + }, + Method { + "body": " + + let result = super.call( + 'overloaded', + 'overloaded(bytes32):(string)', + [ethereum.Value.fromFixedBytes(param0)]) + + return ( result[0].toString())", + "name": "overloaded2", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "Bytes", + }, + ], + "returnType": NamedType { + "name": "string", + }, + }, + Method { + "body": " + + let result = super.tryCall( + 'overloaded', + 'overloaded(bytes32):(string)', + [ethereum.Value.fromFixedBytes(param0)]) + if (result.reverted) { + return new ethereum.CallResult() + } + let value = result.value + return ethereum.CallResult.fromValue( value[0].toString())", + "name": "try_overloaded2", + "params": Immutable.List [ + Param { + "name": "param0", + "type": "Bytes", + }, + ], + "returnType": "ethereum.CallResult", + }, + ], + "name": "Contract", +} +`; diff --git a/packages/cli/src/protocols/ethereum/codegen/abi.test.ts b/packages/cli/src/protocols/ethereum/codegen/abi.test.ts index 07ed2d3b..a274559a 100644 --- a/packages/cli/src/protocols/ethereum/codegen/abi.test.ts +++ b/packages/cli/src/protocols/ethereum/codegen/abi.test.ts @@ -1,14 +1,12 @@ import path from 'node:path'; import fs from 'fs-extra'; -import immutable from 'immutable'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import * as ts from '../../../codegen/typescript.js'; import ABI from '../abi.js'; import AbiCodeGenerator from './abi.js'; let tempdir: string; let abi: ABI; -let generatedTypes: any[]; +let generatedTypes: any[] = []; describe.concurrent('ABI code generation', () => { beforeAll(async () => { @@ -179,153 +177,10 @@ describe.concurrent('ABI code generation', () => { }); describe('Generated types', () => { - test('All expected types are generated', () => { - expect(generatedTypes.map(type => type.name)).toEqual([ - 'Contract__getProposalResultValue0Struct', - 'Contract__getProposalInputParam1Struct', - 'Contract__getProposalInputParam1BarStruct', - 'Contract__getProposalsResultValue1Struct', - 'Contract__getProposalsResult', - 'Contract', - ]); - }); - }); - - describe('Contract class', () => { - test('Exists', () => { - expect(generatedTypes.find(type => type.name === 'Contract')).toBeDefined(); - }); - - test('Has methods', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - expect(contract.methods).toBeInstanceOf(Array); - }); - - test('Has `bind` method', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - expect(contract.methods.find((method: any) => method.name === 'bind')).toBeDefined(); - }); - - test('Has methods for all callable functions', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - expect(contract.methods.map((method: any) => method.name)).toContain('getProposal'); - }); - }); - - describe('Methods for callable functions', () => { - test('Have correct parameters', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - expect(contract.methods.map((method: any) => [method.name, method.params])).toEqual([ - ['bind', immutable.List([ts.param('address', 'Address')])], - ['read', immutable.List()], - ['try_read', immutable.List()], - [ - 'getProposal', - immutable.List([ - ts.param('proposalId', 'BigInt'), - ts.param('param1', 'Contract__getProposalInputParam1Struct'), - ]), - ], - [ - 'try_getProposal', - immutable.List([ - ts.param('proposalId', 'BigInt'), - ts.param('param1', 'Contract__getProposalInputParam1Struct'), - ]), - ], - ['getProposals', immutable.List()], - ['try_getProposals', immutable.List()], - ['overloaded', immutable.List([ts.param('param0', 'string')])], - ['try_overloaded', immutable.List([ts.param('param0', 'string')])], - ['overloaded1', immutable.List([ts.param('param0', 'BigInt')])], - ['try_overloaded1', immutable.List([ts.param('param0', 'BigInt')])], - ['overloaded2', immutable.List([ts.param('param0', 'Bytes')])], - ['try_overloaded2', immutable.List([ts.param('param0', 'Bytes')])], - ]); - }); - - test('Have correct return types', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - expect(contract.methods.map((method: any) => [method.name, method.returnType])).toEqual([ - ['bind', ts.namedType('Contract')], - ['read', ts.namedType('Bytes')], - ['try_read', 'ethereum.CallResult'], - ['getProposal', ts.namedType('Contract__getProposalResultValue0Struct')], - ['try_getProposal', 'ethereum.CallResult'], - ['getProposals', ts.namedType('Contract__getProposalsResult')], - ['try_getProposals', 'ethereum.CallResult'], - ['overloaded', ts.namedType('string')], - ['try_overloaded', 'ethereum.CallResult'], - ['overloaded1', ts.namedType('string')], - ['try_overloaded1', 'ethereum.CallResult'], - ['overloaded2', ts.namedType('string')], - ['try_overloaded2', 'ethereum.CallResult'], - ]); - }); - }); - - describe('Tuples', () => { - test('Tuple types exist for function parameters', () => { - let tupleType = generatedTypes.find( - type => type.name === 'Contract__getProposalInputParam1Struct', - ); - - // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined(); - - // Verify that the tuple type has getters for all tuple fields with - // the right return types - expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ - ['get foo', 'i32'], - ['get bar', 'Contract__getProposalInputParam1BarStruct'], - ]); - - // Inner tuple: - tupleType = generatedTypes.find( - type => type.name === 'Contract__getProposalInputParam1BarStruct', - ); - - // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined(); - - // Verify that the tuple type has getters for all tuple fields with - // the right return types - expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ - ['get baz', 'Address'], - ]); - }); - - test('Tuple types exist for function return values', () => { - const tupleType = generatedTypes.find( - type => type.name === 'Contract__getProposalResultValue0Struct', - ); - - // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined(); - - // Verify that the tuple type has getters for all tuple fields with - // the right return types - expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ - ['get result', 'i32'], - ['get target', 'Address'], - ['get data', 'Bytes'], - ['get proposer', 'Address'], - ['get feeRecipient', 'Address'], - ['get fee', 'BigInt'], - ['get startTime', 'BigInt'], - ['get yesCount', 'BigInt'], - ['get noCount', 'BigInt'], - ]); - }); - - test('Function bodies are generated correctly for tuple arrays', () => { - const contract = generatedTypes.find(type => type.name === 'Contract'); - const getter = contract.methods.find((method: any) => method.name === 'getProposals'); - - expect(getter.body).not.toContain('toTupleArray'); - expect(getter.body).toContain( - 'result[1].toTupleArray()', - ); + test(`Type test`, () => { + for (const generatedType of generatedTypes) { + expect(generatedType).toMatchSnapshot(); + } }); }); }); diff --git a/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap new file mode 100644 index 00000000..f9e5d47a --- /dev/null +++ b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap @@ -0,0 +1,69 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Cosmos subgraph scaffolding > Manifest 1`] = ` +"specVersion: 1.0.0 +indexerHints: + prune: auto +schema: + file: ./schema.graphql +dataSources: + - kind: cosmos + name: CosmosHub + network: cosmoshub-4 + source: + startBlock: 0 + mapping: + apiVersion: 0.0.5 + language: wasm/assemblyscript + entities: + - ExampleEntity + blockHandlers: + - handler: handleBlock + file: ./src/contract.ts +" +`; + +exports[`Cosmos subgraph scaffolding > Mapping (default) 1`] = ` +"import { cosmos, BigInt } from "@graphprotocol/graph-ts" +import { ExampleEntity } from "../generated/schema" + +export function handleBlock(block: cosmos.Block): void { + // Entities can be loaded from the store using a string ID; this ID + // needs to be unique across all entities of the same type + let entity = ExampleEntity.load(block.header.hash.toHex()) + + // Entities only exist after they have been saved to the store; + // \`null\` checks allow to create entities on demand + if (!entity) { + entity = new ExampleEntity(block.header.hash.toHex()) + + // Entity fields can be set using simple assignments + entity.count = BigInt.fromI32(0) + } + + // BigInt and BigDecimal math are supported + entity.count = entity.count + BigInt.fromI32(1) + + // Entity fields can be set based on receipt information + entity.height = block.header.height + + // Entities can be written to the store with \`.save()\` + entity.save() + + // Note: If a handler doesn't require existing field values, it is faster + // _not_ to load the entity from the store. Instead, create it fresh with + // \`new Entity(...)\`, set the fields that should be updated and save the + // entity back to the store. Fields that were not set or unset remain + // unchanged, allowing for partial updates to be applied. +} +" +`; + +exports[`Cosmos subgraph scaffolding > Schema (default) 1`] = ` +"type ExampleEntity @entity { + id: ID! + block: Bytes! + count: BigInt! +} +" +`; diff --git a/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap new file mode 100644 index 00000000..8c778bd1 --- /dev/null +++ b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap @@ -0,0 +1,438 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Ethereum subgraph scaffolding > Manifest 1`] = ` +"specVersion: 1.0.0 +indexerHints: + prune: auto +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum + name: Contract + network: kovan + source: + address: "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d" + abi: Contract + startBlock: 12345 + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + entities: + - ExampleEvent + - ExampleEvent1 + abis: + - name: Contract + file: ./abis/Contract.json + eventHandlers: + - event: ExampleEvent(indexed uint256,bytes[4],string,(uint256,bytes32,string,(uint96,string,bytes32)),indexed string,string) + handler: handleExampleEvent + - event: ExampleEvent(bytes32) + handler: handleExampleEvent1 + file: ./src/contract.ts +" +`; + +exports[`Ethereum subgraph scaffolding > Mapping (default) 1`] = ` +"import { BigInt } from "@graphprotocol/graph-ts" +import { + Contract, + ExampleEvent, + ExampleEvent1 +} from "../generated/Contract/Contract" +import { ExampleEntity } from "../generated/schema" + +export function handleExampleEvent(event: ExampleEvent): void { + // Entities can be loaded from the store using a string ID; this ID + // needs to be unique across all entities of the same type + let entity = ExampleEntity.load(event.transaction.from) + + // Entities only exist after they have been saved to the store; + // \`null\` checks allow to create entities on demand + if (!entity) { + entity = new ExampleEntity(event.transaction.from) + + // Entity fields can be set using simple assignments + entity.count = BigInt.fromI32(0) + } + + // BigInt and BigDecimal math are supported + entity.count = entity.count + BigInt.fromI32(1) + + // Entity fields can be set based on event parameters + entity.a = event.params.a + entity.b = event.params.b + + // Entities can be written to the store with \`.save()\` + entity.save() + + // Note: If a handler doesn't require existing field values, it is faster + // _not_ to load the entity from the store. Instead, create it fresh with + // \`new Entity(...)\`, set the fields that should be updated and save the + // entity back to the store. Fields that were not set or unset remain + // unchanged, allowing for partial updates to be applied. + + // It is also possible to access smart contracts from mappings. For + // example, the contract that has emitted the event can be connected to + // with: + // + // let contract = Contract.bind(event.address) + // + // The following functions can then be called on this contract to access + // state variables and other data: + // + // - contract.someVariable(...) + // - contract.getSomeValue(...) +} + +export function handleExampleEvent1(event: ExampleEvent1): void {} +" +`; + +exports[`Ethereum subgraph scaffolding > Mapping (for indexing events) 1`] = ` +"import { + ExampleEvent as ExampleEventEvent, + ExampleEvent1 as ExampleEvent1Event +} from "../generated/Contract/Contract" +import { ExampleEvent, ExampleEvent1 } from "../generated/schema" + +export function handleExampleEvent(event: ExampleEventEvent): void { + let entity = new ExampleEvent( + event.transaction.hash.concatI32(event.logIndex.toI32()) + ) + entity.a = event.params.a + entity.b = event.params.b + entity.param2 = event.params.param2 + entity.c_c1 = event.params.c.c1 + entity.c_value1 = event.params.c.value1 + entity.c_value2 = event.params.c.value2 + entity.c_c3_c31 = event.params.c.c3.c31 + entity.c_c3_value1 = event.params.c.c3.value1 + entity.c_c3_value2 = event.params.c.c3.value2 + entity.d = event.params.d + entity.internal_id = event.params.id + + entity.blockNumber = event.block.number + entity.blockTimestamp = event.block.timestamp + entity.transactionHash = event.transaction.hash + + entity.save() +} + +export function handleExampleEvent1(event: ExampleEvent1Event): void { + let entity = new ExampleEvent1( + event.transaction.hash.concatI32(event.logIndex.toI32()) + ) + entity.a = event.params.a + + entity.blockNumber = event.block.number + entity.blockTimestamp = event.block.timestamp + entity.transactionHash = event.transaction.hash + + entity.save() +} +" +`; + +exports[`Ethereum subgraph scaffolding > Schema (default) 1`] = ` +"type ExampleEntity @entity { + id: Bytes! + count: BigInt! + a: BigInt! # uint256 + b: [Bytes!]! # bytes[4] +} +" +`; + +exports[`Ethereum subgraph scaffolding > Schema (for indexing events) 1`] = ` +"type ExampleEvent @entity(immutable: true) { + id: Bytes! + a: BigInt! # uint256 + b: [Bytes!]! # bytes[4] + param2: String! # string + c_c1: BigInt! # uint256 + c_value1: Bytes! # bytes32 + c_value2: String! # string + c_c3_c31: BigInt! # uint96 + c_c3_value1: String! # string + c_c3_value2: Bytes! # bytes32 + d: String! # string + internal_id: String! # string + blockNumber: BigInt! + blockTimestamp: BigInt! + transactionHash: Bytes! +} + +type ExampleEvent1 @entity(immutable: true) { + id: Bytes! + a: Bytes! # bytes32 + blockNumber: BigInt! + blockTimestamp: BigInt! + transactionHash: Bytes! +} +" +`; + +exports[`Ethereum subgraph scaffolding > Test Files (default) 1`] = ` +"import { + assert, + describe, + test, + clearStore, + beforeAll, + afterAll +} from "matchstick-as/assembly/index" +import { BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent } from "../generated/schema" +import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" +import { handleExampleEvent } from "../src/contract" +import { createExampleEventEvent } from "./contract-utils" + +// Tests structure (matchstick-as >=0.5.0) +// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 + +describe("Describe entity assertions", () => { + beforeAll(() => { + let a = BigInt.fromI32(234) + let b = [Bytes.fromI32(1234567890)] + let param2 = "Example string value" + let c = "ethereum.Tuple Not implemented" + let d = "Example string value" + let id = "Example string value" + let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d, id) + handleExampleEvent(newExampleEventEvent) + }) + + afterAll(() => { + clearStore() + }) + + // For more test scenarios, see: + // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test + + test("ExampleEvent created and stored", () => { + assert.entityCount("ExampleEvent", 1) + + // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "a", + "234" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "b", + "[1234567890]" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "param2", + "Example string value" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "c", + "ethereum.Tuple Not implemented" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "d", + "Example string value" + ) + + // More assert options: + // https://thegraph.com/docs/en/developer/matchstick/#asserts + }) +}) +" +`; + +exports[`Ethereum subgraph scaffolding > Test Files (default) 2`] = ` +"import { newMockEvent } from "matchstick-as" +import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" + +export function createExampleEventEvent( + a: BigInt, + b: Array, + param2: string, + c: ethereum.Tuple, + d: string, + id: string +): ExampleEvent { + let exampleEventEvent = changetype(newMockEvent()) + + exampleEventEvent.parameters = new Array() + + exampleEventEvent.parameters.push( + new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("d", ethereum.Value.fromString(d)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("id", ethereum.Value.fromString(id)) + ) + + return exampleEventEvent +} + +export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { + let exampleEvent1Event = changetype(newMockEvent()) + + exampleEvent1Event.parameters = new Array() + + exampleEvent1Event.parameters.push( + new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) + ) + + return exampleEvent1Event +} +" +`; + +exports[`Ethereum subgraph scaffolding > Test Files (for indexing events) 1`] = ` +"import { + assert, + describe, + test, + clearStore, + beforeAll, + afterAll +} from "matchstick-as/assembly/index" +import { BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent } from "../generated/schema" +import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" +import { handleExampleEvent } from "../src/contract" +import { createExampleEventEvent } from "./contract-utils" + +// Tests structure (matchstick-as >=0.5.0) +// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 + +describe("Describe entity assertions", () => { + beforeAll(() => { + let a = BigInt.fromI32(234) + let b = [Bytes.fromI32(1234567890)] + let param2 = "Example string value" + let c = "ethereum.Tuple Not implemented" + let d = "Example string value" + let id = "Example string value" + let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d, id) + handleExampleEvent(newExampleEventEvent) + }) + + afterAll(() => { + clearStore() + }) + + // For more test scenarios, see: + // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test + + test("ExampleEvent created and stored", () => { + assert.entityCount("ExampleEvent", 1) + + // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "a", + "234" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "b", + "[1234567890]" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "param2", + "Example string value" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "c", + "ethereum.Tuple Not implemented" + ) + assert.fieldEquals( + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "d", + "Example string value" + ) + + // More assert options: + // https://thegraph.com/docs/en/developer/matchstick/#asserts + }) +}) +" +`; + +exports[`Ethereum subgraph scaffolding > Test Files (for indexing events) 2`] = ` +"import { newMockEvent } from "matchstick-as" +import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" + +export function createExampleEventEvent( + a: BigInt, + b: Array, + param2: string, + c: ethereum.Tuple, + d: string, + id: string +): ExampleEvent { + let exampleEventEvent = changetype(newMockEvent()) + + exampleEventEvent.parameters = new Array() + + exampleEventEvent.parameters.push( + new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("d", ethereum.Value.fromString(d)) + ) + exampleEventEvent.parameters.push( + new ethereum.EventParam("id", ethereum.Value.fromString(id)) + ) + + return exampleEventEvent +} + +export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { + let exampleEvent1Event = changetype(newMockEvent()) + + exampleEvent1Event.parameters = new Array() + + exampleEvent1Event.parameters.push( + new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) + ) + + return exampleEvent1Event +} +" +`; diff --git a/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap new file mode 100644 index 00000000..d5fb1f80 --- /dev/null +++ b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap @@ -0,0 +1,71 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`NEAR subgraph scaffolding > Manifest 1`] = ` +"specVersion: 1.0.0 +indexerHints: + prune: auto +schema: + file: ./schema.graphql +dataSources: + - kind: near + name: Contract + network: near-mainnet + source: + account: "abc.def.near" + mapping: + apiVersion: 0.0.5 + language: wasm/assemblyscript + entities: + - ExampleEntity + receiptHandlers: + - handler: handleReceipt + file: ./src/contract.ts +" +`; + +exports[`NEAR subgraph scaffolding > Mapping (default) 1`] = ` +"import { near, BigInt } from "@graphprotocol/graph-ts" +import { ExampleEntity } from "../generated/schema" + +export function handleReceipt( + receiptWithOutcome: near.ReceiptWithOutcome +): void { + // Entities can be loaded from the store using a string ID; this ID + // needs to be unique across all entities of the same type + let entity = ExampleEntity.load(receiptWithOutcome.receipt.id.toHex()) + + // Entities only exist after they have been saved to the store; + // \`null\` checks allow to create entities on demand + if (!entity) { + entity = new ExampleEntity(receiptWithOutcome.receipt.id.toHex()) + + // Entity fields can be set using simple assignments + entity.count = BigInt.fromI32(0) + } + + // BigInt and BigDecimal math are supported + entity.count = entity.count + BigInt.fromI32(1) + + // Entity fields can be set based on receipt information + entity.block = receiptWithOutcome.block.header.hash + + // Entities can be written to the store with \`.save()\` + entity.save() + + // Note: If a handler doesn't require existing field values, it is faster + // _not_ to load the entity from the store. Instead, create it fresh with + // \`new Entity(...)\`, set the fields that should be updated and save the + // entity back to the store. Fields that were not set or unset remain + // unchanged, allowing for partial updates to be applied. +} +" +`; + +exports[`NEAR subgraph scaffolding > Schema (default) 1`] = ` +"type ExampleEntity @entity { + id: ID! + block: Bytes! + count: BigInt! +} +" +`; diff --git a/packages/cli/src/scaffold/cosmos.test.ts b/packages/cli/src/scaffold/cosmos.test.ts index ded47f80..d73c3c0b 100644 --- a/packages/cli/src/scaffold/cosmos.test.ts +++ b/packages/cli/src/scaffold/cosmos.test.ts @@ -12,75 +12,16 @@ const scaffoldOptions = { const scaffold = new Scaffold(scaffoldOptions); -describe.concurrent('Cosmos subgraph scaffolding', () => { +describe('Cosmos subgraph scaffolding', () => { test('Manifest', async () => { - expect(await scaffold.generateManifest()).toEqual(`\ -specVersion: 1.0.0 -indexerHints: - prune: auto -schema: - file: ./schema.graphql -dataSources: - - kind: cosmos - name: CosmosHub - network: cosmoshub-4 - source: - startBlock: 0 - mapping: - apiVersion: 0.0.5 - language: wasm/assemblyscript - entities: - - ExampleEntity - blockHandlers: - - handler: handleBlock - file: ./src/contract.ts -`); + expect(await scaffold.generateManifest()).toMatchSnapshot(); }); test('Schema (default)', async () => { - expect(await scaffold.generateSchema()).toEqual(`\ -type ExampleEntity @entity { - id: ID! - block: Bytes! - count: BigInt! -} -`); + expect(await scaffold.generateSchema()).toMatchSnapshot(); }); test('Mapping (default)', async () => { - expect(await scaffold.generateMapping()).toEqual(`\ -import { cosmos, BigInt } from "@graphprotocol/graph-ts" -import { ExampleEntity } from "../generated/schema" - -export function handleBlock(block: cosmos.Block): void { - // Entities can be loaded from the store using a string ID; this ID - // needs to be unique across all entities of the same type - let entity = ExampleEntity.load(block.header.hash.toHex()) - - // Entities only exist after they have been saved to the store; - // \`null\` checks allow to create entities on demand - if (!entity) { - entity = new ExampleEntity(block.header.hash.toHex()) - - // Entity fields can be set using simple assignments - entity.count = BigInt.fromI32(0) - } - - // BigInt and BigDecimal math are supported - entity.count = entity.count + BigInt.fromI32(1) - - // Entity fields can be set based on receipt information - entity.height = block.header.height - - // Entities can be written to the store with \`.save()\` - entity.save() - - // Note: If a handler doesn't require existing field values, it is faster - // _not_ to load the entity from the store. Instead, create it fresh with - // \`new Entity(...)\`, set the fields that should be updated and save the - // entity back to the store. Fields that were not set or unset remain - // unchanged, allowing for partial updates to be applied. -} -`); + expect(await scaffold.generateMapping()).toMatchSnapshot(); }); }); diff --git a/packages/cli/src/scaffold/ethereum.test.ts b/packages/cli/src/scaffold/ethereum.test.ts index 9c9eb2a6..3acdc649 100644 --- a/packages/cli/src/scaffold/ethereum.test.ts +++ b/packages/cli/src/scaffold/ethereum.test.ts @@ -80,317 +80,34 @@ const scaffoldWithIndexEvents = new Scaffold({ indexEvents: true, }); -describe.concurrent('Ethereum subgraph scaffolding', () => { +describe('Ethereum subgraph scaffolding', () => { test('Manifest', async () => { - expect(await scaffold.generateManifest()).toEqual(`\ -specVersion: 1.0.0 -indexerHints: - prune: auto -schema: - file: ./schema.graphql -dataSources: - - kind: ethereum - name: Contract - network: kovan - source: - address: "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d" - abi: Contract - startBlock: 12345 - mapping: - kind: ethereum/events - apiVersion: 0.0.7 - language: wasm/assemblyscript - entities: - - ExampleEvent - - ExampleEvent1 - abis: - - name: Contract - file: ./abis/Contract.json - eventHandlers: - - event: ExampleEvent(indexed uint256,bytes[4],string,(uint256,bytes32,string,(uint96,string,bytes32)),indexed string,string) - handler: handleExampleEvent - - event: ExampleEvent(bytes32) - handler: handleExampleEvent1 - file: ./src/contract.ts -`); + expect(await scaffold.generateManifest()).toMatchSnapshot(); }); test('Schema (default)', async () => { - expect(await scaffold.generateSchema()).toEqual(`\ -type ExampleEntity @entity { - id: Bytes! - count: BigInt! - a: BigInt! # uint256 - b: [Bytes!]! # bytes[4] -} -`); + expect(await scaffold.generateSchema()).toMatchSnapshot(); }); test('Schema (for indexing events)', async () => { - expect(await scaffoldWithIndexEvents.generateSchema()).toEqual(`\ -type ExampleEvent @entity(immutable: true) { - id: Bytes! - a: BigInt! # uint256 - b: [Bytes!]! # bytes[4] - param2: String! # string - c_c1: BigInt! # uint256 - c_value1: Bytes! # bytes32 - c_value2: String! # string - c_c3_c31: BigInt! # uint96 - c_c3_value1: String! # string - c_c3_value2: Bytes! # bytes32 - d: String! # string - internal_id: String! # string - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type ExampleEvent1 @entity(immutable: true) { - id: Bytes! - a: Bytes! # bytes32 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} -`); + expect(await scaffoldWithIndexEvents.generateSchema()).toMatchSnapshot(); }); test('Mapping (default)', async () => { - expect(await scaffold.generateMapping()).toEqual(`\ -import { BigInt } from "@graphprotocol/graph-ts" -import { - Contract, - ExampleEvent, - ExampleEvent1 -} from "../generated/Contract/Contract" -import { ExampleEntity } from "../generated/schema" - -export function handleExampleEvent(event: ExampleEvent): void { - // Entities can be loaded from the store using a string ID; this ID - // needs to be unique across all entities of the same type - let entity = ExampleEntity.load(event.transaction.from) - - // Entities only exist after they have been saved to the store; - // \`null\` checks allow to create entities on demand - if (!entity) { - entity = new ExampleEntity(event.transaction.from) - - // Entity fields can be set using simple assignments - entity.count = BigInt.fromI32(0) - } - - // BigInt and BigDecimal math are supported - entity.count = entity.count + BigInt.fromI32(1) - - // Entity fields can be set based on event parameters - entity.a = event.params.a - entity.b = event.params.b - - // Entities can be written to the store with \`.save()\` - entity.save() - - // Note: If a handler doesn't require existing field values, it is faster - // _not_ to load the entity from the store. Instead, create it fresh with - // \`new Entity(...)\`, set the fields that should be updated and save the - // entity back to the store. Fields that were not set or unset remain - // unchanged, allowing for partial updates to be applied. - - // It is also possible to access smart contracts from mappings. For - // example, the contract that has emitted the event can be connected to - // with: - // - // let contract = Contract.bind(event.address) - // - // The following functions can then be called on this contract to access - // state variables and other data: - // - // - contract.someVariable(...) - // - contract.getSomeValue(...) -} - -export function handleExampleEvent1(event: ExampleEvent1): void {} -`); + expect(await scaffold.generateMapping()).toMatchSnapshot(); }); test('Mapping (for indexing events)', async () => { - expect(await scaffoldWithIndexEvents.generateMapping()).toEqual(`\ -import { - ExampleEvent as ExampleEventEvent, - ExampleEvent1 as ExampleEvent1Event -} from "../generated/Contract/Contract" -import { ExampleEvent, ExampleEvent1 } from "../generated/schema" - -export function handleExampleEvent(event: ExampleEventEvent): void { - let entity = new ExampleEvent( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.a = event.params.a - entity.b = event.params.b - entity.param2 = event.params.param2 - entity.c_c1 = event.params.c.c1 - entity.c_value1 = event.params.c.value1 - entity.c_value2 = event.params.c.value2 - entity.c_c3_c31 = event.params.c.c3.c31 - entity.c_c3_value1 = event.params.c.c3.value1 - entity.c_c3_value2 = event.params.c.c3.value2 - entity.d = event.params.d - entity.internal_id = event.params.id - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleExampleEvent1(event: ExampleEvent1Event): void { - let entity = new ExampleEvent1( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.a = event.params.a - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} -`); + expect(await scaffoldWithIndexEvents.generateMapping()).toMatchSnapshot(); }); test('Test Files (default)', async () => { const files = await scaffoldWithIndexEvents.generateTests(); const testFile = files?.['contract.test.ts']; const utilsFile = files?.['contract-utils.ts']; - expect(testFile).toEqual(`\ -import { - assert, - describe, - test, - clearStore, - beforeAll, - afterAll -} from "matchstick-as/assembly/index" -import { BigInt, Bytes } from "@graphprotocol/graph-ts" -import { ExampleEvent } from "../generated/schema" -import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" -import { handleExampleEvent } from "../src/contract" -import { createExampleEventEvent } from "./contract-utils" - -// Tests structure (matchstick-as >=0.5.0) -// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 - -describe("Describe entity assertions", () => { - beforeAll(() => { - let a = BigInt.fromI32(234) - let b = [Bytes.fromI32(1234567890)] - let param2 = "Example string value" - let c = "ethereum.Tuple Not implemented" - let d = "Example string value" - let id = "Example string value" - let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d, id) - handleExampleEvent(newExampleEventEvent) - }) - - afterAll(() => { - clearStore() - }) - - // For more test scenarios, see: - // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test - - test("ExampleEvent created and stored", () => { - assert.entityCount("ExampleEvent", 1) - - // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "a", - "234" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "b", - "[1234567890]" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "param2", - "Example string value" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "c", - "ethereum.Tuple Not implemented" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "d", - "Example string value" - ) - - // More assert options: - // https://thegraph.com/docs/en/developer/matchstick/#asserts - }) -}) -`); - expect(utilsFile).toEqual(`\ -import { newMockEvent } from "matchstick-as" -import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" -import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" -export function createExampleEventEvent( - a: BigInt, - b: Array, - param2: string, - c: ethereum.Tuple, - d: string, - id: string -): ExampleEvent { - let exampleEventEvent = changetype(newMockEvent()) - - exampleEventEvent.parameters = new Array() - - exampleEventEvent.parameters.push( - new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("d", ethereum.Value.fromString(d)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("id", ethereum.Value.fromString(id)) - ) - - return exampleEventEvent -} - -export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { - let exampleEvent1Event = changetype(newMockEvent()) - - exampleEvent1Event.parameters = new Array() - - exampleEvent1Event.parameters.push( - new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) - ) - - return exampleEvent1Event -} -`); + expect(testFile).toMatchSnapshot(); + expect(utilsFile).toMatchSnapshot(); }); test('Test Files (for indexing events)', async () => { @@ -398,133 +115,7 @@ export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { const testFile = files?.['contract.test.ts']; const utilsFile = files?.['contract-utils.ts']; - expect(testFile).toEqual(`\ -import { - assert, - describe, - test, - clearStore, - beforeAll, - afterAll -} from "matchstick-as/assembly/index" -import { BigInt, Bytes } from "@graphprotocol/graph-ts" -import { ExampleEvent } from "../generated/schema" -import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" -import { handleExampleEvent } from "../src/contract" -import { createExampleEventEvent } from "./contract-utils" - -// Tests structure (matchstick-as >=0.5.0) -// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 - -describe("Describe entity assertions", () => { - beforeAll(() => { - let a = BigInt.fromI32(234) - let b = [Bytes.fromI32(1234567890)] - let param2 = "Example string value" - let c = "ethereum.Tuple Not implemented" - let d = "Example string value" - let id = "Example string value" - let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d, id) - handleExampleEvent(newExampleEventEvent) - }) - - afterAll(() => { - clearStore() - }) - - // For more test scenarios, see: - // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test - - test("ExampleEvent created and stored", () => { - assert.entityCount("ExampleEvent", 1) - - // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "a", - "234" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "b", - "[1234567890]" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "param2", - "Example string value" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "c", - "ethereum.Tuple Not implemented" - ) - assert.fieldEquals( - "ExampleEvent", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", - "d", - "Example string value" - ) - - // More assert options: - // https://thegraph.com/docs/en/developer/matchstick/#asserts - }) -}) -`); - expect(utilsFile).toEqual(`\ -import { newMockEvent } from "matchstick-as" -import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" -import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" - -export function createExampleEventEvent( - a: BigInt, - b: Array, - param2: string, - c: ethereum.Tuple, - d: string, - id: string -): ExampleEvent { - let exampleEventEvent = changetype(newMockEvent()) - - exampleEventEvent.parameters = new Array() - - exampleEventEvent.parameters.push( - new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("d", ethereum.Value.fromString(d)) - ) - exampleEventEvent.parameters.push( - new ethereum.EventParam("id", ethereum.Value.fromString(id)) - ) - - return exampleEventEvent -} - -export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { - let exampleEvent1Event = changetype(newMockEvent()) - - exampleEvent1Event.parameters = new Array() - - exampleEvent1Event.parameters.push( - new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) - ) - - return exampleEvent1Event -} -`); + expect(testFile).toMatchSnapshot(); + expect(utilsFile).toMatchSnapshot(); }); }); diff --git a/packages/cli/src/scaffold/near.test.ts b/packages/cli/src/scaffold/near.test.ts index 248bc233..6cc54af6 100644 --- a/packages/cli/src/scaffold/near.test.ts +++ b/packages/cli/src/scaffold/near.test.ts @@ -13,77 +13,16 @@ const scaffoldOptions = { const scaffold = new Scaffold(scaffoldOptions); -describe.concurrent('NEAR subgraph scaffolding', () => { +describe('NEAR subgraph scaffolding', () => { test('Manifest', async () => { - expect(await scaffold.generateManifest()).toEqual(`\ -specVersion: 1.0.0 -indexerHints: - prune: auto -schema: - file: ./schema.graphql -dataSources: - - kind: near - name: Contract - network: near-mainnet - source: - account: "abc.def.near" - mapping: - apiVersion: 0.0.5 - language: wasm/assemblyscript - entities: - - ExampleEntity - receiptHandlers: - - handler: handleReceipt - file: ./src/contract.ts -`); + expect(await scaffold.generateManifest()).toMatchSnapshot(); }); test('Schema (default)', async () => { - expect(await scaffold.generateSchema()).toEqual(`\ -type ExampleEntity @entity { - id: ID! - block: Bytes! - count: BigInt! -} -`); + expect(await scaffold.generateSchema()).toMatchSnapshot(); }); test('Mapping (default)', async () => { - expect(await scaffold.generateMapping()).toEqual(`\ -import { near, BigInt } from "@graphprotocol/graph-ts" -import { ExampleEntity } from "../generated/schema" - -export function handleReceipt( - receiptWithOutcome: near.ReceiptWithOutcome -): void { - // Entities can be loaded from the store using a string ID; this ID - // needs to be unique across all entities of the same type - let entity = ExampleEntity.load(receiptWithOutcome.receipt.id.toHex()) - - // Entities only exist after they have been saved to the store; - // \`null\` checks allow to create entities on demand - if (!entity) { - entity = new ExampleEntity(receiptWithOutcome.receipt.id.toHex()) - - // Entity fields can be set using simple assignments - entity.count = BigInt.fromI32(0) - } - - // BigInt and BigDecimal math are supported - entity.count = entity.count + BigInt.fromI32(1) - - // Entity fields can be set based on receipt information - entity.block = receiptWithOutcome.block.header.hash - - // Entities can be written to the store with \`.save()\` - entity.save() - - // Note: If a handler doesn't require existing field values, it is faster - // _not_ to load the entity from the store. Instead, create it fresh with - // \`new Entity(...)\`, set the fields that should be updated and save the - // entity back to the store. Fields that were not set or unset remain - // unchanged, allowing for partial updates to be applied. -} -`); + expect(await scaffold.generateMapping()).toMatchSnapshot(); }); });