From 25deff6203d4cce3e8a9e557c84590052455e22d Mon Sep 17 00:00:00 2001 From: Sasha Aickin Date: Fri, 24 Mar 2017 13:31:15 -0700 Subject: [PATCH] Add more SSR unit tests for elements and children. (#9221) * Adding more SSR unit tests for elements and children. * Some of my SSR tests were testing for react-text and react-empty elements that no longer exist in Fiber. Fixed the tests so that they expect correct markup in Fiber. * Tweaked some test names after @gaearon review comment https://github.com/facebook/react/pull/9221#discussion_r107045673 . Also realized that one of the tests was essentially a direct copy of another, so deleted it. * Responding to code review https://github.com/facebook/react/pull/9221#pullrequestreview-28996315 . Thanks @spicyj! --- scripts/fiber/tests-failing.txt | 56 ++ scripts/fiber/tests-passing-except-dev.txt | 48 ++ scripts/fiber/tests-passing.txt | 88 +++ .../ReactDOMServerIntegration-test.js | 586 ++++++++++++++++++ 4 files changed, 778 insertions(+) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 4a4444a784390..c583af694fb07 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -46,6 +46,62 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders unknown attributes for custom elements with client render on top of good server markup * renders unknown attributes for custom elements using is with client render on top of good server markup * renders no HTML events with client render on top of good server markup +* renders a div with text with client render on top of good server markup +* renders a div with text with flanking whitespace with client render on top of good server markup +* renders a div with an empty text child with client render on top of good server markup +* renders a div with multiple empty text children with server string render +* renders a div with multiple empty text children with client render on top of good server markup +* renders a div with multiple whitespace children with server string render +* renders a div with multiple whitespace children with client render on top of good server markup +* renders a div with text sibling to a node with server string render +* renders a div with text sibling to a node with client render on top of good server markup +* renders a non-standard element with text with client render on top of good server markup +* renders a custom element with text with client render on top of good server markup +* renders a leading blank child with a text sibling with server string render +* renders a leading blank child with a text sibling with client render on top of good server markup +* renders a trailing blank child with a text sibling with server string render +* renders a trailing blank child with a text sibling with client render on top of good server markup +* renders an element with two text children with server string render +* renders an element with two text children with client render on top of good server markup +* renders a number as single child with client render on top of good server markup +* renders zero as single child with client render on top of good server markup +* renders an element with number and text children with server string render +* renders an element with number and text children with client render on top of good server markup +* renders null single child as blank with client render on top of good server markup +* renders false single child as blank with client render on top of good server markup +* renders undefined single child as blank with client render on top of good server markup +* renders a null component children as empty with server string render +* renders a null component children as empty with client render on top of good server markup +* renders null children as blank with server string render +* renders null children as blank with client render on top of good server markup +* renders false children as blank with server string render +* renders false children as blank with client render on top of good server markup +* renders null and false children together as blank with server string render +* renders null and false children together as blank with client render on top of good server markup +* renders only null and false children as blank with client render on top of good server markup +* renders an svg element with client render on top of good server markup +* renders svg element with an xlink with client render on top of good server markup +* renders a math element with client render on top of good server markup +* renders an img with client render on top of good server markup +* renders a button with client render on top of good server markup +* renders a div with dangerouslySetInnerHTML with client render on top of good server markup +* renders a newline-eating tag with content not starting with \n with client render on top of good server markup +* renders a newline-eating tag with content starting with \n with client render on top of good server markup +* renders a normal tag with content starting with \n with client render on top of good server markup +* renders stateless components with client render on top of good server markup +* renders ES6 class components with client render on top of good server markup +* renders factory components with client render on top of good server markup +* renders single child hierarchies of components with client render on top of good server markup +* renders multi-child hierarchies of components with client render on top of good server markup +* renders a div with a child with client render on top of good server markup +* renders a div with multiple children with client render on top of good server markup +* renders a div with multiple children separated by whitespace with server string render +* renders a div with multiple children separated by whitespace with client render on top of good server markup +* renders a div with a single child surrounded by whitespace with server string render +* renders a div with a single child surrounded by whitespace with client render on top of good server markup +* renders >,<, and & as single child with client render on top of good server markup +* renders >,<, and & as multiple children with server string render +* renders >,<, and & as multiple children with client render on top of good server markup src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js * can reconcile text merged by Node.normalize() alongside other elements diff --git a/scripts/fiber/tests-passing-except-dev.txt b/scripts/fiber/tests-passing-except-dev.txt index 98dda4bba0127..4ab8bafc5e95d 100644 --- a/scripts/fiber/tests-passing-except-dev.txt +++ b/scripts/fiber/tests-passing-except-dev.txt @@ -47,6 +47,54 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders unknown attributes for custom elements with client render on top of bad server markup * renders unknown attributes for custom elements using is with client render on top of bad server markup * renders no HTML events with client render on top of bad server markup +* renders a div with text with client render on top of bad server markup +* renders a div with text with flanking whitespace with client render on top of bad server markup +* renders a div with an empty text child with client render on top of bad server markup +* renders a div with multiple empty text children with client render on top of bad server markup +* renders a div with multiple whitespace children with client render on top of bad server markup +* renders a div with text sibling to a node with client render on top of bad server markup +* renders a non-standard element with text with client render on top of bad server markup +* renders a custom element with text with client render on top of bad server markup +* renders a leading blank child with a text sibling with client render on top of bad server markup +* renders a trailing blank child with a text sibling with client render on top of bad server markup +* renders an element with two text children with client render on top of bad server markup +* renders a number as single child with client render on top of bad server markup +* renders zero as single child with client render on top of bad server markup +* renders an element with number and text children with client render on top of bad server markup +* renders null single child as blank with client render on top of bad server markup +* renders false single child as blank with client render on top of bad server markup +* renders undefined single child as blank with client render on top of bad server markup +* renders a null component children as empty with client render on top of bad server markup +* renders null children as blank with client render on top of bad server markup +* renders false children as blank with client render on top of bad server markup +* renders null and false children together as blank with client render on top of bad server markup +* renders only null and false children as blank with client render on top of bad server markup +* renders an svg element with client render on top of bad server markup +* renders svg element with an xlink with client render on top of bad server markup +* renders a math element with client render on top of bad server markup +* renders an img with client render on top of bad server markup +* renders a button with client render on top of bad server markup +* renders a div with dangerouslySetInnerHTML with client render on top of bad server markup +* renders a newline-eating tag with content not starting with \n with client render on top of bad server markup +* renders a newline-eating tag with content starting with \n with client render on top of bad server markup +* renders a normal tag with content starting with \n with client render on top of bad server markup +* renders stateless components with client render on top of bad server markup +* renders ES6 class components with client render on top of bad server markup +* renders factory components with client render on top of bad server markup +* renders single child hierarchies of components with client render on top of bad server markup +* renders multi-child hierarchies of components with client render on top of bad server markup +* renders a div with a child with client render on top of bad server markup +* renders a div with multiple children with client render on top of bad server markup +* renders a div with multiple children separated by whitespace with client render on top of bad server markup +* renders a div with a single child surrounded by whitespace with client render on top of bad server markup +* renders >,<, and & as single child with client render on top of bad server markup +* renders >,<, and & as multiple children with client render on top of bad server markup +* throws when rendering a string component with clean client render +* throws when rendering a string component with client render on top of bad server markup +* throws when rendering an undefined component with clean client render +* throws when rendering an undefined component with client render on top of bad server markup +* throws when rendering a number component with clean client render +* throws when rendering a number component with client render on top of bad server markup src/renderers/dom/shared/__tests__/ReactMount-test.js * should warn if mounting into dirty rendered markup diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 6a88c7cf95c86..16aab7d56eaaf 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1066,6 +1066,94 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js * renders unknown attributes for custom elements using is with clean client render * renders no HTML events with server string render * renders no HTML events with clean client render +* renders a div with text with server string render +* renders a div with text with clean client render +* renders a div with text with flanking whitespace with server string render +* renders a div with text with flanking whitespace with clean client render +* renders a div with an empty text child with server string render +* renders a div with an empty text child with clean client render +* renders a div with multiple empty text children with clean client render +* renders a div with multiple whitespace children with clean client render +* renders a div with text sibling to a node with clean client render +* renders a non-standard element with text with server string render +* renders a non-standard element with text with clean client render +* renders a custom element with text with server string render +* renders a custom element with text with clean client render +* renders a leading blank child with a text sibling with clean client render +* renders a trailing blank child with a text sibling with clean client render +* renders an element with two text children with clean client render +* renders a number as single child with server string render +* renders a number as single child with clean client render +* renders zero as single child with server string render +* renders zero as single child with clean client render +* renders an element with number and text children with clean client render +* renders null single child as blank with server string render +* renders null single child as blank with clean client render +* renders false single child as blank with server string render +* renders false single child as blank with clean client render +* renders undefined single child as blank with server string render +* renders undefined single child as blank with clean client render +* renders a null component children as empty with clean client render +* renders null children as blank with clean client render +* renders false children as blank with clean client render +* renders null and false children together as blank with clean client render +* renders only null and false children as blank with server string render +* renders only null and false children as blank with clean client render +* renders an svg element with server string render +* renders an svg element with clean client render +* renders svg element with an xlink with server string render +* renders svg element with an xlink with clean client render +* renders a math element with server string render +* renders a math element with clean client render +* renders an img with server string render +* renders an img with clean client render +* renders a button with server string render +* renders a button with clean client render +* renders a div with dangerouslySetInnerHTML with server string render +* renders a div with dangerouslySetInnerHTML with clean client render +* renders a newline-eating tag with content not starting with \n with server string render +* renders a newline-eating tag with content not starting with \n with clean client render +* renders a newline-eating tag with content starting with \n with server string render +* renders a newline-eating tag with content starting with \n with clean client render +* renders a normal tag with content starting with \n with server string render +* renders a normal tag with content starting with \n with clean client render +* renders stateless components with server string render +* renders stateless components with clean client render +* renders ES6 class components with server string render +* renders ES6 class components with clean client render +* renders factory components with server string render +* renders factory components with clean client render +* renders single child hierarchies of components with server string render +* renders single child hierarchies of components with clean client render +* renders multi-child hierarchies of components with server string render +* renders multi-child hierarchies of components with clean client render +* renders a div with a child with server string render +* renders a div with a child with clean client render +* renders a div with multiple children with server string render +* renders a div with multiple children with clean client render +* renders a div with multiple children separated by whitespace with clean client render +* renders a div with a single child surrounded by whitespace with clean client render +* renders >,<, and & as single child with server string render +* renders >,<, and & as single child with clean client render +* renders >,<, and & as multiple children with clean client render +* throws when rendering a string component with server string render +* throws when rendering an undefined component with server string render +* throws when rendering a number component with server string render +* throws when rendering null with server string render +* throws when rendering null with clean client render +* throws when rendering null with client render on top of bad server markup +* throws when rendering false with server string render +* throws when rendering false with clean client render +* throws when rendering false with client render on top of bad server markup +* throws when rendering undefined with server string render +* throws when rendering undefined with clean client render +* throws when rendering undefined with client render on top of bad server markup +* throws when rendering number with server string render +* throws when rendering number with clean client render +* throws when rendering number with client render on top of bad server markup +* throws when rendering string with server string render +* throws when rendering string with clean client render +* throws when rendering string with client render on top of bad server markup src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js * updates a mounted text component in place diff --git a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js index f3aa90ce904c3..eb3c5e25b1592 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js @@ -15,6 +15,7 @@ let ExecutionEnvironment; let React; let ReactDOM; let ReactDOMServer; +let ReactDOMFeatureFlags; // Helper functions for rendering tests // ==================================== @@ -148,6 +149,31 @@ function itClientRenders(desc, testFn) { testFn(clientRenderOnBadMarkup)); } +function itThrows(desc, testFn) { + it(`throws ${desc}`, () => { + return testFn() + .then(() => + expect(false).toBe('The promise resolved and should not have.')) + .catch(() => {}); + }); +} + +function itThrowsWhenRendering(desc, testFn) { + itThrows(`when rendering ${desc} with server string render`, () => + testFn(serverRender)); + itThrows(`when rendering ${desc} with clean client render`, () => + testFn(clientCleanRender)); + + // we subtract one from the warning count here because the throw means that it won't + // get the usual markup mismatch warning. + itThrows( + `when rendering ${desc} with client render on top of bad server markup`, + () => + testFn((element, warningCount = 0) => + clientRenderOnBadMarkup(element, warningCount - 1)), + ); +} + // When there is a test that renders on server and then on client and expects a logged // error, you want to see the error show up both on server and client. Unfortunately, // React refuses to issue the same error twice to avoid clogging up the console. @@ -157,6 +183,7 @@ function resetModules() { React = require('React'); ReactDOM = require('ReactDOM'); ReactDOMServer = require('ReactDOMServer'); + ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); ExecutionEnvironment = require('ExecutionEnvironment'); } @@ -410,4 +437,563 @@ describe('ReactDOMServerIntegration', () => { expect(e.getAttribute('click')).toBe(null); }); }); + + describe('elements and children', function() { + // helper functions. + const TEXT_NODE_TYPE = 3; + const COMMENT_NODE_TYPE = 8; + + function expectNode(node, type, value) { + expect(node).not.toBe(null); + expect(node.nodeType).toBe(type); + expect(node.nodeValue).toMatch(value); + } + + function expectTextNode(node, text) { + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, a React text node is just a DOM text node. + expectNode(node, TEXT_NODE_TYPE, text); + } else { + // with Stack, a React text node is a DOM text node surrounded by + // react-text comment nodes. + expectNode(node, COMMENT_NODE_TYPE, / react-text: [0-9]+ /); + if (text.length > 0) { + node = node.nextSibling; + expectNode(node, TEXT_NODE_TYPE, text); + } + expectNode(node.nextSibling, COMMENT_NODE_TYPE, / \/react-text /); + } + } + + function expectEmptyNode(node) { + expectNode(node, COMMENT_NODE_TYPE, / react-empty: [0-9]+ /); + } + + describe('text children', function() { + itRenders('a div with text', async render => { + const e = await render(
Text
); + expect(e.tagName).toBe('DIV'); + expect(e.childNodes.length).toBe(1); + expectNode(e.firstChild, TEXT_NODE_TYPE, 'Text'); + }); + + itRenders('a div with text with flanking whitespace', async render => { + // prettier-ignore + const e = await render(
Text
); + expect(e.childNodes.length).toBe(1); + expectNode(e.childNodes[0], TEXT_NODE_TYPE, ' Text '); + }); + + itRenders('a div with an empty text child', async render => { + const e = await render(
{''}
); + expect(e.childNodes.length).toBe(0); + }); + + itRenders('a div with multiple empty text children', async render => { + const e = await render(
{''}{''}{''}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just three separate text node children, + // each of which is blank. + expect(e.childNodes.length).toBe(3); + expectTextNode(e.childNodes[0], ''); + expectTextNode(e.childNodes[1], ''); + expectTextNode(e.childNodes[2], ''); + } else { + // with Stack, there are six react-text comment nodes. + expect(e.childNodes.length).toBe(6); + expectTextNode(e.childNodes[0], ''); + expectTextNode(e.childNodes[2], ''); + expectTextNode(e.childNodes[4], ''); + } + }); + + itRenders('a div with multiple whitespace children', async render => { + const e = await render(
{' '}{' '}{' '}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just three text nodes. + expect(e.childNodes.length).toBe(3); + expectTextNode(e.childNodes[0], ' '); + expectTextNode(e.childNodes[1], ' '); + expectTextNode(e.childNodes[2], ' '); + } else { + // with Stack, each of the text nodes is surrounded by react-text + // comment nodes, making 9 nodes in total. + expect(e.childNodes.length).toBe(9); + expectTextNode(e.childNodes[0], ' '); + expectTextNode(e.childNodes[3], ' '); + expectTextNode(e.childNodes[6], ' '); + } + }); + + itRenders('a div with text sibling to a node', async render => { + const e = await render(
TextMore Text
); + let spanNode; + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are only two children, the "Text" text node and + // the span element. + expect(e.childNodes.length).toBe(2); + spanNode = e.childNodes[1]; + } else { + // with Stack, there are four children, a "Text" text node surrounded + // by react-text comment nodes, and the span element. + expect(e.childNodes.length).toBe(4); + spanNode = e.childNodes[3]; + } + expectTextNode(e.childNodes[0], 'Text'); + expect(spanNode.tagName).toBe('SPAN'); + expect(spanNode.childNodes.length).toBe(1); + expectNode(spanNode.firstChild, TEXT_NODE_TYPE, 'More Text'); + }); + + itRenders('a non-standard element with text', async render => { + const e = await render(Text); + expect(e.tagName).toBe('NONSTANDARD'); + expect(e.childNodes.length).toBe(1); + expectNode(e.firstChild, TEXT_NODE_TYPE, 'Text'); + }); + + itRenders('a custom element with text', async render => { + const e = await render(Text); + expect(e.tagName).toBe('CUSTOM-ELEMENT'); + expect(e.childNodes.length).toBe(1); + expectNode(e.firstChild, TEXT_NODE_TYPE, 'Text'); + }); + + itRenders('a leading blank child with a text sibling', async render => { + const e = await render(
{''}foo
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just two text nodes. + expect(e.childNodes.length).toBe(2); + expectTextNode(e.childNodes[0], ''); + expectTextNode(e.childNodes[1], 'foo'); + } else { + // with Stack, there are five nodes: two react-text comment nodes + // without any text between them, and the text node foo surrounded + // by react-text comment nodes. + expect(e.childNodes.length).toBe(5); + expectTextNode(e.childNodes[0], ''); + expectTextNode(e.childNodes[2], 'foo'); + } + }); + + itRenders('a trailing blank child with a text sibling', async render => { + const e = await render(
foo{''}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just two text nodes. + expect(e.childNodes.length).toBe(2); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[1], ''); + } else { + // with Stack, there are five nodes: the text node foo surrounded + // by react-text comment nodes, and two react-text comment nodes + // without any text between them. + expect(e.childNodes.length).toBe(5); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[3], ''); + } + }); + + itRenders('an element with two text children', async render => { + const e = await render(
{'foo'}{'bar'}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just two text nodes. + expect(e.childNodes.length).toBe(2); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[1], 'bar'); + } else { + // with Stack, there are six nodes: two text nodes, each surrounded + // by react-text comment nodes. + expect(e.childNodes.length).toBe(6); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[3], 'bar'); + } + }); + }); + + describe('number children', function() { + itRenders('a number as single child', async render => { + const e = await render(
{3}
); + expect(e.textContent).toBe('3'); + }); + + // zero is falsey, so it could look like no children if the code isn't careful. + itRenders('zero as single child', async render => { + const e = await render(
{0}
); + expect(e.textContent).toBe('0'); + }); + + itRenders('an element with number and text children', async render => { + const e = await render(
{'foo'}{40}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there are just two text nodes. + expect(e.childNodes.length).toBe(2); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[1], '40'); + } else { + // with Stack, there are six nodes: two text nodes, each surrounded + // by react-text comment nodes. + expect(e.childNodes.length).toBe(6); + expectTextNode(e.childNodes[0], 'foo'); + expectTextNode(e.childNodes[3], '40'); + } + }); + }); + + describe('null, false, and undefined children', function() { + itRenders('null single child as blank', async render => { + const e = await render(
{null}
); + expect(e.childNodes.length).toBe(0); + }); + + itRenders('false single child as blank', async render => { + const e = await render(
{false}
); + expect(e.childNodes.length).toBe(0); + }); + + itRenders('undefined single child as blank', async render => { + const e = await render(
{undefined}
); + expect(e.childNodes.length).toBe(0); + }); + + itRenders('a null component children as empty', async render => { + const NullComponent = () => null; + const e = await render(
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, an empty component results in no markup. + expect(e.childNodes.length).toBe(0); + } else { + // with Stack, an empty component results in one react-empty comment + // node. + expect(e.childNodes.length).toBe(1); + expectEmptyNode(e.firstChild); + } + }); + + itRenders('null children as blank', async render => { + const e = await render(
{null}foo
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there is just one text node. + expect(e.childNodes.length).toBe(1); + } else { + // with Stack, there's a text node surronded by react-text comment nodes. + expect(e.childNodes.length).toBe(3); + } + expectTextNode(e.childNodes[0], 'foo'); + }); + + itRenders('false children as blank', async render => { + const e = await render(
{false}foo
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there is just one text node. + expect(e.childNodes.length).toBe(1); + } else { + // with Stack, there's a text node surronded by react-text comment nodes. + expect(e.childNodes.length).toBe(3); + } + expectTextNode(e.childNodes[0], 'foo'); + }); + + itRenders('null and false children together as blank', async render => { + const e = await render(
{false}{null}foo{null}{false}
); + if (ReactDOMFeatureFlags.useFiber) { + // with Fiber, there is just one text node. + expect(e.childNodes.length).toBe(1); + } else { + // with Stack, there's a text node surronded by react-text comment nodes. + expect(e.childNodes.length).toBe(3); + } + expectTextNode(e.childNodes[0], 'foo'); + }); + + itRenders('only null and false children as blank', async render => { + const e = await render(
{false}{null}{null}{false}
); + expect(e.childNodes.length).toBe(0); + }); + }); + + describe('elements with implicit namespaces', function() { + itRenders('an svg element', async render => { + const e = await render(); + expect(e.childNodes.length).toBe(0); + expect(e.tagName).toBe('svg'); + expect(e.namespaceURI).toBe('http://www.w3.org/2000/svg'); + }); + + itRenders('svg element with an xlink', async render => { + let e = await render( + , + ); + e = e.firstChild; + expect(e.childNodes.length).toBe(0); + expect(e.tagName).toBe('image'); + expect(e.namespaceURI).toBe('http://www.w3.org/2000/svg'); + expect(e.getAttributeNS('http://www.w3.org/1999/xlink', 'href')).toBe( + 'http://i.imgur.com/w7GCRPb.png', + ); + }); + + itRenders('a math element', async render => { + const e = await render(); + expect(e.childNodes.length).toBe(0); + expect(e.tagName).toBe('math'); + expect(e.namespaceURI).toBe('http://www.w3.org/1998/Math/MathML'); + }); + }); + // specially wrapped components + // (see the big switch near the beginning ofReactDOMComponent.mountComponent) + itRenders('an img', async render => { + const e = await render(); + expect(e.childNodes.length).toBe(0); + expect(e.nextSibling).toBe(null); + expect(e.tagName).toBe('IMG'); + }); + + itRenders('a button', async render => { + const e = await render(