(callback)
| 112 | const headStartMatch = /<head(?:>| .*?>)/; |
| 113 | |
| 114 | async function act(callback) { |
| 115 | await callback(); |
| 116 | class="cm">// Await one turn around the event loop. |
| 117 | class="cm">// 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 | class="cm">// JSDOM doesn't support stream HTML parser so we need to give it a proper fragment. |
| 125 | class="cm">// We also want to execute any scripts that are embedded. |
| 126 | class="cm">// We assume that we have now received a proper fragment of HTML. |
| 127 | let bufferedContent = buffer; |
| 128 | buffer = class="st">''; |
| 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 | class="cm">// This is the first streamed content. We decide here where to insert it. If we get <html>, <head>, or <body> |
| 140 | class="cm">// we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the |
| 141 | class="cm">// container. This is not really production behavior because you can't correctly stream into a deep div effectively |
| 142 | class="cm">// but it's pragmatic for tests. |
| 143 | |
| 144 | if ( |
| 145 | bufferedContent.startsWith(class="st">'<head>') || |
| 146 | bufferedContent.startsWith(class="st">'<head ') || |
| 147 | bufferedContent.startsWith(class="st">'<body>') || |
| 148 | bufferedContent.startsWith(class="st">'<body ') |
| 149 | ) { |
| 150 | class="cm">// wrap in doctype to normalize the parsing process |
| 151 | bufferedContent = class="st">'<!DOCTYPE html><html>' + bufferedContent; |
| 152 | } else if ( |
| 153 | bufferedContent.startsWith(class="st">'<html>') || |
| 154 | bufferedContent.startsWith(class="st">'<html ') |
| 155 | ) { |
| 156 | throw new Error( |
| 157 | class="st">'Recieved <html> without a <!DOCTYPE html> which is almost certainly a bug in React', |
| 158 | ); |
| 159 | } |
| 160 | |
| 161 | if (bufferedContent.startsWith(class="st">'<!DOCTYPE html>')) { |
| 162 | class="cm">// we can just use the whole document |
| 163 | const tempDom = new JSDOM(bufferedContent); |
| 164 | |
| 165 | class="cm">// Wipe existing head and body content |
| 166 | document.head.innerHTML = class="st">''; |
| 167 | document.body.innerHTML = class="st">''; |
| 168 | |
| 169 | class="cm">// 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