fixtures/dom/src/components/fixtures/fragment-refs/TextNodesCase.js JAVASCRIPT 471 lines View on github.com → Search inside
1import TestCase from '../../TestCase';2import Fixture from '../../Fixture';3import PrintRectsFragmentContainer from './PrintRectsFragmentContainer';4import CompareDocumentPositionFragmentContainer from './CompareDocumentPositionFragmentContainer';5import EventFragmentContainer from './EventFragmentContainer';6import GetRootNodeFragmentContainer from './GetRootNodeFragmentContainer';78const React = window.React;9const {Fragment, useRef, useState} = React;1011function GetClientRectsTextOnly() {12  return (13    <TestCase title="getClientRects - Text Only">14      <TestCase.Steps>15        <li>Click the "Print Rects" button</li>16      </TestCase.Steps>17      <TestCase.ExpectedResult>18        The fragment contains only text nodes. getClientRects should return19        bounding rectangles for the text content using the Range API.20      </TestCase.ExpectedResult>21      <Fixture>22        <Fixture.Controls>23          <PrintRectsFragmentContainer>24            This is text content inside a fragment with no element children.25          </PrintRectsFragmentContainer>26        </Fixture.Controls>27      </Fixture>28    </TestCase>29  );30}3132function GetClientRectsMixed() {33  return (34    <TestCase title="getClientRects - Mixed Content">35      <TestCase.Steps>36        <li>Click the "Print Rects" button</li>37      </TestCase.Steps>38      <TestCase.ExpectedResult>39        The fragment contains both text nodes and elements. getClientRects40        should return bounding rectangles for both text content (via Range API)41        and elements.42      </TestCase.ExpectedResult>43      <Fixture>44        <Fixture.Controls>45          <PrintRectsFragmentContainer>46            Text before the span.47            <span48              style={{49                display: 'inline-block',50                padding: '5px 10px',51                backgroundColor: 'lightblue',52                border: '1px solid blue',53                margin: '0 5px',54              }}>55              Element56            </span>57            Text after the span.58            <div59              style={{60                width: '500px',61                height: '50px',62                backgroundColor: 'lightpink',63                border: '1px solid black',64              }}></div>65            More text at the end.66          </PrintRectsFragmentContainer>67        </Fixture.Controls>68      </Fixture>69    </TestCase>70  );71}7273function FocusTextOnlyNoop() {74  const fragmentRef = useRef(null);75  const [message, setMessage] = useState('');7677  const tryFocus = () => {78    fragmentRef.current.focus();79    setMessage('Called focus() - no-op for text-only fragments');80  };8182  const tryFocusLast = () => {83    fragmentRef.current.focusLast();84    setMessage('Called focusLast() - no-op for text-only fragments');85  };8687  return (88    <TestCase title="focus/focusLast - Text Only (No-op)">89      <TestCase.Steps>90        <li>Click either focus button</li>91      </TestCase.Steps>92      <TestCase.ExpectedResult>93        Calling focus() or focusLast() on a fragment with only text children is94        a no-op. Nothing happens and no warning is logged. This is because text95        nodes cannot receive focus.96      </TestCase.ExpectedResult>97      <Fixture>98        <Fixture.Controls>99          <button onClick={tryFocus}>focus()</button>100          <button onClick={tryFocusLast}>focusLast()</button>101          {message && (102            <div style={{marginTop: '10px', color: '#666'}}>{message}</div>103          )}104        </Fixture.Controls>105        <div106          style={{107            padding: '20px',108            backgroundColor: '#f5f5f5',109            border: '1px solid #ddd',110          }}>111          <Fragment ref={fragmentRef}>112            This fragment contains only text. Text nodes are not focusable.113          </Fragment>114        </div>115      </Fixture>116    </TestCase>117  );118}119120function ScrollIntoViewTextOnly() {121  const fragmentRef = useRef(null);122  const [message, setMessage] = useState('');123124  const tryScrollIntoView = alignToTop => {125    fragmentRef.current.scrollIntoView(alignToTop);126    setMessage(127      `Called scrollIntoView(${alignToTop}) - page should scroll to text`128    );129  };130131  return (132    <TestCase title="scrollIntoView - Text Only">133      <TestCase.Steps>134        <li>Scroll down the page so the text fragment is not visible</li>135        <li>Click one of the scrollIntoView buttons</li>136      </TestCase.Steps>137      <TestCase.ExpectedResult>138        The page should scroll to bring the text content into view. With139        alignToTop=true, the text should appear at the top of the viewport. With140        alignToTop=false, it should appear at the bottom. This uses the Range141        API to calculate text node positions.142      </TestCase.ExpectedResult>143      <Fixture>144        <Fixture.Controls>145          <button onClick={() => tryScrollIntoView(true)}>146            scrollIntoView(true)147          </button>148          <button onClick={() => tryScrollIntoView(false)}>149            scrollIntoView(false)150          </button>151          {message && (152            <div style={{marginTop: '10px', color: 'green'}}>{message}</div>153          )}154        </Fixture.Controls>155        <div156          style={{157            marginTop: '100vh',158            marginBottom: '100vh',159            padding: '20px',160            backgroundColor: '#f0fff0',161            border: '1px solid #cfc',162          }}>163          <Fragment ref={fragmentRef}>164            This fragment contains only text. The scrollIntoView method uses the165            Range API to calculate the text position and scroll to it.166          </Fragment>167        </div>168      </Fixture>169    </TestCase>170  );171}172173function ScrollIntoViewMixed() {174  const fragmentRef = useRef(null);175  const [message, setMessage] = useState('');176177  const tryScrollIntoView = alignToTop => {178    fragmentRef.current.scrollIntoView(alignToTop);179    setMessage(180      `Called scrollIntoView(${alignToTop}) - page should scroll to fragment`181    );182  };183184  const targetStyle = {185    height: 300,186    marginBottom: 50,187    display: 'flex',188    alignItems: 'center',189    justifyContent: 'center',190    fontSize: '24px',191    fontWeight: 'bold',192  };193194  return (195    <TestCase title="scrollIntoView - Mixed Content">196      <TestCase.Steps>197        <li>Scroll down the page so the fragment is not visible</li>198        <li>Click one of the scrollIntoView buttons</li>199      </TestCase.Steps>200      <TestCase.ExpectedResult>201        The fragment contains raw text nodes (not wrapped in elements) and202        elements in alternating order. With alignToTop=true, scroll starts from203        the last child and works backwards, ending with the first text node at204        the top. With alignToTop=false, scroll starts from the first child and205        works forward, ending with the last text node at the bottom. Text nodes206        use the Range API for scrolling.207      </TestCase.ExpectedResult>208      <Fixture>209        <Fixture.Controls>210          <button onClick={() => tryScrollIntoView(true)}>211            scrollIntoView(true)212          </button>213          <button onClick={() => tryScrollIntoView(false)}>214            scrollIntoView(false)215          </button>216          {message && (217            <div style={{marginTop: '10px', color: 'green'}}>{message}</div>218          )}219        </Fixture.Controls>220        <div221          style={{222            marginTop: '100vh',223            marginBottom: '100vh',224            whiteSpace: 'pre-wrap',225            lineHeight: '2',226          }}>227          <Fragment ref={fragmentRef}>228            TEXT NODE 1 - This is a raw text node at the start of the fragment229            <div style={{...targetStyle, backgroundColor: 'lightyellow'}}>230              ELEMENT 1231            </div>232            TEXT NODE 2 - This is a raw text node between elements233            <div style={{...targetStyle, backgroundColor: 'lightpink'}}>234              ELEMENT 2235            </div>236            TEXT NODE 3 - This is a raw text node between elements237            <div style={{...targetStyle, backgroundColor: 'lightcyan'}}>238              ELEMENT 3239            </div>240            TEXT NODE 4 - This is a raw text node at the end of the fragment241          </Fragment>242        </div>243      </Fixture>244    </TestCase>245  );246}247248function CompareDocumentPositionTextNodes() {249  return (250    <TestCase title="compareDocumentPosition - Text Only">251      <TestCase.Steps>252        <li>Click the "Compare All Positions" button</li>253      </TestCase.Steps>254      <TestCase.ExpectedResult>255        compareDocumentPosition should work correctly even when the fragment256        contains only text nodes. The "Before" element should be PRECEDING the257        fragment, and the "After" element should be FOLLOWING.258      </TestCase.ExpectedResult>259      <Fixture>260        <Fixture.Controls>261          <CompareDocumentPositionFragmentContainer>262            This is text-only content inside the fragment.263          </CompareDocumentPositionFragmentContainer>264        </Fixture.Controls>265      </Fixture>266    </TestCase>267  );268}269270function ObserveTextOnlyWarning() {271  const fragmentRef = useRef(null);272  const [message, setMessage] = useState('');273274  const tryObserve = () => {275    setMessage('Called observeUsing() - check console for warning');276    const observer = new IntersectionObserver(() => {});277    fragmentRef.current.observeUsing(observer);278  };279280  return (281    <TestCase title="observeUsing - Text Only Warning">282      <TestCase.Steps>283        <li>Open the browser console</li>284        <li>Click the observeUsing button</li>285      </TestCase.Steps>286      <TestCase.ExpectedResult>287        A warning should appear in the console because IntersectionObserver288        cannot observe text nodes. The warning message should indicate that289        observeUsing() was called on a FragmentInstance with only text children.290      </TestCase.ExpectedResult>291      <Fixture>292        <Fixture.Controls>293          <button onClick={tryObserve}>294            observeUsing(IntersectionObserver)295          </button>296          {message && (297            <div style={{marginTop: '10px', color: 'orange'}}>{message}</div>298          )}299        </Fixture.Controls>300        <div301          style={{302            padding: '20px',303            backgroundColor: '#fff0f0',304            border: '1px solid #fcc',305          }}>306          <Fragment ref={fragmentRef}>307            This fragment contains only text. Text nodes cannot be observed.308          </Fragment>309        </div>310      </Fixture>311    </TestCase>312  );313}314315function EventTextOnly() {316  return (317    <TestCase title="Event Operations - Text Only">318      <TestCase.Steps>319        <li>320          Click "Add event listener" to attach a click handler to the fragment321        </li>322        <li>Click "Dispatch click event" to dispatch a click event</li>323        <li>Observe that the fragment's event listener fires</li>324        <li>Click "Remove event listener" and dispatch again</li>325      </TestCase.Steps>326      <TestCase.ExpectedResult>327        Event operations (addEventListener, removeEventListener, dispatchEvent)328        work on fragments with text-only content. The event is dispatched on the329        fragment's parent element since text nodes cannot be event targets.330      </TestCase.ExpectedResult>331      <Fixture>332        <Fixture.Controls>333          <EventFragmentContainer>334            This fragment contains only text. Events are handled via the parent.335          </EventFragmentContainer>336        </Fixture.Controls>337      </Fixture>338    </TestCase>339  );340}341342function EventMixed() {343  return (344    <TestCase title="Event Operations - Mixed Content">345      <TestCase.Steps>346        <li>347          Click "Add event listener" to attach a click handler to the fragment348        </li>349        <li>Click "Dispatch click event" to dispatch a click event</li>350        <li>Observe that the fragment's event listener fires</li>351        <li>Click directly on the element or text content to see bubbling</li>352      </TestCase.Steps>353      <TestCase.ExpectedResult>354        Event operations work on fragments with mixed text and element content.355        dispatchEvent forwards to the parent element. Clicks on child elements356        or text bubble up through the DOM as normal.357      </TestCase.ExpectedResult>358      <Fixture>359        <Fixture.Controls>360          <EventFragmentContainer>361            Text node before element.362            <span363              style={{364                display: 'inline-block',365                padding: '5px 10px',366                margin: '0 5px',367                backgroundColor: 'lightblue',368                border: '1px solid blue',369              }}>370              Element371            </span>372            Text node after element.373          </EventFragmentContainer>374        </Fixture.Controls>375      </Fixture>376    </TestCase>377  );378}379380function GetRootNodeTextOnly() {381  return (382    <TestCase title="getRootNode - Text Only">383      <TestCase.Steps>384        <li>Click the "Get Root Node" button</li>385      </TestCase.Steps>386      <TestCase.ExpectedResult>387        getRootNode should return the root of the DOM tree containing the388        fragment's text content. For a fragment in the main document, this389        should return the Document node.390      </TestCase.ExpectedResult>391      <Fixture>392        <Fixture.Controls>393          <GetRootNodeFragmentContainer>394            This fragment contains only text. getRootNode returns the document.395          </GetRootNodeFragmentContainer>396        </Fixture.Controls>397      </Fixture>398    </TestCase>399  );400}401402function GetRootNodeMixed() {403  return (404    <TestCase title="getRootNode - Mixed Content">405      <TestCase.Steps>406        <li>Click the "Get Root Node" button</li>407      </TestCase.Steps>408      <TestCase.ExpectedResult>409        getRootNode should return the root of the DOM tree for fragments with410        mixed text and element content. The result is the same whether checking411        from text nodes or element nodes within the fragment.412      </TestCase.ExpectedResult>413      <Fixture>414        <Fixture.Controls>415          <GetRootNodeFragmentContainer>416            Text before element.417            <span418              style={{419                display: 'inline-block',420                padding: '5px 10px',421                margin: '0 5px',422                backgroundColor: 'lightyellow',423                border: '1px solid #cc0',424              }}>425              Element426            </span>427            Text after element.428          </GetRootNodeFragmentContainer>429        </Fixture.Controls>430      </Fixture>431    </TestCase>432  );433}434435export default function TextNodesCase() {436  return (437    <TestCase title="Text Node Support">438      <TestCase.ExpectedResult>439        <p>440          This section demonstrates how various FragmentInstance methods work441          with text nodes.442        </p>443        <p>444          <strong>Supported:</strong> getClientRects, compareDocumentPosition,445          scrollIntoView, getRootNode, addEventListener, removeEventListener,446          dispatchEvent447        </p>448        <p>449          <strong>No-op (silent):</strong> focus, focusLast (text nodes cannot450          receive focus)451        </p>452        <p>453          <strong>Not supported (warns):</strong> observeUsing (observers cannot454          observe text nodes)455        </p>456      </TestCase.ExpectedResult>457      <GetClientRectsTextOnly />458      <GetClientRectsMixed />459      <CompareDocumentPositionTextNodes />460      <FocusTextOnlyNoop />461      <ScrollIntoViewTextOnly />462      <ScrollIntoViewMixed />463      <ObserveTextOnlyWarning />464      <EventTextOnly />465      <EventMixed />466      <GetRootNodeTextOnly />467      <GetRootNodeMixed />468    </TestCase>469  );470}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.