I'm trying to run this code:
var aaa = await page.$$eval(
selector,
list => (list, value) => {
return resolve(list.find(element => element.textContent === value));
},
value
);
But I received an error.
Therefore, I tried to print the items in "list" (because I assumed that the problem is there), I tried this code:
var aaa = await page.$$eval(selector, list => list);
And I received that "aaa" is empty.
Any idea what may be the problem?
You are attempting to return DOM elements from page.$$eval(), which will return undefined because DOM elements are not serializable.
Try using page.$$() instead if you would like to return an ElementHandle array.
Take a look at the Puppeteer Documentation for page.$$eval() below:
page.$$eval(selector, pageFunction[, ...args])
selector <string> A selector to query page for
pageFunction <function> Function to be evaluated in browser context
...args <...Serializable|JSHandle> Arguments to pass to pageFunction
returns: <Promise<Serializable>> Promise which resolves to the return value of pageFunction
This method runs Array.from(document.querySelectorAll(selector)) within the page and passes it as the first argument to pageFunction.
If pageFunction returns a Promise, then page.$$eval would wait for the promise to resolve and return its value.
Examples:
const divsCounts = await page.$$eval('div', divs => divs.length);
Just try to map your array to more serializable one.
For example:
const links = await page.$$eval('h1 > a', e=>e.map((a)=>a.href))
Related
setListOfPosts(curPosts => {
let newPosts = [...curPosts];
newPosts[newPosts.findIndex(p => p.id === postId)].alert = response.data;
}
});
//is curPosts an instance of array or complete array?? my listofPosts is an array of objects
Your setState call needs to return newPosts, and you're creating an array using the spread operator which is why it's coming back as an array of objects.
I'm not sure what your desired output is, but by adding a return function it will set the state:
setListOfPosts(curPosts => {
let newPosts = [...curPosts];
newPosts[newPosts.findIndex(p => p.id === postId)].alert = response.data;
return newPosts
}
});
This is untested but if your logic is correct should return an array of objects with the objects alert value updated.
Another option would be to do your logic before your setState call, by creating a a newState array and then simply updating the state with that new array without the use of the callback.
The callback function is useful if you want to add a new object to state array or do something that preserves the initial state, in your example you could do it without the callback like this:
// Create a copy of the state array that you can manipulate
const newPosts = [...newPosts]
if (data.response) {
// Add your logic to the state copy
newPosts[newPosts.findIndex(p => p.id === postId)].alert = response.data;
// Replace state with state copy
setListOfPosts(newPosts)
}
Again untested but hopefully this should help you understand the use of the callback function and the right way to use it.
I'm working on a search and filter function. When I type text into the search box, the content that matches the criteria will be filtered out. I want to use the following function to achieve this, but when I type, the "TypeError: setFilterFn is not a function" will occur.
I don't know where goes wrong, How should I fix it?
Thx a lot!
const [setFilterFn] = useState({ fn: items => { return items; } })
const handleSearch = e => {
let target = e.target;
setFilterFn({
fn: items => {
if (target.value != "")
return items;
else
return items.filter(item => item.fullName.toLowerCase().includes(target.value.toLowerCase()))
}
})
}
The quick fix... add a comma ...
const [,setFilterFn] = useState((items) => ( items));
it also looks as if you may have an issue with your logic..
if (target.value != "")
The operator here should probably be === otherwise you will only filter for blank strings.
Take a look at useState function, that function returning array with two arguments, first value of state , the second is callback function which will change your satate value. You are providing only one value, so react assuming that is value not a function. You can read more in docs
My issue is that when i call the function getAllFlashCardsFromQuest(), its call all flash cards ever created in all the pages, i wanna only the objects that comes from a specific pathname, or a way to filter the cards array.
async function getCards() {
let cardsValues = await getAllFlashCardsFromQuest() as FlashCard[]
let cardsFiltered = cardsValues.filter(()=>{
return history.location.pathname === 'CriarAlternativaQuest'
})
console.log(cardsFiltered)
setCards(cardsFiltered)
}
the object look like this:
There's not much context with your code, so I can only help so much, but one thing's for sure, and that is history.location.pathname isn't changing and you're comparing it with another constant. So cardsFiltered will be either a list of true or a list of false.
Whenever you're filtering a list, you need to take each item or a property of each item and use that in your comparison.
Ex.
async function getCards() {
let cardsValues = await getAllFlashCardsFromQuest() as FlashCard[]
let cardsFiltered = cardsValues.filter((cardValueItem) => {
return cardValueItem.pathname === 'CriarAlternativaQuest'
})
}
The thing is that you need to figure out what value or property inside of your cardsValues list that you need to compare it with 'CriarAlternativaQuest'
I have an end point that returns a list of favorites, then when this list returns i get each of these favorites and send to another endpoint to get the specific information of each of these favorite:
this.favoriteData = [];
const observables = [];
favoriteList.forEach(favorite => {
observables.push(this.assetService.getAsset(favorite.symbol)
.pipe(takeWhile((response: AssetModel) => response.id !== 0)));
});
merge(...observables)
.subscribe(res => {
this.favoriteData.push(res);
this.showLoading = false;
});
As you can see the getAsset() function calls an endpoint, and it is inside an forEach, and im saving each of these response inside an array and spread this array inside a merge function of RXJS, but when i subscribe to the merged observable and append the response to the array favoriteData, the subscribe function behavior is like, binding one by one of the response data:
i want a behavior that waits all the requests to complete and then get all of the responses in one stream, im trying to use the forkJoin operator but the tslint tells that is deprecated and to use map operator, and i dont know how to use it to do what i want
You could use a combineLatest instead, which waits for all observables to complete before emitting.
combineLatest(...observables)
.subscribe(res => {
this.favoriteData.push(res);
this.showLoading = false;
});
You can use from to generate an Observable which emits each element of the base array one at a time. Then, using mergeMap and toArray, you emit all required data at the end:
const favoriteData$ = from(favoriteList).pipe(
mergeMap(favorite => this.assetService.getAsset(favorite.symbol)
.pipe(takeWhile((response: AssetModel) => response.id !== 0))),
toArray()
);
I'm trying to return a value from a WebDriver promise within a Protractor solution using TypeScript, but I'm getting undefined as response.
get nameInput(): string {
var value: string;
this.nameElement.getAttribute('value').then(v => value = v);
return value;
}
In the above case it seems like the function is not waiting for the promise to return, therefore I tried moving away from the getter style and declared the return type as WebDriver's promise:
getNameInput(): webdriver.promise.Promise<string> {
var nameElement = element(by.id('name'));
return nameElement.getText().then(v => { return v });
}
But I'm getting Function as the return instead of the value of v. Seems like the promise is not being unwrapped by Jasmine's expect, as it happens when running it in JS.
I know I can run the promise directly within the expect, but ideally I would create all the function's logic outside of any expectations, so that I can then feed the expectation the function call with any (if any) parameters only - instead of polluting the test case with promise logic.
Any ideas?
You don't need to resolve the promises, just return them:
getNameInput(): webdriver.promise.Promise<string> {
var nameElement = element(by.id('name'));
return nameElement.getText();
}
Then you need to have a real value returned from the getNameInput() - resolve it in your test:
getNameInput().then(v => { console.log(v) });
Note that, you also let expect() resolve it implicitly:
expect(getNameInput()).toEqual("Expected Value");