diff --git a/packages/react-dom/src/client/__tests__/getNodeForCharacterOffset-test.js b/packages/react-dom/src/client/__tests__/getNodeForCharacterOffset-test.js index 6df208437f073..6e662d264dfb5 100644 --- a/packages/react-dom/src/client/__tests__/getNodeForCharacterOffset-test.js +++ b/packages/react-dom/src/client/__tests__/getNodeForCharacterOffset-test.js @@ -9,74 +9,108 @@ 'use strict'; -// TODO: can we express this test with only public API? -var getNodeForCharacterOffset = require('../getNodeForCharacterOffset').default; - -// Create node from HTML string -function createNode(html) { - var node = (getTestDocument() || document).createElement('div'); - node.innerHTML = html; - return node; -} - -function getTestDocument(markup) { - var doc = document.implementation.createHTMLDocument(''); - doc.open(); - doc.write( - markup || - 'test doc', - ); - doc.close(); - return doc; -} - -// Check getNodeForCharacterOffset return value matches expected result. -function expectNodeOffset(result, textContent, nodeOffset) { - expect(result.node.textContent).toBe(textContent); - expect(result.offset).toBe(nodeOffset); -} - describe('getNodeForCharacterOffset', () => { - it('should handle siblings', () => { - var node = createNode('123456789'); + var React; + var ReactDOM; - expectNodeOffset(getNodeForCharacterOffset(node, 0), '123', 0); - expectNodeOffset(getNodeForCharacterOffset(node, 4), '456', 1); + beforeEach(() => { + React = require('react'); + ReactDOM = require('react-dom'); }); - it('should handle trailing chars', () => { - var node = createNode('123456789'); + it('should re-render an input with the same selection', done => { + const container = document.createElement('div'); + let node, component; + document.body.appendChild(container); - expectNodeOffset(getNodeForCharacterOffset(node, 3), '123', 3); - expectNodeOffset(getNodeForCharacterOffset(node, 9), '789', 3); - }); + class InputComponent extends React.Component { + constructor(props) { + super(props); - it('should handle trees', () => { - var node = createNode( - '' + - '1' + - '' + - '' + - '2' + - '' + - '' + - '' + - '' + - '3' + - '45' + - '' + - '', - ); - - expectNodeOffset(getNodeForCharacterOffset(node, 3), '3', 1); - expectNodeOffset(getNodeForCharacterOffset(node, 5), '45', 2); - expect(getNodeForCharacterOffset(node, 10)).toBeUndefined(); - }); + this.state = { + oneFirst: true, + oneValue: 'foo', + twoValue: 'foo', + }; + } + + componentWillMount() { + component = this; + } + + handleChange(e) { + this.setState({value: e.target.value}); + } + + renderForms() { + if (this.state.oneFirst) { + return [ + (node = e)} + readOnly={true} + />, + , + ]; + } else { + return [ + , + , + ]; + } + } + + render() { + return
{this.renderForms()}
; + } + } + + ReactDOM.render(, container); + + node.focus(); + node.setSelectionRange(1, 1); + + const inputDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'selectionStart'); + + delete HTMLInputElement.prototype.selectionStart; + + let startMarkerNode, startMarkerOffset; + let endMarkerNode, endMarkerOffset; + + // These aren't implemented by jsdom yet, so let's re-implement them + // to test the markers created by getNodeForCharacterOffset + + window.getSelection = () => ({ + removeAllRanges: function() { + return true; + }, + addRange: function(range) {}, + extend: function(endNode, endOffset) { + endMarkerNode = endNode; + endMarkerOffset = endOffset; + }, + }); - it('should handle non-existent offset', () => { - var node = createNode('123'); + document.createRange = () => ({ + setStart: function(startNode, startOffset) { + startMarkerNode = startNode; + startMarkerOffset = startOffset; + }, + setEnd: function(endNode, endOffset) { + endMarkerNode = endNode; + endMarkerOffset = endOffset; + }, + }); - expect(getNodeForCharacterOffset(node, -1)).toBeUndefined(); - expect(getNodeForCharacterOffset(node, 4)).toBeUndefined(); + try { + component.setState({oneFirst: false}, () => { + console.log(startMarkerNode, startMarkerOffset); + console.log(endMarkerNode, endMarkerOffset); + done(); + }); + } finally { + Object.defineProperty(HTMLInputElement.prototype, 'selectionStart', inputDescriptor); + } }); });