Skip to content

Commit 0fdf13d

Browse files
authored
Merge pull request #132 from Developer-DAO/lesson-4-improvements
Lesson 4: Improvements
2 parents 801b01a + 81694ab commit 0fdf13d

File tree

1 file changed

+129
-62
lines changed

1 file changed

+129
-62
lines changed

lessons/projects/4.mdx

Lines changed: 129 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -35,69 +35,45 @@ expected when changes are made.
3535
Automated tests don't fully replace manually testing your smart contract but
3636
it's an important tool to ensuring your contract will work as expected.
3737

38-
## Let's add some tests
38+
## Let's Get Started
3939

40-
### First configure hardhat for testing
40+
### Setting up our project dependencies
4141

42-
<ContentCallout emoji="💡" size="md" variant="info">
43-
We'll depend on `hardhat` as our project framework and will use its testing
44-
features. Your project is already hardhat-based so you should be all set to
45-
continue. However if you're unsure on how to setup the initial hardhat
46-
project, refer to Lesson 2 and search for `npx hardhat` in the "Create your
47-
project" section.
48-
</ContentCallout>
49-
50-
Add a line in your `scripts` section of `package.json` so it looks like this
51-
below. You may already have other scripts' lines so don't get rid of those.
52-
53-
```javascript
54-
"scripts": {
55-
"test": "hardhat test --network hardhat"
56-
},
57-
```
58-
59-
Next create a `test` folder in the root of your project, and add a new file
60-
called `tier-nft.test.js` with these lines:
42+
If you have an existing project from your previous work on the TierNFT lesson,
43+
you have all the Hardhat dependencies installed.
6144

62-
```javascript
63-
const { expect } = require('chai')
45+
Otherwise let's create a new Hardhat project and copy in the contract which
46+
we'll be testing.
6447

65-
describe('TierNFT', function () {
66-
it('placeholder test')
67-
})
68-
```
48+
To create a new project, please refer to _Lesson 3 - Tier NFTs_ and search for
49+
the “First things first 👷‍♂️" section to get your project going. Follow the steps
50+
until "Let’s start coding”, then open up your code editor.
6951

70-
<ContentCallout emoji="💡" size="md" variant="info">
71-
`expect()` from the Chai library is used to test various conditions. There are
72-
many examples in this lesson.
73-
</ContentCallout>
52+
_If you are using VSCode, type `code .` in your terminal to open VSCode._
7453

75-
Now with a test file and a command to run the tests, try `npm test` and you
76-
should see:
54+
After running through that section you'll have a working Hardhat project for the
55+
next steps.
7756

78-
```bash
79-
TierNFT
80-
- placeholder test
57+
### Add test command for running tests
8158

59+
Add a line in your `scripts` section of `package.json` so it looks like this
60+
below. You may already have other scripts' lines so don't get rid of those. If
61+
you already have a `"test"` script line, make sure it now has
62+
`hardhat test --network hardhat`. If you have multiple script lines make sure
63+
the last line does not have a comma at the end, otherwise you'll see an error.
8264

83-
0 passing (5ms)
84-
1 pending
65+
```javascript
66+
"scripts": {
67+
"something": "some other script",
68+
"test": "hardhat test --network hardhat"
69+
},
8570
```
8671

87-
This now proves:
88-
89-
- hardhat is running ok
90-
- the tests are found and are running
72+
### Bring in the contract we'll be testing
9173

92-
`pending` means we haven't added the real test yet, so it is neither passing nor
93-
failing. Adding `pending` placeholders are a good way to brainstorm and remind
94-
yourself what tests you need to write.
95-
96-
## What do we want to test on our TierNFT contract?
97-
98-
Now that the tools are set up, what should we test?
99-
100-
Let's look at our contract from Lesson 3:
74+
If you don't already have `TierNFT.sol` in your project from Lesson 3, below is
75+
that same contract. Please create a new file called `TierNFT.sol` in a
76+
`contracts` folder in the root of the project, and copy in this code:
10177

10278
```solidity
10379
// SPDX-License-Identifier: MIT
@@ -198,6 +174,32 @@ contract TierNFT is ERC721, Ownable {
198174
}
199175
```
200176

177+
### Verify Solidity Version
178+
179+
One small, but crucial change before we proceed. Ensure the version of Solidity
180+
being used to run the contract is the same one configured in
181+
`hardhat.config.js`.
182+
183+
Copy the Solidity version from the `pragma` statement at the top of your
184+
contract, to the `hardhat.config.js` file and replace that `solidity: "version"`
185+
with that of your contract.
186+
187+
For example, since our contract is using Solidity `0.8.12`:
188+
189+
```
190+
require("@nomicfoundation/hardhat-toolbox");
191+
require('dotenv').config();
192+
193+
module.exports = {
194+
solidity: "0.8.12",
195+
};
196+
```
197+
198+
## What do we want to test on our TierNFT contract?
199+
200+
Now that the tools are set up, let's talk about what we want to test in our
201+
smart contract. We'll then create the tests.
202+
201203
What is the contract trying to do?
202204

203205
- it accepts payment and mints NFTs
@@ -212,6 +214,12 @@ We want to test that those functions work in a variety of cases.
212214
For example, we can test that a mint happens when enough Eth is spent and that a
213215
mint fails if there is not enough Eth spent.
214216

217+
### Creating our test file
218+
219+
If you don't have one already, create a `test` folder in the root of your
220+
project, and add a new file called `tier-nft.test.js` which will hold our new
221+
test code.
222+
215223
### Start testing constructor(), mint() and withdraw()
216224

217225
Let's start with testing the `constructor` and making sure we can set and
@@ -220,6 +228,8 @@ retrieve the NFT name and symbol.
220228
In addition to these first two tests we'll add setup code that we'll reuse for
221229
all the other tests too.
222230

231+
Please add the following code to your new `tier-nft.test.js` file:
232+
223233
```javascript
224234
const { expect } = require('chai')
225235

@@ -257,6 +267,20 @@ describe('TierNFT', function () {
257267
})
258268
```
259269

270+
<ContentCallout emoji="💡" size="md" variant="info">
271+
Before we walk through, let's make sure everything is working correctly. Run
272+
the tests using `npm test` and you should see these two initial tests pass.
273+
**This is an important milestone! You created your first tests and they now
274+
pass.**
275+
</ContentCallout>
276+
277+
Now let's walk through the test code we've pasted in and explain what it does.
278+
279+
<ContentCallout emoji="💡" size="md" variant="info">
280+
`expect()` from the Chai library is used to test various conditions. There are
281+
many examples in this lesson.
282+
</ContentCallout>
283+
260284
At the top we see constants with the name and symbol of the NFT collection:
261285

262286
```javascript
@@ -370,7 +394,39 @@ failure looks like:
370394

371395
### Let's add tests for mint()
372396

373-
Here are tests we'll be adding:
397+
Now is time to add tests for our `mint()` method. We'll group these new tests
398+
into a new `describe` section.
399+
400+
Where exactly do we add this `describe` block?
401+
402+
Currently the end of our `tier-nft.test.js` looks like this, with just one
403+
additional comment line I added that says
404+
`// this is where existing describe section ends`:
405+
406+
```javascript
407+
describe('constructor', async () => {
408+
it('set proper collection name', async function () {
409+
const name = await contract.name()
410+
expect(name).to.equal('TierNFT')
411+
})
412+
413+
it('set proper collection symbol', async function () {
414+
const symbol = await contract.symbol()
415+
expect(symbol).to.equal('Tier')
416+
})
417+
})
418+
// this is where existing describe section ends
419+
})
420+
```
421+
422+
Our new `describe` section show below will replace that line that says
423+
`// this is where existing describe section ends`.
424+
425+
<ContentCallout emoji="💡" size="md" variant="info">
426+
Make sure you keep that last line `})` which is the very end of the block of
427+
code that holds **all** of the `describe` blocks you're adding in this whole
428+
lesson.
429+
</ContentCallout>
374430

375431
```javascript
376432
describe('mint', async () => {
@@ -413,6 +469,10 @@ describe('mint', async () => {
413469
})
414470
```
415471

472+
<ContentCallout emoji="💡" size="md" variant="info">
473+
Run the tests using `npm test`
474+
</ContentCallout>
475+
416476
These tests introduce additional code that are helpful when testing contracts.
417477

418478
With minting, one needs to pay the right price, we should also see the total
@@ -424,20 +484,19 @@ occurs. If not enough Eth is sent, the contract fails with an error and the
424484
transaction is reverted as if nothing happened.
425485

426486
In this first test we want to ensure our method call is properly reverted when
427-
the proper amount of Eth is not provided. This happens in the
428-
`await expect().to.be.revertedWith('Not enough value for the minimum Tier')`
429-
line. _The code calling the contract has been temporarily removed to highlight
430-
what's happening._ We're expecting the call to be reverted when not sending
431-
enough payment, along with a specific error message from the contract.
432-
433-
And the method inside that `expect()` method looks like this:
487+
the proper amount of Eth is not provided. This happens here:
434488

435489
```javascript
436-
contract.mint({
437-
value: hre.ethers.utils.parseEther('0.001'),
438-
})
490+
await expect(
491+
contract.mint({
492+
value: hre.ethers.utils.parseEther('0.001'),
493+
}),
494+
).to.be.revertedWith('Not enough value for the minimum Tier')
439495
```
440496

497+
We're expecting the call to be reverted when not sending enough payment, along
498+
with a specific error message from the contract.
499+
441500
Here we're just calling `mint()` with a parameter that sets the amount of Eth we
442501
want to send. In this case `0.001` Eth is less than our contract minimum of
443502
`0.01` Eth so this correctly fails. Our test confirms this.
@@ -487,6 +546,10 @@ describe('withdrawal', async () => {
487546
})
488547
```
489548

549+
<ContentCallout emoji="💡" size="md" variant="info">
550+
Run the tests using `npm test`
551+
</ContentCallout>
552+
490553
You'll see similar patterns from the previous `mint()` tests. Here are a couple
491554
of additional highlights:
492555

@@ -777,6 +840,10 @@ describe('tokenURI and helpers', async () => {
777840
})
778841
```
779842

843+
<ContentCallout emoji="💡" size="md" variant="info">
844+
Run the tests using `npm test`
845+
</ContentCallout>
846+
780847
The final test is an example mentioned earlier about adding a test before
781848
refactoring with helper methods. It checks that the initial `tokenURI()` method
782849
(which returns an encoded Base64 string) returns the right result. It's helpful

0 commit comments

Comments
 (0)