ic-repl: GitHub - chenyan2002/ic-repl. This is designed at the canister level, so that you can use the tool to call canisters written in different languages. It’s also useful if you want to seed data or write scripts.
Quick question about ic-repl: I’m guessing we have to make sure to tear down any objects we create in our ic-repl test scripts? I don’t see it done explicitly in any of the examples (unless they are non-stable variables, in which case the next canister deploy should clear out any test data).
After checking most of these…
ic-repl - wasn’t for me. Doesn’t have the features I need and feels rigid.
deploying and running a canister which tests another canister - pretty slow
The fastest approach (using motoko compiler - moc) - instantly shows results when I click file save: moc -r `vessel sources` test/something.mo
If you are on macos this script will monitor your src and test directories and run the test after every change
#!/bin/sh
fswatch -o src test | xargs -n1 -I{} moc -r `vessel sources` test/something.mo
Limitations I have found so far:
Wont work - Debug.print(Principal.toText(Principal.fromActor(this)))
In addition to the approaches listed by @chenyan above, there is also the approach to use the ic-hs IC simulator as a library, and use Haskell to script the testing of the compiled canister. As it works with the compiled wasm, it works with both Motoko and Rust canisters. This is the approach chosen by the Internet Identity project:
Your skills are highly appreciated, had a quick thought on this, and I made an assumption:
On the Haskell approach, I wouldn’t have to start a local replica and deploy the Canister.
Makes the iterations on implementing code changes and testing faster, then let’s say test via bash or agentjs as it’s require to deploy to a local replica (slow).
Yes, these are some of the benefits. Also you get to use an expressive programming language to describe your tests, re-use testing libraries (tasty, quickcheck) and your tests are statically typed, has Haskell can import the Candid type of your canister into it’s own type system. This way, if you change your canister interface, the Haskell compiler will tell you which tests to update. You also have better control over the IC, e.g. you can change the canister’s time easily.
The downsides are that you need to know Haskell and that not all behavior of the IC is faithfully represented by ic-hs (e.g. no cycle accounting).
I’d guess that basic understanding of Haskell be enough for common assertions when writing tests? As in it being a client call versus the actual implementation.
For some value of “basic”, certainly . I mean, you still have to set the dev environment up, deal with the syntax, and if you use record or variants in the Candid interface, these map to row-types data types, which are probably no longer basic use of Haskell. But give it a try, maybe you’ll like it and will happily learn what’s missing, if anything!
With all the respect, I did take some time to look into Haskell.
For any other readers interested, if you spend a few minutes looking into this subject, you’ll find @nomeata work on Haskell everywhere, here’s a good start: https://haskell-via-sokoban.nomeata.de/
Or, maybe start by doing some music / live coding to learn some basics (this one I remember seeing here in London when I was interested in Algorave a few years ago, a pity didn’t pick it up):
For the test of the canister-api another way is to use this dart library if you are on a linux or if you want to run this with dart in the browser: ic_tools | Dart Package . Dart is a simple language to pick up. To start with dart, make a main folder, put in it a pubspec.yaml file (simple well documented config) and a folder: ‘lib’ and a file main.dart within the lib folder.
pubspec.yaml
lib/main.dart
next in the main folder: run the command: dart pub add ic_tools
Then follow the ic_tools readme to set the lib up.
in the main.dart file you can call your canisters, and run dart lib/main.dart heres a sample: