npx hardhat test returns "0 passing" no matter what I try - chai

I am following this tutorial on youtube "https://www.youtube.com/watch?v=7QsqElEaWBQ"
And I have double checked to make sure my code matches, but I am stuck at the 41:00 minute mark where I am testing the project. It consistently shows "0 passing". There is no fail message which I saw in the tutorial video. This makes me believe that they aren't even getting tested. I have installed all dependencies required in the beginning, checked to make sure my file names match and still no luck. This test is using using hardhat-waffle.
Here is my "Testing.js" file code =>
const { expect } = require("chai");
const { ethers } = require("ethers");
const {
isCallTrace,
} = require("hardhat/internal/hardhat-network/stack-traces/message-trace");
describe("Staking", function () {
beforeEach(async function () {
[signer1, signers2] = await ethers.getSigners();
Staking = await ethers.getContractFactory("Staking", signer1);
staking = await Staking.deploy({
value: ethers.utils.parseEther("10"),
});
});
describe("deploy", function () {
it("should set owner", async function () {
expect(await staking.owner()).to.equal(signer1.address);
});
it("sets up tiers and lockPeriods", async function () {
expect(await staking.lockPeriods(0)).to.equal(30);
expect(await staking.lockPeriods(1)).to.equal(90);
expect(await staking.lockPeriods(2)).to.equal(180);
expect(await staking.tiers(3)).to.equal(700);
expect(await staking.tiers(3)).to.equal(1000);
expect(await staking.tiers(3)).to.equal(1200);
});
});
describe("stakeEther", function () {
it("transfers ether", async function () {
const provider = waffle.provider;
let contractBalance;
let signerBalance;
const transferAmount = ethers.utils.parseEther("2.0");
contractBalance = await provider.getBalance(staking.address);
signerBalance = await signer1.getBalance();
const data = { value: transferAmount };
const transaction = await staking.connect(signer1).stakeEther(30, data);
const receipt = await transaction.wait();
const gasUsed = receipt.gasUsed.mul(receipt.effectiveGasPrice);
//test the change in signer1's ether balance
expect(await signer1.getBalance()).to.equal(
signerBalance.sub(transferAmount).sub(gasUsed)
);
// test the change in contract's ether balance
expect(await provider.getBalance(staking.address)).to.equal(
contractBalance.add(transferAmount)
);
});
});
});
If you know how to solve my issue, please let me know. That would be a great help to me!

Please be sure, that Testing.js is placed in the folder test and folder test is placed next to package.json

Related

Unable to set state variables during staging test on Goerli using Hardhat

I am able to set variables during my unit tests on the local Hardhat Node, however the same test fails on Goerli.
This is the code for my test:
const { getNamedAccounts, deployments, ethers, network } = require("hardhat")
const { developmentChains, networkConfig } = require("../../helper-hardhat-config")
const { assert, expect } = require("chai")
const fs = require("fs")
const path = require("path")
developmentChains.includes(network.name)
? describe.skip
: describe("Whoopy Staging Tests", function () {
let whoopy,
deployer,
player,
cloneAddress,
clonedContract,
txReceipt,
tx,
accountConnectedClone,
manager,
create
const chainId = network.config.chainId
beforeEach(async function () {
accounts = await ethers.getSigners()
deployer = accounts[0]
player = accounts[1]
await deployments.fixture(["all"])
const dir = path.resolve(
__dirname,
"/Users/boss/hardhat-smartcontract-whoopy/artifacts/contracts/Whoopy.sol/Whoopy.json"
)
const file = fs.readFileSync(dir, "utf8")
const json = JSON.parse(file)
const abi = json.abi
whoopy = await ethers.getContract("Whoopy", deployer)
manager = await ethers.getContract("VRFv2SubscriptionManager", deployer)
wf = await ethers.getContract("WhoopyFactory", deployer)
tx = await (await wf.connect(player).createClone(player.address))
txReceipt = await tx.wait(1)
cloneAddress = await txReceipt.events[1].args._instance
clonedContract = new ethers.Contract(cloneAddress, abi, player)
accountConnectedClone = clonedContract.connect(player)
})
describe("Whoopy Tests", function () {
beforeEach(async function () {
create = await accountConnectedClone.createWhoopy(
"Test",
1,
{
value: ethers.utils.parseUnits("10000000000000000", "wei"),
gasLimit: 3000000
})
console.log(create)
})
it("creates Whoopy correctly", async function () {
const whoopyName = await accountConnectedClone.getWhoopyName()
const num = await accountConnectedClone.getNum()
expect(whoopyName).to.equal("Test")
expect(num).to.equal(1)
})
})
Here is the function I am testing:
function createWhoopy( //to be created only once
string memory s_whoopyName,
uint256 s_num,
) public payable restricted {
whoopyName = s_whoopyName;
num = s_num;
}
Seems pretty straight forward but don't know why it's not working. My accounts have enough test eth and goerli is correctly set up in Hardhat config. The test reverts as follows:
AssertionError: expected '' to equal 'Test'
+ expected - actual
+Test
Any guidance would be appreciated! Thanks!
I figured it out. It was something stupid (as I thought it would be). I forgot to put await create.wait(6) which was needed to wait for the blocks to mine the transaction.
It went through on Hardhat because Hardhat mines blocks immediately, but since Goerli is a live Testnet you need to wait for the transaction to be mined.

before, beforeEach does not execute in hardhat test

This code is for testing a Silent Auction smart contract written in hardhat.
When I type everything separately into the it{...} blocks, the test are passing. When using before, and beforeEach to simplify the code it doesnt work.
Error message: "ReferenceError: silentAuction is not defined"
Can somebody tell me which part I do wrong?
const { BigNumber } = require("ethers");
const { ethers } = require("hardhat");
describe("SilentAuction", function () {
before(async function () {
const SilentAuction = await ethers.getContractFactory("SilentAuction");
})
beforeEach(async function () {
const silentAuction = await SilentAuction.deploy();
await silentAuction.deployed();
})
describe("- setItem function tests", function (){
it("Owner should be able to set an item for bid", async function () {
//const SilentAuction = await ethers.getContractFactory("SilentAuction");
//const silentAuction = await SilentAuction.deploy();
//await silentAuction.deployed();
await silentAuction.setItem("SAMPLE", 100, 300);
expect((await silentAuction.items(0)).name).to.be.equal("SAMPLE");
expect((await silentAuction.items(0)).highestPrice.toString()).to.be.equal('100');
expect((await silentAuction.items(0)).successLimit.toString()).to.be.equal('300');
});
it("Not owner cannot call function", async function () {
const [owner, addr1] = await ethers.getSigners();
//const SilentAuction = await ethers.getContractFactory("SilentAuction");
//const silentAuction = await SilentAuction.deploy();
//await silentAuction.deployed();
await expect(silentAuction.connect(addr1).setItem("SAMPLE", 100, 300)).to.be.reverted;
});
});
describe("- bid function tests", function (){
it("Everyone should place a bid", async function () {
const [owner, addr1] = await ethers.getSigners();
//const SilentAuction = await ethers.getContractFactory("SilentAuction");
//const silentAuction = await SilentAuction.deploy();
//await silentAuction.deployed();
await silentAuction.connect(owner).setItem("SAMPLE", 100, 300);
await silentAuction.connect(addr1).bid(200);
expect((await silentAuction.items(0)).highestPrice.toString()).to.be.equal('200');
})
it("Should not replace smaller bids than the recent highest", async function () {
const [owner, addr1] = await ethers.getSigners();
//const SilentAuction = await ethers.getContractFactory("SilentAuction");
//const silentAuction = await SilentAuction.deploy();
//await silentAuction.deployed();
await silentAuction.connect(owner).setItem("SAMPLE", 100, 300);
await silentAuction.connect(addr1).bid(50);
expect((await silentAuction.items(0)).highestPrice.toString()).to.be.equal('100');
})
})
});
silentAuction is a constant which is defined in the scope of before or beforeEach function, not in the scope of whole tests.
If you want to use such variable in the whole tests, you should do something like this:
describe('foo' () => {
let silentAuction;
beforeEach(() => {
silentAuction = ...
})
})
Also the reason you get reference error is that every test function can't find such variable within its or outer scope then it raises Reference Error.

Jest does not continue after async method

I have an async method triggered by a click event where I make a call to an API and then process the response, like this:
async confirmName () {
const {name, description} = this.form;
const [data, error] = await Pipelines.createPipeline({name, description});
if (error) {
console.error(error);
this.serviceError = true;
return false;
}
this.idPipelineCreated = data.pipeline_id;
return true;
}
The test looks like this:
test("API success", async () => {
const ConfirmNameBtn = wrapper.find(".form__submit-name");
await ConfirmNameBtn.vm.$emit("click");
const pipelinesApi = new Pipelines();
jest.spyOn(pipelinesApi, "createPipeline").mockResolvedValue({pipeline_id: 100});
const {name, description} = wrapper.vm.form;
pipelinesApi.createPipeline().then(data => {
expect(wrapper.vm.pipelineNameServiceError).toBe(false);
wrapper.setData({
idPipelineCreated: data.pipeline_id
});
expect(wrapper.vm.idPipelineCreated).toBe(data.pipeline_id)
}).catch(() => {})
})
A basic class mock:
export default class Pipelines {
constructor () {}
createPipeline () {}
}
I'm testing a success API call and I mock the API call returning a resolved promised. The problem is the coverage only covers the first two lines of the method, not the part where I assign the response of the API call. Is this the correct approach?
Edit:
Screenshot of coverage report:
Don't mix up await and then/catch. Prefer using await unless you have very special cases (see this answer):
test("API success", async () => {
const ConfirmNameBtn = wrapper.find(".form__submit-name");
await ConfirmNameBtn.vm.$emit("click");
const pipelinesApi = new Pipelines();
jest.spyOn(pipelinesApi, "createPipeline").mockResolvedValue({pipeline_id: 100});
const {name, description} = wrapper.vm.form;
const data = await pipelinesApi.createPipeline();
expect(wrapper.vm.pipelineNameServiceError).toBe(false);
wrapper.setData({
idPipelineCreated: data.pipeline_id
});
expect(wrapper.vm.idPipelineCreated).toBe(data.pipeline_id)
expect(wrapper.vm.serviceError).toBe(false);
})

Express router's mock post handler doesn't work as expected

I have a documents router which has router.post('/mine', [auth, uploadFile], async (req, res) => { ... }) route handler. The actual implementation of this route handler is below.
documents.js router
const createError = require('./../helpers/createError');
const auth = require('./../middlewares/auth');
const uploadFile = require('./../middlewares/uploadFile');
const express = require('express');
const router = express.Router();
router.post('/mine', [auth, uploadFile], async (req, res) => {
try {
let user = await User.findById(req.user._id);
let leftDiskSpace = await user.leftDiskSpace();
if(leftDiskSpace < 0) {
await accessAndRemoveFile(req.file.path);
res.status(403).send(createError('Your plan\'s disk space is exceeded.', 403));
} else {
let document = new Document({
filename: req.file.filename,
path: `/uploads/${req.user.username}/${req.file.filename}`,
size: req.file.size
});
document = await document.save();
user.documents.push(document._id);
user = await user.save();
res.send(document);
}
} catch(ex) {
res.status(500).send(createError(ex.message, 500));
}
});
module.exports = router;
I'm currently writing integration tests using Jest and Supertest. My current documents.test.js test file is below:
documents.test.js test file
const request = require('supertest');
const { Document } = require('../../../models/document');
const { User } = require('../../../models/user');
const fs = require('fs');
const path = require('path');
let server;
describe('/api/documents', () => {
beforeEach(() => { server = require('../../../bin/www'); });
afterEach(async () => {
let pathToTestFolder = path.join(process.cwd(), config.get('diskStorage.destination'), 'user');
// Remove test uploads folder for next tests
await fs.promises.access(pathToTestFolder)
.then(() => fs.promises.rm(pathToTestFolder, { recursive: true }))
.catch((err) => { return; });
// Remove all users and documents written in test database
await User.deleteMany({});
await Document.deleteMany({});
server.close();
});
describe('POST /mine', () => {
it('should call user.leftDiskSpace method once', async () => {
let user = new User({
username: 'user',
password: '1234'
});
user = await user.save();
let token = user.generateAuthToken();
let file = path.join(process.cwd(), 'tests', 'integration', 'files', 'test.json');
let documentsRouter = require('../../../routes/documents');
let errorToThrow = new Error('An error occured...');
user.leftDiskSpace = jest.fn().mockRejectedValue(errorToThrow);
let mockReq = { user: user };
let mockRes = {};
documentsRouter.post = jest.fn();
documentsRouter.post.mockImplementation((path, callback) => {
if(path === '/mine') {
console.warn('called');
callback(mockReq, mockRes);
}
});
const res = await request(server)
.post('/api/documents/mine')
.set('x-auth-token', token)
.attach('document', file);
expect(documentsRouter.post).toHaveBeenCalled();
expect(user.leftDiskSpace).toHaveBeenCalled();
});
});
});
I create mock post router handler for documents.js router. As you can see from mockImplementation for this route handler, it checks if the path is equal to '/mine' (which is my supertest endpoint), then calls console.warn('called'); and callback. When I run this test file, I can not see any yellow warning message with body 'called'. And also when POST request endpoint /api/documents/mine the server doesn't trigger my mock function documentsRouter.post. It has never been called. So I think the server's documents router is not getting replaced with my mock post route handler. It still uses original post route handler to respond my POST request. What should I do to test if my mock documentsRouter.post function have been called?
Note that my User model has a custom method for checking left disk space of user. I also tried to mock that mongoose custom method but It also doesn't work.

How do I split my Jest + Puppeteer tests in multiple files?

I am writing automated tests using Jest & Puppeteer for a Front-end application written in Vue.js
So far I managed to write a set of tests, but they all reside in the same file:
import puppeteer from 'puppeteer';
import faker from 'faker';
let page;
let browser;
const width = 860;
const height = 1080;
const homepage = 'http://localhost:8001/brt/';
const timeout = 1000 * 16;
beforeAll(async () => {
browser = await puppeteer.launch({
headless: false, // set to false if you want to see tests running live
slowMo: 30, // ms amount Puppeteer operations are slowed down by
args: [`--window-size=${width},${height}`],
});
page = await browser.newPage();
await page.setViewport({ width, height });
});
afterAll(() => {
browser.close();
});
describe('Homepage buttons', () => {
test('Gallery Button', async () => {
// navigate to the login view
await page.goto(homepage);
await page.waitFor(1000 * 0.5); // without this, the test gets stuck :(
await page.waitForSelector('[data-testid="navBarLoginBtn"]');
await page.click('[data-testid="navBarLoginBtn"]'),
await page.waitForSelector('[data-testid="navBarGalleryBtn"]');
await page.click('[data-testid="navBarGalleryBtn"]'),
// test: check if we got to the gallery view (by checking nr of tutorials)
await page.waitForSelector('.card-header');
const srcResultNumber = await page.$$eval('.card-header', (headers) => headers.length);
expect(srcResultNumber).toBeGreaterThan(1);
}, timeout);
});
describe('Register', () => {
const btnLoginToRegister = '#btn-login-to-register';
const btnRegister = '#btn-register';
const btnToLogin = '#btn-goto-login';
test('Register failed attempt: empty fields', async () => {
// navigate to the register form page via the login button
await page.goto(homepage);
await page.waitForSelector(navLoginBtn);
await page.click(navLoginBtn);
await page.waitForSelector(btnLoginToRegister);
await page.click(btnLoginToRegister);
// test; checking for error messages
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
const errNumber = await page.$$eval('#errMessage', (err) => err.length);
expect(errNumber).toEqual(3);
}, timeout);
test('Register failed: invalid char count, email format', async () => {
// fill inputs
await page.waitForSelector('#userInput');
await page.type('#userInput', 'a');
await page.waitForSelector('#emailInput');
await page.type('#emailInput', 'a');
await page.waitForSelector('#emailInput');
await page.type('#passInput', 'a');
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
// test: check if we 3 errors (one for each row), from the front end validations
const err = await page.$$eval('#errMessage', (errors) => errors.length);
expect(err).toEqual(3);
}, timeout);
test('Register: success', async () => {
await page.click('#userInput', { clickCount: 3 });
await page.type('#userInput', name1);
await page.click('#emailInput', { clickCount: 3 });
await page.type('#emailInput', email1);
await page.click('#passInput', { clickCount: 3 });
await page.type('#passInput', password1);
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
// test: check if go to login link appeared
await page.waitForSelector(btnToLogin);
await page.click(btnToLogin);
// await Promise.all([
// page.click(btnToLogin),
// page.waitForNavigation(),
// ]);
}, timeout);
test('Register failed: email already taken', async () => {
// navigate back to the register form
await page.waitForSelector(btnLoginToRegister);
await page.click(btnLoginToRegister);
await page.click('#userInput');
await page.type('#userInput', name2);
await page.click('#emailInput');
await page.type('#emailInput', email1); // <- existing email
await page.click('#passInput');
await page.type('#passInput', password2);
await page.click(btnRegister);
const err = await page.$eval('#errMessage', (e) => e.innerHTML);
expect(err).toEqual('Email already taken');
}, timeout);
});
I would like to be able to have a single test file that does the beforeAll and afterAll stuff, and each test suite: HomepageButtons, Register, etc. to reside in it's own test file. How would I be able to achieve this?
I've tried splitting tets into:
testsUtils.js that would contain the beforeAll and afterAll hooks and code but it doesn't guarantee that it runs when it needs: the beforeAll code to fire before all other test files and the afterAll code to fire after all the test files finished.
Sorry, I'd rather comment on your question, but I don't have reputation for that. Anyway, I think that you are looking for something like a "global beforeAll" and "global afterAll" hooks, right? Jest has it alread. It's called "globalSetup" and "globalTeardown".
Take a look at globalSetup. Excerpt:
This option allows the use of a custom global setup module which
exports an async function that is triggered once before all test
suites.
The Global Teardown one goes the same.
I think you'll have a headache trying to get a reference to the page or browser in globalSetup/globalTeardown and I confess that I never try this. Maybe the answer for that problem (if you have it) is on this page, under "Custom example without jest-puppeteer preset section.
Also there is a repo that tries to facilitate Jest + Puppeteer integration. Maybe you find it util: repo.
Good luck. :)