interactors icon indicating copy to clipboard operation
interactors copied to clipboard

Proof of concept: calling remote interactors

Open jnicklas opened this issue 3 years ago • 9 comments

Depends on #166

I've been unable to knock this idea out of my head. So my weekend hack was to try and see if I could actually make it work. And it kinda sorta works, with a lot of caveats! But I think it proves that the idea itself is fundamentally interesting.

Background

One of the big missing pieces of BigTest and Interactors is that Interactors currently need to be running in the same process as the test runner. This limits us a lot in terms of how interactors can be used. For example we can never have the test runner and the page under test be on different origins, which is very limiting. In many cases, calling interactor directly is good, but in some cases, it would be better to have a request/response cycle for this.

Implementation

This uses the addInteractionWrapper API to make it possible to call interactors running in a different process. Basically when writing your test, you would use interactors as you normally would, but instead of running them in the current process, the interaction is serialized and sent over a websocket connection running in another process (could be a browser!).

Try it out!

Start the server:

cd packages/remote
yarn ts-node example/server.ts

Then run the client:

cd packages/remote
yarn ts-node example/client.ts

You should see output like this:

Screenshot 2022-01-29 at 13 20 32

Note that "Some Link" is rendered in a JSDOM context running in the server!!!

Limitations

  • The implementation of the interactor must match between the client and server for this to behave as expected.
  • Multiple interactors must not have the same name
  • The server is currently running a websocket server, which is limiting since we want it to run in a browser. It should be running a websocket client as well.
  • Composed interactors are not yet implemented (but should be trivial)
  • It does not support matchers
  • It's generally a hacky pile of jank. This is not production grade stuff at all. There are any number of edge cases which will cause this to very much blow up.

jnicklas avatar Jan 29 '22 12:01 jnicklas

⚠️ No Changeset found

Latest commit: cdb1e6ed1c0c0ad9025b87fa8f2c2c83ad3c1606

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Jan 29 '22 12:01 changeset-bot[bot]

Deploy Preview for interactors canceled.

Name Link
Latest commit cdb1e6ed1c0c0ad9025b87fa8f2c2c83ad3c1606
Latest deploy log https://app.netlify.com/sites/interactors/deploys/62553ffabf96e90009f2b856

netlify[bot] avatar Jan 29 '22 12:01 netlify[bot]

@jnicklas @cowboyd I have an idea how we can bypass the first two limitations. When we get interaction in our wrapper we calculate hash from interaction name, available filters/actions, default filters values. So it's like duck typing. And do the same thing on a client for all imported interactors.

wKich avatar Feb 04 '22 19:02 wKich

@jnicklas @cowboyd I have an idea how we can bypass the first two limitations. When we get interaction in our wrapper we calculate hash from interaction name, available filters/actions, default filters values. So it's like duck typing. And do the same thing on a client for all imported interactors.

@wKich Interesting! I think we would also need to check the arity of the action functions too, right?

cowboyd avatar Feb 09 '22 09:02 cowboyd

This is relevant to support Playwright #191 which has its own protocol for referencing and interacting with objects in a remote page. Maybe some abstraction could be made?

cowboyd avatar Mar 08 '22 07:03 cowboyd

Yeah, I already thought about that. But actually for the playwright we can have another solution.

We can add function exposer, ask user to put all his interactors there. That exposer exposes interactors in global namespace, so they will be available through window.Button for example or window.__INTERACTORS__.Button. Then we create helpers for the playwright, like cy.do or cy.expect in these helpers we just need to get code representation and call page.evaluate() with exposed interactors. The problem is you can't pass non-serializable things as well as in this spike.

wKich avatar Mar 14 '22 15:03 wKich

The problem is you can't pass non-serializable things as well as in this spike.

We would need a similar mechanism for matchers

cowboyd avatar Mar 15 '22 09:03 cowboyd

@cowboyd, yeah, we missed that point

wKich avatar Mar 22 '22 05:03 wKich

Since the effection branch was merged (yay!), I've rebased and updated this PR. I've also extracted #197 out of this as a generally sensible thing to do, which shows how remote interactors can really be implemented on top of our existing interactors.

jnicklas avatar Mar 30 '22 07:03 jnicklas