I have an electron app which loads an HTML file on opening.
When I tried to wait for an element with waitUntil method from the opening page, Spectron tries to find that while page loading and it crashes my app and app staying at the blank page. How can I wait for loading of this HTML?
My application launch code is below :
async start() {
try {
await this.spectron.start();
await this.focusOnWindow(0);
return this._checkWindowReady();
} catch (err) {
throw err;
}
}
beforeEach(async function (){
app = new SpectronApplication();
common = new CommonActions();
await app.start();
})
I found a solution like below code :
Firstly when I call app.start() ,
start() function calls _checkWindowReady()
_checkWindowReady calls waitFor()
And finally waitFor calls _callClientAPI() and it looks for specific function and element.
async start() {
try {
await this.spectron.start();
await this.focusOnWindow(0);
return this._checkWindowReady();
} catch (err) {
throw err;
}
}
_checkWindowReady() {
return this.waitFor(this.spectron.client.getHTML, '[id="myApp.main.body"]');
}
waitFor(func, args) {
return this._callClientAPI(func, args);
}
_callClientAPI(func, args) {
let trial = 1;
return new Promise(async(res, rej) => {
while (true) {
if (trial > this._pollTrials) {
rej(`Could not retrieve the element in ${this._pollTrials * this._pollTimeout} seconds.`);
break;
}
let result;
try {
result = await func.call(this.client, args, false);
} catch (e) { }
if (result && result !== '') {
res(result);
break;
}
await this.wait();
trial++;
}
});
}
Related
in my react native components I call async functions defined inside my mobx stores, however when I call them the code after them inmediatly runs instead of waiting for the async function to end.
In my case "ACTION COMPLETED" appears on console before the axios call is completed...
I call it like this inside my components:
const sendVerify = async () =>
{
try
{
//Tried with await
await root.userStore.getLoggedUser(response.data.user.id);
console.log('ACTION COMPLETED');
//Also tried with then at didn't work
root.userStore.getLoggedUser().then(response => console.log('ACTION COMPLETED'));
}
catch (error)
{
throw error;
}
};
Async function inside UserStore:
export class UserStore
{
root = null;
constructor(root)
{
makeAutoObservable(this, { root: false });
this.root = root;
}
async getLoggedUser(user_id = false)
{
try
{
let url = env.BASE_URL+'/api/auth/sanctum/user';
let params = {};
let response = await http.get(url, {params:params});
return true;
}
catch (error)
{
return false;
throw error;
}
}
I have a simple web application for uploading zip files to a server. In the Javascript part I have used a try-catch block for checking whether the files are password protected(A predefined and known password) by reading the entries and catching the corresponding error.
The js library which I am using is https://github.com/gildas-lormeau/zip.js/blob/master/dist/zip.min.js.
let reader;
try {
reader = new zip.ZipReader(new zip.BlobReader(file), {
password
});
const entries = await reader.getEntries();
for (const entry of entries) {
try {
await entry.getData(new zip.BlobWriter(), {
onprogress: (index, max) => {
zip.BlobWriter.$cancel()
reader.close()
}
});
} catch (error) {
if (error.message === zip.ERR_ENCRYPTED ||
error.message === zip.ERR_INVALID_PASSWORD) {
alert("Incorrect password")
return false;
} else {
console.log(error)
}
}
}
} catch (error) {
console.log(error)
} finally {
await reader.close();
}
The above code successfully finds out if the file is not encrypted by the predetermined password. However, for some files the error statement is as below.
TypeError: Cannot read properties of undefined (reading 'importKey')
I would like to know why this happens and how to know whether the file is password protected or not.
Thank You
There are some issues with the code you proposed, for example BlobWriter.$cancel is not documented anywhere and does not exist actually. Also, you should call reader.close() only once.
Here is below how such a function could be written.
const verifyZipPassword = async (file, password) => {
const reader = new zip.ZipReader(new zip.BlobReader(file), { password });
const entries = await reader.getEntries();
try {
for (const entry of entries) {
const abortController = new AbortController();
const signal = abortController.signal;
const onprogress = () => abortController.abort();
await entry.getData(new zip.BlobWriter(), { signal, onprogress });
}
} catch (error) {
if (error.message == zip.ERR_INVALID_PASSWORD) {
return false;
} else if (error.message != zip.ERR_ABORT) {
throw error;
}
} finally {
await reader.close();
}
return true;
};
I want to restart my code when catch function is returned an error.
let ig = require('instagram-scraping')
module.exports.instagram = async (req, res) => {
ig.scrapeTag('postthisonmypersonalblogtoo').then(async result => {
let myPostCodes = [];
result.medias.forEach(content => {
if(content.owner_id == '10601516006'){
myPostCodes.push(content.shortcode);
}
})
await res.render('instagram', {
myPosts : myPostCodes
});
}).catch((err) => {
console.error(err);
// if(err){
//ig.scrapeTag('postthisonmypersonalblogtoo').then(async result => { ... } //do same things as above
}
})
}
The reason that i wanted to do this: sometimes ig.scrapeTag method find my posts but sometimes cant find anything and return me that;
Error: Error scraping tag page "postthisonmypersonalblogtoo"
at Request._callback (C:\Users\Byte\Desktop\BLOG\node_modules\instagram-scraping\index.js:114:24)
at Request.self.callback (C:\Users\Byte\Desktop\BLOG\node_modules\request\request.js:185:22)
So when i take this error i want to reset ig.scrapeTag to research my posts on instagram again
(By the way sorry for my bad English and if you guys have a advice for another instagram api let me know (api can be official or unofficial doesn't matter)
I would move scrape functionality into separate function and introduce retry counter to keep track of number of retries. Also not sure why you mix and match then/catch with async/await. I think it is more readable and consistent to use async/await everywhere. Something like this:
let ig = require('instagram-scraping')
const MAX_RETRY_COUNT = 2;
async function scrapeInstagram() {
let retryCount = 0;
const scrapeTag = async () => {
try {
const result = await ig.scrapeTag('postthisonmypersonalblogtoo');
return result;
}
catch(e) {
if (retryCount < MAX_RETRY_COUNT) {
retryCount++;
scrapeTag();
} else {
throw e;
}
}
}
const result = await scrapeTag();
let myPostCodes = [];
result.medias.forEach(content => {
if(content.owner_id == '10601516006'){
myPostCodes.push(content.shortcode);
}
});
return myPostCodes;
}
module.exports.instagram = async (req, res) => {
try {
const myPostCodes = await scrapeInstagram();
await res.render('instagram', {
myPosts : myPostCodes
});
}
catch(e) {
console.log(e);
res.status(500).send("Could not load from Instagram")
}
}
Let's say that the button is clicked one after another.
In this case, I do not want the functionC() to run at every click.
However, every click functionA() and functionB() must work.
I want the function C() to work according to the dataA and dataB values in the last click.
For example, if the button is clicked 100 times and the button is not clicked again within 5 seconds after the last click, the functionC() should work according to the latest dataA and dataB values.
async function functionABC() {
try {
var dataA = await functionA();
} catch (error) { console.log(error); }
try {
var dataB = await functionB();
} catch (error) { console.log(error); }
try {
await functionC(dataA, dataB);
} catch (error) { console.log(error); }
}
<Button title="Buton" onPress={() => functionABC()}/>
NEW DESCRIPTION
(1)
The button was clicked.
functionA and functionB worked.
It was clicked again before the 5 second period expired.
functionC not worked.
(2)
functionA and functionB worked.
It was clicked again before the 5 second period expired.
functionC not worked.
...
(n-1)
functionA and functionB worked.
It was clicked again before the 5 second period expired.
functionC not worked.
(n)
functionA and functionB worked.
5 seconds have expired.
functionC worked.
What you need is to somehow store an identifier for "last running function call" so that you can make your check before functionC. Using a Symbol works well in this case, but any other unique ID would be fine (for example an incremental integer, or an empty object).
let lastClick
async function functionABC() {
const thisClick = Symbol()
lastClick = thisClick
try {
var dataA = await functionA();
} catch (error) { console.log(error); }
try {
var dataB = await functionB();
} catch (error) { console.log(error); }
try {
if(lastClick === thisClick)
await functionC(dataA, dataB);
} catch (error) { console.log(error); }
}
function functionA() {
console.log('run A')
return new Promise(resolve => setTimeout(resolve, 500))
}
function functionB() {
console.log('run B')
return new Promise(resolve => setTimeout(resolve, 500))
}
function functionC() {
console.log('run C')
return new Promise(resolve => setTimeout(resolve, 500))
}
<button onclick="functionABC()"> click me </button>
If you really need to artificially extend the time it takes for functionA and functionB to resolve (and to give your user more time to click again before calling functionC), you could use Promise.all as the simplest solution.
Note that this solution will call functions A & B concurrently. Also, I didn't take care of the error handling. This is just to give you ideas.
let lastClick
async function functionABC() {
const thisClick = Symbol()
lastClick = thisClick
const [dataA, dataB] = await Promise.all([
functionA(),
functionB(),
new Promise(resolve => setTimeout(resolve, 5000))
])
if(thisClick === lastClick)
functionC(dataA, dataB)
}
function functionA() {
console.log('run A')
return new Promise(resolve => setTimeout(resolve, 500))
}
function functionB() {
console.log('run B')
return new Promise(resolve => setTimeout(resolve, 500))
}
function functionC() {
console.log('run C')
return new Promise(resolve => setTimeout(resolve, 500))
}
<button onclick="functionABC()"> click me </button>
I am not sure exactly what you are looking for but according to your example I assumed that this is what you might be looking for.
let counter = 0;
async function functionABC() {
counter++;
try {
var dataA = await functionA();
} catch (error) { console.log(error); }
try {
var dataB = await functionB();
} catch (error) { console.log(error); }
if(counter % 100 === 0) {
setTimeout(() => {
if(counter % 100 === 0) {
try {
await functionC(dataA, dataB);
} catch (error) { console.log(error); }
}
}, 5000)
}
}
<Button title="Buton" onPress={() => functionABC()}/>
Please let me know if not and what exactly you wish to acheive.
EDIT
let timestamp = 0;
let firstClicked = false;
async function functionABC() {
const currentTimestamp = Date.now();
try {
var dataA = await functionA();
} catch (error) { console.log(error); }
try {
var dataB = await functionB();
} catch (error) { console.log(error); }
if(firstClicked) {
if(currentTimestamp - timestamp >= 5000) {
try {
await functionC(dataA, dataB);
} catch (error) { console.log(error); }
}
}
}
firstclicked = true;
timestamp = currentTimestamp;
}
<Button title="Buton" onPress={() => functionABC()}/>
How can I find how much time this function takes to execute?
export async function queryElasticSearch(userQuery, index) {
if (_.isEmpty(userQuery)) {
throw new Error('User query is empty or null');
}
try {
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} catch (err) {
throw err;
}
}
Something like this:
export async function queryElasticSearch(userQuery, index) {
const start = Date.now()
try {
if (_.isEmpty(userQuery)) throw new Error('User query is empty or null');
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} finally {
console.log(Date.now() - start)
}
}
Or alternatively, you can use performance.now() if you want precision in microseconds...
Edit: added finally per Bergi suggestion.
you can also implement this with console.time ie
export async function queryElasticSearch(userQuery, index) {
console.time('time');
try {
if (_.isEmpty(userQuery)) throw new Error('User query is empty or null');
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} finally {
console.timeEnd('time')
}
}