mdasberg / ng-apimock

Node plugin that provides the ability to use scenario based api mocking: for local development for protractor testing
MIT License
99 stars 26 forks source link

ngApimock.selectScenario does not change scenario. I keep getting the default scenario. #48

Closed ghost closed 6 years ago

ghost commented 6 years ago

As the title says, I'm experiencing issues with the selectScenario function to set a scenario from a protractor script. Calling the function does change the selected scenario in the /mocking frontend. However, the server still gives me back the default scenario. When I run express in debug mode I see the selectScenario call from the protractor script arriving in my server.

My setup is as follows: I testing against an angular 5 app (not hybrid)

My protractor conf contains:

ngApimockOpts: {
    angularVersion: 5,
  },
  onPrepare: () => {
    global.ngApimock = require(`../../../.tmp/ngApimock/protractor.mock`);
  }

My server.js is as follows:

const express = require('express');
const ngApimock = require('ng-apimock')();
const path = require('path');
const cors = require('cors');

const distDirectory = path.resolve(`${__dirname}/dist`);
const mocksOutputDirectory = path.resolve(`${__dirname}/.tmp/ngApimock`);
const mocksSourceDirecory = path.resolve(`${__dirname}/test/integration/api-mocks`);

const ngApiMockConfig = {
  outputDir: mocksOutputDirectory,
 src: mocksSourceDirecory
};

const app = express();

ngApimock.run(ngApiMockConfig);
ngApimock.watch(ngApiMockConfig.src);

app
  .use(cors())
  .use(require('ng-apimock/lib/utils').ngApimockRequest)
  .use('/mocking', express.static(mocksOutputDirectory))
  .use(express.static(distDirectory))
  .use((req, res) => res.sendFile('index.html', { root: distDirectory }))
  .listen(3000, 'localhost');

I have tried many things such as adding hybrid to the ngApimockOpts in the protractor conf, using a proxy for use with the angular-cli as described, adding the option useAllAngular2AppRoots: true.

All results in the same problem: The default response of my mock.

mdasberg commented 6 years ago

hi @bastiannijboer can you post the code in which you call selectScenario?

ghost commented 6 years ago

Jep, it is: await ngApimock.selectScenario('GET-clientportal-productsoverview', 'error'); await browser.get('/mijn-producten'); expect(await mijnProductenPage.errorEl.isPresent()).to.be.true;

mdasberg commented 6 years ago

That should work. Could you try and chain the api call and see if that works?

await ngApimock.selectScenario('GET-clientportal-productsoverview', 'error').then(async ()=> 
await browser.get('/mijn-producten'));
ghost commented 6 years ago

Thanks for the quick reply. Unfortunately it did not help. It still returns me the default scenario.

mdasberg commented 6 years ago

could you try and put the following attribute in your protractor.conf

SELENIUM_PROMISE_MANAGER: false

ghost commented 6 years ago

I currently have that. I also tried it without, but it keeps returning the default response. However, a strange thing is; When I debug my test code and I set a breakpoint before my expect in this code: await ngApimock.selectScenario('GET-clientportal-productsoverview', 'error'); await browser.get('/mijn-producten'); expect(await mijnProductenPage.errorEl.isPresent()).to.be.true;

When I have SELENIUM_PROMISE_MANAGER: false, set: When I then open the ng-apimock frontend (at localhost:3000/mocking) I see that the response is shown as being set to 'default'.

When I have SELENIUM_PROMISE_MANAGER: true, set: When I then open the ng-apimock frontend (at localhost:3000/mocking) I see that the response is shown as being set to 'error', which is the response that I wanted, but in reality I get the default response back.

wswebcreation commented 6 years ago

@bastiannijboer Have you tried renaming the scenario's without the -, camelcase them. I remember we had a problem with that in the past.

ghost commented 6 years ago

@wswebcreation I tried await ngApimock.selectScenario('GETclientportalproductsoverview', 'error') Also I removed the '-' characters from the filename. Unfortunately that also does not seem to work.. Still I get the default response.

wswebcreation commented 6 years ago

@mdasberg and @bastiannijboer

What I find strange is this remark

When I have SELENIUM_PROMISE_MANAGER: true, set: When I then open the ng-apimock frontend (at localhost:3000/mocking) I see that the response is shown as being set to 'error', which is the response that I wanted, but in reality I get the default response back.

This should not be visible in the frondend because it uses a cookie based on the session. It now looks like no cookie has been set that is related to the instance, or am I wrong @mdasberg ?

@bastiannijboer What I also wonder. When you run you app and you change the scenario manual, you get the right response which you also see in the network tab?

ghost commented 6 years ago

What I also wonder. When you run you app and you change the scenario manual, you get the right response which you also see in the network tab?

When I start my server and I change the scenario manually then I do get the expected response.

mdasberg commented 6 years ago

@bastiannijboer there is a difference between what is selected in protractor and what is shown in the web-interface. Because protractor is using a session identifier, so when you have multiple protractor instances running parallel, you don't get the response set in another test.

I think I know what the issue is. ngapimock uses a cookie for protractor to get the correct response for the protractor session. the cookie hasn't been set yet, when you navigate to your url. Therefor you need to navigate to a page first in order to set the cookie for ngapimock.

can you do this:

await browser.get('your base url');
await ngApimock.selectScenario('GET-clientportal-productsoverview', 'error');
await browser.get('/mijn-producten');

I am currently working on rewriting the core of ngapimock. I have already fixed this issue there. I will add a fix for it on the current version as well.

Can you let me know if that works?

ghost commented 6 years ago

@mdasberg I tried your suggested work around with both
SELENIUM_PROMISE_MANAGER: false and SELENIUM_PROMISE_MANAGER: true Unfortunately both still result in the default response.

wswebcreation commented 6 years ago

hi @bastiannijboer

We've been checking the code of ng-apimock, tests and I also checked my local setup and we don't experience this issue. Can you please provide an example project with the same setup you have so we can help you debug the issue. We now assume that the issue is in your setup and this is the only solution we have for now now.

ghost commented 6 years ago

Ofcourse. I have created an example by using an angular 5 example app. In this repo you find my setup together with the app: https://github.com/bastiannijboer/ReproduceIssueNgApimock

To reproduce you have to do the following: Run the app:

Then run the test:

Here I expect to get the "heroes" response. But in fact I'm getting the error response (which is default).

ghost commented 6 years ago

Sorry for closing and reopening this issue, I accidentally hit the wrong button..

mdasberg commented 6 years ago

@bastiannijboer after fixing your repo (missed angular-cli.json) I did a debug and found out that you forgot to proxy your e2e.

if you update your package.json e2e script with

"e2e": "ng e2e --prod --proxy-config proxy.config.json",

it will work

ghost commented 6 years ago

@mdasberg Sorry for the confusion: The e2e tests came with the sample app, I should have removed them to prevent confusion. It is about the integration tests that you can run with npm run it. In order to do this you need to start the application first with the npm start command. This command does include the proxy setup.

I have updated the repo and it should have the missing files. I also removed the tests in the e2e folder.

mdasberg commented 6 years ago

@bastiannijboer so apparently your angular application was configured incorrectly.

You did not proxy your api calls because in the in proxy.config.json you route /api instead of /heroes

and in your app.config.ts you have your url set to http://localhost:3000/heroes instead of /heroes

So this will never proxy. Apimock will return the default response because you have a cookie set on http://localhost:4200 and not on 3000

ghost commented 6 years ago

@mdasberg I am somehow happy that in the sample repo I have made this mistake. It was indeed this problem but I would have never found this otherwise: In the "real" app that I want to test I did not make use of a proxy. But after checking all the url's I realized that this app is of course pointing to a different backend server. So the api's that I want to mock are not running on the baseUrl as where the angular app is running. This probably results in a cookie that is set on the baseUrl of the angular app and thus not on the baseUrl of the actual api. I was not aware of this. The solution is then exactly how you have described: I configured the angular app in a way that it is expecting the api's to run on the same baseUrl as the app. And I am now using the proxy as described.. and it works! Many thanks for your help @mdasberg and @wswebcreation

wswebcreation commented 6 years ago

You're welcome

smasala commented 5 years ago

@mdasberg we have that problem in regards to the cookie settings with protractor: https://github.com/mdasberg/ng-apimock/issues/48#issuecomment-379536068 will a fix be released for this?