Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Commit e879409

Browse files
authored
Added circular JSON handling to forwardToMain (#2242)
* Added circular JSON handling to forwardToMain * Added changelog entry * Updated changelog
1 parent 860b5f2 commit e879409

3 files changed

Lines changed: 47 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## Unreleased
8+
## Fixed
9+
- [client] Added circular JSON handling to `forwardToMain.ts` which fixed a bug preventing the Emulator from connecting to Direct Line Speech bots in PR [2242](https://github.com/microsoft/BotFramework-Emulator/pull/2242)
810

9-
## v4.12.0 - 2021 - 3 - 04
11+
## v4.12.0 - 2021 - 3 - 05
1012
## Added
1113
- [client/main] Added UI to open bot dialog that allows the user to set transcript testing properties `randomSeed` and `randomValue` in PR [2209](https://github.com/microsoft/BotFramework-Emulator/pull/2209)
1214
- [client] Added a dialog to the "Conversation -> Send System Activity" menu that allows the user to send custom activity payloads to their bot in PR [2213](https://github.com/microsoft/BotFramework-Emulator/pull/2213)

packages/app/client/src/state/middleware/forwardToMain.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,33 @@ describe('forwardToMain middleware', () => {
7979
expect(mockNext).toHaveBeenCalledWith(mockAction);
8080
expect(mockIpcRenderer.sendSync).toHaveBeenCalledWith('sync-store', mockAction);
8181
});
82+
83+
it('should skip forwarding the action to the main process if the payload has a circular structure', () => {
84+
const innerObject = { outerObject: undefined };
85+
const outerObject = { innerObject: undefined };
86+
innerObject.outerObject = outerObject;
87+
outerObject.innerObject = innerObject;
88+
const mockNext = jest.fn();
89+
const mockAction: any = {
90+
type: 'actionType',
91+
payload: { outerObject },
92+
};
93+
forwardToMain(null)(mockNext)(mockAction);
94+
95+
expect(mockNext).toHaveBeenCalledWith(mockAction);
96+
expect(mockIpcRenderer.sendSync).not.toHaveBeenCalled();
97+
});
98+
99+
it('should surface errors that are not circular JSON errors', () => {
100+
const mockNext = jest.fn();
101+
const mockAction: any = {
102+
type: 'actionType',
103+
payload: { someProp: 123 },
104+
};
105+
mockIpcRenderer.sendSync.mockImplementationOnce(() => {
106+
throw new Error('some error >:(');
107+
});
108+
109+
expect(() => forwardToMain(null)(mockNext)(mockAction)).toThrowError(new Error('some error >:('));
110+
});
82111
});

packages/app/client/src/state/middleware/forwardToMain.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,20 @@ export const forwardToMain: Middleware = _store => next => action => {
4545
return next(action);
4646
}
4747

48-
// Electron 9 does not allow functions to be sent over ipc (https://www.electronjs.org/docs/api/ipc-renderer#ipcrenderersendchannel-args)
49-
// JSON.stringify() removes function properties from objects -- these functions do not need to be maintained in the main process' copy of state
50-
const processedAction = JSON.parse(JSON.stringify(action));
48+
try {
49+
// Electron 9 does not allow functions to be sent over ipc (https://www.electronjs.org/docs/api/ipc-renderer#ipcrenderersendchannel-args)
50+
// JSON.stringify() removes function properties from objects -- these functions do not need to be maintained in the main process' copy of state
51+
const processedAction = JSON.parse(JSON.stringify(action));
5152

52-
// forward the action over ipc to the main process
53-
ipcRenderer.sendSync('sync-store', processedAction);
54-
return next(action);
53+
// forward the action over ipc to the main process
54+
ipcRenderer.sendSync('sync-store', processedAction);
55+
return next(action);
56+
} catch (e) {
57+
if (e.message && e.message.includes('circular structure')) {
58+
// the payload of the action contains a circular JSON structure and cannot be stringified;
59+
// skip forwarding the action to the main process
60+
return next(action);
61+
}
62+
throw e;
63+
}
5564
};

0 commit comments

Comments
 (0)