Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
Hi there,
Thanks for the awesome product!
I have a strangely behaving bug that prevents me from running some of the tests. All stories are valid and can be opened in local browser. And when I add one more story, the failing stories changes, so for example story A, that had error before I added story B, now is valid, and story B has the same error. Hope it makes sense.
> loki test
loki test v0.14.0
❯ Chrome (docker)
✔ Prepare environment
✔ Start
✔ Fetch list of stories
❯ Test chrome.laptop
❯ App
✖ sign in page
→ Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
✖ waiting
→ Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
✔ error
✖ dashboard
→ Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
✔ Login page
❯ Dashboard
✖ default state
→ Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
✔ Top header
✔ Left side panel
✔ Stop
I use storybook v4.0.6, react 16.6.3, docker v18.09.0, and run this all on Ubuntu 16.04.5 LTS
Hey @ayatkevich Could you please create an example project in a repo where we can reproduce the issue?
I encountered similar issues in the past. The changes in this PR fix it for me: https://github.com/oblador/loki/pull/102
@techeverri I'll try to post some examples of when this can happen
Here are two examples where Loki will show an error, but the browser will work just fine:
const Message = ({ show }) => (show ? <h1>Hello</h1> : null);
storiesOf('LokiErrors', module)
.add('Example 1', () => (
<div>
<h1 style={{ position: 'fixed' }}>Hello</h1>
</div>
))
.add('Example 2', () => <Message show={false} />);
Loki will report the following errors:
LokiErrors: Example 1 [failed]
→ Failed with "Error: TypeError: Reduce of empty array with no initial value" after 4 tries
LokiErrors: Example 2 [failed]
→ Failed with "Error: Unable to get position of selector "#root > *". Review the `chromeSelector` option and make sure your story doesn't crash." after 4 tries
In example 1, the parent div has zero dimensions because it's child is fixed positioned. Loki fails because it can't take a screenshot with zero dimensions.
In example 2, the story renders nothing. Loki gets confused because now the #root > * selector that it uses to capture screenshots matches nothing.
@ayatkevich I worked around that error in my stories by adding a container element that has 100% width and height.
Basically, I changed my stories from this:
storiesOf('MyComponent', module).add('Example', () => (
<MyComponent />
));
to this
storiesOf('MyComponent', module).add('Example', () => (
<div style={{ width: '100%', height: '100%' }}>
<MyComponent />
</div>
));
@priomsrb For the second example that's kind of intended behaviour, although there's been a few issues posted about it so might have to reconsider that decision. The thinking is that if we somehow can't find an element to screenshot then it's likely that something is wrong.
For the first example, it sounds like a bug. But for the sake of tracking down the bug, could you try changing the chromeSelector to be something that matches your fixed element? So something like this:
// chromeSelector: ".wrapper > *"
.add('Example 1', () => (
<div className="wrapper">
<h1 style={{ position: 'fixed' }}>Hello</h1>
</div>
))
@oblador
For the second example that's kind of intended behaviour, although there's been a few issues posted about it so might have to reconsider that decision. The thinking is that if we somehow can't find an element to screenshot then it's likely that something is wrong.
It can be useful to take an empty screenshot when the page is empty. For example, I want to create a story to make sure that <MyComponent show={false}> doesn't render anything. That way if someone introduces a bug into to MyComponent so that it does render something when show={false}, then loki will flag it for me. If I skip creating the story for the show={false} case then I might miss this regression.
For the first example, it sounds like a bug.
Yup it is. I have a fix for it in this line of my PR: https://github.com/oblador/loki/pull/102/files#diff-22b2b3e305064426035bcb31d3bd573bR52
@priomsrb Technically that's logic you're testing, not visual regression, but I agree that it could be useful.
About your fix, I'm not sure if actually fixes the real problem. I think the algorithm should be improved in that we'd detect which child elements that are outside of the regular rendering flow (position absolute/fixed) and add them to the viewport size.
@priomsrb Thanks for that PR!
The 'Unable to find a visible, non-wrapper element' error is much clearer.
Defaulting to the body tag in my particular case still did not do what I needed (I am experimenting with some really weird things with absolute positioned elements in relative 0 x 0 wrappers for a personal project)
In my case, I ended up not raising an error if I did not find a visible non-wrapper, but using the window details (using https://github.com/oblador/loki/pull/102 as a starting point):
// throw new Error('Unable to find a visible, non-wrapper element');
const windowDefaults = {
x: 0,
y: 0,
width: window.innerWidth,
height: window.innerHeight,
};
return windowDefaults;
I'm using a library which uses React Portals. It renders as a sibling of the app's root.
I've set the chromeSelector as #loki > * and the markup is like this:
<body>
<div id="root"> <!-- React app -->
<div id="loki">
...
</div>
</div>
<div>...</div> <!-- React Portal -->
</body>
Since the React Portal is outside of the chromeSelector, I see the same error message as the OP.
I found a workaround that worked really well in this scenario. In the story, I appended the chromeSelector to the component that I wanted to capture. So in my case, I added id="loki" to the component.
Has anyone got this working?
I figured it out, you cannot use @storybook/addon-centered as a decorator