OK so I've been doing some work on this and have come up with this solution, which works for what I want, without the need to set a common selector to be captured with every single scenario.
The initial goal was to capture my React components, displayed on Storybook, in isolation (ie. without the markdown or prop tables getting in the way).
Just for everyones reference, these are the relevant dependencies and versions that I'm using (copied and pasted from my projects package.json
file):
"@storybook/addon-actions": "^3.4.8",
"@storybook/addon-info": "^3.4.8",
"@storybook/addon-links": "^3.4.8",
"@storybook/addon-options": "^3.4.8",
"@storybook/addons": "^3.4.8",
"@storybook/react": "^3.4.8",
"backstopjs": "^3.2.19",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-dom": "^16.4.1"
As a further note, I'm using puppeteer
with backstopjs
.
The first issue I had to get around was the fact that Storybook displays your component, markdown and prop-tables inside an inner <iframe>
element on each page. This caused an issue with backstopjs
since the CSS scope had no concept of the inner document
inside that inner <iframe>
. If my component was bigger than what was visible in the immediate UI then it wouldn't realise that the inner document
was longer than the outer one. In addition to this, I wasn't able to set any hideSelectors
or removeSelectors
for any components inside that inner <iframe>
since it was out of scope.
So the first major discovery that helped to isolate that inner <iframe>
on its own page was to add iframe.html
to the URL as follows (for example - suppose you're running Storybook on your localhost
at the default port):
http://localhost:6006/iframe.html?selectedKind=...
This isolates that previously inner <iframe>
on its own page without the left menu panel appearing. So, from here, I could now hide and remove selectors as I wanted to since everything was now in scope. The Storybook markdown and prop-tables that are displayed on the page are, conveniently, inside a single <div>
element. The unique CSS selector that I used to point to this <div>
element is as follows:
div[id="root"] > div > div > div[style*="font-family: -apple-system"]
So what I decided to do, instead of setting up a common selector to be captured with each scenario, was to invoke a common onReadyScript
in my backstop.json
configuration file as follows:
{
"id": "suite_name",
"viewports": [
...
],
"onReadyScript": "my-on-ready-script.js",
"scenarios": [
...
],
...
}
My script, then, was set up to remove the markdown and prop-tables <div>
element as follows:
module.exports = async function (puppeteer) {
/* Remove the markdown and prop tables from the Storybook preview panel */
await puppeteer
.$eval('div[id="root"] > div > div > div[style*="font-family: -apple-system"]', (markdownAndPropTables) => {
markdownAndPropTables.parentNode.remove();
});
};
This leaves my component displayed completely in isolation on each page and backstopjs
, then, can capture that component all on its own.
This is the best solution I've been able to find to achieve my goals with this. I'm putting this out there as a potential solution for everyone else, too. Hopefully there's something in this that will help someone else out there looking to do the same thing that I wanted to!