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

Add connection #96

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ const connection = connectToChild({
return num1 + num2;
},
},
// Callback function to be called when the connection with the child is lost.
onConnectionLost: () => {
console.log('Connection with child lost');
},
// Callback function to be called when the connection with the child is established or re-established.
onConnection: () => {
console.log('Connection with child established or re-established');
},
});

connection.promise.then((child) => {
Expand Down Expand Up @@ -100,6 +108,14 @@ const connection = connectToParent({
});
},
},
// Callback function to be called when the connection with the parent is lost.
onConnectionLost: () => {
console.log('Connection with parent lost');
},
// Callback function to be called when the connection with the parent is established or re-established.
onConnection: () => {
console.log('Connection with parent established or re-established');
},
});

connection.promise.then((parent) => {
Expand Down Expand Up @@ -141,6 +157,14 @@ The amount of time, in milliseconds, Penpal should wait for the child to respond

Enables or disables debug logging. Debug logging is disabled by default.

`options.onConnectionLost: Function` (optional)

A callback function to be called when the connection with the child is lost.

`options.onConnection: Function` (optional)

A callback function to be called when the connection with the child is established or re-established.

#### Return value

The return value of `connectToChild` is a `connection` object with the following properties:
Expand Down Expand Up @@ -173,6 +197,14 @@ The amount of time, in milliseconds, Penpal should wait for the parent to respon

Enables or disables debug logging. Debug logging is disabled by default.

`options.onConnectionLost: Function` (optional)

A callback function to be called when the connection with the parent is lost.

`options.onConnection: Function` (optional)

A callback function to be called when the connection with the parent is established or re-established.

#### Return value

The return value of `connectToParent` is a `connection` object with the following properties:
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion src/child/connectToParent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ type Options = {
* Whether log messages should be emitted to the console.
*/
debug?: boolean;
/**
* Callback function to be called when the connection with the parent is lost.
*/
onConnectionLost?: () => void;
/**
* Callback function to be called when the connection with the parent is established or re-established.
*/
onConnection?: () => void;
};

type Connection<TCallSender extends object = CallSender> = {
Expand All @@ -59,7 +67,7 @@ type Connection<TCallSender extends object = CallSender> = {
export default <TCallSender extends object = CallSender>(
options: Options = {}
): Connection<TCallSender> => {
const { parentOrigin = '*', methods = {}, timeout, debug = false } = options;
const { parentOrigin = '*', methods = {}, timeout, debug = false, onConnectionLost, onConnection } = options;
const log = createLogger(debug);
const destructor = createDestructor('Child', log);
const { destroy, onDestroy } = destructor;
Expand Down Expand Up @@ -107,6 +115,9 @@ export default <TCallSender extends object = CallSender>(
window.removeEventListener(NativeEventType.Message, handleMessage);
stopConnectionTimeout();
resolve(callSender);
if (onConnection) {
onConnection();
}
}
}
};
Expand All @@ -121,6 +132,10 @@ export default <TCallSender extends object = CallSender>(
if (error) {
reject(error);
}

if (onConnectionLost) {
onConnectionLost();
}
});
}
);
Expand Down
17 changes: 16 additions & 1 deletion src/parent/connectToChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ type Options = {
* Whether log messages should be emitted to the console.
*/
debug?: boolean;
/**
* Callback function to be called when the connection with the child is lost.
*/
onConnectionLost?: () => void;
/**
* Callback function to be called when the connection with the child is established or re-established.
*/
onConnection?: () => void;
};

/**
Expand All @@ -49,7 +57,7 @@ type Options = {
export default <TCallSender extends object = CallSender>(
options: Options
): Connection<TCallSender> => {
let { iframe, methods = {}, childOrigin, timeout, debug = false } = options;
let { iframe, methods = {}, childOrigin, timeout, debug = false, onConnectionLost, onConnection } = options;

const log = createLogger(debug);
const destructor = createDestructor('Parent', log);
Expand Down Expand Up @@ -100,6 +108,9 @@ export default <TCallSender extends object = CallSender>(
if (callSender) {
stopConnectionTimeout();
resolve(callSender);
if (onConnection) {
onConnection();
}
}
return;
}
Expand All @@ -116,6 +127,10 @@ export default <TCallSender extends object = CallSender>(
if (error) {
reject(error);
}

if (onConnectionLost) {
onConnectionLost();
}
});
}
);
Expand Down
76 changes: 76 additions & 0 deletions test/connectionManagement.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,80 @@ describe('connection management', () => {
expect(error.code).toBe(Penpal.ErrorCode.ConnectionDestroyed);
}
);

it('calls onConnectionLost when connection with child is lost', (done) => {
const iframe = createAndAddIframe(`${CHILD_SERVER}/default.html`);

const connection = Penpal.connectToChild({
iframe,
onConnectionLost: () => {
expect(true).toBe(true);
done();
},
});

connection.promise.then(() => {
document.body.removeChild(iframe);
});
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is failing for me because it times out after 5 seconds (5 seconds is the Jasmine test timeout period). I believe the test isn't completing in time because removing the iframe doesn't immediately (or even quickly) destroy the connection. The code that destroys the connection when the iframe is removed can be found in monitorIframeRemoval.ts. Notice that monitorIframeRemoval.ts only checks to see if the iframe is removed every 60 seconds. If the iframe is not found at that point, then it destroys the connection.

A somewhat naive or partial approach to address this problem would be either of these options:

However, there's a bigger question that needs to be addressed as part of #58, which is: What constitutes the connection being lost? I'll expound on this in a comment at the PR level. The solution to this failing test depends on the answer to that question.


it('calls onConnection when connection with child is established or re-established', (done) => {
const iframe = createAndAddIframe(`${CHILD_SERVER}/default.html`);

let connectionCount = 0;

const connection = Penpal.connectToChild({
iframe,
onConnection: () => {
connectionCount += 1;
if (connectionCount === 2) {
expect(true).toBe(true);
connection.destroy();
done();
}
},
});

connection.promise.then((child) => {
child.reload();
});
});

it('calls onConnectionLost when connection with parent is lost', (done) => {
const iframe = createAndAddIframe(`${CHILD_SERVER}/default.html`);

const connection = Penpal.connectToParent({
iframe,
onConnectionLost: () => {
expect(true).toBe(true);
done();
},
});

connection.promise.then(() => {
document.body.removeChild(iframe);
});
});

it('calls onConnection when connection with parent is established or re-established', (done) => {
const iframe = createAndAddIframe(`${CHILD_SERVER}/default.html`);

let connectionCount = 0;

const connection = Penpal.connectToParent({
iframe,
onConnection: () => {
connectionCount += 1;
if (connectionCount === 2) {
expect(true).toBe(true);
connection.destroy();
done();
}
},
});

connection.promise.then((parent) => {
parent.reload();
});
});
});