/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ describe('useEditableValue', () => { let act; let React; let ReactDOM; let useEditableValue; beforeEach(() => { const utils = require('./utils'); act = utils.act; React = require('react'); ReactDOM = require('react-dom'); useEditableValue = require('../devtools/views/hooks').useEditableValue; }); it('should not cause a loop with values like NaN', () => { let state; function Example({value = NaN}) { const tuple = useEditableValue(value); state = tuple[0]; return null; } const container = document.createElement('div'); ReactDOM.render(, container); expect(state.editableValue).toEqual('NaN'); expect(state.externalValue).toEqual(NaN); expect(state.parsedValue).toEqual(NaN); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); }); it('should override editable state when external props are updated', () => { let state; function Example({value}) { const tuple = useEditableValue(value); state = tuple[0]; return null; } const container = document.createElement('div'); ReactDOM.render(, container); expect(state.editableValue).toEqual('1'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); // If there are NO pending changes, // an update to the external prop value should override the local/pending value. ReactDOM.render(, container); expect(state.editableValue).toEqual('2'); expect(state.externalValue).toEqual(2); expect(state.parsedValue).toEqual(2); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); }); it('should not override editable state when external props are updated if there are pending changes', () => { let dispatch, state; function Example({value}) { const tuple = useEditableValue(value); state = tuple[0]; dispatch = tuple[1]; return null; } const container = document.createElement('div'); ReactDOM.render(, container); expect(state.editableValue).toEqual('1'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); // Update (local) editable state. act(() => dispatch({ type: 'UPDATE', editableValue: '2', externalValue: 1, }), ); expect(state.editableValue).toEqual('2'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(2); expect(state.hasPendingChanges).toBe(true); expect(state.isValid).toBe(true); // If there ARE pending changes, // an update to the external prop value should NOT override the local/pending value. ReactDOM.render(, container); expect(state.editableValue).toEqual('2'); expect(state.externalValue).toEqual(3); expect(state.parsedValue).toEqual(2); expect(state.hasPendingChanges).toBe(true); expect(state.isValid).toBe(true); }); it('should parse edits to ensure valid JSON', () => { let dispatch, state; function Example({value}) { const tuple = useEditableValue(value); state = tuple[0]; dispatch = tuple[1]; return null; } const container = document.createElement('div'); ReactDOM.render(, container); expect(state.editableValue).toEqual('1'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); // Update (local) editable state. act(() => dispatch({ type: 'UPDATE', editableValue: '"a', externalValue: 1, }), ); expect(state.editableValue).toEqual('"a'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(true); expect(state.isValid).toBe(false); }); it('should reset to external value upon request', () => { let dispatch, state; function Example({value}) { const tuple = useEditableValue(value); state = tuple[0]; dispatch = tuple[1]; return null; } const container = document.createElement('div'); ReactDOM.render(, container); expect(state.editableValue).toEqual('1'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); // Update (local) editable state. act(() => dispatch({ type: 'UPDATE', editableValue: '2', externalValue: 1, }), ); expect(state.editableValue).toEqual('2'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(2); expect(state.hasPendingChanges).toBe(true); expect(state.isValid).toBe(true); // Reset editable state act(() => dispatch({ type: 'RESET', externalValue: 1, }), ); expect(state.editableValue).toEqual('1'); expect(state.externalValue).toEqual(1); expect(state.parsedValue).toEqual(1); expect(state.hasPendingChanges).toBe(false); expect(state.isValid).toBe(true); }); });