diff --git a/packages/enzyme-test-suite/test/Utils-spec.jsx b/packages/enzyme-test-suite/test/Utils-spec.jsx index 1c3d7ad2d..9a463b42b 100644 --- a/packages/enzyme-test-suite/test/Utils-spec.jsx +++ b/packages/enzyme-test-suite/test/Utils-spec.jsx @@ -10,6 +10,7 @@ import { spyMethod, nodeHasType, isCustomComponentElement, + makeOptions, } from 'enzyme/build/Utils'; import getAdapter from 'enzyme/build/getAdapter'; import { @@ -17,6 +18,7 @@ import { mapNativeEventNames, propFromEvent, } from 'enzyme-adapter-utils'; +import { get, reset, merge as configure } from 'enzyme/build/configuration'; import './_helpers/setupAdapters'; @@ -590,6 +592,107 @@ describe('Utils', () => { }); }); + describe('makeOptions', () => { + let originalConfig; + const adapter = getAdapter(); + const initialConfig = { + adapter, + foo: 'bar', + }; + const node = {}; + const otherNode = {}; + + beforeEach(() => { + originalConfig = get(); + reset(initialConfig); + }); + + afterEach(() => { + reset(originalConfig); + }); + + it('throws when passed attachTo and hydrateIn do not agree', () => { + expect(() => makeOptions({ attachTo: node, hydrateIn: otherNode })).to.throw( + TypeError, + 'If both the `attachTo` and `hydrateIn` options are provided, they must be === (for backwards compatibility)', + ); + }); + + it('throws when config attachTo and hydrateIn do not agree', () => { + configure({ attachTo: node, hydrateIn: otherNode }); + expect(() => makeOptions({})).to.throw( + TypeError, + 'If both the `attachTo` and `hydrateIn` options are provided, they must be === (for backwards compatibility)', + ); + }); + + it('returns an object that includes the config', () => { + expect(makeOptions({ bar: 'baz' })).to.eql({ + ...initialConfig, + bar: 'baz', + }); + }); + + it('sets attachTo and hydrateIn to hydrateIn, when attachTo is missing', () => { + expect(makeOptions({ hydrateIn: node })).to.eql({ + ...initialConfig, + hydrateIn: node, + attachTo: node, + }); + }); + + it('sets attachTo and hydrateIn to hydrateIn, when attachTo === hydrateIn', () => { + expect(makeOptions({ hydrateIn: node, attachTo: node })).to.eql({ + ...initialConfig, + hydrateIn: node, + attachTo: node, + }); + }); + + it('only sets attachTo, when hydrateIn is missing', () => { + expect(makeOptions({ attachTo: node })).to.eql({ + ...initialConfig, + attachTo: node, + }); + }); + + describe('when DOM node options are set in the config', () => { + it('inherits attachTo', () => { + reset({ ...initialConfig, attachTo: node }); + expect(makeOptions({})).to.eql({ + ...initialConfig, + attachTo: node, + }); + }); + + it('inherits hydrateIn', () => { + reset({ ...initialConfig, hydrateIn: node }); + expect(makeOptions({})).to.eql({ + ...initialConfig, + attachTo: node, + hydrateIn: node, + }); + }); + + it('allows overriding of attachTo', () => { + reset({ ...initialConfig, attachTo: node }); + expect(makeOptions({ attachTo: otherNode })).to.eql({ + ...initialConfig, + attachTo: otherNode, + }); + }); + + it('allows overriding of hydrateIn', () => { + reset({ ...initialConfig, hydrateIn: node }); + expect(makeOptions({ hydrateIn: otherNode })).to.eql({ + ...initialConfig, + attachTo: otherNode, + hydrateIn: otherNode, + }); + }); + }); + }); + describe('spyMethod', () => { it('can spy last return value and restore it', () => { class Counter { diff --git a/packages/enzyme/src/Utils.js b/packages/enzyme/src/Utils.js index b1a8c93d4..4c26a4972 100644 --- a/packages/enzyme/src/Utils.js +++ b/packages/enzyme/src/Utils.js @@ -18,24 +18,32 @@ export function getAdapter(options = {}) { return realGetAdapter(options); } -export function makeOptions(options) { - const { attachTo, hydrateIn } = options; - +function validateMountOptions(attachTo, hydrateIn) { if (attachTo && hydrateIn && attachTo !== hydrateIn) { throw new TypeError('If both the `attachTo` and `hydrateIn` options are provided, they must be === (for backwards compatibility)'); } +} + +export function makeOptions(options) { + const { attachTo: configAttachTo, hydrateIn: configHydrateIn, ...config } = get(); + validateMountOptions(configAttachTo, configHydrateIn); + + const { attachTo, hydrateIn } = options; + validateMountOptions(attachTo, hydrateIn); // neither present: both undefined // only attachTo present: attachTo set, hydrateIn undefined // only hydrateIn present: both set to hydrateIn // both present (and ===, per above): both set to hydrateIn + const finalAttachTo = hydrateIn || configHydrateIn || configAttachTo || attachTo || undefined; + const finalHydrateIn = hydrateIn || configHydrateIn || undefined; const mountTargets = { - attachTo: hydrateIn || attachTo || undefined, - hydrateIn: hydrateIn || undefined, + ...(finalAttachTo && { attachTo: finalAttachTo }), + ...(finalHydrateIn && { hydrateIn: finalHydrateIn }), }; return { - ...get(), + ...config, ...options, ...mountTargets, };