1

I'm using Protractor to run integration tests on my Angular web app. My web app makes API calls using my custom Angular service ApiClient. I mock that service with browser.addMockModule and angular.module().factory(). This lets me mock all my backend APIs! Here's my code:

setup() {
  // Out in WebDriver.

  // Third argument 'apiRequestsMap' is made available as an argument 'map'
  // to the anonymous function which constructs the module.
  browser.addMockModule(
      'mockDataModule',
      (map) =>
          angular.module('mockDataModule', []).value('apiRequestsMap', map),
      this.apiRequestsMap_);

  const apiModuleMaker = () => {
    const mockModule = angular.module('mockapiModule', ['mockDataModule']);
    mockModule.factory(
        'apiClient',
        ($q, apiRequestsMap) => ({
          request: (req) => {
            // In Browser.
            // I can access 'apiRequestsMap'!
            // And I use it to mock those API calls.
          }
        }));
  };
  browser.addMockModule('mockapiModule', apiModuleMaker);
  browser.get('www.mywebpage.com/example');
}

This works pretty well and lets me set up mock APIs in my Protractor tests. The important part is that I can pass the this.apiRequestsMap_ variable from WebDriver to the Browser as apiRequestsMap.

Now I'm wondering - can I do the opposite? How can I pass a variable from the Browser back out to WebDriver?

My first attempt was simply to edit the apiRequestsMap object I passed in. But this seems to have been a one-way transfer. ie, when In Browser, setting apiRequestsMap.aVar = 5; does not change this.apiRequestsMap_.aVar.

Looking at the Protractor API, I also found browser.getRegisteredMockModules. Unfortunately console.log(JSON.stringify(browser.getRegisteredMockModules())); prints out [null, null, null, null, null].

Sorry for posting so much code and context! I'm in way over my head, so I wasn't sure which parts I could remove while allowing my code to still run. Maybe there's a better way to mock API calls directly with WebDriver? This would be a fine workaround.

Another possible take-away is me filing a feature request/bug to the Protractor developers.

hubatish
  • 5,070
  • 6
  • 35
  • 47
  • 1
    What object do you want to pass? Does it have only values? Can it be converted to JSON? Are you able to print that data in Browser console directly without executing JS code using Selenium? – Tarun Lalwani Jul 27 '17 at 17:11
  • Ideally the full object I'd like to pass is an array of objects (all able to be converted with JSON.stringify). I can personally access it right now with `console.log(JSON.stringify(req));`. Not sure how to access that via code, but thanks for the idea! – hubatish Jul 27 '17 at 17:29
  • Since I'm just writing tests, I might also be able to "communicate" with just an `assert` or other failure condition. This is probably what I'll try next. – hubatish Jul 27 '17 at 17:33

1 Answers1

2

You can execute Javascript code in the Browser directly from Protractor.

So in your javascript do something like below

window.__myvariable__ = {data:2, name: "abc"};

Which can be accessed by executing some Javascript code with Selenium. In Protractor that's

browser.executeScript('return window.__myvariable__;');

which returns a normal expectable Protractor promise. Note the window.__myvariable__ object returned should be json convertible.

This will get the value in your test code and it will remain until the page is refreshed. For a more detailed response look at

Access window object / browser scope from protractor

Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • Where should I put this return statement? Inside the Browser context somewhere; window is undefined when executing WebDriver code. – hubatish Jul 27 '17 at 17:49
  • See https://stackoverflow.com/questions/26102132/access-window-object-browser-scope-from-protractor for a more in depth explanation – hubatish Aug 01 '17 at 00:28