-
Notifications
You must be signed in to change notification settings - Fork 0
/
Raffle.test.js
198 lines (190 loc) · 12.1 KB
/
Raffle.test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
const { assert, expect } = require("chai")
const { network, deployments, ethers } = require("hardhat")
const { developmentChains, networkConfig } = require("../../helper-hardhat-config")
!developmentChains.includes(network.name)
? describe.skip
: describe("Raffle Unit Tests", function () {
let raffle, raffleContract, vrfCoordinatorV2Mock, raffleEntranceFee, interval, player // , deployer
beforeEach(async () => {
accounts = await ethers.getSigners() // could also do with getNamedAccounts
// deployer = accounts[0]
player = accounts[1]
await deployments.fixture(["mocks", "raffle"]) // Deploys modules with the tags "mocks" and "raffle"
vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock") // Returns a new connection to the VRFCoordinatorV2Mock contract
raffleContract = await ethers.getContract("Raffle") // Returns a new connection to the Raffle contract
raffle = raffleContract.connect(player) // Returns a new instance of the Raffle contract connected to player
raffleEntranceFee = await raffle.getEntranceFee()
interval = await raffle.getInterval()
})
describe("constructor", function () {
it("initializes the raffle correctly", async () => {
// Ideally, we'd separate these out so that only 1 assert per "it" block
// And ideally, we'd make this check everything
const raffleState = (await raffle.getRaffleState()).toString()
// Comparisons for Raffle initialization:
assert.equal(raffleState, "0")
assert.equal(
interval.toString(),
networkConfig[network.config.chainId]["keepersUpdateInterval"]
)
})
})
describe("enterRaffle", function () {
it("reverts when you don't pay enough", async () => {
await expect(raffle.enterRaffle()).to.be.revertedWith( // is reverted when not paid enough or raffle is not open
"Raffle__SendMoreToEnterRaffle"
)
})
it("records player when they enter", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
const contractPlayer = await raffle.getPlayer(0)
assert.equal(player.address, contractPlayer)
})
it("emits event on enter", async () => {
await expect(raffle.enterRaffle({ value: raffleEntranceFee })).to.emit( // emits RaffleEnter event if entered to index player(s) address
raffle,
"RaffleEnter"
)
})
it("doesn't allow entrance when raffle is calculating", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
// for a documentation of the methods below, go here: https://hardhat.org/hardhat-network/reference
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
// we pretend to be a keeper for a second
await raffle.performUpkeep([]) // changes the state to calculating for our comparison below
await expect(raffle.enterRaffle({ value: raffleEntranceFee })).to.be.revertedWith( // is reverted as raffle is calculating
"Raffle__RaffleNotOpen"
)
})
})
describe("checkUpkeep", function () {
it("returns false if people haven't sent any ETH", async () => {
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x") // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert(!upkeepNeeded)
})
it("returns false if raffle isn't open", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
await raffle.performUpkeep([]) // changes the state to calculating
const raffleState = await raffle.getRaffleState() // stores the new state
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x") // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert.equal(raffleState.toString() == "1", upkeepNeeded == false)
})
it("returns false if enough time hasn't passed", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() - 5])
await network.provider.request({ method: "evm_mine", params: [] })
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x") // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert(!upkeepNeeded)
})
it("returns true if enough time has passed, has players, eth, and is open", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x") // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert(upkeepNeeded)
})
})
describe("performUpkeep", function () {
it("can only run if checkupkeep is true", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
const tx = await raffle.performUpkeep("0x")
assert(tx)
})
it("reverts if checkup is false", async () => {
await expect(raffle.performUpkeep("0x")).to.be.revertedWith(
"Raffle__UpkeepNotNeeded"
)
})
it("updates the raffle state and emits a requestId", async () => {
// Too many asserts in this test!
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
const txResponse = await raffle.performUpkeep("0x") // emits requestId
const txReceipt = await txResponse.wait(1) // waits 1 block
const raffleState = await raffle.getRaffleState() // updates state
const requestId = txReceipt.events[1].args.requestId
assert(requestId.toNumber() > 0)
assert(raffleState == 1) // 0 = open, 1 = calculating
})
})
describe("fulfillRandomWords", function () {
beforeEach(async () => {
await raffle.enterRaffle({ value: raffleEntranceFee })
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1])
await network.provider.request({ method: "evm_mine", params: [] })
})
it("can only be called after performupkeep", async () => {
await expect(
vrfCoordinatorV2Mock.fulfillRandomWords(0, raffle.address) // reverts if not fulfilled
).to.be.revertedWith("nonexistent request")
await expect(
vrfCoordinatorV2Mock.fulfillRandomWords(1, raffle.address) // reverts if not fulfilled
).to.be.revertedWith("nonexistent request")
})
// This test is too big...
// This test simulates users entering the raffle and wraps the entire functionality of the raffle
// inside a promise that will resolve if everything is successful.
// An event listener for the WinnerPicked is set up
// Mocks of chainlink keepers and vrf coordinator are used to kickoff this winnerPicked event
// All the assertions are done once the WinnerPicked event is fired
it("picks a winner, resets, and sends money", async () => {
const additionalEntrances = 3 // to test
const startingIndex = 2
for (let i = startingIndex; i < startingIndex + additionalEntrances; i++) { // i = 2; i < 5; i=i+1
raffle = raffleContract.connect(accounts[i]) // Returns a new instance of the Raffle contract connected to player
await raffle.enterRaffle({ value: raffleEntranceFee })
}
const startingTimeStamp = await raffle.getLastTimeStamp() // stores starting timestamp (before we fire our event)
// This will be more important for our staging tests...
await new Promise(async (resolve, reject) => {
raffle.once("WinnerPicked", async () => { // event listener for WinnerPicked
console.log("WinnerPicked event fired!")
// assert throws an error if it fails, so we need to wrap
// it in a try/catch so that the promise returns event
// if it fails.
try {
// Now lets get the ending values...
const recentWinner = await raffle.getRecentWinner()
const raffleState = await raffle.getRaffleState()
const winnerBalance = await accounts[2].getBalance()
const endingTimeStamp = await raffle.getLastTimeStamp()
await expect(raffle.getPlayer(0)).to.be.reverted
// Comparisons to check if our ending values are correct:
assert.equal(recentWinner.toString(), accounts[2].address)
assert.equal(raffleState, 0)
assert.equal(
winnerBalance.toString(),
startingBalance // startingBalance + ( (raffleEntranceFee * additionalEntrances) + raffleEntranceFee )
.add(
raffleEntranceFee
.mul(additionalEntrances)
.add(raffleEntranceFee)
)
.toString()
)
assert(endingTimeStamp > startingTimeStamp)
resolve() // if try passes, resolves the promise
} catch (e) {
reject(e) // if try fails, rejects the promise
}
})
// kicking off the event by mocking the chainlink keepers and vrf coordinator
const tx = await raffle.performUpkeep("0x")
const txReceipt = await tx.wait(1)
const startingBalance = await accounts[2].getBalance()
await vrfCoordinatorV2Mock.fulfillRandomWords(
txReceipt.events[1].args.requestId,
raffle.address
)
})
})
})
})