Test-Driven Design for NEAR Smart Contracts
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
TDD is a software development process that can improve the quality of your code and reduce your long-term technical debt by making it easier for teams to iterate over time. Join Dennis from Pagoda's DevRel team to learn more about TDD and see a practical example of using this approach on a NEAR smart contract.
------- Join NEAR's community: Website: near.org Reddit: / nearprotocol Discord: near.chat Medium: / nearprotocol Blog: near.org/blog Twitter: / nearprotocol GitHub: github.com/near github.com/nearprotocol Dev Docs: docs.near.org Create a wallet: wallet.near.org/create Apps on NEAR: awesomenear.com Learn to Build On NEAR: near.university Grants & Funding: near.org/grants #Blockchain #FutureisNEAR #NEAR #nearprotocol #nft #dao
Transcript
2,708 wordsCaptions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.
- 0:07
Hello everybody welcome to this short video on test driven design for new smart contracts I'm Dennis I'm part of the devil team here at Pagoda and I'll be running through how to implement this for JavaScript smart contracts so let's get to it so I opened up my terminal here in my projects folder and we're going to use this cool Pagoda tli tool called create your app which will help us with the scaffolding for our project we're going to tell we want this typescript or JavaScript smart contract
- 0:41
we'll skip the front end from now and we'll call it my demo what this will do is it will set up the structure of the files and folders and includes testing as well for our project so while it does that and it will also install dependencies which should take a while I'll speed up the video and I'll resume once we're there great so the Project's all set up now and we can start browsing the files inside so let's go
- 1:20
so here we are now in My Demo project so if we look to the left we'll see we have our package.json file and our integration tests folder containing our testing suite and our contracts folder containing our smart contract code specifically it's in the source folder it gives us uh the npx create new app gives us a simple set and get string smart contract as we can see here so it's just one variable that's saved on chain uh yeah and you can change it or
- 1:55
or get it for the integration tests they also live in source we see that we make use of near workspaces that's our key dependency here um what it does is it creates a virtualized version of near blockchain running on the machine running the tests so first it creates this sandbox server it deploys the contract you tell it to deploy in this case it's this one up here uh the exact configurations are in both of these package.json files you can have a look uh your cells by running
- 2:31
that command um yeah so it deploys that contract and then we pass on to the other tests we pass it on some data some data you can use as context the worker and both accounts created here so both of these are accounts and near everything's uh every user is pretty much an account and every account can have one smart contract deployed to it so the relationship is one two one because this is typescript we have to
- 3:00
specify both these two when we're passing it on so we have to specify that there's a data container for what we want to save in it and what we're going to save in it if it were just JavaScript we don't need these lines over here we're going to make use of Ava Ava is a testing library in JS that allows us to run tests async which is so in parallel which is particularly useful to test if tests take a take a while to run most of the time these tests can take between 5 and 10 seconds
- 3:30
to run so having them run async is very useful so yeah if we look closer here we also see that we're running uh both in before each and after each hooks that means that the this piece of logic runs before every test and this piece of logic runs after every test there's also a general before hook and a general after hook which means that piece of logic will run before all tests and the other will run after all tests that's particularly useful if you want to share data between all tests uh like for example you want
- 4:02
to initialize some specific state of uh uh yeah of your smart contract um but yeah I generally don't do this I start I start a new I start afresh and uh I create helper methods to uh uh to implement in every in every test as to obtain the state I want for that particular uh um test I'm looking at so yeah the npx creating your app Group gives us already two tests for our very simple get and set string uh smart
- 4:33
contract so what I'm going to do now is I'm going to delete these two and if we were to follow tdd by the book and that's what we're going to do we're going to think about uh what we want our app to do we're going to write tests for it first and then we're going to adapt our smart contract code AS to match what are what we specified in the tests that it should do so I am thinking I want this smart contract to do the same thing it already does but to allow everybody to interact with it
- 5:05
and everybody has their own strength so every account would have their own strength so uh and if it and if nobody uh has written or a particular account has not written to it yet it should return a not found error when someone's querying the string for that given account so should return that sound if account ID is not found and uh on the other case in our happy path should save message
- 5:42
by account ID and retrieve okay bye so I'm using GitHub copilot here which pretty much gets us everything I'm thinking about and let's see if we can do it now yeah it gave a good suggestion I think look yeah this makes sense it's it's saying now unknown but what I like to do in my test as well is I like to create a test case user so we'll do create user Alice says this is proper syntax so that looks good pass Alice as well to our to our tests
- 6:24
and we're fetching Outlets again here and here we'll that's Alice's account ID I think this is a property so we don't need to include use any brackets after that great so we'll get the results it should be a knock found this Tesla is good let's see what co-pilot says here message okay it got this wrong so in this case Analyst has to call the contract so this is the Syntax for it and uh yeah the function names are also incorrect I notice so it should be get
- 6:56
message and it should be set message and there we go great so what's happening here is that Alice performs a call to that smart contract and it uh it calls that specific function we we're going to specify in the smart contract code and it passes in uh that message as a parameter you can also pass additional parameters here in the call function namely the guess the attached deposit sign with key
- 7:28
um but yeah these are all uh uh defaults when you call it like this so this should be fine for the for the moment for example the default gas parameter is 30 Tera gas when performing it like this but you can jack it up all the way to the max at which at the moment is 300 Tera gas in case you have a computationally expensive function so uh let's see line 46 we get a result from contract get message and on the account
- 7:53
ID yeah this looks perfect so uh great our tests are done now so let's get on to our smart contract code so here we are with our smart contract code now if you remember MPX create new app set us up with a very simple uh smart contract for getting and setting strings but we want to make a couple changes to it so I'm going to just delete the contents of the functions for now and we're going to specify our data container which in this case was greetings
- 8:28
we want to save a bunch of them index by account ID so and whenever we're going to fetch a greeting we want to do so by account of these so that's going to have that's going to have to be in a parameter that we provided so uh in typescript we also have to tell what kind of something this account ID is which is very simple in this example it's only a string it's a lot of format that and yeah this is exactly what we wanted
- 8:55
right we wanted it to return not found if it's not found else give us the greeting for that accounted and in this case um yeah we're gonna set an account ID by the callers account ID so we can get that out the context of the call so and we use near for this uh there's a special section in our docs in docs.near.org that explains what kind of stuff you can get out of the context so
- 9:27
let's just dig in here and we can see a bunch of stuff in here so there's in fact a lot you can get out of it um in our case we are going to get the uh it's not even here perhaps nope no we're going to get something else we're going to get a predecessor a county this is also explained in the docs there's a difference between the signer account ID and the predecessor account ID
- 9:55
namely the predecessor is a account that originally initiated the transaction sometimes you can have an account that initiates a transaction and then another account executes a part of it and by coincidence this other account that executes a part of the transaction can also be the most recent one so if you do this you're getting the most recent account and if you do this you get the one that initiated the call so that's uh
- 10:22
in short what the difference is it's explained more in detail on dotsonier.org also uh what you get in docstoneer.org is uh yeah everything that you can get out of the context when uh this this small piece of logic is being run um uh yes such as those two variables but I think you could also get stuff about the storage uh there's a lot of different concepts in here but yeah they're all explained in detail over
- 10:46
there so great so now the contract is doing exactly what we wanted to so uh we have our greetings they're indexed by account ID if it's not found then until it's not found and yeah we can set we can set the message or message string that will be just an Xbox exactly that we wanted to be indexed by so our next step right now is to execute the tests and hopefully they'll pass so let's see what we get
- 11:14
okay so we're back to the terminal now what I'm going to do is run r so if we look closely we're in we're in the uh we're in the project repository so I'm going to run the command for running the test switch um it's further specified in the package.json file so if you have a look around there you're going to see what it's uh the batch commands that it's going to run so uh yeah what it's also
- 11:39
telling us here in the output is it's using near sdkjs to um create a DOT wasn't file with a JavaScript logic logic in the end in a near what you need to deploy a smart contract to an account is a DOT wasn't file the dot wasn't file holds the logic for your smart contract and as long as you have that you can deploy to your account so you could write your contract code in any language of choice right now there's a good sdks for both JavaScript and rust out there but the community is
- 12:11
also working in a couple more so uh yeah there's incredible flexibility there um yeah so if we look at the outcomes of our tests uh they failed um but uh the wasn't file was created here and it was deployed to the localized uh near blockchain um but yeah our test failed this happens all the time uh let's see what we got here uh yeah this was our first test case and it's telling us in the message uh the method's not being found so my
- 12:41
guess is uh probably there's something wrong with the function names so we're back here to our project in vs code and if I read our tests here I see where I see a couple things actually we're calling this get message and set message that's probably different to what we have yeah get greeting and set creating this or smart contract code so the name of the function does not match so that doesn't match what we designed in our tests so
- 13:13
uh yeah this this code is wrong in fact it should match what we have originally devised here so let's let's just change the name of the functions set message and yes message that's right and we are supposed to pass in an account ID with this name so in snake case instead of camel case so in our interface we should also do that so account ID do this and there we go and we also pass it in like that
- 13:52
makes much more sense so I think our smart contract code now matches what we originally designed in our tests so let's give this one a go and see how it goes all right so let's run these tests again and see how we do this time so we're running npm tests again which will create a new awesome file in this case from our smart contract code we need that to happen because we updated our smart contract and then it will run our tests against
- 14:25
that updated wasn't so let's see how it goes I'll speed up the video now and uh we'll jump to the result great so our test passed and we're now done we've designed and developed the JavaScript smart contract for near using tdd so yay so let's wrap it up so we've done the entire cycle uh we started with a blank project we thought about our functionality then we started with the tests
- 15:06
that made our requirements concrete and set our uh design in code then we made our smart contract code we ran our tests they failed uh we worked through the errors and now everything works so that really is the entire Spectrum within 15 minutes I hope you guys liked it there are a couple of more things I'd like to share uh one of them is this link so near.dev is going to take you to a site that has a few smart contract examples
- 15:37
for you guys to have a look through by all means feel inspired have a look around I've implemented a lot of the tests uh NCI for these examples and if you think it can be done better by all means also open up a PR that will make you very happy um yeah so uh feel free to explore and adventure around we are also available on a Discord server so if you follow this link that will be uh invite for Discord server we
- 16:05
have a dedicated deaf support chat where you can ask questions on developing on the year and we also host office hours both in the America's time zones and in the Europe time zones so you can find us there live and ask us questions ask us ask us questions they're live as well so also by all means feel free uh yeah so once again thank you guys very much uh I hope uh this will be this will mean a
- 16:31
lot for you and your development and you'll be able to improve your development Cycles as I have been able to uh with the help of these libraries and this way of approaching development um and yeah maybe see you next time