When I tested my contract, I got this error ""before all" hook: prepare suite:"
Does anyone know how to solve this error?
This is my dependencies.
"truffle": "5.0.7",
"web3": "1.0.0-beta.46"
npm uninstall -g truffle
npm install -g truffle#5.1.10 (always got me back on track)
Also, this issue occurs when used several test suites that use async test-helpers without await (for example, OpenZeppelin Test Helpers: expectEvent, expectRevert).
Consider example:
contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Test03 {
address public owner;
int32 public id;
event ContractCreated();
constructor() {
owner = msg.sender;
emit ContractCreated();
}
function doSmth(int32 _id) public {
require(id != 0, "id is zero");
id= _id;
}
}
test
const { expectEvent, expectRevert } = require('#openzeppelin/test-helpers');
const TestContract = artifacts.require('Test03');
contract('Test03', function (accounts) {
const [owner] = accounts;
const txParams = { from: owner };
beforeEach(async function () {
this.testContract = await TestContract.new(txParams);
});
describe('construction', function () {
it('initial state', async function () {
expect(await this.testContract.owner()).to.equal(owner);
// !! DONT FORGET await before expectEvent-call <<------------------------------
await expectEvent.inConstruction(this.testContract, 'ContractCreated');
});
});
describe('doSmth', function () {
it('fail when passed zero id', async function () {
// !! DONT FORGET await before expectRevert-call <<------------------------------
await expectRevert(
this.testContract.doSmth(0, txParams),
"id is zero");
});
});
});
package.json
{
..
"devDependencies": {
"#openzeppelin/test-helpers": "^0.5.10"
}
..
}
Related
I'm trying to test a Solidity Library directly using hardhat and chaï.
This is a Library example I would like to test:
library LibTest {
function testFunc() public view returns(bool) {
return true;
}
}
and this is how I'm trying to test it.
beforeEach(async () => {
const LibTest = await ethers.getContractFactory("LibTest");
const libTest = await LibTest.deploy();
await libTest.deployed();
})
describe('Testing test()', function () {
it("is working testFunc ?", async function () {
console.log(await libTest.testFunc());
})
})
But I have the error message:
ReferenceError: libTest is not defined
I read everything I can on Chai doc and Hardhat doc but can't found any solution
I would say to use fixture and also utilize waffle and to deploy the library contract once and save the snapshot of the contract:
const {loadFixture } = require('#nomicfoundation/hardhat-network-helpers');
const {expect} = require('chai');
const {ethers, waffle} = require('hardhat');
const {deployContract} = waffle;
const LibArtifact = require('../artifacts/contracts/lib.sol/LibTest.json');
describe("Lib tests", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshopt in every test.
async function deployOnceFixture() {
const [owner, ...otherAccounts] = await ethers.getSigners();
lib = (await deployContract(owner, LibArtifact));
return { lib, owner, otherAccounts };
}
describe("Testing test()", function () {
it("s working testFunc ?", async function () {
const { lib } = await loadFixture(deployOnceFixture);
expect(await lib.testFunc()).to.be.true;
});
});
});
Instructions to add the waffle plugin:
Hardhat-waffle
Basically, you need to install the libraries:
npm install --save-dev #nomiclabs/hardhat-waffle 'ethereum-waffle#^3.0.0' #nomiclabs/hardhat-ethers 'ethers#^5.0.0'
And then import hardhat-waffle in the hardhat-config.js file:
require("#nomiclabs/hardhat-waffle");
Also, notice I put the test file in a test directory so I needed to go back one folder to find artifacts generated by running npx hardhat compile.
For convenience I pushed the solution in a Github repo: https://github.com/Tahlil/run-solidity-lib
The best way I have found to go about this is to create a LibTest.sol contract that invokes and tests the Lib itself. And just running abstracted tests in JS/TS to invoke the LibTest contract, connecting the Lib.sol contract to it during deployment in Hardhat.
const Lib = await ethers.getContractFactory("Lib");
const lib = await Lib.deploy();
const LibTest = await ethers.getContractFactory("LibTest", {
libraries: {
Lib: lib.address,
},
});
const libTest = await LibTest.deploy();
/// later: console.log(await libTest.testLibFunc());
LibTest.sol:
import "./Lib.sol";
library LibTest {
function testLibFunc() public view returns(bool) {
bool response = Lib.testFunc();
return response;
}
}
Were you able to find a better method?
Getting the below error while trying to deploy a smart contract from hardhat. Error details
TypeError: Cannot read property 'sendTransaction' of null
at ContractFactory.<anonymous> (C:\Collection\node_modules\#ethersproject\contracts\src.ts\index.ts:1249:38)
at step (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:48:23)
at Object.next (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:29:53)
at fulfilled (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:20:58)
Here are the config files
hardhat.config.js
require('#nomiclabs/hardhat-waffle');
require("#nomiclabs/hardhat-ethers");
require("dotenv").config();
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.2",
networks: {
mumbai: {
url: process.env.MUMBAI_URL,
account: process.env.PRIVATE_KEY
}
}
};
deploy.js
const {ethers} = require("hardhat");
async function main() {
const SuperMario = await ethers.getContractFactory("SuperMario");
const superInstance = await SuperMario.deploy("SuperMarioCollection", "SMC");
await superInstance.deployed();
console.log("contract was deployed to:", superInstance.address());
await superInstance.mint("https://ipfs.io/ipfs/XXXXXXX");
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
I am trying to deploy it using the following command
npx hardhat run scripts/deploy.js --network mumbai
thanks
Change account to accounts in the network config
found the fix. There was an error in the hardhat.config file
instead of account:, it should have been
accounts:[process.env.PRIVATE_KEY]
I am trying to write a test of a simple TODO App.
This is my service test class:
const mockTaskRepository = () => ({
createTask: jest.fn(),
});
describe('TasksService', () => {
let tasksService;
let taskRepository;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [TasksService, { provide: TaskRepository, useFactory: mockTaskRepository }],
}).compile();
tasksService = await module.get<TasksService>(TasksService);
taskRepository = await module.get<TaskRepository>(TaskRepository);
});
describe('create task', () => {
it('calls taskRepository.create() and returns the result', async () => {
const createTaskDto = {
title: 'Test task',
description: 'Test desc',
};
taskRepository.createTask.mockResolvedValue('someTask');
expect(taskRepository.createTask).not.toHaveBeenCalled();
const result = await tasksService.createTask(createTaskDto);
expect(taskRepository.createTask).toHaveBeenCalledWith(createTaskDto);
expect(result).toEqual('someValue');
});
});
});
And this is my task service:
#Injectable()
export class TasksService {
constructor(
#InjectRepository(TaskRepository)
private taskRepository: TaskRepository,
) {}
async createTask(createTaskDto: CreateTaskDto): Promise<Task> {
const { title, description } = createTaskDto;
const task = new Task();
task.title = title;
task.description = description;
task.status = TaskStatus.IN_PROGRESS;
await task.save();
return task;
}
}
When I try to run the Create a Task test, the error below occurs.
FAIL src/tasks/tasks.service.spec.ts
● TasksService › create task › calls taskRepository.create() and returns the result
ConnectionNotFoundError: Connection "default" was not found.
at new ConnectionNotFoundError (error/ConnectionNotFoundError.ts:8:9)
at ConnectionManager.Object.<anonymous>.ConnectionManager.get (connection/ConnectionManager.ts:40:19)
at Object.getConnection (index.ts:247:35)
at Function.Object.<anonymous>.BaseEntity.getRepository (repository/BaseEntity.ts:85:72)
at Task.Object.<anonymous>.BaseEntity.save (repository/BaseEntity.ts:50:42)
at TasksService.createTask (tasks/tasks.service.ts:35:14)
at Object.<anonymous> (tasks/tasks.service.spec.ts:69:38)
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 failed, 8 passed, 9 total
Anyone know what's the mistake in the code?
..........................................
Thanks in advance!
If it is looking for connection default then I assume that the TypeOrmModule configs are still being taken into account. Instead of provide: TaskRepository try changing it to provide: getRepositoryToken(TaskEntity) if you have a TaskEntity. This will tell Nest to override the default repo that the #InjectRepository() decorator tries to provide.
If that isn't the case, do you think you could add your TaskService and TaskModule classes as well?
You should mock the repository then bringing up the context of Test Module. Otherwise, the real Repository is being injected (via Nest's DI) into service.
const module = await Test.createTestingModule({
providers: [
{
provide: getRepositoryToken(YourEntityClass),
useValue: mockedRepo, // or use class
},
TasksService],
}).compile();
tasksService = await module.get<TasksService>(TasksService);
// taskRepository = await module.get<TaskRepository>(TaskRepository); don't have to do that if `useValue` was used instead of factory
So, TL;DR :
provide: TaskRepository should provide Token of given Injectable in this case: https://docs.nestjs.com/fundamentals/custom-providers#non-class-based-provider-tokens
The test expected method Repository.createTask to be called, but method Service.createTask didn't make that call.
The fix: Update the Service method to delegate to the Repository method the task creation.
// tasks.service.ts
async createTask(createTaskDto: CreateTaskDto, user: User): Promise<Task> {
return this.taskRepository.createTask(createTaskDto, user);
}
// tasks.repository.ts
async createTask(createTaskDto: CreateTaskDto, user: User): Promise<Task> {
const { title, description } = createTaskDto;
const task = new Task();
task.title = title;
task.user = user;
task.description = description;
task.status = TaskStatus.IN_PROGRESS;
await task.save();
delete task.user;
return task;
}
}
I am a subscription setup but onNext is not getting triggered I am not sure why since this is my first time implementing subscription and docs was not much help with the issue.
Here are the code implementations:
import {
graphql,
requestSubscription
} from 'react-relay'
import environment from '../network';
const subscription = graphql`
subscription chatCreatedSubscription{
chatCreated{
id
initiate_time
update_time
support_id
category_id
email
name
}
}
`;
function chatCreated(callback) {
const variables = {};
requestSubscription(environment, {
subscription,
variables,
onNext: () => {
console.log("onNext");
callback()
},
updater: () => {
console.log("updater");
}
});
}
module.exports = chatCreated;
and here is my network for the subscription
import { Environment, Network, RecordSource, Store } from "relay-runtime";
import Expo from "expo";
import { SubscriptionClient } from "subscriptions-transport-ws";
import { WebSocketLink } from 'apollo-link-ws';
import { execute } from 'apollo-link';
import accessHelper from "../helper/accessToken";
const networkSubscriptions = async (operation, variables) => {
let token = await accessHelper();
if (token != null || token != undefined) {
const subscriptionClient = new SubscriptionClient("ws://localhost:3000/graphql",
{
reconnect: true,
connectionParams: {
Authorization: token,
},
});
execute(new WebSocketLink(subscriptionClient), {
query: operation.text,
variables,
});
}
}
const network = Network.create(fetchQuery, networkSubscriptions);
const store = new Store(new RecordSource());
const environment = new Environment({
network,
store
});
export default environment;
the subscription is called in a componentDidMount method on a component it executes but the onNext method inside the subscription is never triggered when new information is added to what the subscription is listening to.
so i figured out that my issue was the network js not being setup properly and the version of subscription-transport-ws. i added version 0.8.3 of the package and made the following changes to my network file:
const networkSubscriptions = async (config, variables, cacheConfig, observer) => {
const query = config.text;
let token = await accessHelper();
if (token != null || token != undefined) {
const subscriptionClient = new SubscriptionClient(`ws://${api}/graphql`,
{
reconnect: true,
connectionParams: {
Authorization: token,
},
});
subscriptionClient.subscribe({ query, variables }, (error, result) => {
observer.onNext({ data: result })
})
return {
dispose: subscriptionClient.unsubscribe
};
}
}
i hope this helps you if you get stuck with the same issue as mine.
So I have this setup : truffle and ganache-cli
I'm sending some ether to my contract, here is the related part of my contract:
mapping(address => uint256) public balanceOf;
function () payable public {
uint amount = msg.value;
balanceOf[msg.sender] += amount;
}
In truffle this is how I send the ether.
it("Test if can be payed", function(){
return web3.eth.sendTransaction({
from:fromAddr,
to:MyContract.address,
value:amountToSend
}).then(function(res){
expect(res).to.not.be.an("error"); // test passed
});
});
it("Test if contract received ether", function(){
return web3.eth.getBalance(MyContract.address,
function(err, res){
expect(parseInt(res)).to.be.at.least(1000000000000000000); // test passed
});
});
it("Catch if balanceOf "+fromAddr, function(){
return sale.balanceOf.call(fromAddr).then(function(res){
expect(parseInt(res)).to.be.at.least(1); // fails the test
});
});
Am I doing it right? What could be the reason for failed test?
truffle test output :
AssertionError: expected 0 to be at least 1
+ expected - actual
-0
+1
I can provide more info if needed.
UPDATE :
for clarification on sale which is global variable.
it("Test if MyContract is deployed", function(){
return MyContract.deployed().then(function(instance){
sale = instance;
});
});
I think this is what you are looking for:
File path:
test/vault.js
const Vault = artifacts.require("Vault");
contract("Vault test", async accounts => {
// Rely on one instance for all tests.
let vault;
let fromAccount = accounts[0];
let oneEtherInWei = web3.utils.toWei('1', 'ether');
// Runs before all tests.
// https://mochajs.org/#hooks
before(async () => {
vault = await Vault.deployed();
});
// The `receipt` will return boolean.
// https://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransactionreceipt
it("Test if 1 ether can be paid", async () => {
let receipt = await web3.eth.sendTransaction({
from: fromAccount,
to: vault.address,
value: oneEtherInWei
});
expect(receipt.status).to.equal(true);
});
it("Test if contract received 1 ether", async () => {
let balance = await web3.eth.getBalance(vault.address);
expect(balance).to.equal(oneEtherInWei);
});
// In Web3JS v1.0, `fromWei` will return string.
// In order to use `at.least`, string needs to be parsed to integer.
it("Test if balanceOf fromAccount is at least 1 ether in the contract", async () => {
let balanceOf = await vault.balanceOf.call(fromAccount);
let balanceOfInt = parseInt(web3.utils.fromWei(balanceOf, 'ether'));
expect(balanceOfInt).to.be.at.least(1);
});
});
You can see the full project here. Do note that I'm using Truffle v5 and Ganache v2. See the README file inside that GitLab repository.
Back to your question, there were 2 mistakes:
The sale is not defined. I have a feeling that you were actually referring to MyContract.
In order to use the least method in ChaiJS, you need to make sure you are passing integers. The balanceOf call is returning BigNumber or BN object and you can't use it with .least method.
FYI, Truffle v5 is now using BN by default (previously BigNumber). More about it here.
Let me know if this helps.