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 integration test to check inter-frame communication #4090

Merged
merged 2 commits into from
Jan 20, 2022

Conversation

esanzgar
Copy link
Contributor

@esanzgar esanzgar commented Jan 3, 2022

This new integration test checks that PortFinder, PortProvider and
PortRPC work in harmony. A change in one could lead to the others no
working as planned.

@esanzgar
Copy link
Contributor Author

esanzgar commented Jan 3, 2022

I have created three simpler tests the following three communication channels:

  • guest-host
  • guest-sidebar (a little bit more complex)
  • sidebar-host

This new integration test checks that `PortFinder`, `PortProvider` and
`PortRPC` work in harmony. One change in one could lead to the others no
working as planned.
@esanzgar esanzgar force-pushed the implement-inter-frame-communication-integration-test branch from 78a541b to ccf9852 Compare January 19, 2022 14:07
@codecov
Copy link

codecov bot commented Jan 19, 2022

Codecov Report

Merging #4090 (dbc8c92) into master (53f0618) will not change coverage.
The diff coverage is n/a.

❗ Current head dbc8c92 differs from pull request most recent head a49c51c. Consider uploading reports for the commit a49c51c to get more accurate results
Impacted file tree graph

@@           Coverage Diff           @@
##           master    #4090   +/-   ##
=======================================
  Coverage   99.06%   99.06%           
=======================================
  Files         217      217           
  Lines        8170     8170           
  Branches     1918     1918           
=======================================
  Hits         8094     8094           
  Misses         76       76           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 53f0618...a49c51c. Read the comment docs.

@esanzgar
Copy link
Contributor Author

We exchanged comments about the subclassing vs using helper functions here

Please, let me know if you want me to using helper functions.

Copy link
Member

@robertknight robertknight left a comment

Choose a reason for hiding this comment

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

I think the subclassing is OK for now. There are ways it could be abstracted, but the current implementation is easy enough to follow.

I had a suggestion regarding the grouping of the code that represents each of the different frames in the test, namely to split them into separate functions, to make it clear that they are meant to represent activities happening in different frames which run concurrently and don't share any state (except via a message channel).

Generally LGTM though.

assert.equal(response, 'pong');
done();
});
});
Copy link
Member

Choose a reason for hiding this comment

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

The done resolver could potentially be replaced by doing the portFinder.discover call in the Promise callback:

const done = new Promise(resolve => {
  portFinder.discover('host').then(port => {
    hostRPC.connect(port);
    hostRPC.call('ping', response => {
      assert.equal(response, 'pong');
      resolve();
    });
  });
});

...

return done;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea! Thanks!

});
});

await delay(10); // add some realism
Copy link
Member

Choose a reason for hiding this comment

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

Can you clarify what you mean by realism here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Guest can be ready before the Host frame. If that's the case, Guest will polls the Host. I was trying to simulate that scenario.

portProvider.listen();
const guestRPC = new PortRPC();

// Register RPC method *before* connection
Copy link
Member

Choose a reason for hiding this comment

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

I suggest to remove these comments, and leave it to the PortRPC docs to explain that correct usage of the class requires calling on before connect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏼

destroyables.forEach(instance => instance.destroy());
});

it('enables the communication between guest-host', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

To summarize what these tests are doing, each runs a bunch of concurrent activities that simulate the guest, host and sidebar roles in the inter-frame communication process. All the only communication between frames has to go via message channels (no shared variables). One way to make this structure more obvious might be to wrap each "actor" in a function and then run all the actors concurrently at the end.

it('enables ... communication', async () => {
  const simulateGuest = async () => {
    // Guest steps here
  };

  const simulateHost = async () => {
    // Host steps here
  };

  return Promise.all([simulateGuest(), simulateHost()]);
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very good idea! Thanks!

const promise = new Promise(resolve => (done = resolve));

// guest frame;
const portFinder1 = new PortFinder({
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const portFinder1 = new PortFinder({
const guestPortFinder = new PortFinder({

Alternatively, if you wrap each actor in a separate function, the variable names won't conflict.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I use separate functions.


it('enables the communication between sidebar-host', async () => {
let done;
const promise = new Promise(resolve => (done = resolve));
Copy link
Member

Choose a reason for hiding this comment

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

If you are going to use this pattern, I'd suggest to let done be the promise as it is a name of a state (similar to loaded or completed), and call the resolver resolveDone. Alternatively, skip the resolver variable and just use the promise callback:

const done = new Promise(resolve => {
   ...
   hostRPC.call('ping', response => { ...; resolve(); });
});

@esanzgar esanzgar force-pushed the implement-inter-frame-communication-integration-test branch 3 times, most recently from 61a4721 to dbc8c92 Compare January 20, 2022 11:59
Copy link
Contributor Author

@esanzgar esanzgar left a comment

Choose a reason for hiding this comment

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

I incorporated your feedback on the second commit.

destroyables.forEach(instance => instance.destroy());
});

it('enables the communication between guest-host', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very good idea! Thanks!

assert.equal(response, 'pong');
done();
});
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea! Thanks!

portProvider.listen();
const guestRPC = new PortRPC();

// Register RPC method *before* connection
Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏼

const promise = new Promise(resolve => (done = resolve));

// guest frame;
const portFinder1 = new PortFinder({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I use separate functions.

@esanzgar esanzgar force-pushed the implement-inter-frame-communication-integration-test branch from dbc8c92 to 80e009e Compare January 20, 2022 12:02
Co-authored-by: Robert Knight <robertknight@gmail.com>
@esanzgar esanzgar force-pushed the implement-inter-frame-communication-integration-test branch from 80e009e to a49c51c Compare January 20, 2022 12:03
@esanzgar esanzgar merged commit 01d6718 into master Jan 20, 2022
@esanzgar esanzgar deleted the implement-inter-frame-communication-integration-test branch January 20, 2022 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants