5

We've recently started using Cypress for our E2E tests with our Angular 6 UI. It's proving to be great and, in our opinion, much better to use than Protractor.

Our plan is to mock all interactions with the server. This has been easy for all REST/XHR calls using cy.route() and fixtures.

However, we also use a web socket. And mocking the interactions with that is proving to be not at all so easy.

From the research I've done so far, the only advice I can find suggests using cy.stub(). Which sounds fine in principal but I can't find any elaboration on this, ideally with some examples of using it to mock a web socket.

Another approach I thought might work is to use Angular's TestBed service. Injecting our own service that handles our interaction with the web socket.

But are either of those the correct route to go down? Can anyone provide any examples of the best way it should be done?

Any pointers to get me going in the right direction to get me started will be massively appreciated. Thanks.

eebsie
  • 396
  • 5
  • 18

2 Answers2

1

I had a similar problem at work and ended up with a similar solution to yours (I think).

Our app depends on another library which does some networking stuff. Rather than using TestBed or similar, I used Angular's environment files to sub in a different service for the e2e tests, which followed the same interface as the real service.

Then within the stub service (which returns fixture data), I exposed methods on the window object for interacting with the stub at run time to make it return different data etc.

I have made a blog post explaining the approach, along with commits.

http://wtfisanapi.com/htf-do-i-write-e2e-tests-with-a-stubbed-dependency-angular-nrwl-nx-edition/

The full code can be found here https://github.com/robt1019/e2e-stub-demo

How did your solution work out for you?

robt1019
  • 51
  • 1
0

After much playing around with this, I finally came up with my own solution. Essentially this comes from using ng.probe().

Specifically for Cypress, access to ng is obtained via the cy.window() function, e.g.:

cy.window().then((win: any) => {
    const ngComponent = win.ng.probe(win.document.getElementsByTagName("component-name")[0].componentInstance;
    const myService = ngComponent.myService;
    myService.doSomething();
});

Note here that you get to a service by first getting a handle on a component that injects that service. In my case the services I was after were injected in to the app-root component so I got a handle on that and then to the websocket service I wanted to call or mock for my tests.

eebsie
  • 396
  • 5
  • 18
  • 3
    Problem with that solution is: You won't be able to test the production code. Production code is likely to call `enableProdMode` which won't let you use `ng.probe` after that. So if you're app does have AOT compilation issues you may not find out – maxime1992 Sep 24 '18 at 08:57