Solidity test case to check "withdraw" function in a contract? - solidity

I want to write a test case to check if my withdraw function works correctly. The code looks like this:
function withdraw(uint _amount, address _to) public onlyAuthors {
require(!isNullAddress(_to));
require(_amount <= this.balance);
_to.transfer(_amount);
}
But in a test case, it looks like this.balance or [some_address].balance are not available. Is there any good way to test this kind of function in a unit test?

1) make a contract factory:
import web3 from './web3';
import contractFactory from './build/ContractFactory.json';
const instance = new web3.eth.Contract(
JSON.parse(contractFactory.interface),
'<address of deployed contract>'
);
export default instance;
2)In your test you new up a contract and do the required actions to get the balance in a state that you want to test against. In your test file:
const compiledFactory = require('../ethereum/build/ContractFactory.json');
const compiledContract = require('../ethereum/build/Contract.json');
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' });
factory.setProvider(provider);
await factory.methods.createContract('100').send({
from : accounts[ 0 ],
gas : '1000000'
});
ect. This step will vary according to your contract.
3)Try to interact with the contract(E.G. attempt to withdrawal more than the amount you are allowed or whatever. Then expect the behavior you are testing for.

I think you can use web3.eth.getBalance(address) to retrieve contract balance.

Related

hardhat deploy method not working anymore with fund how to fund the contract?

So I have written the same code as the hardhat documentation suggest here for deploying with funding maybe.
import hre from "hardhat";
const main = async () => {
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const unlockTime = currentTimestampInSeconds + ONE_YEAR_IN_SECS;
const lockedAmount = hre.ethers.utils.parseEther("1");
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy(unlockTime,
{ value: lockedAmount }
);
await waveContract.deployed();
console.log("Contract deployed to:", waveContract.address);
}
but the problem is it will give me an error about the argument.
even if it's the same code that the documentation suggest here: https://hardhat.org/hardhat-runner/docs/guides/deploying.
First I have written code in a different manner from buildspace website as a part of learning about web3.
// from buildspace website
const main = async () => {
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy({
value: hre.ethers.utils.parseEther("0.001"),
});
await waveContract.deployed();
console.log("WavePortal address: ", waveContract.address);
};
This above code from buildspace but the problem is it will also give the error and I thought it could be the old deprecated code so I look into docs.
The JS deploy() function accepts N required params, followed by 1 optional:
N arguments of the Solidity constructor
1 optional object that overridesĀ default params of the deploying transaction (in your case the value)
Based on the error message "Expected 0-1 arguments", the WavePortal constructor expects 0 params. Which makes the deploy() function to expect 0 constructor params, plus the 1 optional overriding object.
However your code is trying to pass unlockTime as the constructor param.
Solution: Remove the unlockTime from the JS code - or accept it in the Solidity code.

Shopify Storage Redis Issue with Node React App

I have added session storage in serve.js as follows :-
import SessionHandler from "./SessionHandler";
const sessionStorage = new SessionHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October21,
IS_EMBEDDED_APP: false,
// This should be replaced with your preferred storage strategy
//SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(
sessionStorage.storeCallback,
sessionStorage.loadCallback,
sessionStorage.deleteCallback
),
});
My router get function is
router.get("(.*)", async (ctx) => {
const shop = ctx.query.shop;
let documentQuery = { shop: shop };
let data = await SessionStorage.findOne(documentQuery); //this finds the store in the session table
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
if (data == null) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
} else {
await handleRequest(ctx);
}
});
and than in the SessionHandler file added code as attached in file ,
but when I run install the app it goes to the storeCallback , loadcallback and deletecallback function multiple times
StoreCallback Function Code
Load and delete callback function code
sorry I have edited my answer as I think its incorrect . all I can say for now is to look at this example:https://github.com/Shopify/shopify-api-node/blob/main/docs/usage/customsessions.md
if you havent already..

Mocking a return value for a Subject - Unit Testing with Jasmine

I'm unit testing and part of the testing has a Subject. I'm new to Subjects and get the general gist of how they work but am struggling to mock a return value on one. I've tried various ways in the hopes of stumbling on the correct way like using a spy and returnvalue to return the number 3.
In the component:
....
private searchEvent: Subject<string> = new Subject<string>();
....
this.searchEvent.pipe(debounceTime(500)).subscribe(value => {
if (value.length >= 3) {
this.retrieveAssets(value);
}
})
....
In my spec file I basically have:
component['searchStockEvent'].subscribe(x=> of(3));
fixture.whenStable().then(() => {
expect(component['retrieveAssets']).toHaveBeenCalled();
});
searchEvent being private will make it difficult to call next directly on the subject so you have to find a way of what makes searchEvent emit a value of greater than 3 and go that route.
For this demo, we will make it public:
....
public searchEvent: Subject<string> = new Subject<string>();
....
this.searchEvent.pipe(debounceTime(500)).subscribe(value => {
if (value.length >= 3) {
this.retrieveAssets(value);
}
})
....
import { fakeAsync, tick } from '#angular/core/testing';
it('should call retrieve assets', fakeAsync(() => {
component.searchEvent.next(3);
// we need to pass 501ms in a fake way
tick(501);
expect(component.retreiveAssets).toHaveBeenCalled();
}));

Sinon stub withArgs ignores extra arguments

My production code looks like:
exports.convertWord = number => { /* some logic here */ }
exports.methodUnderTest = () => {
return exports.convertWord(1);
}
Test code:
const mockConvertToWord = sinon.stub();
mockConvertToWord.withArgs(1).returns('one');
fileUnderTest.convertWord = mockConvertToWord;
const result = fileUnderTest.methodUnderTest();
expect(result).toBeEqual('one');
Test above is green. I expect my test will break if I change prod code to this:
exports.convertWord = number => { /* some logic here */ }
exports.methodUnderTest = () => {
return exports.convertWord(1, 'another arg');
}
but it's not. Sinon works fine even when I pass extra params which I didn't point in withArgs method. How can I tell sinon to return value only when method has been called with exact number of params?
stub
One way to do this is to use stub.callsFake(fakeFunction):
mockConvertToWord.callsFake((...args) => args.length === 1 && args[0] === 1 ? 'one' : undefined);
An alternative approach with a stub is to use a sinon.assert to make sure the stub was called with the epected arguments as noted by #deerawan.
mock
Another approach is to use a mock:
const mock = sinon.mock(fileUnderTest);
mock.expects('convertWord').withExactArgs(1).returns("one");
const result = fileUnderTest.methodUnderTest();
expect(result).toBeEqual('one');
mock.verify();
Another alternative, perhaps you can try to check the call of convertToWord like
...
expect(result).toBeEqual('one');
// check the function
sinon.assert.alwaysCalledWithExactly(mockConvertToWord, '1');
Ref:
https://sinonjs.org/releases/v6.3.4/assertions/#sinonassertalwayscalledwithexactlyspy-arg1-arg2-
Hope it helps

error handling in angular 5, catch errors from backend api in frontend

I need advise for handling errors in front-end of web application.
When I call a service to get the community according to community in web app, I want it to catch an error. For example for catching errors like 404.
There is a service for getting community according to id provided.
getCommunity(id: number) {
return this.http.get(`${this.api}/communities/` + id + ``);
}
that is called in events.ts file
setCommunityBaseUrl() {
this.listingService.getCommunity(environment.communityId).subscribe((data: any) => {
this.communityUrl = data.url + `/` + data.domain;
});
}
The id is provided in environment. Let's say there are 20 communities in total. When I provide id = 1 the events according to community = 1 appears.
export const environment = {
production: ..,
version: 'v2',
apiUrl: '...',
organization: '...',
websiteTitle: '...',
communityId: 1,
googleMapsApiKey: '...'
};
The problem is that when I provide id = null all community events are occurring | all events list in the backend is occurring.
Please, help ^^
When you subscribe you subscribe with an Observer pattern. So the first function you pass in
.subscribe(() => {} );
fires when the Observable calls .next(...)
and after that you can provide another function which will fire whenever the Observable calls .error(...)
so
.subscribe(() => {}, (error) => { handleTheError(error); } );
The this.http.get(...); returns an Observable which will fire the .error(...) on http error
We also know that this.http.get(...) completes or "errors" and it's not an endless one (a one that never completes). So you can make it a promise and manipulate on it promise like.
async getMeSomething(...) {
try {
this.mydata = await this.http.get(...).toPromise();
}
catch(error) {
handleTheError(error)
}
}
But what I really recommend is to use Swagger for your backend and then generate the API Client class with NSwagStudio so you don't have to write the client manually or adjust it or deal with error catching. I use it all the time and it saves us an enormous amount of time
Because you are using ".subscribe" you can create your own error handler and catch the errors like this, directly on the method.
This is an example on how you can use this:
constructor(
private _suiteAPIService: SuitesAPIService,
private _testcaseService: TestcaseService,
public _tfsApiService: TfsApiService,
private _notificationService: NotificationService) { }
errorHandler(error: HttpErrorResponse) {
return observableThrowError(error.message || "Server Error")
}
public something = "something";
GetTestcasesFromSuiteSubscriber(Project, BuildNumber, SuiteId) {
this._suiteAPIService.GetTestResults(Project, BuildNumber, SuiteId).subscribe(
data => {
console.log(data);
this._testcaseService.ListOfTestcases = data;
//Notofication service to get data.
this._notificationService.TestcasesLoaded();
},
error => {
//Here we write som error
return this.something;
}
);
}