I'm writing unit tests for my e-commerce smart contract and they keep failing. Wonder what I'm doing wrong.
I want to check;
- that buyer pays exact price
- that seller cannot be the buyer
- that product is bought successfully and emits event
The first test passes even when the
testPrice
is less the required price.The second test reverts with;
AssertionError: Expected transaction to be reverted with custom error 'Ecommerce__SellerCannotBeBuyer', but it reverted with custom error 'Ecommerce__PriceNotMet'
- The third test reverts with;
Error: VM Exception while processing transaction: reverted with custom error 'Ecommerce__PriceNotMet()'
Ecommerce.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Ecommerce {
// properties of a product
struct Product {
string title;
string description;
uint price;
uint productId;
address payable seller;
address buyer;
bool delivered;
}
Product[] public products;
uint counter = 1;
//errors
error Ecommerce__PriceMustBeGreater0();
error Ecommerce__PriceNotMet();
error Ecommerce__SellerCannotBeBuyer();
// events
event Registered(string title, uint productId, address seller);
event Bought(uint productId, address buyer);
event Delivered(uint productId);
constructor() {}
function registerProduct(
string memory _title,
string memory _description,
uint _price
) public {
//require(_price > 0, "Price has to be greater than 0!");
if (_price <= 0) {
revert Ecommerce__PriceMustBeGreater0();
}
Product memory tempProduct;
tempProduct.title = _title;
tempProduct.description = _description;
tempProduct.price = _price * 10 ** 18;
tempProduct.seller = payable(msg.sender);
tempProduct.productId = counter;
products.push(tempProduct);
counter++;
//products[tempProduct.productId - 1].seller = payable(msg.sender);
emit Registered(_title, tempProduct.productId, msg.sender);
}
function buy(uint _productId) public payable {
/* require(
products[_productId - 1].price == msg.value,
"Please pay the exact price"
); */
if (products[_productId - 1].price != msg.value) {
revert Ecommerce__PriceNotMet();
}
/* require(
products[_productId - 1].seller != msg.sender,
"You can't buy your own products!"
); */
if (products[_productId - 1].seller == msg.sender) {
revert Ecommerce__SellerCannotBeBuyer();
}
products[_productId - 1].buyer = msg.sender;
emit Bought(_productId, msg.sender);
}
function delivery(uint _productId) public {
require(
products[_productId - 1].buyer == msg.sender,
"only the buyer can call this fuction"
);
products[_productId - 1].delivered = true;
products[_productId - 1].seller.transfer(
products[_productId - 1].price // we can charge a fee for the buyer's using our platform at this point eg. (price * 98%)
);
emit Delivered(_productId);
}
}
test.js
describe("Buying a Product", () => {
it("checks that buyer pays exact price", async () => {
const productId = 1
const testPrice = ethers.utils.parseEther("0")
// connect the buyer/player
const playerConnectedEcommerce = ecommerce.connect(player)
// first register product
await ecommerce.registerProduct(TITLE, DESCRIPTION, PRICE)
// buy
console.log("Now we buy")
await expect(
playerConnectedEcommerce.buy(productId, { value: testPrice })
).to.be.revertedWithCustomError(ecommerce, "Ecommerce__PriceNotMet")
// Passes even with the testPrice as 0eth. It should fail.
})
it("checks that seller cannot be the buyer ", async () => {
const productId = 1
// first register product
await ecommerce.registerProduct(TITLE, DESCRIPTION, PRICE)
// buy
// should revert if the same person who registered(seller), tries to buy
await expect(
ecommerce.buy(productId, { value: PRICE })
).to.be.revertedWithCustomError(ecommerce, "Ecommerce__SellerCannotBeBuyer")
})
it("checks that product is bought successfully and emits event", async () => {
const productId = 1
// connect the buyer/player
const playerConnectedEcommerce = ecommerce.connect(player)
// first register product
await ecommerce.registerProduct(TITLE, DESCRIPTION, PRICE)
// buy
console.log("Now we buy")
await expect(playerConnectedEcommerce.buy(productId)).to.emit("Bought")
})
})
deploy.js
const { network } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")
module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
log("-----------------------------------------------------")
const args = []
const ecommerce = await deploy("Ecommerce", {
from: deployer,
args: args,
log: true,
waitConfirmations: network.config.blockConfirmations || 1,
})
// verify contract
if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
log("Verifying.....")
await verify(ecommerce.address, args)
}
log("-----------------------------------------------------")
}
module.exports.tags = ["all", "ecommerce"]
For full code check my [Git Repo] (https://github.com/kihiuFrank/EcommerceSmartContract)