Writing Tests for TheGraph Protocol on Windows
In a previous blog post, I discussed how to set up TheGraph to index your blockchain data. In this post, I will delve into how to write unit tests for it on Windows. Since it is not possible to run the tests on Windows directly, there is a trick to get it running.
The Importance of Writing Tests
Since Liminal.market handles stock trades, it is crucial that the data is correct. Having good test coverage helps to achieve high-quality data. When writing code, you typically manage everything correctly about 98% of the time. However, unit tests help you to reach 99–100% correctness. Therefore, for Liminal.market, unit testing is a must. It is impossible to know if you are at 100%, but you can try your best to get as close to it as possible. This is where unit testing comes in.
Tips and Nuances for Unit Testing on Windows
TheGraph uses the Matchstick testing framework, https://thegraph.com/docs/en/developing/unit-testing-framework/, which utilizes the Postgresql database to store the entities. Since we are on Windows and we can’t test on a Windows machine, you will need to have Windows Subsystem for Linux (WSL) installed.
You should have Matchstick already installed, but if not, run the following command “npm –save-dev matchstick-as” in your project folder.
To install Postgresql, open WSL (search for WSL or Ubuntu in your start menu) and run “sudo apt install postgresql”. There may be a few nuances that need to be fixed (although I didn’t encounter any). Check out the documentation if have issues
Be sure to use AssemblyScript version 0.5.4 for Matchstick, as higher versions of AssemblyScript (0.19.x) may cause problems.
To run the tests, open WSL(Window start button, type in WSL or Ubuntu) and navigate to your project on the C drive. The C drive is located under the /mnt path. For example, the path for me is /mnt/c/users/{windows_username}/source/repos/liminal.blog
You can find the testing code in my repository, https://github.com/ingig/liminal.market.thegraph.blog/tree/main/tests
Now that we are ready, let’s start writing tests!
Code setup
We had 3 function that handled events
- handleTokenCreated
- handleOrderExecuted
- handleOrderFailed
These tests are demonstrations and don’t cover all test cases. It’s meant to show how to create entities, mock events, store them, clear the storage and validate the expected behavior.
Important:
When you are creating a mocked object, you must push the parameters in the correct order that they are defined in ABI.
So let’s get into it.
handleTokenCreated
ChatGPT description of the function:
The function starts by creating a new Symbol object and assigning the “symbol” parameter from the event’s parameters to it. Then it assigns the token address from the event’s parameters to the “contract” property of the Symbol object and creates a logo URL using the symbol parameter and a fixed string “https://app.liminal.market/img/logos/" + symbol + “.png”. Next, it assigns the timestamp of the block containing the event to the “created” property of the Symbol object, sets the “txCount” property to 0 and calls the “save()” method to save the Symbol object. After that, the function retrieves the “LiminalMarketInfo” object and pushes the Symbol object’s id to the “symbols” property of the LiminalMarketInfo object and increments the “symbolCount” property. Finally, it saves the updated LiminalMarketInfo object.
Create a function that creates the mocked object
The order of the parameters are important, I first push tokenAddress then symbol parameter, this is because the ABI defines the tokenAddress first. If you push the symbol first, you will get the symbol when asking for tokenAddress, giving you wrong data and errors.
There are 2 helper functions, getSymbolAddressParam and getStringParam
This is not all the code, so check out the TestHelpers.ts file to get all the function
We now have a mocked event, it will act as it’s coming from blockchain. We can now write the test
In the beforeAll function we clear the storage of the database. handleTokenCreated is our code that we want to test.
Let now run the test. Open WSL and go to the path where you code it located, in my case /mnt/c/users/{windows_username}/source/repos/liminal.blog
Run command “npm run test” and you should see 1 test passing
handleOrderExecuted
Let’s get ChatGPT to describe the function.
The function first calls a function named “getLiminalMarketInfo()” which returns an object representing the current state of a “LiminalMarketInfo”. The function then updates the “txCount” and “orderExecutedCount” properties of the liminalMarketInfo object by incrementing them by 1.
It then checks the “side” property of the event’s parameters and updates the “tslWei” and “tsl” properties of the liminalMarketInfo object accordingly. If the “side” property is “buy”, the “tslWei” and “tsl” properties are incremented by the value of the “filledQty” property of the event’s parameters, otherwise they are decremented by that value.
Then it updates the “lastOrderAt” property of the liminalMarketInfo object with the timestamp of the block. Finally, it saves the updated liminalMarketInfo object.
So for the test, we should at least test the buy and sell event and validate that the calculation of tsl & tslWei is correct.
You will notice tsl and tslWei, to make it easier for those who use the GraphQL I’m providing both a human readable number and the Wei number (18 decimal points). This is just so that the developer integrating with our API doesn´t have to do all the manual work of converting the numbers.
There is also a helper function, getOrderExecutedEvent, the code for it is located in the TestHelpers.ts file.
Notice how array validation is handled. It is just a text string, [AAPL], if you have multiple items in the array it’s comma separated, [AAPL, MSFT]
Now when we run the test, we should have 3 successful tests.
handleOrderFailed
Lastly, we will test that OrderFailed is working correctly. It simply increases the property orderFailedCount
Run the tests, and we have 4 successful tests
Conclusion
These tests are just an example of how to write unit tests on top of TheGraph. They get you started on writing this important mechanism that increases the likelihood of correct data. Don’t underestimate the value of unit tests.
For our official subgraph that liminal.market uses, we have a lot more tests and information to validate. You can check out our repository here https://github.com/liminal-market/liminal.market.thegraph/tree/main/tests