Puppeteer: TypeError: page.waitForXpath is not a function - mocha.js

I am using this code. Output of the code always shows TypeError: page.waitForXpath is not a function. Puppeteer version: 8.0.0 and puppeteer-xpath version: 0.1.0 I have also used this command to upgrade: npm install https://github.com/GoogleChrome/puppeteer/ but that does not work. Here is my code:
const { expect } = require('chai');
const puppeteer = require('puppeteer');
var browser, page;
before(async () => {
browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
devtools: false,
args: [
"--disable-web-security",
"--disable-features=IsolateOrigins,site-per-process",
"--window-size=1920,1080"
]
});
page = await browser.newPage();
})
describe("Search to google", async () => {
it("write something to searchbar", async () => {
await page.goto("https://www.google.com");
let searchBarSelector = '[name=q]';
await page.waitForSelector(searchBarSelector);
let [searchBarElement] = await page.$$(searchBarSelector);
await searchBarElement.type("JavaScript Tutorial");
// await page.type(searchBarSelector,"JavaScript Tutorial");
await page.keyboard.press("Enter");
let imageXpath = "//a[contains(text(),'Images')]";
await page.waitForXpath(imageXpath);
let imageTextElement = await page.$x(imageXpath);
expect(imageTextElement != null).equals(true);
})
})
after(async () => {
await browser.close();
})
Output:

You just have a typo: it is page.waitForXPath(), not page.waitForXpath().
See page.waitForXPath(xpath[, options]) in the docs.

Related

How make make await as useDispatch

Can you please explain why await on dispatch has no effect?.Use dispatch is synchronous by default. But is there any way to make it to async?
I have one issue by using dispatch and createAsyncthunk.I think it halts the render of other components. I may be wrong please suggest a better way to handle this rendering issue. I think dispatch is still synchronous.
//API services
const getPersonLists = async (query) => {
return await axios.get(`${endPoint}/person?page=${query.page}&perPage=${query.perPage}`);
};
const fetchPeronWithAsyncThunk = createAsyncThunk('userSlice/userList', async (query) => await getPersonLists(query));
//Slice
const userSlice = createSlice({
name: 'userSlice',
initialState: {
users: [],
loading: false,
},
extraReducers: {
[fetchPeronWithAsyncThunk.pending]: (state) => {
state.loading = true;
},
[fetchPeronWithAsyncThunk.rejected]: (state) => {
state.loading = false;
},
[fetchPeronWithAsyncThunk.fulfilled]: (state, action) => {
state.loading = false;
state.users = action.payload;
},
},
});
//Component
const MyComponent = () => {
const { users } = useUserList(); //selector
const dispatch = useDispatch();
const getList = async () => {
//await has no effect
await dispatch(fetchPeronWithAsyncThunk({ page: 1, perPage: 10 }));
};
return (
<div>
<button onClick={getList}>Fetch user</button>
<div>{users.length && users.map((user, index) => <div key={index}>{user?.name}</div>)}</div>
</div>
);
};
await at that point has exactly the effect you are waiting for.
But since you are in a closure your state will not update within your getList function.
You can get the result of the thunk in your code though:
const result = await dispatch(fetchPeronWithAsyncThunk({ page: 1, perPage: 10 })).unwrap();
Also, you should be using the builder notation for extraReducers. We will deprecate the object notation you are using soon.

Async await not working for function - create pdf document and then email it

const pdf = require('pdfkit')
const QR = require('qrcode')
const emailTickets = async (userEvent, tickets) => {
await createQRCodes(tickets)
await createTicketPDF(tickets, userEvent)
await sendGridEmail(emailDetails, true)
}
The problem seems to be that async/await isn't working properly for the createTicketPDF function.
When I run the above emailTickets function a blank pdf document is emailed. However, when I run it with the below setTimeOut, the pdf contains all the detail that I want.
const emailTickets = async (userEvent, tickets) => {
await createQRCodes(tickets)
await createTicketPDF(tickets, userEvent)
setTimeout(async() => {await sendGridEmail(emailDetails, true)}, 5000);
}
I would prefer a solution where the code waited for the createTicketPDF function to finish before calling the sendGridEmail function.
Below is the code for the createTicketPDF function:
const createTicketPDF = async (tickets, userEvent) => {
const doc = new pdf
doc.pipe(fs.createWriteStream(`./tickets/${tickets[0]._id}.pdf`))
await tickets.map(async(ticket, index)=> {
return(
await doc.fontSize(30),
await doc.text(userEvent.title),
await doc.fontSize(10),
await doc.moveDown(),
await doc.text(`Venue: ${userEvent.venue}, ${userEvent.address1} `),
await doc.moveDown(),
await doc.fontSize(20),
await doc.text(`Ticket ${index+1} of ${tickets.length}: ${ticket.ticketType}`),
await doc.image(`./qrCodes/${ticket._id}.png`, {
align: 'center',
valign: 'center'
}),
await doc.addPage()
)
})
doc.end()
}
I had a forEach loop in this function but replaced it with a map on learning that forEach loops don't work well with async await.
I have also tried using (const ticket of tickets){} but this didn't work either
VS code is suggesting that none of the awaits within the map do anything
For completeness, below is the createQRCodes. This function is working perfectly.
const createQRCodes = async (tickets) => {
let CreateQRCodes = tickets.map(ticket => {
return(
QR.toFile(`./qrCodes/${ticket._id}.png`, String([ticket._id, ticket.randomNumber, ticket.creationTime.getTime(), ticket.userEvent]))
)})
await Promise.all(CreateQRCodes)
}
Any ideas where I am going wrong
Twilio SendGrid developer evangelist here.
As far as I can tell from the documentation, PDFKit is a synchronous library. The only thing that is asynchronous is writing the PDF to disk. So your code should not need to await anything within the createTicketPDF function. You do need to listen for the stream to finish though, so you could return a promise that resolves when the stream is finished, like this:
const createTicketPDF = (tickets, userEvent) => {
const doc = new pdf
const stream = doc.pipe(fs.createWriteStream(`./tickets/${tickets[0]._id}.pdf`))
tickets.map((ticket, index)=> {
return(
doc.fontSize(30),
doc.text(userEvent.title),
doc.fontSize(10),
doc.moveDown(),
doc.text(`Venue: ${userEvent.venue}, ${userEvent.address1} `),
doc.moveDown(),
doc.fontSize(20),
doc.text(`Ticket ${index+1} of ${tickets.length}: ${ticket.ticketType}`),
doc.image(`./qrCodes/${ticket._id}.png`, {
align: 'center',
valign: 'center'
}),
doc.addPage()
)
})
doc.end()
const promise = new Promise((resolve) => {
stream.on("finish", () => {
resolve();
})
});
return promise;
}
const emailTickets = async (userEvent, tickets) => {
await createQRCodes(tickets)
await createTicketPDF(tickets, userEvent)
await sendGridEmail(emailDetails, true)
}

Package: chrome-aws-lambda Error: Navigation failed because browser has disconnected

I'm using mocha, puppeteer, and running test cases in the AWS lambda. I'm opening multiple tabs in the browser using the below code.
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true,
});
let browerTabs = Array.from({length: 50}).map(() => {
return openTab(browser)
})
const openTab = async (browser) => {
try{
url1 = process.env.URL || 'https://www.google.com/'
let page = await browser.newPage();
await page.goto(url1, { waitUntil: ["load", "networkidle2"] });
const content = await page.evaluate(() => document.body.innerHTML);
}catch(err) {
console.log("browser tab open error ==> ", err)
}
return content
}
If I'm opening 40 tabs it's working fine. But If I trying to open 50 tabs then I'm getting the below issue. RAM is not even 30% used. What could be the reason for this error?
Everything is fine in the local
at /var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/common/LifecycleWatcher.js:51:147
at /var/task/node_modules/puppeteer-core/lib/cjs/vendor/mitt/src/index.js:47:62
at Array.map (<anonymous>)
at Object.emit (/var/task/node_modules/puppeteer-core/lib/cjs/vendor/mitt/src/index.js:47:43)
at CDPSession.emit (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/common/EventEmitter.js:72:22)
at CDPSession._onClosed (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:247:14)
at Connection._onClose (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:128:21)
at WebSocket.<anonymous> (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/common/WebSocketTransport.js:17:30)
at WebSocket.onClose (/var/task/node_modules/ws/lib/event-target.js:129:16)
at WebSocket.emit (events.js:315:20)

Webdriverio wait until visible

I'm using webdriverio and need to wait for an element to be in the viewport
So I tried
browser.waitUntil(async () => {
const b = await link.isDisplayedInViewport()
return b;
}, 5000, 'expected to be visible after 5s');
But somehow waitUntil wants a boolean not a Promise<boolean>
How can I fix this?
Update:
I use WebdriverIO in a NodeJs app as follows
const { remote } = require('webdriverio');
(async () => {
const browser = await remote({
logLevel: 'error',
path: '/',
capabilities: {
browserName: 'chrome'
}
});
await browser.url('https://example.com');
const link = await browser.$('.special-link');
const ok = await browser.waitUntil(async () => {
const b = await link.isDisplayedInViewport()
return b;
}, 5000, 'expected to be visible after 5s');
await link.click();
const title = await browser.getTitle();
console.log('Title was: ' + title);
await browser.deleteSession();
})().catch((e) => console.error(e));
source
In the options is don't see anything about with or without async/await. Furthermore I don't use a testing framework!
Sorry for the late answer. But if you are still looking for a solution, Please try this if you want to avoid aync/await
get link() { return browser.element('.special-link'); }
browser.waitUntil(() => this.link.isVisibleWithinViewport(), 20000, 'link not visible')
const elementWaitingToBeDisplayed = $("some element locators")
elementWaitingToBeDisplayed.waitForDisplayed(10000, false)
If you set the second argument of elementWaitingToBeDisplayed.waitForDisplayed to true it waits for the opposite.

react native parsing Lottie file into state?

I am trying to implement Lottie animation into my app, i am using expo SDK,
so i followed the documentation on expo,
_loadAnimationAsync = async () => {
let result = await fetch(
'https://cdn.rawgit.com/airbnb/lottie-react-native/635163550b9689529bfffb77e489e4174516f1c0/example/animations/Watermelon.json'
);
this.setState(
{ animation: JSON.parse(result._bodyText) },
this._playAnimation
);
};
i got an [Unhandled promise rejection: SyntaxError: JSON Parse error: Unexpected identifier "undefined"].
is it result ._bodyText who is empty or undefined ??
I just meet the same issue and fixed.
modify _loadAnimationAsync should get it work.
_loadAnimationAsync = async () => {
let result = await fetch(
'https://cdn.rawgit.com/airbnb/lottie-react-native/635163550b9689529bfffb77e489e4174516f1c0/example/animations/Watermelon.json'
)
.then(data => {
return data.json();
})
.catch(error => {
console.error(error);
});
this.setState({ animation: result }, this._playAnimation);
};
I also start a pr for this issue if you are interested. here

Resources