Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid throwing errors if container is no longer in page #424

Merged
merged 8 commits into from
Apr 24, 2023
7 changes: 7 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ export const POST_MESSAGE = {
ALLOW_DELEGATE: `${ZOID}_allow_delegate`,
};

export const RENDER_ERRORS = {
oscarleonnogales marked this conversation as resolved.
Show resolved Hide resolved
oscarleonnogales marked this conversation as resolved.
Show resolved Hide resolved
NAVIGATED_AWAY: "Window navigated away",
COMPONENT_DESTROYED: "Component destroyed",
COMPONENT_CLOSED: "Component closed",
WINDOW_CLOSED: "Detected component window close",
};

export const PROP_TYPE = {
STRING: ("string": "string"),
OBJECT: ("object": "object"),
Expand Down
21 changes: 15 additions & 6 deletions src/parent/parent.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {
METHOD,
WINDOW_REFERENCE,
DEFAULT_DIMENSIONS,
RENDER_ERRORS,
} from "../constants";
import {
getGlobal,
Expand Down Expand Up @@ -315,7 +316,7 @@ export function parentComponent<P, X, C>({
let currentProxyContainer: ?ProxyObject<HTMLElement>;
let childComponent: ?ChildExportsType<P>;
let currentChildDomain: ?string;
let currentContainer: HTMLElement | void;
oscarleonnogales marked this conversation as resolved.
Show resolved Hide resolved
let currentContainer: HTMLElement;

const onErrorOverride: ?OnError = overrides.onError;
let getProxyContainerOverride: ?GetProxyContainer =
Expand Down Expand Up @@ -729,7 +730,15 @@ export function parentComponent<P, X, C>({
return clean.all(err);
})
.then(() => {
initPromise.asyncReject(err || new Error("Component destroyed"));
const error = err || new Error(RENDER_ERRORS.COMPONENT_DESTROYED);
if (
isElementClosed(currentContainer) ||
error.message === RENDER_ERRORS.NAVIGATED_AWAY
) {
initPromise.resolve();
} else {
initPromise.asyncReject(error);
}
});
};

Expand All @@ -749,7 +758,7 @@ export function parentComponent<P, X, C>({
return ZalgoPromise.try(() => {
return event.trigger(EVENT.CLOSE);
}).then(() => {
return destroy(err || new Error(`Component closed`));
return destroy(err || new Error(RENDER_ERRORS.COMPONENT_CLOSED));
});
});
});
Expand Down Expand Up @@ -823,7 +832,7 @@ export function parentComponent<P, X, C>({
window,
"unload",
once(() => {
destroy(new Error(`Window navigated away`));
destroy(new Error(RENDER_ERRORS.NAVIGATED_AWAY));
})
);

Expand Down Expand Up @@ -870,15 +879,15 @@ export function parentComponent<P, X, C>({
.then((isClosed) => {
if (isClosed) {
closed = true;
return close(new Error(`Detected component window close`));
return close(new Error(RENDER_ERRORS.WINDOW_CLOSED));
}

return ZalgoPromise.delay(200)
.then(() => proxyWin.isClosed())
.then((secondIsClosed) => {
if (secondIsClosed) {
closed = true;
return close(new Error(`Detected component window close`));
return close(new Error(RENDER_ERRORS.WINDOW_CLOSED));
}
});
})
Expand Down
59 changes: 59 additions & 0 deletions test/tests/remove.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,63 @@ describe("zoid remove cases", () => {
});
});
});

it("should not throw an error when parent container is removed before render completes", () => {
return wrapPromise(() => {
const { container } = getContainer();

window.__component__ = () => {
return zoid.create({
tag: "test-remove-before-render-complete",
url: () => "mock://www.child.com/base/test/windows/child/index.htm",
domain: "mock://www.child.com",
});
};

const component = window.__component__();
const onRenderedPromise = new ZalgoPromise();
const onClosePromise = new ZalgoPromise();

const renderPromise = component({
onRendered: () => onRenderedPromise.resolve(),
onClose: () => onClosePromise.resolve(),
}).render(container);

// manually remove before render completes
container.remove();

return renderPromise.then(() => {
ZalgoPromise.delay(5);
});
});
});

it("should not throw an error when window navigates away before render completes", () => {
return wrapPromise(() => {
const { container } = getContainer();

window.__component__ = () => {
return zoid.create({
tag: "test-navigation-before-render-complete",
url: () => "mock://www.child.com/base/test/windows/child/index.htm",
domain: "mock://www.child.com",
});
};

const component = window.__component__();
const onRenderedPromise = new ZalgoPromise();
const onClosePromise = new ZalgoPromise();

const renderPromise = component({
onRendered: () => onRenderedPromise.resolve(),
onClose: () => onClosePromise.resolve(),
}).render(container);

// manually reload window before render completes
window.dispatchEvent(new Event("unload"));
return renderPromise.then(() => {
ZalgoPromise.delay(5);
});
});
});
});