Cannot read property innerText of null for valid selector using playwright - dom

This script is supposed to retrieve the innerText of a DOM element, the elements selector is
('div[class=QzVHcLdwl2CEuEMpTUFaj]') and I've hand-tested the selector and called the getSharePrice function in the REPL which also works.
const { chromium } = require('playwright');
const util = require('util');
const setTimeoutPromise = util.promisify(setTimeout);
(async () => {
const userDataDir = 'path'
const browser = await chromium.launchPersistentContext(userDataDir, {headless: false });
const page = await browser.newPage();
await page.goto('https://robinhood.com', {timeout: 60000, waitUntil: 'domcontentloaded'});
await getSharePrice(page)
await setTimeoutPromise(1000);
await browser.close();
})();
async function getSharePrice(page) {
const price = await page.evaluate(() => {
return {
price: document.querySelector('div[class=QzVHcLdwl2CEuEMpTUFaj]').innerText.replace(/\D/g,'')
}
});
console.log(price)
}
for some reason, I am getting a (node:59324) UnhandledPromiseRejectionWarning: Error: Evaluation failed: TypeError: Cannot read property 'innerText' of null error, not sure why.
The only thing that I could come up with is that the element hasn't been loaded yet, causing it to evaluate to null which is why innerText can't be called.

adding await page.waitForSelector('div[class=QzVHcLdwl2CEuEMpTUFaj]') before my evaluate block fixed this. Looks like the issue was caused by the element not being loaded yet

Related

Error <path> attribute d: Expected number, "MNaN,NaN\n A32.5,…"

Error: attribute d: Expected number, "MNaN,NaN\n A32.5,…". bundle.js:16703
I seem to be getting this error after calling a function (getInfoById(id)).
useEffect(() => {
async function fetchData() {
const realm_id = //id omitted
const app = new Realm.App({ id: realm_id });
const credentials = //credentials omitted
try {
const user = await app.logIn(credentials);
debugger;
await user.functions
.getInfoById(id)
.then((result) => setInfo(result));
} catch (error) {
console.log("This went wrong: ", error);
}
}
fetchData();
}, [id]);
I have looked up this error and all I can find online is that it looks like it might be an issue with nested data. But the result is an object, as expected, so I can't figure out what is happening. Everything is working like I expect, I'm just trying to clear out/ understand this error.

React useEffect hook running infinite loop despite static dependencies

Can someone please point to me what part of this code is causing an infinite loop?
I have tried wrapping this in useCallback as well but it still runs forever.
slug is the page url that will not change over time
likesCollectionRef is also goint to remain constant
isAuth can change overtime depending on if the user is logged in or out
export default function CommentForm({ slug, isAuth, setReloadTS }) {
const [isLiked, setIsLiked] = useState(false);
const likesCollectionRef = collection(fireStore, 'likes');
useEffect(() => {
if (!isAuth) return;
const qry = query(
likesCollectionRef,
where('slug', '==', slug),
where('author.id', '==', auth.currentUser.uid)
);
const findLike = async () => {
const data = await getDocs(qry);
console.log(`initial like: ${data.docs}`);
setIsLiked(data.docs !== 'undefined' && data.docs);
};
findLike();
}, [slug, isAuth, likesCollectionRef]);
}
likesCollectionRef is declared each render cycle. Place the likes collection reference in a React ref so it's a stable reference. auth also appears to be an external dependency. If it's external to the component this is ok, but if it's internal to the component it should be added to the dependency array.
export default function CommentForm({ slug, isAuth, setReloadTS }) {
const [isLiked, setIsLiked] = useState(false);
const likesCollectionRef = useref(collection(fireStore, 'likes'));
useEffect(() => {
if (!isAuth) return;
const qry = query(
likesCollectionRef.current,
where('slug', '==', slug),
where('author.id', '==', auth.currentUser.uid)
);
const findLike = async () => {
const data = await getDocs(qry);
console.log(`initial like: ${data.docs}`);
setIsLiked(data.docs !== 'undefined' && data.docs);
};
findLike();
}, [isAuth, likesCollectionRef, slug]);
...
}

access document.documentElement from puppeteer

I can get access to the entire HTML for any URL by opening dev-tools and typing:
document.documentElement
I am trying to replicate the same behavior using puppeteer, however, the snippet below returns {}
const puppeteer = require('puppeteer'); // v 1.1.0
const iPhone = puppeteer.devices['Pixel 2 XL'];
async function start(canonical_url) {
const browserURL = 'http://127.0.0.1:9222';
const browser = await puppeteer.connect({browserURL});
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto(canonical_url, {
waitUntil: 'networkidle2',
});
const data = await page.evaluate(() => document.documentElement);
console.log(data);
}
returns:
{}
Any idea on what I could be doing wrong here?

In puppeteer how to wait for DOM element to load and then click

In puppeteer how to wait for DOM element to load and then click. I am trying access a simple page, hit the Start button and then a text field should appear, and I need to type in that text field.
Code given as below.
const puppeteer = require('puppeteer');
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
(async () => {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto('https://janus.conf.meetecho.com/videocalltest.html');
await page.click('#start', {waitUntil: 'domcontentloaded'});
//await sleep(5000);
await page.type('#username', 'austin');
await sleep(5000);
await browser.close();
})();
However if I put a sleep of 5 second (commented in above code), then I am able to type in text field.
I want to avoid giving sleep. Please suggest what's the work around.
You need to wait for the element to be visible because the element is present in the DOM, but not visible.
Here is the script that works:
(async () => {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto('https://janus.conf.meetecho.com/videocalltest.html');
await page.click('#start');
await page.waitForSelector('#username', { visible: true });
await page.type('#username', 'austin');
// await browser.close(); // commented it just to make sure that text is typed in the input before close browser.
})();
You can use ;page.waitForSelector(selector[, options]):
await page.waitForSelector('#username', {visible: true})
//Errors
await page.waitForSelector('#username', {visible: true})
.then(()=>{
console.log('success');
})
.catch((err)=>{
console.log(err);
}

Getting all styles with devtool-protocol in puppeteer

I'm trying to get all styles for all nodes on page and for that i want to use CSS.getMatchedStylesForNode from devtool-protocol, but its only working for one node. If loop through an array of nodes i get a lot of warning in console(code below) and nothing is returned. What i'm doing wrong ?
warning in console:
(node:5724) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 11): Error: Protocol error (CSS.getMatchedStylesForNode): Target closed.
my code
'use strict';
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page._client.send('DOM.enable');
await page._client.send('CSS.enable');
const doc = await page._client.send('DOM.getDocument');
const nodes = await page._client.send('DOM.querySelectorAll', {
nodeId: doc.root.nodeId,
selector: '*'
});
const styleForSingleNode = await page._client.send('CSS.getMatchedStylesForNode', {nodeId: 3});
const stylesForNodes = nodes.nodeIds.map(async (id) => {
return await page._client.send('CSS.getMatchedStylesForNode', {nodeId: id});
});
console.log(JSON.stringify(stylesForNodes));
console.log(JSON.stringify(styleForSingleNode));
await browser.close();
})();
Puppeteer version: 0.13.0
Platform: Window 10
Node: 8.9.3
Works using for of loop
const stylesForNodes = []
for (id of nodes.nodeIds) {
stylesForNodes.push(await page._client.send('CSS.getMatchedStylesForNode', {nodeId: id}));
}