(callback)
| 192 | const headStartMatch = /<head(?:>| .*?>)/; |
| 193 | |
| 194 | async function act(callback) { |
| 195 | await callback(); |
| 196 | // Await one turn around the event loop. |
| 197 | // This assumes that we'll flush everything we have so far. |
| 198 | await new Promise(resolve => { |
| 199 | setImmediate(resolve); |
| 200 | }); |
| 201 | if (hasErrored) { |
| 202 | throw fatalError; |
| 203 | } |
| 204 | // JSDOM doesn't support stream HTML parser so we need to give it a proper fragment. |
| 205 | // We also want to execute any scripts that are embedded. |
| 206 | // We assume that we have now received a proper fragment of HTML. |
| 207 | let bufferedContent = buffer; |
| 208 | buffer = ''; |
| 209 | |
| 210 | if (!bufferedContent) { |
| 211 | jest.runAllTimers(); |
| 212 | return; |
| 213 | } |
| 214 | |
| 215 | const bodyMatch = bufferedContent.match(bodyStartMatch); |
| 216 | const headMatch = bufferedContent.match(headStartMatch); |
| 217 | |
| 218 | if (streamingContainer === null) { |
| 219 | // This is the first streamed content. We decide here where to insert it. If we get <html>, <head>, or <body> |
| 220 | // we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the |
| 221 | // container. This is not really production behavior because you can't correctly stream into a deep div effectively |
| 222 | // but it's pragmatic for tests. |
| 223 | |
| 224 | if ( |
| 225 | bufferedContent.startsWith('<head>') || |
| 226 | bufferedContent.startsWith('<head ') || |
| 227 | bufferedContent.startsWith('<body>') || |
| 228 | bufferedContent.startsWith('<body ') |
| 229 | ) { |
| 230 | // wrap in doctype to normalize the parsing process |
| 231 | bufferedContent = '<!DOCTYPE html><html>' + bufferedContent; |
| 232 | } else if ( |
| 233 | bufferedContent.startsWith('<html>') || |
| 234 | bufferedContent.startsWith('<html ') |
| 235 | ) { |
| 236 | throw new Error( |
| 237 | 'Recieved <html> without a <!DOCTYPE html> which is almost certainly a bug in React', |
| 238 | ); |
| 239 | } |
| 240 | |
| 241 | if (bufferedContent.startsWith('<!DOCTYPE html>')) { |
| 242 | // we can just use the whole document |
| 243 | const tempDom = new JSDOM(bufferedContent); |
| 244 | |
| 245 | // Wipe existing head and body content |
| 246 | document.head.innerHTML = ''; |
| 247 | document.body.innerHTML = ''; |
| 248 | |
| 249 | // Copy the <html> attributes over |
| 250 | const tempHtmlNode = tempDom.window.document.documentElement; |
| 251 | for (let i = 0; i < tempHtmlNode.attributes.length; i++) { |
no test coverage detected