diff --git a/specs/Modal.events.spec.js b/specs/Modal.events.spec.js
index 5e223288..0e61c1bf 100644
--- a/specs/Modal.events.spec.js
+++ b/specs/Modal.events.spec.js
@@ -1,5 +1,6 @@
/* eslint-env mocha */
import React from "react";
+import ReactDOM from "react-dom";
import "should";
import sinon from "sinon";
import Modal from "react-modal";
@@ -11,24 +12,37 @@ import {
mouseUpAt,
escKeyDown,
tabKeyDown,
- withModal
+ withModal,
+ withElementCollector,
+ createHTMLElement
} from "./helper";
export default () => {
it("should trigger the onAfterOpen callback", () => {
const afterOpenCallback = sinon.spy();
- const props = { isOpen: true, onAfterOpen: afterOpenCallback };
- withModal(props, null, () => {});
- afterOpenCallback.called.should.be.ok();
+ withElementCollector(() => {
+ const props = { isOpen: true, onAfterOpen: afterOpenCallback };
+ const node = createHTMLElement("div");
+ ReactDOM.render(, node);
+ requestAnimationFrame(() => {
+ afterOpenCallback.called.should.be.ok();
+ ReactDOM.unmountComponentAtNode(node);
+ });
+ });
});
it("should call onAfterOpen with overlay and content references", () => {
const afterOpenCallback = sinon.spy();
- const props = { isOpen: true, onAfterOpen: afterOpenCallback };
- withModal(props, null, modal => {
- sinon.assert.calledWith(afterOpenCallback, {
- overlayEl: modal.portal.overlay,
- contentEl: modal.portal.content
+ withElementCollector(() => {
+ const props = { isOpen: true, onAfterOpen: afterOpenCallback };
+ const node = createHTMLElement("div");
+ const modal = ReactDOM.render(, node);
+ requestAnimationFrame(() => {
+ sinon.assert.calledWith(afterOpenCallback, {
+ overlayEl: modal.portal.overlay,
+ contentEl: modal.portal.content
+ });
+ ReactDOM.unmountComponentAtNode(node);
});
});
});
diff --git a/specs/Modal.spec.js b/specs/Modal.spec.js
index 47c25482..c32db56e 100644
--- a/specs/Modal.spec.js
+++ b/specs/Modal.spec.js
@@ -348,32 +348,42 @@ export default () => {
});
it("overrides content classes with custom object className", () => {
- const props = {
- isOpen: true,
- className: {
- base: "myClass",
- afterOpen: "myClass_after-open",
- beforeClose: "myClass_before-close"
- }
- };
- withModal(props, null, modal => {
- mcontent(modal).className.should.be.eql("myClass myClass_after-open");
+ withElementCollector(() => {
+ const props = {
+ isOpen: true,
+ className: {
+ base: "myClass",
+ afterOpen: "myClass_after-open",
+ beforeClose: "myClass_before-close"
+ }
+ };
+ const node = createHTMLElement("div");
+ const modal = ReactDOM.render(, node);
+ requestAnimationFrame(() => {
+ mcontent(modal).className.should.be.eql("myClass myClass_after-open");
+ ReactDOM.unmountComponentAtNode(node);
+ });
});
});
it("overrides overlay classes with custom object overlayClassName", () => {
- const props = {
- isOpen: true,
- overlayClassName: {
- base: "myOverlayClass",
- afterOpen: "myOverlayClass_after-open",
- beforeClose: "myOverlayClass_before-close"
- }
- };
- withModal(props, null, modal => {
- moverlay(modal).className.should.be.eql(
- "myOverlayClass myOverlayClass_after-open"
- );
+ withElementCollector(() => {
+ const props = {
+ isOpen: true,
+ overlayClassName: {
+ base: "myOverlayClass",
+ afterOpen: "myOverlayClass_after-open",
+ beforeClose: "myOverlayClass_before-close"
+ }
+ };
+ const node = createHTMLElement("div");
+ const modal = ReactDOM.render(, node);
+ requestAnimationFrame(() => {
+ moverlay(modal).className.should.be.eql(
+ "myOverlayClass myOverlayClass_after-open"
+ );
+ ReactDOM.unmountComponentAtNode(node);
+ });
});
});
@@ -668,11 +678,18 @@ export default () => {
});
it("adds --after-open for animations", () => {
- const props = { isOpen: true };
- withModal(props, null, modal => {
+ withElementCollector(() => {
const rg = /--after-open/i;
- rg.test(mcontent(modal).className).should.be.ok();
- rg.test(moverlay(modal).className).should.be.ok();
+ const props = { isOpen: true };
+ const node = createHTMLElement("div");
+ const modal = ReactDOM.render(, node);
+ requestAnimationFrame(() => {
+ const contentName = modal.portal.content.className;
+ const overlayName = modal.portal.overlay.className;
+ rg.test(contentName).should.be.ok();
+ rg.test(overlayName).should.be.ok();
+ ReactDOM.unmountComponentAtNode(node);
+ });
});
});
@@ -722,25 +739,24 @@ export default () => {
});
it("keeps the modal in the DOM until closeTimeoutMS elapses", done => {
- const closeTimeoutMS = 100;
+ function checkDOM(count) {
+ const overlay = document.querySelectorAll(".ReactModal__Overlay");
+ const content = document.querySelectorAll(".ReactModal__Content");
+ overlay.length.should.be.eql(count);
+ content.length.should.be.eql(count);
+ }
+ withElementCollector(() => {
+ const closeTimeoutMS = 100;
+ const props = { isOpen: true, closeTimeoutMS };
+ const node = createHTMLElement("div");
+ const modal = ReactDOM.render(, node);
- const props = { isOpen: true, closeTimeoutMS };
- withModal(props, null, modal => {
modal.portal.closeWithTimeout();
-
- function checkDOM(count) {
- const overlay = document.querySelectorAll(".ReactModal__Overlay");
- const content = document.querySelectorAll(".ReactModal__Content");
- overlay.length.should.be.eql(count);
- content.length.should.be.eql(count);
- }
-
- // content is still mounted after modal is gone
checkDOM(1);
setTimeout(() => {
- // content is unmounted after specified timeout
checkDOM(0);
+ ReactDOM.unmountComponentAtNode(node);
done();
}, closeTimeoutMS);
});
diff --git a/src/components/ModalPortal.js b/src/components/ModalPortal.js
index b7ac6cea..d28ee455 100644
--- a/src/components/ModalPortal.js
+++ b/src/components/ModalPortal.js
@@ -222,14 +222,16 @@ export default class ModalPortal extends Component {
}
this.setState({ isOpen: true }, () => {
- this.setState({ afterOpen: true });
-
- if (this.props.isOpen && this.props.onAfterOpen) {
- this.props.onAfterOpen({
- overlayEl: this.overlay,
- contentEl: this.content
- });
- }
+ requestAnimationFrame(() => {
+ this.setState({ afterOpen: true });
+
+ if (this.props.isOpen && this.props.onAfterOpen) {
+ this.props.onAfterOpen({
+ overlayEl: this.overlay,
+ contentEl: this.content
+ });
+ }
+ });
});
}
};