const path = require('path');
const solc = require('solc');
const fs = require('fs-extra');
const buildPath = path.resolve(__dirname, 'build');
fs.removeSync(buildPath);
const campaignPath = path.resolve(__dirname, 'contracts', 'Campaign.sol');
const source = fs.readFileSync(campaignPath, 'utf-8');
const output = solc.compile(source, 1).contracts;
fs.ensureDirSync(buildPath);
for(let contract in output) {
fs.outputJsonSync(
path.resolve(buildPath, contract.replace(':', '') + '.json'),
output[contract]
);
}
build
--Campaign.json
--CampaignFactory.json
contracts
--Campaign.sol
To run our tests we are using mocha as our testing framework, utilizing ganache to set up a local etherium blockchain, and using web3 to inter-act with that blockchain. From the ganache website: "Quickly fire up a personal Ethereum blockchain which you can use to run tests, execute commands, and inspect state while controlling how the chain operates."
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());
const compiledFactory = require('../etherium/build/CompaignFactory.json')
const compiledCampaign = require('../etherium/build/Campaign.json')
let accounts;
let factory;
let campaignAddress;
let campaign;
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
factory = await new web3.eth.Contract(JSON.parse(compiledFactory.interface))
.deploy({ data: compiledFactory.bytecode })
.send({ from: accounts[0], gas: '1000000'});
await factory.methods.createCampaign('100').send({
from: accounts[0],
gas: '1000000'
});
[campaignAddress] = await factory.methods.getDeployedCampaigns().call();
campaign = await new web3.eth.Contract(
JSON.parse(compiledCampaign.interface),
campaignAddress
)
});
describe('Campaigns', () => {
it('deploys a factory and a campaign', () => {
assert.ok(factory.options.address);
assert.ok(campaign.options.address);
})
})
What's essentially happening here is that in the beforeEach() loop which gets called before each describe block, we are getting an array of accounts generated by our local ganache blockchain server. We are then using the first account in that array to deploy a compaignfactory contract to our local blockchain, then using that campaign factory to create a campaign with the createCampaign method. In both cases we have to send gas from our account. The only test here is testing whether or not the factory contract and the campaign contract successfully deployed. This is where I encountered an error I've spent awhile debugging. I get the message "Error: No callback provided to provider's send function. As of web3 1.0, provider.send is no longer synchronous and must be passed a callback as its final argument.". However, I am calling the function asynchronously using es6 syntax that has worked in the past with async, await. In googling about similar issues some people had similar problems:
It seems likely to be a versioning issue. I have a working similar set of tests on a different contract, so I tried that set up. I also tried the versions in the above answer to no avail. This is annoying because writing tests for my own contract is a pretty important next-step. I might just skip it and start working on the front-end but... annoying. I'm also gonna put up my own question on stack overflow and see.