Code Monkey home page Code Monkey logo

core's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

core's Issues

Reflect data changes (POST, PUT, PATCH or DELETE requests)

Is there a way to make the mocks hold some kind of status so we can make adding/removing/editing entities work?

For example, json-server has a way to do it:

If you make POST, PUT, PATCH or DELETE requests, changes will be automatically and safely saved to db.json using lowdb.

I was wondering if in ng-apimock we can have something similar.

not able to set non-string variables

Is there a way to set non-string variables? Right now setVariable() takes a string for value. I tried passing in a json string of the object, but it comes back with double quotes around them in the mock response. Same thing with numbers.

Thanks.

Nested body expressions are incorrectly matched

I was looking at documentation between the new and old repos on the use of body matching but isn't entirely clear to me to me and/or isn't currently working.

based on my interpretation of it, I tried two different things:

  1. created two mocks for the same call, each with a different body matching
  2. tried this with just one mock with one body argument

My specific goal was for a response to trigger when a specific email was used in the email, however I find that with case 2, if the body doesn't match. For case 1, regardless of which body I try to match, it always tries to match with first mock that was put into ng-apimock.
example mock I created

{
    "name": "some_call",
    "isArray": false,
    "request": {
        "url": "/api/some_call",
        "method": "POST",
        "body": {
            "user": {
                "first_name": ".*",
                "last_name": ".*",
                "phone_number": ".*",
                "email": "[email protected]",
                "password": ".*",
                "invitation_token": ".*",
                "creation_date": ".*",
                "updated_date": ".*"
            }
        },
        "headers": {}
    },
    "responses": {
        "failed": {
            "status": 400,
            "data": {},
            "headers": {},
            "default": true
        }
    }
}

There's not way to specify the order that routes are resolved

I have two API endpoints
v1/workflows/
v1/workflows/tabs/

The mocks for these two endpoints only work when the files are named to be parsed in a certain order. For example:
workflows.mock.json
workflows-tabs.mock.json
Doesn't work because workflows.mock.json is resolved before workflows-tabs.mock.json. However:
a-workflows-tabs.mock.json
workflows.mock.json
Works correctly because the routes are resolved the other way around.

I couldn't find anything in the documentation that explained another way to do this other than file naming. This seems unlikely. Am I missing something?

Interpolation does not work when providing data from a file

ie:

    "name": "my mock",
    "isArray": true,
    "request": {
        "url": "/some/url,
        "method": "GET"
    },
    "responses": {
        "success": {
            "file": "some.success.json",
            "headers": {
                "Content-type": "application/json"
            },
            "default": true
        },
        "server-error": {
            "default": false,
            "status": 500
        }
    }
}

Body matching with regex not working when migrating from old ng-apimock

The below mock used to work with the old ng-apimock. With the new version this is not working.
https://www.npmjs.com/package/ng-apimock#howto-write-mocks

Actual request body content:
image

Mock json:-
{ "name": "post-test-mock", "isArray": false, "responses": { "default": { "default": true, "delay": 1000, "data": { "mock": "mock" } } }, "request": { "url": "/mock/url/api.php", "body": "(.*)page=0&page_size=25(.*)", "method": "POST" } }

Also the migration script is not updating the body in a request
https://github.com/ng-apimock/core/blob/master/MIGRATION.md#convert-your-mocks-to-the-new-json-format

State.matchesBody() has a false positive for similar mocks

I have created a fix, but am receiving a 403 when trying to push the branch.

Lets say you have two mocks with similar bodies:
Mock A: body: { nested: { number: '\\d+', identifier: '^[a-zA-Z]{4}$' } }
and
Mock B: body: { nested: { number: '\\d+', identifier: '^[a-zA-Z]{4}$', tuple: ['\\d+', '[\'true\'|\'false\']'] } }

Upon receiving a request with body: { nested: { number: 123, identifier: 'abcd', tuple: [1, false] } }

the State.matchesBody() function will return Mock A instead of Mock B.

Fix is ready, how can I contribute?

Show (Error) logging

I have got an issue with the ng-apimock.
When a mockfile contains a reference to a file (to include the body) that does not exist, i don't see error logging.

Is there an option to configure the loglevel (to debug/error)?
Or is it possible to scan all the mockfiles at the start for possible configuration errors?

Thank you in advance!

Make the endpoints configurable.

Currently @ng-apimock/core expects the endpoints to be served under /ngapimock.
It should be possible to make this configurable.

Dynamically select a scenario

Is it possible to dynamically select a scenario? That would help a lot when writing automated tests.

For example, a way to send a special HTTP request to the mock server in order to set a specific scenario for a specific route.

It would be great to have such a feature.

Support inheritance for mocks

I was thinking it might be helpful to have the ability to do some sort of inheritance for the mocks you specify (within a given endpoint). For example say you are mocking something like a hypothetical GET /configuration and the API you're mocking returns a pretty big thing of configuration. Then when you are writing your e2e specs, most of the time if - the thing you are testing can be configured - you want to have a scenario for that specific configuration. It would be convenient if you could build up these scenarios using some sort of inheritance rather than each scenario duplicating some base thing.

Example of desired ability

{
  "name": "get-configuration",
  "request": {
    "url": "/api/configuration",
    "method": "GET"
  },
  "responses": {
    "base-scenario": {
      "default": true,
      "status": 200,
      "data": {
        "color": "red",
        "name": "bar",
        "lots-more-stuff": "..."
      }
    },
    "name-is-foo": {
      "extends": "base-scenario",
      "dataOverrides": {
        "name": "foo"
      }
    },
    "color-is-blue": {
      "extends": "base-scenario",
      "dataOverrides": {
        "color": "blue"
      }
    }
  }
}

Not sure the best way to handle if you want to override a nested object, but I could see this feature being useful for keeping the mocks organized.

Great tool!

Multiple matching mocks

Hi,

As our collection of mocks is growing, it gets harder and harder to ensure that not multiple mocks match a certain request.

it would increase the user experience to throw an error when multiple mocks matches a request.

We run our ngapimock as part of our NX-workspace. At this time we are unable to clean the dist-folder upon build. Thus when switching branches renamed mockfiles get left behind in the dist-folder and can cause conflicts. This is a hard to debug situation.

Also renaming a mockfile while running in watcher mode will introduce this conflict.

thanks!

Chaining responses

As a user
I want to be able to specify
When a mock is hit
Which scenario's should be selected next

Dynamically modify responses by having a callback

Would it be possible to dynamically modify responses, by having a callback? The callback, if provided, would receive the current HTTP request, the current Mock and MockResponse, the interpolated chunk and return an eventually modified chunk, headers and status. One single callback would be enough, set as an additional property on the MiddlewareConfiguration class.

This apparently simple change would allow all kinds of dynamic behaviors, like injecting values from the request into the response, call public or private APIs that provide random data, etc. etc.

Having the same functionality available through the docker container would be trickier, the callback would have to be a physical JavaScript file provided through a volume mount. My node.js knowledge doesn't go that far... Maybe the default image could have a dummy callback file that would not make any change to the response items. Maybe it's not even worth to consider, for this kind of scenarios it would be better to just let people create their own docker images.

The proposed code change would have to be applied on MockRequestHandler class (mock.request.handler.ts)

handle(request: http.IncomingMessage, response: http.ServerResponse, next: Function, params: { id: string, mock: Mock }): void {
        const _response: MockResponse = this.state.getResponse(params.mock.name, params.id);
        if (_response !== undefined) {
            const { headers } = _response;
            const { status } = _response;
            const { then } = _response;
            const delay: number = this.state.getDelay(params.mock.name, params.id);
            const jsonCallbackName = this.getJsonCallbackName(request);

            try {
                const chunk = this.getChunk(_response, params, jsonCallbackName);

// call external callback, providing request, _response, params, chunk, overwritting chunk, headers and status with returned values
// ideally, the jsonCallbackName should be applied after the external callback is invoked
// delay could also be allowed to be dynamically changed, why not?

                setTimeout(() => {
                    this.respond(params, then, response, status, headers, chunk);
                }, delay);
            } catch (e) {
                response.writeHead(HttpStatusCode.INTERNAL_SERVER_ERROR, HttpHeaders.CONTENT_TYPE_APPLICATION_JSON);
                response.end(JSON.stringify(e, ['message']));
            }
        } else {
            next();
        }
    }

Let me know if this can be easily applied into the code. This is an amazingly simple tool, covers all my mocking needs except this particular one.

Thank you

PassThrough scenarios do not work for requests with JSON body

PassThrough scenarios do not work for requests with JSON body (JSON body of request and not response).
In this sitution the request is forwarded to the server, but reading JSON content result in error:
java.io.EOFException: Connection closed: Read failed. Possible end of stream encountered.
Above is JAVA application server (Websphere Liberty), but the same problem has been reproduced with Postman mock server:

C:\Ontwikkel\WAS9\VerhuisDialoogFrontend\node_modules\http-proxy\lib\http-proxy\index.js:120
throw err;
^
Error: read ECONNRESET
at TLSWrap.onStreamRead (internal/stream_base_commons.js:209:20)
{ code: 'ECONNRESET', syscall: 'read' }

Exactly the same request but with the body content type changed to e.g. text will arrive at the server.
So it looks it is something related to JSON parser.

I have this problem with with POST requests but the same seems to happen also when I send GET with JSON body.

Is this maybe related ?:
https://github.com/expressjs/body-parser/issues/207

State returns incorrect state depending on the order of load

I encountered an issue where the wrong mock is being used.

Turns out that if two mock have similar url, and the one with the shortest url is loaded first, the second one never is used.

Example:

	"name": "Countries",
	"request": {
		"url": "/api/v1/countries",
		"method": "GET"
	},
	"responses": {
		"default": {
			"default": true,
			"status": 200,
			"headers": {
				"Content-type": "application/json"
			},
			"data": {}
		}
	}
}

and

{
	"name": "Provinces Canada",
	"request": {
		"url": "/api/v1/countries/CA",
		"method": "GET"
	},
	"responses": {
		"default": {
			"default": true,
			"status": 200,
			"headers": {
				"Content-type": "application/json"
			},
			"data": {}
		}
	}
}

The if you make a request to "/api/v1/countries/CA" the first mock is used since the url also matches.

This could be fixed by sorting the mocks by url length on the state on getMatchingMock. That would make the more complete url to be matched first.

Otherwise the user would need to define all urls ending with "$" so the regex only matches exact urls.

Multiple mocks with same name

Hi,

every now and then a developer adds a new mock by cloning an existing mock-file, but forgets to change the name of the mock. (Doh!) Ngapimock does not check for this situation.

I think that having mocks with the same name is invalid in every situation and should throw an error on this. This will increase the user-experience of novice ngapimock users.

thanks!

middleware does not seem to run -- Cannot PUT /mocking/mocks

Here is my setup:

const apimock = require('@ng-apimock/core');
const devInterface = require("@ng-apimock/dev-interface");
const connect = require("connect");
const serveStatic = require('serve-static')
const cors = require("cors");
const chalk = require('chalk');

const CONFIG = {
  port: 5001,
  urlPath: '/mocking',
  mockFilesPath: 'src/mock'
};

apimock.processor.process({
  src: CONFIG.mockFilesPath,
  watch: true
});

const app = connect();
app.use(apimock.middleware);
app.use(CONFIG.urlPath, serveStatic(devInterface));
app.use(cors());

app.listen(CONFIG.port, (error) => {
  if (!error) {
    console.log(`Ng-Apimock running on port ${chalk.cyan(CONFIG.port)}`);
  }
});

When starting the server and calling:

curl --request PUT \
  --url http://localhost:5001/mocking/mocks \
  --header 'Content-Type: application/json' \
  --data '{
	"name":"scenarioName",
	"scenario":"error"
}'

The response is:
404 Not Found - Cannot PUT /mocking/mocks

Also tried it with the cypress plugin with cypress context (where you have added headers with cookies and identifiers etc) but same result.

Any known resaon why the middleware does not seem to run?

Regression when updating from 3.2 to 3.11

  • Could be related to #957

I'm trying to update my ng-apimock from version 3.2 to the latest (currently 3.11 and I found an annoying regression.

I'm using the Advanced request matchin by specifying a "body" for my requests so I could differenciate different scenarios, for example in my mock definition:

     // MOCK DEFINITION
     "body": {
      "someParam": "SOME_VALUE"
    }

This used to work for all requests having someParam with SOME_VALUE as well as other parameters too.
In other words, this matched with requests such as:

    // Request match: ok with version 3.2, not ok with version 3.11 because of the extra "someOtherParam"
    "body": {
      "someParam": "SOME_VALUE",
      "someOtherParam": "it did not matter what value is here or weather this is even there or not"
    }

so it matched ALL requests having "someParam": "SOME_VALUE",` no matter if there were other params or not.

After upgrading from 3.2 to version 3.11 (I don't know which exact version it introduced this regression) it ONLY matches requests that have ONLY "someParam": "SOME_VALUE", and it does not match if additional params are specified.

Match on partial body in mock

When including the body in the mock, is there a way to only include a partial match on a single field? For example, if the full request body is something like this:

{
   "item": "00001",
   "color": "blue",
   "model" "X"
}

but I want the mock to only match on a single field like "item" and ignore whatever is in the remaining fields:

{
  "name": "some name",
  "request": {
    "url": "/some/url",
    "method": "POST",
    "body": {
      "item": "00001"
    }
  },
  "responses": {
    "ok": {
      "default": true,
        "data": {"response": "default mock"}
    }
}

Is this possible with ng-apimock or do I need to include the full request body in the mock?

Mock response variable not replaced when defined in "file"

When a mock response contains a variable like "%%today%%" in a scenario when using the "data" property, this works fine.
But when the same mock response that has a variable is defined via the "file" property, the variable is not replaced.

I would be nice to have this functionality also work when using files. Using version 3.5.0.

Can't set headers after they are sent.

Does anyone tested it with latest Angular ?
It is not working for me anymore.
I see:
_http_outgoing.js:491 throw new Error('Can\'t set headers after they are sent.');

server.js:

const ngApimock = require('@ng-apimock/core');
const app = express();

const mocksDir = 'e2e/mocks/endpoints';

ngApimock.processor.process({
  src: mocksDir,
  pattern: '**/*.mock.json', // optional, defaults to **/*.json
});
app.set('port', process.env.PORT || 9900);
app.use(ngApimock.middleware);

app.listen(app.get('port'), function() {
  console.log('app running on port', app.get('port'));
});```

POST mocks resulting in 404

Somhow POST mocks result in a 404 when having content-type application/json, while postman calls work..

{
  "name": "user-userProperties-POST",
  "isArray": true,
  "expression": "api/user/userProperties",
  "request": {
    "url": "/user/userProperties",
    "method": "POST"
  },
  "responses": {
    "default": {
      "default": true,
      "file": "../POST_200.preset.json",
      "headers": { "Content-type": "application/json" }
    },
    "internal-server-error": {
      "status": 500
    }
  }
}

post works without content type, but when adding content type the request just times out

Use jest

It is not necessary to use sinonjs when also using jest.
Therefor sinonjs should be removed.

core exits when then clause specifies a non existing mock

When specifying a mock in the then clause that does not exists, @ng-apimock/core will exit with system.exit(1);

{
    "then": {
        "mocks": [ { 
            "name": "some-other-mock", // does not match any mock 
            "scenario": "some-scenario"
        }],
        "times": 3 // optional
    }
}

Logging Error > ENOENT: no such file or directory

Hello Mischa,

The added debug logging is helpful for troubleshooting.
Thanks a lot!

When a mockfile contains a path to file/directory that not exists the code returns an error in the message.
It would be helpfull when this message also would be added to the debug log.

By adding exports.log(e.message); in /middleware/handlers/mock/mock.request.handler.js:43
i receive the logging like:
ng-apimock: handler-request ENOENT: no such file or directory, open 'e2e\mocks\fileNotExists.json'

Duplicate apimockid cookies

Hi,

We are using ngapimock in combination with Cypress for our E2E-tests. I’ve created a Cypress command to retrieve the apimockid-cookie from the selectPreset-command and add also the apimockid cookie on the requests triggered by our app. This to allow for running E2E tests in parallel.

In some situations this results in multiple (the same) apimockid cookies to be added to the requests. My strong suspicision is that this leads to a new ngapimock-context.

Is it possible to ensure ngapimock only uses 1
instance of the apimockid cookie?

Thanks!

Preset with scenario Passthrough does not work

When selecting a preset that has a mock set to passThrough, the selection fails with the following message:

message: "No scenario matching ['passThrough'] found for mock with name ['...']"

delayResponse does not seem to work

Hello,

We have been trying to implement a delayResponse on one of the scenarios. We are basically testing that a class does not show before all data is loaded (therefore the delayResponse on the mocked api call).

However the delayResponse does not seem to work within protractor. (The behaviour does work when we set a delay within the GUI of ng-apimock). Is there any way to do this through protractor?

Update documentation with a full example (for instance for the protractor plugin)

Hello,

I tried to implement ngApiMock in a simple project using protractor.
However, i am faced with a lot of problems while following your documentation (Doc protractor-plugin) .

First of all, it's not clear either we should follow the steps for the core-installation or not.
And then there's no explanation on how to link the tests to the mocks.

Here's where i am stuck right now, if you can kindly help:

/serve.mock.js

const apimock = require('@ng-apimock/core');
const express = require('express');
const app = express();
app.set('port', 9999);

apimock.processor.process({
    src: 'src/mocks',
});

app.use(apimock.middleware);

app.listen(app.get('port'), () => {
    console.log('@ng-apimock/core running on port', app.get('port'));
});

/mocks/fact.mock.json

{
    "name": "FACT_MOCK",
    "request": {
        "url": "https://cat-fact.herokuapp.com/facts/5e236d6bdc76630015d4c51f",
        "method": "GET"
    },
    "responses": {
        "fake_fact": {
            "text": "a fake fact"
        },
        "real_fact": {
            "text": "a real fact"
        }
    }
}

/e2e/protractor.conf.js

// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');

/**
 * @type { import("protractor").Config }
 */
exports.config = {
  allScriptsTimeout: 11000,
  specs: [
    './src/**/*.e2e-spec.ts'
  ],
  capabilities: {
    browserName: 'chrome'
  },
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  plugins: [
    {
      package: '@ng-apimock/protractor-plugin',
      options: {
        globalName: 'ngApimock',
      }
    }
  ],
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function () { }
  },
  onPrepare() {
    require('ts-node').register({
      project: require('path').join(__dirname, './tsconfig.json')
    });
    jasmine.getEnv().addReporter(new SpecReporter({
      spec: {
        displayStacktrace: StacktraceOption.PRETTY
      }
    }));
  }
};

/e2e/src/app.e2e-spec.ts

import { AppPage } from './app.po';
import { browser, logging } from 'protractor';

import { Client } from '@ng-apimock/protractor-plugin';
declare const ngApimock: Client;

describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display fake fact message', async () => {

    page.navigateTo();
    await ngApimock.selectScenario('FACT_MOCK', 'fake_fact');

    expect(page.getTitleText()).toEqual('a fake fact app is running!');
  });

  it('should display real fact message', async () => {

    page.navigateTo();
    await ngApimock.selectScenario('FACT_MOCK', 'real_fact');

    expect(page.getTitleText()).toEqual('a fake fact app is running!');
  });

  afterEach(async () => {
    // Assert that there are no errors emitted from the browser
    const logs = await browser.manage().logs().get(logging.Type.BROWSER);
    expect(logs).not.toContain(jasmine.objectContaining({
      level: logging.Level.SEVERE,
    } as logging.Entry));
  });
});

the result of launching the mock server with: $ node serve.mock.js :

Processed 1 unique mocks.
Processed 0 unique presets.
@ng-apimock/core running on port 9999

the result of launching the test: $ ng e2e :

**************************************************
*                    Failures                    *
**************************************************

1) workspace-project App should display fake fact message
  - Error: An error occured while invoking http://localhost:4200/ngapimock/mocks that resulted in status code 404

2) workspace-project App should display real fact message
  - Error: An error occured while invoking http://localhost:4200/ngapimock/mocks that resulted in status code 404

Executed 2 of 2 specs (2 FAILED) in 0.29 sec.
[16:50:21] I/launcher - 0 instance(s) of WebDriver still running
[16:50:21] I/launcher - chrome #01 failed 2 test(s)
[16:50:21] I/launcher - overall: 2 failed spec(s)
[16:50:21] E/launcher - Process exited with error code 1
npm ERR! code ELIFECYCLE
npm ERR! errno 1

Was watch dropped?

As my project has been using the core since your help, I just wanted to confirm if 'watch' was dropped. No worries if it has, can happily wait if it is going to be added into the core. So far I like the change.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.