feat: forward modal-close event to children on modal close (#1238)

* feat: forward modal-close event to children on modal close

* fix: update tests
This commit is contained in:
Ben Warzeski
2023-11-21 14:38:46 -05:00
committed by GitHub
parent 748e73d128
commit fe773d1700
2 changed files with 52 additions and 15 deletions

View File

@@ -15,19 +15,27 @@ const useModalIFrameBehavior = () => {
const [isOpen, setIsOpen] = useKeyedState(stateKeys.isOpen, false);
const [options, setOptions] = useKeyedState(stateKeys.options, { height: DEFAULT_HEIGHT });
const receiveMessage = React.useCallback(({ data }) => {
const { type, payload } = data;
const handleModalClose = () => {
const rootFrame = document.querySelector('iframe');
setIsOpen(false);
rootFrame.contentWindow.postMessage({ type: 'plugin.modal-close' }, '*');
};
const receiveMessage = React.useCallback((event) => {
const { type, payload } = event.data;
if (!type) {
return;
}
if (type === 'plugin.modal') {
setOptions((current) => ({ ...current, ...payload }));
setIsOpen(true);
}
if (type === 'plugin.modal-close') {
handleModalClose();
}
}, []);
useEventListener('message', receiveMessage);
const handleModalClose = () => {
setIsOpen(false);
};
return {
handleModalClose,
modalOptions: { isOpen, ...options },

View File

@@ -19,6 +19,13 @@ describe('useModalIFrameBehavior', () => {
jest.clearAllMocks();
state.mock();
});
const testHandleModalClose = ({ trigger }) => {
const postMessage = jest.fn();
document.querySelector = jest.fn().mockReturnValue({ contentWindow: { postMessage } });
trigger();
state.expectSetStateCalledWith(stateKeys.isOpen, false);
expect(postMessage).toHaveBeenCalledWith({ type: 'plugin.modal-close' }, '*');
};
describe('behavior', () => {
it('initializes isOpen to false', () => {
useModalIFrameBehavior();
@@ -29,29 +36,51 @@ describe('useModalIFrameBehavior', () => {
state.expectInitializedWith(stateKeys.options, { height: DEFAULT_HEIGHT });
});
describe('eventListener', () => {
const oldOptions = { some: 'old', options: 'yeah' };
const prepareListener = () => {
useModalIFrameBehavior();
expect(useEventListener).toHaveBeenCalled();
const call = useEventListener.mock.calls[0][1];
expect(call.prereqs).toEqual([]);
return call.cb;
};
it('consumes modal events and opens sets modal options with open: true', () => {
const oldOptions = { some: 'old', options: 'yeah' };
state.mockVals({
[stateKeys.isOpen]: false,
[stateKeys.options]: oldOptions,
});
useModalIFrameBehavior();
expect(useEventListener).toHaveBeenCalled();
const { cb, prereqs } = useEventListener.mock.calls[0][1];
expect(prereqs).toEqual([]);
const receiveMessage = prepareListener();
const payload = { test: 'values' };
cb({ data: { type: messageTypes.modal, payload } });
receiveMessage({ data: { type: messageTypes.modal, payload } });
expect(state.setState.isOpen).toHaveBeenCalledWith(true);
expect(state.setState.options).toHaveBeenCalled();
const [[setOptionsCb]] = state.setState.options.mock.calls;
expect(setOptionsCb(oldOptions)).toEqual({ ...oldOptions, ...payload });
});
it('ignores events with no type', () => {
state.mockVals({
[stateKeys.isOpen]: false,
[stateKeys.options]: oldOptions,
});
const receiveMessage = prepareListener();
const payload = { test: 'values' };
receiveMessage({ data: { payload } });
expect(state.setState.isOpen).not.toHaveBeenCalled();
expect(state.setState.options).not.toHaveBeenCalled();
});
it('calls handleModalClose behavior when receiving a "plugin.modal-close" event', () => {
const receiveMessage = prepareListener();
testHandleModalClose({
trigger: () => {
receiveMessage({ data: { type: 'plugin.modal-close' } });
},
});
});
});
});
describe('output', () => {
test('handleModalClose sets modal options to closed', () => {
useModalIFrameBehavior().handleModalClose();
state.expectSetStateCalledWith(stateKeys.isOpen, false);
test('returns handleModalClose callback', () => {
testHandleModalClose({ trigger: useModalIFrameBehavior().handleModalClose });
});
it('forwards modalOptions from state values', () => {
const modalOptions = { test: 'options' };