Solidity (Truffle): Works fine with truffle console, but fails with truffle test - solidity

I'm running something with truffle console that works fine, but fails with truffle test.
The code is:
contract Geekt {
address[] usersByAddress;
function registerNewUser(string handle, bytes32 city, bytes32 state, bytes32 country) public returns (bool success) {
address newUserAddress = msg.sender;
usersByAddress.push(newUserAddress);
return true;
}
function getUsers() public constant returns (address[]) {
return usersByAddress;
}
}
And the tests are:
var Geekt = artifacts.require("Geekt");
contract('Geekt', function (accounts) {
it('should get initial users as empty array', function () {
return Geekt.deployed().then(function (instance) {
return instance.getUsers.call();
}).then(function (res) {
assert.equal(res.length, 0, "Expected empty array after init.");
});
});
it('should successfully add user', function () {
var geekt;
return Geekt.deployed().then(function (instance) {
geekt = instance;
return geekt.registerNewUser.call("elie222", "London", "State", "UK");
}).then(function (res) {
assert.equal(res, true, "Expected registerNewUser to return true.");
}).then(function (res) {
return geekt.getUsers.call();
}).then(function (res) {
// for debugging, but this assert passes: assert.equal(res.length, 0, "Expected array of size 0 after registerNewUser.");
// res == [] so the next line fails:
assert.equal(res.length, 1, "Expected array of size 1 after registerNewUser.");
});
});
});
It works great with truffle console:
truffle(development)> Geekt.then(function(instance){return instance.registerNewUser("Tectract","Denver","CO","USA");})
{ tx: '0x8eeea303ff9f5ceee56d71fd1265da61991749aa3d5e82db0d2d630a98fd6eb5',
receipt:
{ transactionHash: '0x8eeea303ff9f5ceee56d71fd1265da61991749aa3d5e82db0d2d630a98fd6eb5',
transactionIndex: 0,
blockHash: '0xf9a0da5ec0aba80a3338781f6d6414ceb43ec0fc023c31649a1cc347a4aba2ea',
blockNumber: 14,
gasUsed: 24566,
cumulativeGasUsed: 24566,
contractAddress: null,
logs: [] },
logs: [] }
truffle(development)> Geekt.then(function(instance){return instance.getUsers();})
[ '0x1a004a36a6bc9bcde42c6d2b237c6477cf0f535f' ]
How could this happen? What am I doing wrong?

The issue was that I was doing a call instead of a transaction.
Transactions change state whereas method calls do not and are only to read from the network.
You can read more about it here:
https://truffle.readthedocs.io/en/beta/getting_started/contracts/

Related

How to call function on XMLHttpRequest status = true in Vue 2? I get "this.xxxx not a function" error

I have the following code, which works fine except for the "makeToast" function that I'm trying to call when status response is true. I get a "this.makeToast is not a function" error on the console.
This function is working fine if I call it after the XMLHttpRequest code. The data is also not being assigned to the msgForm property. I could not figure out why. The "alert(..." message work fine.
<script>
import ToastMixins from '/src/mixins/ToastMixins'
let config = {
headers: {
}
}
export default {
name: 'ModalDestaque',
mixins: [
ToastMixins
],
methods: {
myFunction() {
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log('onreadystatechange');
console.log('responseText 1', xhr.responseText);
this.loading = false;
if (xhr.status == 200) {
console.log('responseText 2', xhr.responseText);
let responseObj = JSON.parse(xhr.responseText);
console.log('responseObj', responseObj);
if (responseObj.status == true) {
//alert('Ok');
// this is not working:
this.msgForm = "Message success!";
this.makeToast('b-toaster-bottom-right', true, 'success');
} else {
alert('Not ok...');
}
}
}
};
}
}
}
What am I doing wrong?
I've found the solution while reading the docs at W3 Schools.
W3 Schools AJAX XMLHttp - Multiple Callback Functions
Although, I haven't found a working example anywhere.
In my code, at the button click event that triggers the XMLHttpRequest, I've added the function name "callToast" as a variable, so:
#click="onClickSubmit(myValue, myId, myTitle, callToast)"
Then in the script:
<script>
onClickSubmit(amount, id, title, cFunction) {
// stuff
if (xhr.status == 200) {
let responseObj = JSON.parse(xhr.responseText);
if (responseObj.status == true) {
// here I call the callToast function:
cFunction(this);
alert('Ok');
} else {
alert('Not ok...');
}
}
},
callToast() {
this.msgForm = "Message success!";
this.makeToast('b-toaster-bottom-right', true, 'success');
}
</script>

How to avoid duplicate entries in IBM JSONStore

WL.JSONStore.get(collectionName).change(data, options) method does not seem to work for duplicate values. I get duplicate values entered whenever data is loaded through the adapter. Below is the code that I have used to avoid duplicate entries.
init(){
console.log('JSONStore init function callled');
let collections = {
activities: {
searchField: {serialKey: 'string'},
adapter: {
name: 'ServiceAdapter',
add: 'pushActivities',
remove: 'removeActivity',
replace: 'replaceActivity',
load: {
procedure: 'getActivities',
params: [],
key: 'rows'
}
}
}
}
WL.JSONStore.init(collections).then((success) => {
console.log('-->JSONStore init success')
}, (failure) => {
console.log('-->JSONStore init failed', failure)
})
}
load() {
let dataRequest = new
WLResourceRequest("/adapters/ServiceAdapter/getActivities",
WLResourceRequest.GET);
dataRequest.send().then(
(response) => {
this.data = response.responseJSON.rows;
this.activityService.put(this.data);
})
}
put(data){
console.log('--> JSONStore put function called');
let collectionName = 'activities';
let options = {
replaceCriteria: ['serialKey'],
addNew: true,
markDirty: false
};
WL.JSONStore.get(collectionName).change(data, options).then((success) => {
console.log('--> JSONStore put success')
}, (failure) => {
console.log('--> JSONStore put failed', failure)
})
}
Adapter Function:
function getActivities() {
var path = 'employees' + '/_all_docs?include_docs=true';
var input = {
method : 'get',
returnedContentType : 'json',
path : path,
};
var response = MFP.Server.invokeHttp(input);
if (!response.rows) {
response.isSuccessful = false;
return response;
} else {
var results = [];
for (var i=0; i < response.rows.length; i++) {
results.push(response.rows[i].doc);
}
return {'rows': results};
}
}
I have even tried by:
searchFields: {serialKey: 'string',serialId: 'string'}
replaceCriteria: ['serialKey','serialId']
But no luck.
NOTE: There is no error in the former one, whereas the later results in an error.
ERROR : PROVISION_TABLE_SEARCH_FIELDS_MISMATCH (I have already tried to destroy the collection and perform the change, as the link suggests.
I have followed the below link:
https://www.youtube.com/watch?v=Ep6w1zXoI-k
I am using the below versions:
mfpdev : 8.0.0-2017102406
Let me know if you need any more details.

Bind validation results from ajax request to form model in mithril

Hi I would like to bind html inputs with validation response model returned from API like that:
{"userName":[{"memberNames":["UserName"],"errorMessage":"Field User Name is required."}],"acceptTerms":[{"memberNames":["AcceptTerms"],"errorMessage":"Accepting terms is requried"}]}
And my component in mithril
var RegisterPage = {
vm: {
userName: m.prop(),
password: m.prop(),
confirmPassword: m.prop(),
acceptTerms: m.prop(false)
},
controller: function (args) {
this.title = 'Register new user account';
this.vm = RegisterPage.vm;
this.register = function (e) {
e.preventDefault();
apiRequest({ method: "POST", url: "http://localhost:12116/auth/register", data: RegisterPage.vm }).then(RegisterPage.vm.registerResult)
}
},
view: function (ctrl, args) {
return m('form.input-group',
[
m('.input-row', [m('label', 'Email'), m('input[type=email][placeholder=Your email address like myemail#email.com]', { onchange: m.withAttr("value", ctrl.vm.email) })]),
m('.input-row', [m('label', 'Password'), m('input[type=password][placeholder=your password]', { onchange: m.withAttr("value", ctrl.vm.password) })]),
m('.input-row', [m('label', 'Confirm password'), m('input[type=password][placeholder=your password]', { onchange: m.withAttr("value", ctrl.vm.confirmPassword) })]),
m('.input-row', [m('label', 'Accept terms and conditions'), m('input[type=checkbox]', { onchange: m.withAttr("checked", ctrl.vm.acceptTerms) })]),
m('button[type=submit].btn btn-positive btn-block', { onclick: ctrl.register }, 'Register account')
]);
}
}
I am looking for some generic solution. I would like to mark invalid fields with css class and add field validation message.
UPDATE
In my project I use some wrapper around m.request to get more details when 400 is thrown
function apiRequest(args) {
NProgress.start();
if (!args.unwrapError) {
args.unwrapError = function (data, xhr) {
if (xhr.status === 401)
{
layout.badRequestMsg(xhr.statusText);
}
NProgress.done();
return data;
}
}
if (!args.unwrapSuccess) {
args.unwrapSuccess = function (data, xhr) {
NProgress.done();
return data;
}
}
return m.request(args);
}

Howto remove a entry from the tree in a Less visitor plugin

I tried the following:
module.exports = function(less) {
function RemoveProperty() {
this._visitor = new less.visitors.Visitor(this);
};
RemoveProperty.prototype = {
isReplacing: true,
isPreEvalVisitor: true,
run: function (root) {
return this._visitor.visit(root);
},
visitRule: function (ruleNode, visitArgs) {
if(ruleNode.name[0].value != '-some-aribitrary-property')
{
return ruleNode;
}
else
{
return new less.tree.Rule([], [], 0,"");
}
}
};
return RemoveProperty;
};
return new less.tree.Rule([], [], 0,""); still result in a empty output like : ; also return nothing will give me an error: TypeError: Cannot read property 'splice' of undefined.
It can.. but its not ideal from a performance perspective.. return an empty array
visitRule: function (ruleNode, visitArgs) {
if (ruleNode.variable) {
return [];
}
return ruleNode;
},
If you check out the toCSS visitor it does this alot.
But I think it should allow undefined too.. Will look at adding that soon.

Extjs4, wait for ajax request

I should run multiple ajax requests in one button click, but all requests should wait until the first one is executed. I have tried to put all requests in the success callback of the first one but this gives this error:
TypeError: o is undefined
return o.id;
And just the first request is executed.
This is my code:
if(form1.isValid()) {
form1.submit(me._genFormSubmitAction('my_DB','my_Action', function() {
console.log('form1 success');
//Submit Form2
if(form2.isValid()) {
form2.submit(me._genFormSubmitAction('my_DB','my_Action', function() {
console.log('form2 success');
}));
//Submit Form3
....
_genFormSubmitAction:
_genFormSubmitAction: function(db,action, successCallback) {
var me = this;
return {
clientValidation : true,
url : me.getApplication().apiUrl,
waitMsg : '<p align=right>..الرجاء الإنتظار</p>',
async:false,
params : {
_module: 'administrationcassocial',
_action: action,
_db:db
},
success : function(form, action) {
if(action.result.success == true) {
Ext.callback(successCallback, me);
form.owner.destroy();
} else {
console.log('url=',url);
Ext.Msg.alert(action.result.error, action.result.errormessages.join("\n"));
}
},
failure : function(form, action) {
switch (action.failureType) {
case Ext.form.action.Action.CLIENT_INVALID:
Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');
break;
case Ext.form.action.Action.CONNECT_FAILURE:
Ext.Msg.alert('Failure', 'Ajax communication failed');
break;
case Ext.form.action.Action.SERVER_INVALID:
Ext.Msg.alert(action.result.error, action.result.errormessages.join("\n"));
}
}
};
}
This is a scope issue.
The callback of form1.submit happens in the callback own scope, so it has no idea what form2 is.
You can try:
if(form1.isValid()) {
var me = this;
form1.submit(me._genFormSubmitAction('my_DB','my_Action', function() {
console.log('form1 success');
//Submit Form2
if( me.form2.isValid() ) {
form2.submit(me._genFormSubmitAction('my_DB','my_Action', function() {
console.log('form2 success');
}));
}
}));
}
Or the more proper solution in my view:
// Added aScope var
_genFormSubmitAction: function( db,action, aScope, successCallback ) {
var me = this;
return {
// ...
scope: aScope
}
}
Then you call:
form1.submit(me._genFormSubmitAction('my_DB','my_Action', this, function() {
}));