Birim Testi Framework'ü
Reading time: 23 min
Learn how to use Matchstick, a unit testing framework developed by . Matchstick enables subgraph developers to test their mapping logic in a sandboxed environment and sucessfully deploy their subgraphs.
- It's written in Rust and optimized for high performance.
- It gives you access to developer features, including the ability to mock contract calls, make assertions about the store state, monitor subgraph failures, check test performance, and many more.
In order to use the test helper methods and run tests, you need to install the following dependencies:
yarn add --dev matchstick-as
graph-node
depends on PostgreSQL, so if you don't already have it, then you will need to install it.
Note: It's highly recommended to use the commands below to avoid unexpected errors.
Installation command:
brew install postgresql
En son libpq.5.lib'e bir sembolik bağ oluşturun. Bu dizini önce oluşturmanız gerekebilir /usr/local/opt/postgresql/lib/
ln -sf /usr/local/opt/postgresql@14/lib/postgresql@14/libpq.5.dylib /usr/local/opt/postgresql/lib/libpq.5.dylib
Installation command (depends on your distro):
sudo apt install postgresql
Matchstick'i WSL'de Docker yaklaşımı ve ikili yaklaşımı kullanarak kullanabilirsiniz. WSL biraz alengirli olabileceğinden, aşağıdaki gibi sorunlarla karşılaşırsanız birkaç ipucu verelim
static BYTES = Symbol("Bytes") SyntaxError: Unexpected token =
yada
<PROJECT_PATH>/node_modules/gluegun/build/index.js:13 throw up;
Lütfen daha yeni bir Node.js sürümünde olduğunuzdan emin olun. graph-cli artık v10.19.0'ı desteklemiyor ve bu sürüm, hala WSL'deki yeni Ubuntu görüntülerinin varsayılan sürümüdür. Örneğin, Matchstick'in v18.1.0 ile WSL'de çalıştığı doğrulandı, nvm aracılığıyla veya global Node.js'inizi güncelleyerek buna geçebilirsiniz. Nodejs'nizi güncelledikten sonra node_modules
'ı silmeyi ve node_modules
'u tekrar çalıştırmayı unutmayın! Daha sonra, libpq yüklü olduğundan emin olun, bunu çalıştırarak yapabilirsiniz
sudo apt-get install libpq-dev
Son olarak, graph test
'i kullanmayın (global graph-cli yüklemenizi kullanmaktadır ve bazı nedenlerden dolayı şu anda WSL'de bozuk gibi görünüyor), bunun yerine yarn test
veya npm run test
kullanın (bu, proje düzeyindeki yerel graph-cli örneğini kullanacaktır, bu da harika çalışır). Bunun için tabiki package.json
dosyanızda bir "test"
script'i olması gerektiğini unutmayın, bunun gibi basit bir şey olabilir
{"name": "demo-subgraph","version": "0.1.0","scripts": {"test": "graph test",...},"dependencies": {"@graphprotocol/graph-cli": "^0.56.0","@graphprotocol/graph-ts": "^0.31.0","matchstick-as": "^0.6.0"}}
Matchstick'i subgraph proje'nizde kullanmak için sadece bir terminal açın, proje'nizin kök(root) klasörüne gidin ve basitçe graph test [options] <datasource>
- komutunu çalıştırın - bu en son Matchstick ikili dosyasını indirir ve belirtilen testi veya test klasöründeki tüm testleri çalıştırır (verikaynağı bayrağı belirtilmezse mevcut tüm testler).
Bu, test klasöründeki tüm testleri çalıştıracaktır:
graph test
Bu, gravity.test.ts adında bir testi ve/veya gravity adında bir klasördeki tüm testleri çalıştıracaktır:
graph test gravity
Bu sadece belirtilen test dosyasını çalıştıracaktır:
graph test path/to/file.test.ts
Seçenekler:
-c, --coverage Testleri kapsama modunda çalıştırır-d, --docker Testleri bir docker konteynerinde çalıştırır (Not: Subgraph kök klasöründen çalıştırın)-f, --force İkili: İkilinin yeniden indirilmesini sağlar. Docker: Dockerfile'ın yeniden indirilmesi ve docker görüntüsünün yeniden oluşturulması.-h, --help Kullanım bilgilerini gösterir-l, --logs İşletim sistemi, CPU modeli ve indirme URL'si hakkında konsola günlük bilgilerini yazar (hata ayıklama amaçlıdır)-r, --recompile Testlerin yeniden derlenmesini zorlar-v, --version <tag> İndirmek/kullanmak istediğiniz rust ikilisinin sürümünü seçmenize yarar
graph-cli 0.25.2
'den itibaren graph test
-d
bayrağı ile matchstick
'i bir docker konteynerinde çalıştırmayı desteklemektedir. Docker uygulaması, kullandığından, graph test -d
komutu her çalıştırıldığında docker görüntüsünü yeniden oluşturmak zorunda değildir. Alternatif olarak, deposundan docker'ı manuel olarak çalıştırmak için talimatları izleyebilirsiniz.
❗ graph test -d
, docker run
'un -t
bayrağıyla çalışmasını zorlar. Bu, etkileşimli olmayan ortamlar (örneğin, GitHub CI) içinde çalıştırmak için kaldırılmalıdır.
❗ Daha önce graph test
çalıştırdıysanız, docker build sırasında aşağıdaki hatayla karşılaşabilirsiniz:
error from sender: failed to xattr node_modules/binary-install-raw/bin/binary-<platform>: permission denied
Bu durumda, kök klasör içinde bir .dockerignore
dosyası oluşturun ve node_modules/binary-install-raw/bin
'i ekleyin
Matchstick, matchstick.yaml
yapılandırma dosyası aracılığıyla özel testler, kütüphaneler ve manifest yolunu kullanacak şekilde yapılandırılabilir:
testsFolder: path/to/testslibsFolder: path/to/libsmanifestPath: path/to/subgraph.yaml
sunu klonlayarak bu kılavuzdaki örnekleri deneyebilir ve ve istediğinizi yapabilirsiniz
Ayrıca, "" konulu video serisine göz atabilirsiniz
ÖNEMLİ: Aşağıda açıklanan test yapısı matchstick-as
sürümünün >=0.5.0 olmasını gerektirir
describe(name: String , () => {})
- Bir test grubunu tanımlar.
Notlar:
- Açıklamalar zorunlu değildir. Hala test() fonksiyonunu describe() bloklarının dışında kullanabilirsiniz
Örnek:
import { describe, test } from "matchstick-as/assembly/index"import { handleNewGravatar } from "../../src/gravity"describe("handleNewGravatar()", () => {test("Should create a new Gravatar entity", () => {...})})
İç içe describe()
örneği:
import { describe, test } from "matchstick-as/assembly/index"import { handleUpdatedGravatar } from "../../src/gravity"describe("handleUpdatedGravatar()", () => {describe("When entity exists", () => {test("updates the entity", () => {...})})describe("When entity does not exists", () => {test("it creates a new entity", () => {...})})})
test(name: String, () =>, should_fail: bool)
- Bir test durumu tanımlar. test() fonksiyonunu describe() blokları içinde veya bağımsız olarak kullanabilirsiniz.
Örnek:
import { describe, test } from "matchstick-as/assembly/index"import { handleNewGravatar } from "../../src/gravity"describe("handleNewGravatar()", () => {test("Should create a new Entity", () => {...})})
yada
test("handleNewGravatar() should create a new entity", () => {...})
Dosyadaki tüm testlerden önce bir kod bloğu çalıştırır. beforeAll
, describe
bloklarının içinde tanımlanırsa, o describe
bloğunun başında çalışır.
Örnekler:
beforeAll
içindeki kod, dosyadaki tüm testlerden önce bir kez çalıştırılacaktır.
import { describe, test, beforeAll } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"import { Gravatar } from "../../generated/schema"beforeAll(() => {let gravatar = new Gravatar("0x0")gravatar.displayName = “First Gravatar”gravatar.save()...})describe("When the entity does not exist", () => {test("it should create a new Gravatar with id 0x1", () => {...})})describe("When entity already exists", () => {test("it should update the Gravatar with id 0x0", () => {...})})
beforeAll
içindeki kod, ilk describe bloğundaki tüm testlerden önce bir kez çalıştırılacaktır
import { describe, test, beforeAll } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"import { Gravatar } from "../../generated/schema"describe("handleUpdatedGravatar()", () => {beforeAll(() => {let gravatar = new Gravatar("0x0")gravatar.displayName = “First Gravatar”gravatar.save()...})test("updates Gravatar with id 0x0", () => {...})test("creates new Gravatar with id 0x1", () => {...})})
Dosyadaki tüm testlerden sonra bir kod bloğu çalıştırır. afterAll
, describe
bloklarının içinde tanımlanırsa, o describe
bloğunun sonunda çalışır.
Örnek:
afterAll
içindeki kod, dosyadaki tüm testlerden sonra bir kez çalıştırılacaktır.
import { describe, test, afterAll } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"import { store } from "@graphprotocol/graph-ts"afterAll(() => {store.remove("Gravatar", "0x0")...})describe("handleNewGravatar, () => {test("creates Gravatar with id 0x0", () => {...})})describe("handleUpdatedGravatar", () => {test("updates Gravatar with id 0x0", () => {...})})
afterAll
içindeki kod, ilk describe bloğundaki tüm testlerden sonra bir kez çalıştırılacaktır
import { describe, test, afterAll, clearStore } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"describe("handleNewGravatar", () => {afterAll(() => {store.remove("Gravatar", "0x1")...})test("It creates a new entity with Id 0x0", () => {...})test("It creates a new entity with Id 0x1", () => {...})})describe("handleUpdatedGravatar", () => {test("updates Gravatar with id 0x0", () => {...})})
Her testten önce bir kod bloğu çalıştırır. beforeEach
, describe
bloklarının içinde tanımlanırsa, o describe
bloğunun her testinden önce çalıştırılır.
Örnekler: beforeEach
içindeki kod, her testten önce çalıştırılacaktır.
import { describe, test, beforeEach, clearStore } from "matchstick-as/assembly/index"import { handleNewGravatars } from "./utils"beforeEach(() => {clearStore() // <-- clear the store before each test in the file})describe("handleNewGravatars, () => {test("A test that requires a clean store", () => {...})test("Second that requires a clean store", () => {...})})...
beforeEach
içindeki kod, yalnızca o describe bloğundaki her testten önce çalıştırılacaktır
import { describe, test, beforeEach } from 'matchstick-as/assembly/index'import { handleUpdatedGravatar, handleNewGravatar } from '../../src/gravity'describe('handleUpdatedGravatars', () => {beforeEach(() => {let gravatar = new Gravatar('0x0')gravatar.displayName = 'First Gravatar'gravatar.imageUrl = ''gravatar.save()})test('Upates the displayName', () => {assert.fieldEquals('Gravatar', '0x0', 'displayName', 'First Gravatar')// displayName'i 1. Gravatar olarak güncellemesi gereken kodassert.fieldEquals('Gravatar', '0x0', 'displayName', '1st Gravatar')store.remove('Gravatar', '0x0')})test('Updates the imageUrl', () => {assert.fieldEquals('Gravatar', '0x0', 'imageUrl', '')// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kodassert.fieldEquals('Gravatar', '0x0', 'imageUrl', 'https://www.gravatar.com/avatar/0x0')store.remove('Gravatar', '0x0')})})
Her testten sonra bir kod bloğu çalıştırır. afterEach
, describe
bloklarının içinde tanımlanırsa, o describe
bloğunun her testinden sonra çalıştırılır.
Örnekler:
afterEach
içindeki kod, her testten sonra çalıştırılacaktır.
import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"beforeEach(() => {let gravatar = new Gravatar("0x0")gravatar.displayName = “First Gravatar”gravatar.save()})afterEach(() => {store.remove("Gravatar", "0x0")})describe("handleNewGravatar", () => {...})describe("handleUpdatedGravatar", () => {test("Upates the displayName", () => {assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar")// displayName'i 1. Gravatar olarak güncellemesi gereken kodassert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")})test("Updates the imageUrl", () => {assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kodassert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")})})
afterEach
içindeki kod, yalnızca o describe bloğundaki her testten sonra çalıştırılacaktır
import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index"import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity"describe("handleNewGravatar", () => {...})describe("handleUpdatedGravatar", () => {beforeEach(() => {let gravatar = new Gravatar("0x0")gravatar.displayName = "First Gravatar"gravatar.imageUrl = ""gravatar.save()})afterEach(() => {store.remove("Gravatar", "0x0")})test("Upates the displayName", () => {assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar")// displayName'i 1. Gravatar olarak güncellemesi gereken kodassert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar")})test("Updates the imageUrl", () => {assert.fieldEquals("Gravatar", "0x0", "imageUrl", "")// imageUrl'yi https://www.gravatar.com/avatar/0x0 olarak değiştirmesi gereken kodassert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0")})})
fieldEquals(entityType: string, id: string, fieldName: string, expectedVal: string)equals(expected: ethereum.Value, actual: ethereum.Value)notInStore(entityType: string, id: string)addressEquals(address1: Address, address2: Address)bytesEquals(bytes1: Bytes, bytes2: Bytes)i32Equals(number1: i32, number2: i32)bigIntEquals(bigInt1: BigInt, bigInt2: BigInt)booleanEquals(bool1: boolean, bool2: boolean)stringEquals(string1: string, string2: string)arrayEquals(array1: Array<ethereum.Value>, array2: Array<ethereum.Value>)tupleEquals(tuple1: ethereum.Tuple, tuple2: ethereum.Tuple)assertTrue(value: boolean)assertNull<T>(value: T)assertNotNull<T>(value: T)entityCount(entityType: string, expectedCount: i32)
Sürüm 0.6.0 itibariyle, assert fonksiyonları özel hata mesajlarını da desteklemektedir
assert.fieldEquals('Gravatar', '0x123', 'id', '0x123', 'Id 0x123 olmalıdır')assert.equals(ethereum.Value.fromI32(1), ethereum.Value.fromI32(1), 'Value 1'e eşit olmalıdır')assert.notInStore('Gravatar', '0x124', 'Gravatar store'da olmamalıdır')assert.addressEquals(Address.zero(), Address.zero(), 'Adres sıfır olmalıdır')assert.bytesEquals(Bytes.fromUTF8('0x123'), Bytes.fromUTF8('0x123'), 'Byte değerleri eşit olmalıdır')assert.i32Equals(2, 2, 'I32, 2'ye eşit olmalıdır')assert.bigIntEquals(BigInt.fromI32(1), BigInt.fromI32(1), 'BigInt 1'e eşit olmalıdır')assert.booleanEquals(true, true, 'Boolean true olmalıdır')assert.stringEquals('1', '1', 'String 1'e eşit olmalıdır')assert.arrayEquals([ethereum.Value.fromI32(1)], [ethereum.Value.fromI32(1)], 'Array'ler eşit olmalıdır')assert.tupleEquals(changetype<ethereum.Tuple>([ethereum.Value.fromI32(1)]),changetype<ethereum.Tuple>([ethereum.Value.fromI32(1)]),'Tuple'lar eşit olmalıdır',)assert.assertTrue(true, 'True olmalıdır')assert.assertNull(null, 'Null olmalıdır')assert.assertNotNull('not null', 'Null olmamalıdır')assert.entityCount('Gravatar', 1, '2 gravatar olmalıdır')assert.dataSourceCount('GraphTokenLockWallet', 1, 'GraphTokenLockWallet şablonunda bir veri kaynağı olmalıdır')assert.dataSourceExists('GraphTokenLockWallet',Address.zero().toHexString(),'GraphTokenLockWallet sıfır adresi için bir veri kaynağına sahip olmalıdır',)
'taki Gravatar örneklerini kullanarak nasıl basit bir birim test görüneceğini görelim.
Aşağıdaki işleyici fonksiyonuna sahip olduğumuzu varsayarsak (iki yardımcı işlevle birlikte):
export function handleNewGravatar(event: NewGravatar): void {let gravatar = new Gravatar(event.params.id.toHex())gravatar.owner = event.params.ownergravatar.displayName = event.params.displayNamegravatar.imageUrl = event.params.imageUrlgravatar.save()}export function handleNewGravatars(events: NewGravatar[]): void {events.forEach((event) => {handleNewGravatar(event)})}export function createNewGravatarEvent(id: i32,ownerAddress: string,displayName: string,imageUrl: string,): NewGravatar {let mockEvent = newMockEvent()let newGravatarEvent = new NewGravatar(mockEvent.address,mockEvent.logIndex,mockEvent.transactionLogIndex,mockEvent.logType,mockEvent.block,mockEvent.transaction,mockEvent.parameters,)newGravatarEvent.parameters = new Array()let idParam = new ethereum.EventParam('id', ethereum.Value.fromI32(id))let addressParam = new ethereum.EventParam('ownderAddress',ethereum.Value.fromAddress(Address.fromString(ownerAddress)),)let displayNameParam = new ethereum.EventParam('displayName', ethereum.Value.fromString(displayName))let imageUrlParam = new ethereum.EventParam('imageUrl', ethereum.Value.fromString(imageUrl))newGravatarEvent.parameters.push(idParam)newGravatarEvent.parameters.push(addressParam)newGravatarEvent.parameters.push(displayNameParam)newGravatarEvent.parameters.push(imageUrlParam)return newGravatarEvent}
Önce projemizde bir test dosyası oluşturmamız gerekiyor. Bunun nasıl görünebileceğine dair bir örnek:
import { clearStore, test, assert } from 'matchstick-as/assembly/index'import { Gravatar } from '../../generated/schema'import { NewGravatar } from '../../generated/Gravity/Gravity'import { createNewGravatarEvent, handleNewGravatars } from '../mappings/gravity'test('Can call mappings with custom events', () => {// Bir test varlığı oluşturun ve bunu depoya başlangıç durumu olarak kaydedin (isteğe bağlı)let gravatar = new Gravatar('gravatarId0')gravatar.save()// Mock etkinlikleri oluşturunlet newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')// Az önce oluşturduğumuz olayları geçiren çağrı eşleştirme fonksiyonlarıhandleNewGravatars([newGravatarEvent, anotherGravatarEvent])// Deponun durumunu doğrulayınassert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0')assert.fieldEquals('Gravatar', '12345', 'owner', '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')assert.fieldEquals('Gravatar', '3546', 'displayName', 'cap')// Bir sonraki testi temiz bir sayfa üzerinde başlatmak için depoyu boşaltınclearStore()})test('Next test', () => {//...})
Analiz edilecek çok fazla şey var! Öncelikle fark etmemiz gereken önemli şey AssemblyScript yardımcı kütüphanemiz (npm modülü olarak dağıtılır) matchstick-as
'den işleri içe aktardığımız. Repositoriyi bulabilirsiniz. matchstick-as
bize yararlı test yöntemleri sağlar ve ayrıca test blokları oluşturmak için kullanacağımız test()
işlevini tanımlar. Geri kalanı oldukça açık - şöyle olur:
- İlk durumumuzu ayarlıyor ve bir özel Gravatar varlığı ekliyoruz;
createNewGravatarEvent()
fonksiyonunu kullanarak verileriyle birlikte ikiNewGravatar
r olay nesnesini tanımlıyoruz;handleNewGravatars()
yöntemlerimizi bu olaylar için çağırıyoruz ve özel olay listemizi geçiyoruz;- Depo durumunu doğruluyoruz. Bu nasıl çalışır? - Bir varlık türü ve kimliğinin benzersiz bir kombinasyonunu geçiriyoruz. Ardından, bu varlıkta belirli bir alanı kontrol ediyoruz ve beklediğimiz değeri almasını sağlıyoruz. Hem depoya eklediğimiz ilk Gravatar Varlığı için hem de işleyici işlevi çağrıldığında eklenen iki Gravatar varlığı için bunu yapıyoruz;
- Ve son olarak
clearStore()
kullanarak depoyu temizliyoruz, böylece bir sonraki testimiz temiz ve boş bir depo nesnesiyle başlayabilir. İstediğimiz kadar test bloğu tanımlayabiliriz.
İşte başardın - ilk testimizi oluşturduk! 👏
Şimdi testlerimizi çalıştırmak için subgraph kök klasörünüzde şunu çalıştırmanız yeterlidir:
graph test Gravity
Ve her şey yolunda giderse aşağıdakiyle karşılaşacaksınız:
Kullanıcılar bilinen bir varlık kümesiyle depoyu doldurabilirler. Aşağıdaki örnek depoyu Gravatar varlığıyla başlatmak için kullanılabilir:
let gravatar = new Gravatar('entryId')gravatar.save()
Kullanıcı, depoya bağlı bir eşleştirme fonksiyonuna özel bir olay oluşturabilir ve onu iletebilir:
import { store } from 'matchstick-as/assembly/store'import { NewGravatar } from '../../generated/Gravity/Gravity'import { handleNewGravatars, createNewGravatarEvent } from './mapping'let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')handleNewGravatar(newGravatarEvent)
Kullanıcılar test fikstürleriyle eşleştirmeleri çağırabilirler.
import { NewGravatar } from '../../generated/Gravity/Gravity'import { store } from 'matchstick-as/assembly/store'import { handleNewGravatars, createNewGravatarEvent } from './mapping'let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac')handleNewGravatars([newGravatarEvent, anotherGravatarEvent])
export function handleNewGravatars(events: NewGravatar[]): void {events.forEach(event => {handleNewGravatar(event);});}
Kullanıcılar sözleşme çağrılarını mocklayabilir:
import { addMetadata, assert, createMockedFunction, clearStore, test } from 'matchstick-as/assembly/index'import { Gravity } from '../../generated/Gravity/Gravity'import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')let expectedResult = Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947')let bigIntParam = BigInt.fromString('1234')createMockedFunction(contractAddress, 'gravatarToOwner', 'gravatarToOwner(uint256):(address)').withArgs([ethereum.Value.fromSignedBigInt(bigIntParam)]).returns([ethereum.Value.fromAddress(Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947'))])let gravity = Gravity.bind(contractAddress)let result = gravity.gravatarToOwner(bigIntParam)assert.equals(ethereum.Value.fromAddress(expectedResult), ethereum.Value.fromAddress(result))
Gösterildiği gibi, bir sözleşme çağrısını mocklamak ve bir dönüş değeri sabitlemek için kullanıcı, bir sözleşme adresi, işlev adı, işlev imzası, bir argüman dizisi ve elbette dönüş değerini sağlamalıdır.
Kullanıcılar ayrıca fonksiyon geri çevirilerinide mocklayabilirler:
let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7')createMockedFunction(contractAddress, 'getGravatar', 'getGravatar(address):(string,string)').withArgs([ethereum.Value.fromAddress(contractAddress)]).reverts()
Kullanıcılar mockIpfsFile(hash, filePath)
fonksiyonunu kullanarak IPFS dosyalarını mocklama yeteneğine sahiptirler. Fonksiyon, ilk argümanı IPFS dosya hash/yol'u ve ikinci argümanı yerel bir dosyanın yolu olmak üzere iki argüman kabul eder.
NOT: ipfs.map/ipfs.mapJSON
'u test ederken matchstck'in bunu algılaması için geri çağrıma işlevinin test dosyasından dışa aktarılması gerekiyor, örneğin aşağıdaki test örneğindeki processGravatar()
fonksiyonu gibi:
.test.ts
dosyası:
import { assert, test, mockIpfsFile } from 'matchstick-as/assembly/index'import { ipfs } from '@graphprotocol/graph-ts'import { gravatarFromIpfs } from './utils'// Matchstck'in algılaması için ipfs.map() geri çağrısını dışa aktarınexport { processGravatar } from './utils'test('ipfs.cat', () => {mockIpfsFile('ipfsCatfileHash', 'tests/ipfs/cat.json')assert.entityCount(GRAVATAR_ENTITY_TYPE, 0)gravatarFromIpfs()assert.entityCount(GRAVATAR_ENTITY_TYPE, 1)assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '1', 'imageUrl', 'https://i.ytimg.com/vi/MELP46s8Cic/maxresdefault.jpg')clearStore()})test('ipfs.map', () => {mockIpfsFile('ipfsMapfileHash', 'tests/ipfs/map.json')assert.entityCount(GRAVATAR_ENTITY_TYPE, 0)ipfs.map('ipfsMapfileHash', 'processGravatar', Value.fromString('Gravatar'), ['json'])assert.entityCount(GRAVATAR_ENTITY_TYPE, 3)assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '1', 'displayName', 'Gravatar1')assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '2', 'displayName', 'Gravatar2')assert.fieldEquals(GRAVATAR_ENTITY_TYPE, '3', 'displayName', 'Gravatar3')})
utils.ts
dosyası:
import { Address, ethereum, JSONValue, Value, ipfs, json, Bytes } from "@graphprotocol/graph-ts"import { Gravatar } from "../../generated/schema"...// ipfs.map geri çağrısıexport function processGravatar(value: JSONValue, userData: Value): void {// İşlem yapmayla ilgili ayrıntılar için JSONValue belgelerine bakın// JSON değerleri ilelet obj = value.toObject()let id = obj.get('id')if (!id) {return}// Geri çağrılar ayrıca varlıklar oluşturabilirlet gravatar = new Gravatar(id.toString())gravatar.displayName = userData.toString() + id.toString()gravatar.save()}// ipfs.cat'i çağıran fonksiyonexport function gravatarFromIpfs(): void {let rawData = ipfs.cat("ipfsCatfileHash")if (!rawData) {return}let jsonData = json.fromBytes(rawData as Bytes).toObject()let id = jsonData.get('id')let url = jsonData.get("imageUrl")if (!id || !url) {return}let gravatar = new Gravatar(id.toString())gravatar.imageUrl = url.toString()gravatar.save()}
Kullanıcılar, varlıkları doğrulayarak deponun nihai (veya orta) durumunu doğrulayabilirler. Bunun için, kullanıcı bir Varlık türü, bir Varlığın belirli bir kimliği, o Varlıktaki bir alanın adı ve alanın beklenen değerini sağlamalıdır. Hızlıca bir örneğe bakalım:
import { assert } from 'matchstick-as/assembly/index'import { Gravatar } from '../generated/schema'let gravatar = new Gravatar('gravatarId0')gravatar.save()assert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0')
assert.fieldEquals () fonksiyonunu çalıştırmak, verilen alanın verilen beklenen değere karşı eşitliğini kontrol edecektir. Değerler eşit DEĞİLSE test başarısız olacak ve bir hata mesajı verecektir. Aksi takdirde, test başarılı bir şekilde geçecektir.
Kullanıcılar newMockEvent()
fonksiyonunu kullanarak ethereum.Event döndürebilen varsayılan işlem üst verilerini kullanabilir. Aşağıdaki örnek, Olay nesnesindeki bu alanlara nasıl okuma/yazma yapabileceğinizi gösterir:
// Okumalet logType = newGravatarEvent.logType// Yazmalet UPDATED_ADDRESS = '0xB16081F360e3847006dB660bae1c6d1b2e17eC2A'newGravatarEvent.address = Address.fromString(UPDATED_ADDRESS)
assert.equals(ethereum.Value.fromString("hello"); ethereum.Value.fromString("hello"));
Kullanıcılar, bir varlığın depoda olmadığını doğrulayabilirler. Bu fonksiyon, bir varlık türü ve bir kimlik alır. Eğer varlık gerçekten depoda ise, test ilgili bir hata mesajı vererej başarısız olacaktır. Fonksiyonun nasıl kullanılacağına dair hızlıca bir örneğe bakalım:
assert.notInStore('Gravatar', '23')
Bu yardımcı fonksiyon kullanılarak deponun tamamı konsola yazdırılabilir:
import { logStore } from 'matchstick-as/assembly/store'logStore()
Sürüm 0.6.0 itibarıyla, logStore
türetilmiş alanları yazdırmaz. Bunun yerine kullanıcılar yeni logEntity
fonksiyonunu kullanabilir. Elbette ki logEntity
, yalnızca türetilmiş alanlara sahip olanları değil, herhangi bir varlığı yazdırmak için kullanılabilir. logEntity
, varlık türünü, varlık kimliğini ve ilgili türetilmiş varlıkları yazdırmak isteyip istemediğinizi belirten bir showRelated
bayrağını alır.
import { logEntity } from 'matchstick-as/assembly/store'logEntity("Gravatar", 23, true)
Kullanıcılar, shouldFail bayrağını test() fonksiyonlarında kullanarak beklenen test başarısızlıklarına sahip olabilirler:
test('Should throw an error',() => {throw new Error()},true,)
Test, shouldFail = true olarak işaretlenirse ama BAŞARISIZ olmazsa, bu kayıtlarda bir hata olarak görünecek ve test bloğu başarısız olacaktır. Ayrıca, with shouldFail = false (the default state) olarak işaretlenirse, test yürütücüsü çökecektir.
Birim testlerinde özel kayıt tutmanın eşitlemelerdeki kayıt tutmaktan tamamen aynıdır. Fark, günlük nesnesinin graph-ts yerine matchstick-as'dan içe aktarılması gerektmesidir. İşte tüm kritik olmayan kayıt türleriyle ilgili basit bir örnek:
import { test } from "matchstick-as/assembly/index";import { log } from "matchstick-as/assembly/log";test("Success", () => {log.success("Success!". []);});test("Error", () => {log.error("Error :( ", []);});test("Debug", () => {log.debug("Debugging...", []);});test("Info", () => {log.info("Info!", []);});test("Warning", () => {log.warning("Warning!", []);});
Kullanıcılar ayrıca şu şekilde kritik bir hatayı simüle edebilirler:
test('Blow everything up', () => {log.critical('Boom!')})
Kritik hataları kayıt altına almak, testlerin yürütülmesini durduracak ve her şeyi mahvedecektir. Sonuçta, kodunuzun dağıtımda kritik kayıtları içermediğinden emin olmak istiyoruz ve bunun olması durumunda hemen fark etmeniz gerekiyor.
Türetilmiş alanları test etme özelliği, belirli bir varlıkta bir alan belirleyip, bu varlıktan türetilmiş bir alan içeriyoren başka bir varlığın otomatik olarak güncellenmesini sağlayan bir özelliktir.
Sürüm 0.6.0
öncesinde, türetilmiş varlıklarıa varlık alanları/özellikleri olarak erişerek şu şekilde ulaşmak mümkündü:
let entity = ExampleEntity.load('id')let derivedEntity = entity.derived_entity
Sürüm 0.6.0
itibarıyla bu işlem, graph-node’un loadRelated
fonksiyonu kullanılarak yapılmaktadır. Türetilmiş varlıklara, işleyicilerdekiyle aynı şekilde erişilebilir.
test('Derived fields example test', () => {let mainAccount = GraphAccount.load('12')!assert.assertNull(mainAccount.get('nameSignalTransactions'))assert.assertNull(mainAccount.get('operatorOf'))let operatedAccount = GraphAccount.load('1')!operatedAccount.operators = [mainAccount.id]operatedAccount.save()mockNameSignalTransaction('1234', mainAccount.id)mockNameSignalTransaction('2', mainAccount.id)mainAccount = GraphAccount.load('12')!assert.assertNull(mainAccount.get('nameSignalTransactions'))assert.assertNull(mainAccount.get('operatorOf'))const nameSignalTransactions = mainAccount.nameSignalTransactions.load()const operatorsOfMainAccount = mainAccount.operatorOf.load()assert.i32Equals(2, nameSignalTransactions.length)assert.i32Equals(1, operatorsOfMainAccount.length)assert.stringEquals('1', operatorsOfMainAccount[0].id)mockNameSignalTransaction('2345', mainAccount.id)let nst = NameSignalTransaction.load('1234')!nst.signer = '11'nst.save()store.remove('NameSignalTransaction', '2')mainAccount = GraphAccount.load('12')!assert.i32Equals(1, mainAccount.nameSignalTransactions.load().length)})
Sürüm 0.6.0
itibarıyla, kullanıcılar loadInBlock
işlevini mockInBlockStore
kullanarak test edebilir, bu sayede blok önbelleğindeki varlıkları simüle edebilirler.
import { afterAll, beforeAll, describe, mockInBlockStore, test } from 'matchstick-as'import { Gravatar } from '../../generated/schema'describe('loadInBlock', () => {beforeAll(() => {mockInBlockStore('Gravatar', 'gravatarId0', gravatar)})afterAll(() => {clearInBlockStore()})test('entity.loadInBlock() metodunu kullanarak mevcut bloktaki önbellek depodan varlığı alabilir', () => {let retrievedGravatar = Gravatar.loadInBlock('gravatarId0')assert.stringEquals('gravatarId0', retrievedGravatar!.get('id')!.toString())})test('Varlık mevcut blokta yoksa entity.loadInBlock() çağrıldığında null döndürür', () => {let retrievedGravatar = Gravatar.loadInBlock('IDoNotExist')assert.assertNull(retrievedGravatar)})})
Dinamik veri kaynaklarının test edilmesi dataSource ad alanının context()
, address()
ve network()
fonksiyonlarının geri dönüş değerlerinin mocklanmasıyla yapılabilir. Bu fonksiyonlar şu anda şunları döndürmektedir: context()
- boş bir varlık döndürür (DataSourceContext), address()
- 0x0000000000000000000000000000000000000000
döndürür, network()
- mainnet
döndürür. create(...)
ve createWithContext(...)
fonksiyonları hiçbir şey yapmamak için mocklanmıştır bu nedenle testlerde çağrılmaları gerekmez. Dönüş değerlerinde yapılacak değişiklikler matchstick-as
'deki (version 0.3.0+)dataSourceMock
ad alanının fonksiyonlarıyla yapılabilir.
Aşağıdaki örnekte:
Öncelikle aşağıdaki olay işleyicisine sahibiz (veri kaynağı mocklamasını göstermek için kasıtlı olarak amaç değişikliği):
export function handleApproveTokenDestinations(event: ApproveTokenDestinations): void {let tokenLockWallet = TokenLockWallet.load(dataSource.address().toHexString())!if (dataSource.network() == 'rinkeby') {tokenLockWallet.tokenDestinationsApproved = true}let context = dataSource.context()if (context.get('contextVal')!.toI32() > 0) {tokenLockWallet.setBigInt('tokensReleased', BigInt.fromI32(context.get('contextVal')!.toI32()))}tokenLockWallet.save()}
Ardından, dataSourceMock ad alanındaki yöntemlerden birini kullanarak tüm veri kaynağı fonksiyonları için yeni bir geri dönüş değeri ayarlayan testi görüyoruz:
import { assert, test, newMockEvent, dataSourceMock } from 'matchstick-as/assembly/index'import { BigInt, DataSourceContext, Value } from '@graphprotocol/graph-ts'import { handleApproveTokenDestinations } from '../../src/token-lock-wallet'import { ApproveTokenDestinations } from '../../generated/templates/GraphTokenLockWallet/GraphTokenLockWallet'import { TokenLockWallet } from '../../generated/schema'test('Data source simple mocking example', () => {let addressString = '0xA16081F360e3847006dB660bae1c6d1b2e17eC2A'let address = Address.fromString(addressString)let wallet = new TokenLockWallet(address.toHexString())wallet.save()let context = new DataSourceContext()context.set('contextVal', Value.fromI32(325))dataSourceMock.setReturnValues(addressString, 'rinkeby', context)let event = changetype<ApproveTokenDestinations>(newMockEvent())assert.assertTrue(!wallet.tokenDestinationsApproved)handleApproveTokenDestinations(event)wallet = TokenLockWallet.load(address.toHexString())!assert.assertTrue(wallet.tokenDestinationsApproved)assert.bigIntEquals(wallet.tokensReleased, BigInt.fromI32(325))dataSourceMock.resetValues()})
dataSourceMock.resetValues()'in en sonda çağrıldığına dikkat edin. Bunun nedeni değerler değiştirildiğinde hatırlanır ve varsayılan değerlere geri dönmek istiyorsanız sıfırlanmaları gerekir.
Sürüm 0.6.0
itibarıyla, yeni bir veri kaynağının bir şablonu temel alarak oluşturulup oluşturulmadığını test etmek mümkündür. Bu özellik hem ethereum/sözleşme hem de dosya/ipfs şablonlarını destekler. Bunun için dört fonksiyon bulunmaktadır:
assert.dataSourceCount(templateName, expectedCount)
belirli bir şablondan beklenen veri kaynağı sayısını doğrulamak için kullanılabilirassert.dataSourceExists(templateName, address/ipfsHash)
belirli bir şablondan belirtilen kimliğe sahip (bu kimlik sözleşme adresi veya IPFS dosya hash’i olabilir) bir veri kaynağının oluşturulmuş olduğunu doğrularlogDataSources(templateName)
, belirtilen şablonda bulunan tüm veri kaynaklarını hata ayıklama amacıyla konsola yazdırırreadFile(path)
, bir IPFS dosyasını temsil eden JSON dosyasını okur ve içeriği Bytes olarak döndürür
test('ethereum/sözleşme dataSource oluşturma örneği', () => {// GraphTokenLockWallet şablonundan oluşturulmuş veri kaynağı olmadığını doğrulaassert.dataSourceCount('GraphTokenLockWallet', 0)// 0xA16081F360e3847006dB660bae1c6d1b2e17eC2A adresiyle yeni bir GraphTokenLockWallet veri kaynağı oluşturGraphTokenLockWallet.create(Address.fromString('0xA16081F360e3847006dB660bae1c6d1b2e17eC2A'))// datSource oluşturulduğunu doğrulaassert.dataSourceCount('GraphTokenLockWallet', 1)// İkinci dataSource'u bağlamıyla eklelet context = new DataSourceContext()context.set('contextVal', Value.fromI32(325))GraphTokenLockWallet.createWithContext(Address.fromString('0xA16081F360e3847006dB660bae1c6d1b2e17eC2B'), context)// Şimdi 2 veri kaynağı olduğunu doğrulaassert.dataSourceCount('GraphTokenLockWallet', 2)// "0xA16081F360e3847006dB660bae1c6d1b2e17eC2B" adresine sahip bir veri kaynağının oluşturulduğunu doğrula// `Address` türü çözümlendiğinde küçük harfe dönüştürüldüğünden, doğrulama yaparken adresi tamamen küçük harf olarak geçmelisinizassert.dataSourceExists('GraphTokenLockWallet', '0xA16081F360e3847006dB660bae1c6d1b2e17eC2B'.toLowerCase())logDataSources('GraphTokenLockWallet')})
🛠 {"0xa16081f360e3847006db660bae1c6d1b2e17ec2a": {"kind": "ethereum/contract","name": "GraphTokenLockWallet","address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2a","context": null},"0xa16081f360e3847006db660bae1c6d1b2e17ec2b": {"kind": "ethereum/contract","name": "GraphTokenLockWallet","address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2b","context": {"contextVal": {"type": "Int","data": 325}}}}
Akıllı sözleşme dinamik veri kaynaklarına benzer şekilde kullanıcılar, test dosyası veri kaynaklarını ve bunların işleyicilerini test edebilirler
...templates:- kind: file/ipfsname: GraphTokenLockMetadatanetwork: mainnetmapping:kind: ethereum/eventsapiVersion: 0.0.6language: wasm/assemblyscriptfile: ./src/token-lock-wallet.tshandler: handleMetadataentities:- TokenLockMetadataabis:- name: GraphTokenLockWalletfile: ./abis/GraphTokenLockWallet.json
"""Kilitli GRT tutan Token Kilit Cüzdanları"""type TokenLockMetadata @entity {"Token kilit cüzdanının adresi"id: ID!"Serbest bırakma programının başlangıç zamanı"startTime: BigInt!"Serbest bırakma programının bitiş zamanı"endTime: BigInt!"Başlangıç zamanı ile bitiş zamanı arasındaki periyot sayısı"periods: BigInt!"Serbest bırakmaların başladığı zaman"releaseStartTime: BigInt!}
{"startTime": 1,"endTime": 1,"periods": 1,"releaseStartTime": 1}
export function handleMetadata(content: Bytes): void {// dataSource.stringParams() File Veri Kaynağı CID'sini döndürür// stringParam() işleyici testinde taklit edilecektir// daha fazla bilgi için https://thegraph.com/docs/en/developing/creating-a-subgraph/#create-a-new-handler-to-process-filesprocess - fileslet tokenMetadata = new TokenLockMetadata(dataSource.stringParam())const value = json.fromBytes(content).toObject()if (value) {const startTime = value.get('startTime')const endTime = value.get('endTime')const periods = value.get('periods')const releaseStartTime = value.get('releaseStartTime')if (startTime && endTime && periods && releaseStartTime) {tokenMetadata.startTime = startTime.toBigInt()tokenMetadata.endTime = endTime.toBigInt()tokenMetadata.periods = periods.toBigInt()tokenMetadata.releaseStartTime = releaseStartTime.toBigInt()}tokenMetadata.save()}}
import { assert, test, dataSourceMock, readFile } from 'matchstick-as'import { Address, BigInt, Bytes, DataSourceContext, ipfs, json, store, Value } from '@graphprotocol/graph-ts'import { handleMetadata } from '../../src/token-lock-wallet'import { TokenLockMetadata } from '../../generated/schema'import { GraphTokenLockMetadata } from '../../generated/templates'test('dosya/ipfs veri kaynağı oluşturma örneği', () => {// ipfsHash + ipfs dosya yolu kullanılarak veri kaynağı CID'si oluşturulur// Örneğin QmaXzZhcYnsisuue5WRdQDH6FDvqkLQX1NckLqBYeYYEfm/example.jsonconst ipfshash = 'QmaXzZhcYnsisuue5WRdQDH6FDvqkLQX1NckLqBYeYYEfm'const CID = `${ipfshash}/example.json`// Oluşturulan CID kullanılarak yeni bir dataSource oluşturulurGraphTokenLockMetadata.create(CID)// dataSource oluşturulduğunu doğrulaassert.dataSourceCount('GraphTokenLockMetadata', 1)assert.dataSourceExists('GraphTokenLockMetadata', CID)logDataSources('GraphTokenLockMetadata')// Şimdi dataSource metadatasını ve spesifik olarak dataSource.stringParam()'ı taklit etmemiz gerekiyor// dataSource.stringParams aslında dataSource.address() değerini kullanır, bu yüzden matchstick-as kütüphanesinden aldığımız dataSourceMock ile adresi taklit edeceğiz// İlk olarak değerleri sıfırlayıp ardından dataSourceMock.setAddress() ile CID'yi atayacağızdataSourceMock.resetValues()dataSourceMock.setAddress(CID)// Şimdi dataSource işleyicisine geçirmek için Bytes oluşturmalıyız// Bunun yerel bir json dosyasını okuyan ve içeriğini Bytes olarak döndüren readFile fonksiyonunu kullanıyoruzconst content = readFile(`path/to/metadata.json`)handleMetadata(content)// Şimdi bir TokenLockMetadata'nın oluşturulup oluşturulmadığını test edeceğizconst metadata = TokenLockMetadata.load(CID)assert.bigIntEquals(metadata!.endTime, BigInt.fromI32(1))assert.bigIntEquals(metadata!.periods, BigInt.fromI32(1))assert.bigIntEquals(metadata!.releaseStartTime, BigInt.fromI32(1))assert.bigIntEquals(metadata!.startTime, BigInt.fromI32(1))})
Subgraph geliştiricileri Matchstick'i kullanarak, yazılan birim testlerinin test kapsamını hesaplayacak bir komut dosyası çalıştırabilirler.
Test kapsama aracı derlenmiş test wasm
ikililerini alır ve bunları daha sonra subgraph.yaml
dosyasında tanımlanan işlevlerin çağrılıp çağrılmadığını görmek için kolayca incelenebilen wat
dosyalarına dönüştürür. Kod kapsamı (ve bir bütün olarak test) AssemblyScript ve WebAssembly'de çok erken aşamalarda olduğundan, Matchstick dallanma kapsamını kontrol edemez. Bunun yerine, belirli bir işleyici çağrılmışsa, bunun için olay/fonksiyonun uygun şekilde taklit edildiği savına güveniyoruz.
Matchstick tarafından sağlanan test kapsama fonksiyonlarını çalıştırmak için önceden hazırlamanız gereken birkaç şey bulunmaktadır:
Matchstick'in hangi işleyicilerin çalıştığını kontrol etmesi için, bu işleyicilerin test file'dan dışa aktarılması gerekir. Mesela, bizim örneğimizde gravity.test.ts dosyamızda aşağıdaki işleyici içe aktarılır:
import { handleNewGravatar } from '../../src/gravity'
Bu fonksiyonun görünür olması için (adıyla wat
dosyasına dahil edilmesi için) ayrıca onuda şöyle dışa aktarmamız gerekmektedir:
export { handleNewGravatar }
Her şey hazır olduğunda, test kapsama aracını çalıştırmak için basitçe şunu çalıştırın:
graph test -- -c
Ayrıca package.json
dosyanıza şu şekilde özel bir kapsama(coverage
) komutu ekleyebilirsiniz:
"scripts": {/.../"coverage": "graph test -- -c"},
Bu, kapsama aracını çalıştıracak ve terminalde buna benzer bir şey göreceksiniz:
$ graph test -cSkipping download/install step because binary already exists at /Users/petko/work/demo-subgraph/node_modules/binary-install-raw/bin/0.4.0___ ___ _ _ _ _ _| \/ | | | | | | | (_) | || . . | __ _| |_ ___| |__ ___| |_ _ ___| | __| |\/| |/ _` | __/ __| '_ \/ __| __| |/ __| |/ /| | | | (_| | || (__| | | \__ \ |_| | (__| <\_| |_/\__,_|\__\___|_| |_|___/\__|_|\___|_|\_\Compiling...Running in coverage report mode.️Reading generated test modules... 🔎️Generating coverage report 📝Handlers for source 'Gravity':Handler 'handleNewGravatar' is tested.Handler 'handleUpdatedGravatar' is not tested.Handler 'handleCreateGravatar' is tested.Test coverage: 66.7% (2/3 handlers).Handlers for source 'GraphTokenLockWallet':Handler 'handleTokensReleased' is not tested.Handler 'handleTokensWithdrawn' is not tested.Handler 'handleTokensRevoked' is not tested.Handler 'handleManagerUpdated' is not tested.Handler 'handleApproveTokenDestinations' is not tested.Handler 'handleRevokeTokenDestinations' is not tested.Test coverage: 0.0% (0/6 handlers).Global test coverage: 22.2% (2/9 handlers).
Tutulan kayıt çıktısı test çalışma süresini içerir. İşte buna bir örnek:
[Thu, 31 Mar 2022 13:54:54 +0300] Program executed in: 42.270ms.
Critical: Could not create WasmInstance from valid module with context: unknown import: wasi_snapshot_preview1::fd_write has not been defined
Bu hata kodunuzda console.log
kullandığınız anlamına gelir. Bu komut AssemblyScript tarafından desteklenmez. Lütfen 'yi kullanmayı düşünün.
ERROR TS2554: Expected ? arguments, but got ?.
return new ethereum.Block(defaultAddressBytes, defaultAddressBytes, defaultAddressBytes, defaultAddress, defaultAddressBytes, defaultAddressBytes, defaultAddressBytes, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt, defaultBigInt);
in ~lib/matchstick-as/assembly/defaults.ts(18,12)
ERROR TS2554: Expected ? arguments, but got ?.
return new ethereum.Transaction(defaultAddressBytes, defaultBigInt, defaultAddress, defaultAddress, defaultBigInt, defaultBigInt, defaultBigInt, defaultAddressBytes, defaultBigInt);
in ~lib/matchstick-as/assembly/defaults.ts(24,12)
Argümanlardaki uyumsuzluk, graph-ts
ve matchstick-as
arasındaki uyumsuzluktan kaynaklanır. Bu gibi sorunları düzeltmenin en iyi yolu her şeyi en son yayınlanan sürüme güncellemektir.
For any additional support, check out this .
Soru, geri bildirim, özellik istekleri veya sadece iletişim kurmak istiyorsanız en iyi yer Matchstick için ayrılmış bir kanal olan 🔥| unit-testing kanalına sahip olduğumuz The Graph Discord'udur.