I have a React application running. I'd like to know if it's possible to access state values using Puppeteer.
For example, in React I have:
const [gridBlocks, setGridBlocks] = useState([])
This value is later updated to set gridBlocks
to an array of values.
Then, using Puppeteer I have:
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000/', {
waitUntil: 'networkidle2'
});
// Can I get access to React and other javascript values now?
// Something like console.log(await page.evaluate(() => <are React variables available here>));
// Another way?
await browser.close();
})();
The gridBlocks
state has values that I'd like to loop through to update the UI and grab screenshot of each. I won't know what the gridBlocks
values are ahead of time so I can't just "hard code" them in my Puppeteer script. I really like to be able to read it from the loaded page, from page.goto
.
Most articles I've seen deal with testing and they pass props
to components. I'd like to read directly from the loaded page ... if possible.
Thanks!
I found a quick and dirty way to do this on puppeteer. First you need to grab the extension file from chrome. This method is faster than cloning the react repository from github and whatnot.
There are two major steps,
First steps:
extension
for name.Load the extension, make sure to keep the devtools open.
const browser = await puppeteer.launch({
headless: false,
devtools: true,
args: [
'--disable-extensions-except=./extension/',
'--load-extension=./extension/',
]
});
Open the react page, and make sure it is fully loaded.
const page = await browser.newPage();
await page.goto('http://localhost:3000', {waitUntil: 'networkidle0'});
Now, we will find the child element from the root element and use the internal commands used in the devtools.
The waitFor is important as well. We should give it some time to initializing the selection.
await page.evaluate(()=>{
const rootElement = document.querySelector('#root').childNodes[0];
__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent.selectNode(rootElement);
})
await page.waitFor(1000);
Finally we have the state for this particular element inside $r,
const data = await page.evaluate(()=>{
return $r;
})
I couldn't do much with it on the node context, but I'm sure you can modify and execute different stuff using this.
Full code,
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
devtools: true,
args: [
'--disable-extensions-except=./extension/',
'--load-extension=./extension/',
]
});
const page = await browser.newPage();
await page.goto('http://localhost:3000', {waitUntil: 'networkidle0'});
await page.evaluate(()=>{
const rootElement = document.querySelector('#root').childNodes[0];
__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent.selectNode(rootElement);
})
await page.waitFor(1000);
const data = await page.evaluate(()=>{
return $r;
})
console.log(data)
})();
Here is the example react app,
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Example;
Note:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With