(callback)
| 112 | const headStartMatch = /<head(?:>| .*?>)/; |
| 113 | |
| 114 | async function act(callback) { |
| 115 | await callback(); |
| 116 | // Await one turn around the event loop. |
| 117 | // This assumes that we'll flush everything we have so far. |
| 118 | await new Promise(resolve => { |
| 119 | setImmediate(resolve); |
| 120 | }); |
| 121 | if (hasErrored) { |
| 122 | throw fatalError; |
| 123 | } |
| 124 | // JSDOM doesn't support stream HTML parser so we need to give it a proper fragment. |
| 125 | // We also want to execute any scripts that are embedded. |
| 126 | // We assume that we have now received a proper fragment of HTML. |
| 127 | let bufferedContent = buffer; |
| 128 | buffer = ''; |
| 129 | |
| 130 | if (!bufferedContent) { |
| 131 | jest.runAllTimers(); |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | const bodyMatch = bufferedContent.match(bodyStartMatch); |
| 136 | const headMatch = bufferedContent.match(headStartMatch); |
| 137 | |
| 138 | if (streamingContainer === null) { |
| 139 | // This is the first streamed content. We decide here where to insert it. If we get <html>, <head>, or <body> |
| 140 | // we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the |
| 141 | // container. This is not really production behavior because you can't correctly stream into a deep div effectively |
| 142 | // but it's pragmatic for tests. |
| 143 | |
| 144 | if ( |
| 145 | bufferedContent.startsWith('<head>') || |
| 146 | bufferedContent.startsWith('<head ') || |
| 147 | bufferedContent.startsWith('<body>') || |
| 148 | bufferedContent.startsWith('<body ') |
| 149 | ) { |
| 150 | // wrap in doctype to normalize the parsing process |
| 151 | bufferedContent = '<!DOCTYPE html><html>' + bufferedContent; |
| 152 | } else if ( |
| 153 | bufferedContent.startsWith('<html>') || |
| 154 | bufferedContent.startsWith('<html ') |
| 155 | ) { |
| 156 | throw new Error( |
| 157 | 'Recieved <html> without a <!DOCTYPE html> which is almost certainly a bug in React', |
| 158 | ); |
| 159 | } |
| 160 | |
| 161 | if (bufferedContent.startsWith('<!DOCTYPE html>')) { |
| 162 | // we can just use the whole document |
| 163 | const tempDom = new JSDOM(bufferedContent); |
| 164 | |
| 165 | // Wipe existing head and body content |
| 166 | document.head.innerHTML = ''; |
| 167 | document.body.innerHTML = ''; |
| 168 | |
| 169 | // Copy the <html> attributes over |
| 170 | const tempHtmlNode = tempDom.window.document.documentElement; |
| 171 | for (let i = 0; i < tempHtmlNode.attributes.length; i++) { |
no test coverage detected