Using the mock function below along with the dev console:
This call will work:
chrome.webNavigation.onCompleted.addListener(processWebNavChange, filtera);
but when I actually pass in my real var filter it throws this error:
Uncaught TypeError: Could not add listener
My actual data looks like this:
{
url: [ {hostContains: ".im88rmbOwZ"} ]
}
function registerWebNavListener() {
var matchers = getUrlMatchers();
var filter = {
url: matchers
};
// test with mock data filtera that actually works
const filtera = {
url:
[
{hostContains: "example.com"},
]
}
if (matchers.length > 0) {
chrome.webNavigation.onCompleted.addListener(processWebNavChange, filtera);
}
}
async function processWebNavChange(data) {
}
Is there something wrong with my data structure that I'm actually using? I don't believe that the filter object I returned is incorrect
}
EDIT:
I added a new
const filterb = {
url: [ {hostContains: ".im88rmbOwZ"} ]
};
and it still fails with that. The single entry {hostContains: ".im88rmbOwZ"}, was the first item returned from getURLMatchers() which I used as an example of real data being returned.
The above comment on the upper-case letters was the cause of the issue. Converting everything to lowercase resolved the problem.
Although, I am not clear as to why that was a problem to begin with. (If there are any hints in the chromium source code event filter handlers, I'd appreciate it if it could be pointed out).
I have 2 scipts almost identical with a cascade of function calls nested in a fiber.
This one (parsing Tx in a blockchain) with three calls works perfectly
wait.launchFiber(blockchain)
function blockchain() {
foreach block {
parseBlock (blockIndex)
}
}
function parseBlock(blockIndex) {
foreach Tx in block {
parseTx(txHash)
}
}
function parseTx (txHash) {
if ( txHashInDB(txHash) ) {
do something
}
}
function txHashInDB (txHash) {
var theTx = wait.forMethod(Tx, 'findOne', {'hash': txHash});
return (theTx) ? true : false;
}
Then I have to do something similar with the mempool. In this case I don't have blocks, only transactions, so I have only 2 calls and I get this error message:
Error: wait.for can only be called inside a fiber
wait.launchFiber(watchMempool);
function watchMempool() {
web3.eth.filter('pending', function (error, txHash) {
parseTx(txHash);
});
}
function parseTx (txHash) {
if ( txHashInDB(txHash) ) {
do something
}
}
function txHashInDB (txHash) {
var theTx = wait.forMethod(Tx, 'findOne', {'hash': txHash});
return (theTx) ? true : false;
}
I don't understand what the problem is. Those two scripts have the same structure !
I think for array functions like map or filter you need to use the wait.parallel extensions, i.e. in your case something like:
function watchMempool() {
wait.parallel.filter(web3.eth, parseTx);
}
(Note: I'm just assuming web3.eth is an array; if not, you should probably add a bit more context to your question, or try to boil down the problem to a more generic example).
Following this question on stackoverflow, I've tried to make the promiseFor method work without success. Since I don't have enough "reputation" to comment on that thread, here I am. This is the recursive loop:
var promiseFor = Promise.method(function(condition, action, value) {
if (!condition(value)) return value;
return action(value).then(promiseFor.bind(null, condition, action));
});
And this is how I've tested it:
promiseFor(function(arr){ //condition
return arr.length < 3;
}, function(arr){ //action
arr.push(arr.length+1);
return arr;
}, []) //initial value
.done(function(arr){
console.log(arr);
});
I was expecting to have an output of [1,2,3]. But instead I got a TypeError: undefined is not a function pointing to the line:
return action(value).then(promiseFor.bind(null, condition, action));
This happens to be the line that I haven't fully understood. What exactly does promiseFor.bind(null, condition, action) do?
EDIT:
Thanks to kyrylkov I've changed the action to:
function(arr){
return new Promise(function(resolve){
arr.push(arr.length + 1);
resolve(arr);
});
}
Working like a charm now.
In your test, action (2nd argument in anonymous function wrapped in Promise.method) is a function that returns an array, not a promise:
function(arr){
arr.push(arr.length+1);
return arr;
}
As a result you get the error in call action(value).then because the array doesn't have then method.
This question is about functional tests written with the Intern.
The elementsByXYZ methods returns an array of elements. I've noticed that I'm able to call the method click() on these returned elements, but I cannot for example call the method getAttribute(attributeName).
What is the list of methods that can be called on elements returned by a a elementsByXYZ method ?
Here is a code snippet that illustrates what I'm trying to achieve:
return this.remote
.get(require.toUrl("./testpage.html"))
.waitForCondition('ready', 5000)
.elementById('widget1')
.elementsByTagName('div')
.then(function(children){
assert.equal(7, children.length, 'The expected number of children is wrong');
for(var i=0; i < 7; i++){
console.log(children[i].getAttribute('className'));
children[i].click();
}
});
The console shows that children[i].getAttribute('className') returns undefined, while I can see that the clicks are correctly performed on each child.
Wouldn't you need to use something like:
elem.getAttribute('class', function (err, text) {
console.log(text);
)};
When using wd.js? e.g. https://github.com/admc/wd/blob/master/doc/jsonwire-mapping.md
getAttribute(element, attrName, cb) -> cb(err, value)
That works for me.
I have started using mustache.js and so far I am very impressed. Although two things puzzle me. The first leads on to the second so bear with me.
My JSON
{"goalsCollection": [
{
"Id": "d5dce10e-513c-449d-8e34-8fe771fa464a",
"Description": "Multum",
"TargetAmount": 2935.9,
"TargetDate": "/Date(1558998000000)/"
},
{
"Id": "eac65501-21f5-f831-fb07-dcfead50d1d9",
"Description": "quad nomen",
"TargetAmount": 6976.12,
"TargetDate": "/Date(1606953600000)/"
}
]};
My handling function
function renderInvestmentGoals(collection) {
var tpl = '{{#goalsCollection}}<tr><td>{{Description}}</td><td>{{TargetAmount}}</td><td>{{TargetDate}}</td></tr>{{/goalsCollection}}';
$('#tblGoals tbody').html('').html(Mustache.to_html(tpl, collection));
}
Q1
As you can see my 'TargetDate' needs parsing but I am unsure of how to do that within my current function.
Q2
Say I wanted to perform some function or formatting on one or more of my objects before rendering, what is the best way of doing it?
You can use "Lambdas" from mustache(5)
"TargetDate": "/Date(1606953600000)/",
"FormatDate": function() {
return function(rawDate) {
return rawDate.toString();
}
}, ...
Then in the markup:
<td>
{{#FormatDate}}
{{TargetDate}}
{{/FormatDate}}
</td>
From the link:
When the value is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered.
I have created a small extension for Mustache.js which enables the use of formatters inside of expressions, like {{expression | formatter}}
You would anyway need to create a function that parses your date value like this:
Mustache.Formatters = {
date: function( str) {
var dt = new Date( parseInt( str.substr(6, str.length-8), 10));
return (dt.getDate() + "/" + (dt.getMonth() + 1) + "/" + dt.getFullYear());
}
};
And then just add the formatter to your expressions:
{{TargetDate | date}}
You can grab the code from here: http://jvitela.github.io/mustache-wax/
It's a long time ago but got on this looking for exactly the same. Mustachejs (now) allows you to call functions of the passed data and not only that; in the function the value of this is whatever value is true in a section.
If my template is like this:
{{#names}}
<p>Name is:{{name}}</p>
<!-- Comment will be removed by compileTemplates.sh
#lastLogin is an if statement if lastLogin it'll do this
^lastLogin will execute if there is not lastLogin
-->
{{#lastLogin}}
<!--
formatLogin is a method to format last Login
the function has to be part of the data sent
to the template
-->
<p>Last Login:{{formatLogin}}</p>
{{/lastLogin}}
{{^lastLogin}}
not logged in yet
{{/lastLogin}}
{{#name}}
passing name to it now:{{formatLogin}}
{{/name}}
{{/names}}
And Data like this:
var data={
names:[
{name:"Willy",lastLogin:new Date()}
],
formatLogin:function(){
//this is the lastDate used or name based on the block
//{{#name}}{{formatLogin}}{{/name}}:this is name
//{{#lastLogin}}{{formatLogin}}{{/lastLogin}}:this is lastLogin
if(!/Date\]$/.test(Object.prototype.toString.call(this))){
return "Invalid Date:"+this;
}
return this.getFullYear()
+"-"+this.getMonth()+1
+"-"+this.getDate();
}
};
var output = Mustache.render(templates.test, data);
console.log(output);
You can get the timestamp using simple String methods:
goalsCollection.targetDate = goalsCollection.targetDate.substring(6,18);
Of course, this depends on your timestamp being the same length each time. Another option is:
goalsCollection.targetDate =
goalsCollection.targetDate.substring(6, goalsCollection.targetDate.length - 1);
These techniques aren't specific to Mustache and can be used to manipulate data for any library. See the Mozilla Developer Center Documentation on substring for more details.
To declare a function within a json you can always do this.
var json = '{"RESULTS": true, "count": 1, "targetdate" : "/Date(1606953600000)/"}'
var obj = JSON.parse(json);
obj.newFunc = function (x) {
return x;
}
//OUTPUT
alert(obj.newFunc(123));
Working example of a 'lambda' function for parsing an ISO-8601 date and formatting as UTC:
var data = [
{
"name": "Start",
"date": "2020-04-11T00:32:00.000-04:00"
},
{
"name": "End",
"date": "2022-04-11T00:32:00.000-04:00"
},
]
var template = `
{{#items}}
<h1>{{name}}</h1>
{{#dateFormat}}
{{date}}
{{/dateFormat}}
{{/items}}
`;
var html = Mustache.render(template, {
items: data,
dateFormat: function () {
return function (timestamp, render) {
return new Date(render(timestamp).trim()).toUTCString();
};
}
});
document.getElementById("main").innerHTML = html;
<script src="https://unpkg.com/mustache#4.2.0/mustache.min.js"></script>
<div id="main"></div>
If you want fancier date formatting you could use for example something like:
new Date().toLocaleDateString('en-GB', {
day : 'numeric',
month : 'short',
year : 'numeric', hour: 'numeric', minute: 'numeric'
})
// outputs '14 Apr 2022, 11:11'
I've been using Mustache for my projects as well, due to its ability to be shared across client/server. What I ended up doing was formatting all values (dates, currency) to strings server-side, so I don't have to rely on helper Javascript functions. This may not work well for you though, if you're doing logic against these values client-side.
You might also want to look into using handlebars.js, which is essentially Mustache, but with extensions that may help with client-side formatting (and more). The loss here is that you will probably not be able to find a server-side implementation of handlebars, if that matters to you.