Code Monkey home page Code Monkey logo

mockttp's Introduction

Mockttp Build Status Available on NPM Try Mockttp on RunKit

Part of HTTP Toolkit: powerful tools for building, testing & debugging HTTP(S)

Mockttp lets you intercept, transform or test HTTP requests & responses in JavaScript - quickly, reliably & anywhere.

You can use Mockttp for integration testing, by intercepting real requests as part of your test suite, or you can use Mockttp to build custom HTTP proxies that capture, inspect and/or rewrite HTTP in any other kind of way you like.

HTTP testing is the most common and well supported use case. There's a lot of tools to test HTTP, but typically by stubbing the HTTP functions in-process at the JS level. That ties you to a specific environment, doesn't truly test the real requests that you code would send, and only works for requests made in the same JS process. It's inflexible, limiting and inaccurate, and often unreliable & tricky to debug too.

Mockttp meanwhile allows you to do accurate true integration testing, writing one set of tests that works out of the box in node or browsers, with support for transparent proxying & HTTPS, strong typing & promises throughout, fast & safe parallel testing, and with debuggability built-in at every stage.

Mockttp is also battle-tested as a scriptable rewriting proxy, powering all the HTTP internals of HTTP Toolkit. Anything you can do with HTTP Toolkit, you can automate with Mockttp as a headless script.

Features

Let's get specific. Mockttp lets you:

  • Write easy, fast & reliable node.js & browser HTTP integration tests
  • Stub server responses and verify HTTP requests
  • Intercept HTTPS too, with built-in self-signed certificate generation
  • Mock requests inside or outside your process/tab, including subprocesses, native code, remote devices, and more
  • Test true real-world behaviour, verifying the real requests made, and testing exactly how your whole stack will handle a response in reality
  • Stub direct requests as a mock server, or transparently stub requests sent elsewhere as an HTTP mocking proxy
  • Mock HTTP in both node & browser tests with the same code (universal/'isomorphic' HTTP mocking)
  • Safely mock HTTP in parallel, with autoconfiguration of ports, mock URLs and proxy settings, for super-charged integration testing
  • Debug your tests easily, with full explainability of all mock matches & misses, mock autosuggestions, and an extra detailed debug mode
  • Write modern test code, with promises all the way down, async/await, and strong typing (with TypeScript) throughout

Get Started

npm install --save-dev mockttp

Get Testing

To run an HTTP integration test, you need to:

  • Start a Mockttp server
  • Mock the endpoints you're interested in
  • Make some real HTTP requests
  • Assert on the results

Here's a simple minimal example of all that using plain promises, Mocha, Chai & Superagent, which works out of the box in Node and modern browsers:

const superagent = require("superagent");
const mockServer = require("mockttp").getLocal();

describe("Mockttp", () => {
    // Start your mock server
    beforeEach(() => mockServer.start(8080));
    afterEach(() => mockServer.stop());

    it("lets you mock requests, and assert on the results", async () => {
        // Mock your endpoints
        await mockServer.forGet("/mocked-path").thenReply(200, "A mocked response");

        // Make a request
        const response = await superagent.get("http://localhost:8080/mocked-path");

        // Assert on the results
        expect(response.text).to.equal("A mocked response");
    });
});

(Want to play with this yourself? Try running a standalone version live on RunKit: https://npm.runkit.com/mockttp)

That is pretty easy, but we can make this simpler & more powerful. Let's take a look at some more fancy features:

const superagent = require("superagent");
require('superagent-proxy')(superagent);
const mockServer = require("mockttp").getLocal();

describe("Mockttp", () => {
    // Note that there's no start port here, so we dynamically find a free one instead
    beforeEach(() => mockServer.start());
    afterEach(() => mockServer.stop());

    it("lets you mock without specifying a port, allowing parallel testing", async () => {
        await mockServer.forGet("/mocked-endpoint").thenReply(200, "Tip top testing");

        // Try mockServer.url or .urlFor(path) to get a the dynamic URL for the server's port
        let response = await superagent.get(mockServer.urlFor("/mocked-endpoint"));

        expect(response.text).to.equal("Tip top testing");
    });

    it("lets you verify the request details the mockttp server receives", async () => {
        const endpointMock = await mockServer.forGet("/mocked-endpoint").thenReply(200, "hmm?");

        await superagent.get(mockServer.urlFor("/mocked-endpoint"));

        // Inspect the mock to get the requests it received and assert on their details
        const requests = await endpointMock.getSeenRequests();
        expect(requests.length).to.equal(1);
        expect(requests[0].url).to.equal(`http://localhost:${mockServer.port}/mocked-endpoint`);
    });

    it("lets you proxy requests made to any other hosts", async () => {
        // Match a full URL instead of just a path to mock proxied requests
        await mockServer.forGet("http://google.com").thenReply(200, "I can't believe it's not google!");

        // One of the many ways to use a proxy - this assumes Node & superagent-proxy.
        // In a browser, you can simply use the browser settings instead.
        let response = await superagent.get("http://google.com").proxy(mockServer.url);

        expect(response.text).to.equal("I can't believe it's not google!");
    });
});

These examples use Mocha, Chai and Superagent, but none of those are required: Mockttp will work with any testing tools that can handle promises (and with minor tweaks, many that can't), and can mock requests from any library, tool or device you might care to use.

Documentation

Credits

mockttp's People

Contributors

ashishmadeti avatar azerum avatar exoego avatar hanvyj avatar igrayson avatar jimbodriven avatar josiebigler avatar kaciras avatar kunal-mandalia avatar legobeat avatar lipsumar avatar mathiasduc avatar mattleff avatar mikemey avatar niclim avatar pimterry avatar pmdartus avatar ridafkih avatar sethew avatar stas-pavlov avatar tw3 avatar ueberhammdesign avatar wachunei avatar

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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mockttp's Issues

Question on how to run standalone from command-line

Hello again,

I have a question about how I could go about creating a mockttp standalone server through the command line that would always be listening.

What I am trying to accomplish is to have a server that is always running in one shell, that would pass through any requests that are not matching a rule. Then, I want to have tests that can configure the mock server to add/remove rules using code such that I can intercept and do the rewrites accordingly and reset to a default state when it finishes.

I read that I can do
Running mockttp -c [test command], to start the server before your tests, and automatically shut it down afterwards.
but I don't want the server to shutdown.

Is this possible?

Dependency node-forge Prototype Pollution

Performing yarn audit I found

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ high          โ”‚ Prototype Pollution in node-forge                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Package       โ”‚ node-forge                                                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Patched in    โ”‚ >= 0.10.0                                                    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Dependency of โ”‚ mockttp                                                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Path          โ”‚ mockttp > node-forge                                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ More info     โ”‚ https://www.npmjs.com/advisories/1561                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Is it possible to upgrade to the latest version of node-fetch?

Rules leaking between mock servers?

I have a project that uses Mocha + Chai for tests, and I am creating my Mockttp server in a before-filter like so:

  beforeEach(async () => {
    mockServer = getLocal()
    await mockServer.start(8080)
  })

and I am destroying it like so:

  afterEach(async () => {
    await mockServer.stop()
  })

I have two tests that each set up separate rules for the Mockttp server:

    it('loads the first page of backups', async () => {
      await mockServer.get('/backups.json').thenReply(200, JSON.stringify(backupsJSON))
      expect(await store.dispatch('loadBackups', { restart: false })).to.be.true
    })

    it('loads the next page of backups', async () => {
      await mockServer.get('/backups.json').thenReply(
        200,
        JSON.stringify(backupsJSON.slice(0, 10)),
        { 'X-Next-Page': '/backups.json?page=2' }
      )
      await mockServer.get('/backups.json').withQuery({ page: 2 }).thenReply(
        200,
        JSON.stringify(backupsJSON.slice(10, 20))
      )

      expect(await store.dispatch('loadBackups', { restart: false })).to.be.true
    })

What I've noticed is that the result from the Mockttp server in test #2 is the same as the result in test #1, even though I've set up different rules in test #2. Also, even more perplexingly, if I delete or disable test #1, test #2 works, implying that the rules I set up in test #1 are somehow leaking to test #2, even though I set up completely different instances of the local Mockttp server between tests.

Any idea what the problem could be?

Feature Request: Include request body in server events

I would like to do some bit more complicated things, maybe which are not intended but would be quite simple if on a request the body of the message would also be preserved. With GET was a bit easier to do but I was trying to something like:

let a = [1,2,3]

function changeA(index: number, val: number) {
   a[index] = val;
}

await mockServer.post(/url).thenReply(200, 'OK');

mockServer.on('request-initiated', req => {
   // the req would be a JSON object where would be an index and a value
   changeA(request.body.index, request.body.value);  //Error: request.body is not there
}) 

Question: HTTPS and Appium + iOS

I'm not able to get HTTPS to work. I followed these instructions:
https://github.com/httptoolkit/mockttp/blob/master/docs/setup.md#mocking-https

Installed the generated cert on my iOS simulator (I can see the cert under Certificate Trust Settings) and then configured mockttp to use the cert and key. I've also configured my system's network connection (macOS Catalina 10.15.7) to use the proxy for HTTP and HTTPS traffic (the simulator uses the machine's network configuration).

I'm then launching and interacting with my app under test using Appium (Webdriver.io). However the app fails when making HTTPS connections.

Any suggestions on how to debug this scenario?

Doc request: websocket example please

Sorry if it's actually covered somewhere in the docs, I failed to find it.

Could you please point out on the proper place in the docs or provide a basic example on how to mock a websocket service?

Use case: a front-end script wants to talk to a websocket server and we mock it using mockttp.

Thanks in advance!

Feature Request: data as a function.

Hello,

I've been playing this morning with this library to write some tests, thanks for making it available on the first place ๐Ÿ˜„

I don't know if this already exists as a feature, but I'm looking to do this, I think a example would be better to understand:

const mockServer = require('mockttp').getLocal();

describe('Mockttp', () => {
  beforeEach(() => mockServer.start(8888));
  afterEach(() => mockServer.stop());

  it('can detect params', async () => {
    await mockServer
      .get('/resource/:id/nested')
      .thenJSON(200, (params) => ({ nested: [], resource: params.id }));

    const id = 3;
    const response = await fetch(`localhost:8888/resource/${id}/nested`);

    expect(response.data.resource).to.equal(id);
  });
});

Is this something done or you would like to be done ๐Ÿ‘€?

Sending hearders in the response doesn't work.

Hello,

Thanks a lot for this great library it helped me a lot when writing test for our internal tooling,
but i recently got stuck when trying to send headers in the response. Here is the minimal reproducing case i came up with:

import axios from 'axios';

const mockServer = require('mockttp').getLocal({ cors: true });

it('send a sucessfull request', async () => {
    const testHeaders = { Test: 'testValue' };
    const testData = 'many data';

    await mockServer.start();
    await mockServer.get('/test').thenReply(200, testData, testHeaders);

    const response = await axios.request({ method: 'get', url: mockServer.urlFor('/test') });
    expect(response.data).toEqual(testData);
    expect(response.headers).toEqual(testHeaders);
});

The first expect pass but the second doesn't

my version: "mockttp": "^0.7.1",

Did the PR #1 got broken ?
I tried to look into the source code, but did not found anything that seems to help me.
Isn't there a test that would test specifically that?
Should i write one?
I dont know typescript but i could try.
Thanks!

Question: How do you delete individual replies ?

My use case is currently as follows:

  1. I create a mockttp server on some port
  2. I create replies for paths and match specific fields in the headers

How do I go about deleting individual replies in place i.e without using reset() ?

Example Code :

const mockserver = require('mockttp').getLocal();

async function runServer(){

    await mockserver.start(3001);

    await mockserver.forGet("/sample/request").withHeaders({"id" : '0000'}).thenReply(200, JSON.stringify({
        "headers": {
            "id": "0000"
        },
        "statusCode": 200,
        "body": "response 0000"
    }))

    // How would you go about deleting this rule on the fly ?
    await mockserver.forGet("/sample/request").withHeaders({"id" : '0001'}).thenReply(200, JSON.stringify({
        "headers": {
            "id": "0001"
        },
        "statusCode": 200,
        "body": "response 0001"
    }))
}
runServer()

Broken dependency to graphql - outdated apollo modules

Hi,
It looks like there is a problem with graphql dependency. Some modules requires (as a peer dependency) an older version of graphql that is defined as a direct dependency of mockttp.

Test case (note UNMET PEER DEPENDENCY error)

$ docker run -it node:6 /bin/bash
root@5511b703a053:/# mkdir test_mockttp
root@5511b703a053:/# cd test_mockttp/
root@5511b703a053:/test_mockttp# npm init -y .
Wrote to /test_mockttp/package.json:

{
  "name": "test_mockttp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


root@5511b703a053:/test_mockttp# npm install --save-dev mockttp

> [email protected] postinstall /test_mockttp/node_modules/core-js
> node scripts/postinstall || echo "ignore"

[email protected] /test_mockttp
`-- [email protected]
  +-- @types/[email protected]
  +-- @types/[email protected]
  | +-- @types/[email protected]
  | | `-- @types/[email protected]
  | +-- @types/[email protected]
  | | `-- @types/[email protected]
  | `-- @types/[email protected]
  |   `-- @types/[email protected]
  +-- @types/[email protected]
  +-- @types/[email protected]
  +-- [email protected]
  | +-- [email protected]
  | | +-- [email protected]
  | | | `-- UNMET PEER DEPENDENCY [email protected] - 0.13.x
  | | +-- [email protected]
  | | | `-- UNMET PEER DEPENDENCY [email protected] - 0.13.x
  | | +-- UNMET PEER DEPENDENCY [email protected] - 0.13.x
  | | `-- [email protected]
  | |   +-- [email protected]
  | |   `-- [email protected]
  | |     +-- [email protected]
  | |     `-- [email protected]
  | +-- [email protected]
  | `-- UNMET PEER DEPENDENCY graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0
  +-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | `-- [email protected]
  |   +-- [email protected]
  |   `-- [email protected]
  |     `-- [email protected]
  +-- [email protected]
  | `-- [email protected]
  +-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | `-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | +-- [email protected]
  | | +-- [email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | `-- [email protected]
  +-- [email protected]
  | `-- [email protected]
  |   +-- [email protected]
  |   `-- [email protected]
  +-- UNMET PEER DEPENDENCY [email protected]
  | `-- [email protected]
  +-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | | +-- [email protected]
  | | +-- [email protected]
  | | `-- [email protected]
  | |   `-- [email protected]
  | +-- [email protected]
  | | +-- @wry/[email protected]
  | | `-- [email protected]
  | +-- [email protected]
  | `-- UNMET PEER DEPENDENCY graphql@^0.10.5 || ^0.11.3 || ^0.12.0 || ^0.13.0
  +-- [email protected]
  +-- [email protected]
  +-- [email protected]
  +-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | | `-- [email protected]
  | `-- [email protected]
  |   `-- [email protected]
  +-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | `-- [email protected]
  |   `-- [email protected]
  +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | +-- [email protected]
  | `-- [email protected]
  |   `-- [email protected]
  +-- [email protected]
  +-- [email protected]
  | `-- [email protected]
  |   `-- [email protected]
  +-- [email protected]
  `-- [email protected]
    +-- [email protected]
    | +-- [email protected]
    | | `-- [email protected]
    | |   `-- [email protected]
    | `-- [email protected]
    +-- [email protected]
    +-- [email protected]
    | +-- [email protected]
    | +-- [email protected]
    | +-- [email protected]
    | +-- [email protected]
    | `-- [email protected]
    +-- [email protected]
    `-- [email protected]

npm WARN [email protected] requires a peer of graphql@^0.10.5 || ^0.11.3 || ^0.12.0 || ^0.13.0 but none was installed.
npm WARN [email protected] requires a peer of graphql@^0.11.0 || ^0.12.0 but none was installed.
npm WARN [email protected] requires a peer of graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 but none was installed.
npm WARN [email protected] requires a peer of [email protected] - 0.13.x but none was installed.
npm WARN [email protected] requires a peer of [email protected] - 0.13.x but none was installed.
npm WARN [email protected] requires a peer of [email protected] - 0.13.x but none was installed.
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
root@5511b703a053:/test_mockttp# node -v
v6.17.1
root@5511b703a053:/test_mockttp# npm --versions
{ test_mockttp: '1.0.0',
  npm: '3.10.10',
  ares: '1.10.1-DEV',
  http_parser: '2.8.0',
  icu: '58.2',
  modules: '48',
  napi: '3',
  node: '6.17.1',
  openssl: '1.0.2r',
  uv: '1.16.1',
  v8: '5.1.281.111',
  zlib: '1.2.11' } 

EADDRINUSE errors when tests run concurrently

We have multiple tests in our test suite that depend on mockttp, making use of its capability to randomly assign a port, and when Jest runs these tests concurrently we occasionally see errors in the form:

listen EADDRINUSE: address already in use :::8000
      at MockttpServer.<anonymous> (node_modules/mockttp/src/server/mockttp-server.ts:138:22)            
      at fulfilled (node_modules/mockttp/dist/server/mockttp-server.js:8:58)

To reproduce this issue we set up the following test:

import { getLocal } from 'mockttp';

describe('mockttp tests running in parallel', () => {
    const mockServer = getLocal();

    beforeAll(async () => {
        await mockServer.start();
    });

    afterAll(async () => await mockServer.stop());

    it('should pass', () => {
        expect(true).toBe(true);
    });
});

and then executed:

printf %s\\n {0..64} | xargs -n 1 -P 16 npx jest <test-name>

to run 16 instances of the test in parallel (on our 16 core machine) 4 times in a row. On most runs we see this issue occurring.

Can we introduce some kind of locking or retry mechanism in mockttp-server.start, or do you think we're using the library in a way it wasn't intended to be used?

Tested on version 0.21.2.

Cypress: unable to share a client instance between spec files

I am trying to migrate from MockServer to mockttp and I'm having a few different issues getting mockttp to play nicely with Cypress. (I have already followed the discussion in #35 but the problems described here are different.)

Throughout this description I will refer to some branches which include test cases. The repository lives here: https://github.com/OliverJAsh/cypress-mockttp.

At the end I have a proposal to add a useConfig method, but first I'll describe the problem I'm having.

We want to start the mock server before all of our tests run. It seems like this is something we should do in a global before hook. This is defined outside of a describe block so it will run once before all tests.

import {getRemote} from 'mockttp'

const server = getRemote({ standaloneServerUrl: 'http://localhost:1773' })

before(async () => {
  await server.start(8080)
})

describe('Mockttp serves mocked responses', () => {
  it('to cy.request', () => {
    cy.wrap(server.get("/mocked-path").thenReply(200, 'this is a mocked response'))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

(Branch: init)

In Cypress this works fine until we want to have multiple spec files. As soon as we have multiple spec files we need to move the before hook somewhere else, so it runs before all tests.

In Cypress it's recommended to define the global before in the cypress/support/index.js, as this is guaranteed to only run once before all spec files and tests. https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests#:~:text=you%20can%20define%20behaviors%20in

However, if we do that then the spec files will not be able to reference the existing client instance (server)โ€”each spec file will have to create its own:

cypress/support/index.js:

import {getRemote} from 'mockttp'

const server = getRemote({ standaloneServerUrl: 'http://localhost:1773' })

before(async () => {
  await server.start(8080)
})

after(async () => {
  await server.stop()
})

dummy.spec.ts:

import {getRemote} from 'mockttp'

const server = getRemote({ standaloneServerUrl: 'http://localhost:1773' })

describe('Mockttp serves mocked responses', () => {
  it('to cy.request', () => {
    // This won't work because server has been started but this client instance
    // hasn't been configured with the port.
    cy.wrap(server.get("/mocked-path").thenReply(200, 'this is a mocked response'))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

(Branch: support)

This doesn't work either because the client won't work until you call start:

image

โ€ฆ and we can't call start in each spec file because the server has already been started by the client we created in cypress/support/index.js. We only want to configure the client in our spec to use the existing server that has already been started.

I hoped I might be able to move the initialised client (server) into a module and then import it from each spec file, e.g.:

server-client.js:

import {getRemote} from 'mockttp'

export const server = getRemote({ standaloneServerUrl: 'http://localhost:1773' })

console.log('registering before hook')

before(async () => {
  await server.start(8080)
})

after(async () => {
  await server.stop()
})

dummy.spec.ts:

import { server } from "./server-client";

describe('Mockttp serves mocked responses', () => {
  it('to cy.request', () => {
    cy.wrap(server.get("/mocked-path").thenReply(200, 'this is a mocked response'))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

dummy2.spec.ts:

import { server } from "./server-client";

describe('Mockttp serves mocked responses', () => {
  it('to cy.request', () => {
    cy.wrap(server.get("/mocked-path").thenReply(200, 'this is a mocked response'))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

(Branch: import)

However, this doesn't work either, because the imported server-client.js module will be initialised not once but rather once for each spec file, because of the way Cypress works. This means the before hook is registered twice and thus we try to start the server twice. We can see this from the console.log I added:

image

We didn't have these problems when we were using MockServer because the client worked in a slightly different way. The client wasn't stateful, nor was it responsible for starting the mock server. Rather, with MockServer you have to configure it with port of a mock server which is already running. This meant we could create a new client as many times as we like without any of the issues I described above:

import { mockServerClient as createMockServerClient } from 'mockserver-client';

// This doesn't perform any side effects. It's just configuring the client.
// This means we can easily move it to a module and import it in each spec file.
const mock = createMockServerClient('localhost', 8080);

describe('MockServer serves mocked responses', () => {
  it('to cy.request', () => {
    cy.wrap(mock.mockSimpleResponse('/mocked-path', 'this is a mocked response', 200))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

This makes me think it would be good if mockttp worked in a similar way. Perhaps we could expose a new function on the client that just initialises the client with an existing mockServerConfig:

// Also open a stream connection, for 2-way communication we might need later.
this.mockServerStream = await this.openStreamToMockServer(mockServerConfig);
// Create a subscription client, preconfigured & ready to connect if on() is called later:
this.prepareSubscriptionClientToMockServer(mockServerConfig);
// We don't persist the config or resolve this promise until everything is set up
this.mockServerConfig = mockServerConfig;
// Load the schema on server start, so we can check for feature support
this.mockServerSchema = (await this.queryMockServer<any>(introspectionQuery)).__schema;

We would need to start the mock server outside of the tests. Usage in the tests would then look something like this:

dummy.spec.ts:

import {getRemote} from 'mockttp'

const server = getRemote({ standaloneServerUrl: 'http://localhost:1773' })

before(() => server.useConfig({ port: 8080, mockRoot: 'http://localhost:8080' }));

describe('Mockttp serves mocked responses', () => {
  it('to cy.request', () => {
    cy.wrap(server.get("/mocked-path").thenReply(200, 'this is a mocked response'))

    const url = 'http://localhost:8080/mocked-path'
    cy.request(url).its('body').should('equal', 'this is a mocked response')
  })
})

I have tested the idea by patching my node_modules locally and it seems to solve the problem. The branch useConfig-2 has a full reduced test case, including a patch that adds a useConfig method. (The patch is applied when you run yarn via the patch-package tool.)

What do you think? Perhaps you have a better idea of how to solve this!

any way to use patterns for a path matcher?

I would like to be able to use path patterns like
.get("/**")
or
.get("/?**)
or most flexible :

.match(context=>{
// custom matcher here which can access headers, query string parameters, url from the context

})

would this be hard to add ?

thenCallback(): Multiple HTTP response headers with the same name

Thank you for making a good library first.
There was work to test the HTTPS MITM related logic, and I use it very well.
But there was one thing that made me sad.

In order to respond to multiple HTTP headers with the same name, I assigned the value of the header to array[], and see that they are combined into one header and the value is separated by a comma(',').

proxyServer.anyRequest().thenCallback(request => 
    ({ 
        status: 200, 
        headers: { 
            'content-type': 'text/plain', 
            'set-cookie': ['key1=value1', 'key2=value2', 'key3=value3'] 
        }, 
        body: 'Hello World' 
    })
);

I checked the request-util.ts code and found it to be 'value.toString()'.

export const setHeaders = (response: express.Response, headers: Headers) => {
    Object.keys(headers).forEach((header) => {
        let value = headers[header];
        if (!value) return;

        response.setHeader(header, value.toString());
    });
};

So when I removed '.toString()' and tested it, I found that it is normally divided into three headers.

response.setHeader(header, value);

Dependency apollo-server-express and apollo-server-core Information Exposure

Performing yarn audit I found

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ moderate      โ”‚ Information Exposure                                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Package       โ”‚ apollo-server-core                                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Patched in    โ”‚ >=2.14.2                                                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Dependency of โ”‚ mockttp                                                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Path          โ”‚ mockttp > apollo-server-express > apollo-server-core         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ More info     โ”‚ https://www.npmjs.com/advisories/1528                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ moderate      โ”‚ Information Exposure                                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Package       โ”‚ apollo-server-express                                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Patched in    โ”‚ >=2.14.2                                                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Dependency of โ”‚ mockttp                                                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Path          โ”‚ mockttp > apollo-server-express                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ More info     โ”‚ https://www.npmjs.com/advisories/1531                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Is it possible to upgrade to 2.14.2?

Cannot setup mockttp with karma for browser tests

Hi,
I'm trying to setup mockttp with karma for browser tests as you suggested in your documentation:
mockttp -c karma start

With that, my test fails due to error:
Error: Not connected to mock server
at MockttpClient.

I guess that the standalone server is not ready when the local mock server is trying to connect to it...

Another interesting thing is that when running karma for debug (mockttp -c karma start -single-run=false) I see the same error in browser console, but after refreshing the browser window (after setting a breakpoint for example), I don't get to the karma debug page and instead I get a message that no rule is defined for debug.html request (which I guess that is coming from the mock server)...

After closing the browser tab and killing the process it got even worse when running "mockttp -c karma start" again, now I get another error:
events.js:183
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE :::45456
at Object._errnoException (util.js:992:11)
at _exceptionWithHostPort (util.js:1014:20)
at Server.setupListenHandle [as _listen2] (net.js:1355:14)
at listenInCluster (net.js:1396:12)
at Server.listen (net.js:1480:7)
at Function.listen (...\node_modules\express\lib\application.js:618:24)
at ...\node_modules\mockttp\dist\standalone\mockttp-standalone.js:137:87
at new Promise ()
at MockttpStandalone. (...\node_modules\mockttp\dist\standalone\mockttp standalone.js:136:46)
at step (...\node_modules\mockttp\dist\standalone\mockttp-standalone.js:35:23)

My test code (TypeScript):

import mockttp = require("mockttp");
describe("Client side integration tests from browser context", () => {
    const mockServer = mockttp.getLocal();
    beforeEach(() => {
        mockServer.start(9876);
    });
    afterEach(() => {
        mockServer.stop();
    });
.  .  .
});

Tried also defining mockServer outside the describe, with no luck...

My karma.conf.js configuration:

module.exports = function(config) {
    config.set({
        frameworks: ["mocha", "karma-typescript"],
        autoWatch: false,
        singleRun: true,
        files: [
            "src/client/**/*.ts",
            "test/karma/**/*.spec.ts"
        ],
        preprocessors: {
            "**/*.ts": "karma-typescript"
        },
        karmaTypescriptConfig: {
            tsconfig: "./tsconfig.json"
        },
        reporters: ["progress", "karma-typescript"],
        browsers: ["Chrome"],
        port: 9876
    });
};

Can you please assist?
Would appreciate adding a section to your documentation with full setup details of mockttp and karma.

Thanks,
Rotem

Easiest Way to Access Request Object While Manipulating Response

Hello there,

I am trying to develop a simple intercepting proxy using mockttp that stores all request/response pairs to a persistance storage in JSON form. Basically, I am using a pass through handler that captures upstream response just before the end of request&response lifecycle (ie. beforeResponse callback). However, I haven't managed to access the HTTP request object from inside beforeResponse callback. My code snippet is below. What is the most appropriate way to achieve this?

Thank you.

server.forAnyRequest().always().thenPassThrough({
	beforeResponse: (response) => {
		let res = JSON.stringify(response);
		let req = JSON.stringify(response.getRequest()); // How to obtain request data of this response?
		
		// @TODO: Persist request&response pair to the storage in a serial form.
		return {};
	}		
});

Unknown TLS error: invalid library

Hey!

I have a problem, that after starting https proxy i see pretty often this error:

Unknown TLS error: [Error] {
  library: 'invalid library (0)',
  function: 'OPENSSL_internal',
  reason: 'invalid library (0)',
  code: 'ERR_SSL_INVALID_LIBRARY_(0)'
}

Node v12.16.0

Https requests works as intended. What does this error means and what can I do to remove it ;)

Request body JSON matcher (or custom matchers)

I want to create a mock that matches a request only if it has certain things in its JSON body (e.g. _.isMatch(request, partialContents)). The recently-added regex body matcher lets me match a single simple field in the body, but I want to match more complicated structures.

I can see three potential ways to be able to do this.

  1. Have mockttp define such a matcher
  2. Define my own custom matcher on the MockRuleBuilder
  3. I could do something fancy in thenCallback, but this seems less clean

Are any of these possible?

localhost:45456/start CORS error

Recently I created a repo to showcase how Mockttp can be controlled from within Cypress tests: https://github.com/mvasin/cypress-mockttp

The tests pass in GitHub Actions, but locally I bumped into an interesting problem.

The example repo fails with a CORS error, but only on one of my Macs. The other Mac does not have CORS issues. All I do on both Macs is

git clone https://github.com/mvasin/cypress-mockttp
cd cypress-mockttp
yarn && yarn cy

Here's the screenshot from the first Mac:

Screenshot 2020-06-18 at 19 39 29

And here's the screenshot from the second Mac:

Screenshot 2020-06-18 at 19 50 26

You can see on the screenshots that the /start pre-flight request on the first Mac does contain access-control-allow-origin: *, while the second doesn't, hence the CORS error on the second screenshot.

How can that happen given the same MacOS (10.5.5), same node version (12.13.0), the same Chrome version (83) that comes with the same Cypress version... I'm puzzled.

Given that I can't reproduce the issue myself ๐Ÿ˜… (on the second computer) I'm fine with closing it if no one has a hint on what could it be.

Question: Can mockhttp be used to intercept traffic and respond with a mock?

Hi,

In our case, for every set of tests ran in the CI a new environment is created and made available for testing.
This means that the front-end client is already up-and-running and available when the integration tests are starting.

Having this in mind, would it be possible to use mockhttp to intercept the requests sent and respond with a mock instead of having the request go to the server?

In my head this would look like:

Prerequisites: Client K8s Pod is configured to use the proxy and up-and-running

Flow:

  1. The tests container is started and starts the mockhttp standalone server
  2. Client is opened in the browser and starts making request. These look like: https://env-.staging.domain.com
  3. mockhttp server receives the requests and responds with a mock

Is this possible? Am I missing something?

Thank you!

speedtest (lose of speed)

Hello,

With mockttp proxy, i'm losing 30 mbps of download speed with speedtest-cli.

How can i increase/optimize the file transfers from mockttp ?

Rule builder docs?

Are there any docs for how to use the rule builder?

Or is there a way to easily get mockhttp to respond 200 to multiple requests?

Iโ€™m looking to setup tests for functions that make multiple requests to multiple urls.

Ideally I want to be able to assert that the request method and headers are correct.

Run mockttp in Angular runtime - ng serve

Hi
When I try to run mockttp from a angular component i get the following error
anyone know how to fixed?

ERROR in ./node_modules/brotli/dec/dictionary-browser.js
Module not found: Error: Can't resolve 'fs' in 'C:\SEON\media-management-ui\node_modules\brotli\dec'
ERROR in ./node_modules/mockttp/dist/util/socket-util.js
Module not found: Error: Can't resolve 'net' in 'C:\SEON\media-management-ui\node_modules\mockttp\dist\util'

The _stream_wrap module is deprecated

On node 12.13.0 I see this warning:

(node:3822) [DEP0125] DeprecationWarning: The _stream_wrap module is deprecated.

It can be a low priority, of course, but it's nice to keep track of it.

How to catch "Failed to handle request" error?

My proxy code is as follows:

server.forUnmatchedRequest().thenPassThrough({});

And I get lots of messages like this in the console:

Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com
Failed to handle request: getaddrinfo ENOTFOUND ton.local.twitter.com

I tried beyond a shadow of a doubt this:

server.forUnmatchedRequest().thenPassThrough({}).catch((e) => {
      console.log("ERROR", e);
});

but apparently it didn't work.

So is there a way to intercept errors like this?

ERR_CONTENT_DECODING_FAILED when intercepting and modifying JSON responses

Hi,

I'm trying to integrate Mockttp into a test suite, but changing the JSON response results in a network error in the browser, ERR_CONTENT_DECODING_FAILED. I've tried using both body with a string and json with an object to return a modified response, but neither seems to be working. Changing just the response status or the headers is working correctly. This is a snippet of the code:

(async () => {
  const mockttp = require("mockttp");
  const chromeLauncher = require("chrome-launcher");

  const https = await mockttp.generateCACertificate();
  const server = mockttp.getLocal({ https });

  const loginError = '{"errors":[{"detail":"Invalid login details."}]}';

  server.anyRequest().thenPassThrough({
    beforeResponse: async (res) => {
      if (res.headers["content-type"] === "application/json;charset=utf-8") {
        const payload = await res.body.getJson();

        if (payload.access_token) {
          return {
            status: 403,
            body: loginError,
          };
        }

        return res;
      }

      return res;
    },
  });

  await server.start();

  const caFingerprint = mockttp.generateSPKIFingerprint(https.cert);
  console.log(`Server running on port ${server.port}`);
  console.log(`CA cert fingerprint ${caFingerprint}`);

  const chrome = await chromeLauncher.launch({
    chromeFlags: [
      "--window-size=1200,800",
      "--user-data-dir=/c/Users/path/to/profile",
      "--auto-open-devtools-for-tabs",
      `--proxy-server=localhost:${server.port}`,
      `--ignore-certificate-errors-spki-list=${caFingerprint}`,
    ],
  });
})();

Question: data manipulation on event emission

Hello.

I've read the documentation thoroughly but I couldn't find a concrete answer. Reading the source didn't help much, either.

I'm currently mapping some requests with

server.on("request", function( request ) {
    let json = request.body.getJson();
    json.field = "????";
    //request.body.json = json;
});

But apparently there's no way for me to mock/edit the data from these fields.

I have tried several ways, even as the following (as buffer was apparently raw [not a copy])

let data = request.body.buffer.toString("utf8");
data = JSON.parse(data);
data.field = "???";
request.body.buffer = Buffer.from(JSON.stringify(data), "utf8");

But I failed to edit anything.

What I had to do is to set a transformRequest even before knowing whether the endpoint would be called or not, which is not the behavior I really planned to have.

server.post("path")
    .once() // I don't even know if the request is truly being called, but I was forced to use this
    .thenPassThrough({
        transformRequest:{
            updateJsonBody:{
                field: "???"
            }
        }
    });
    
server.on("request", (request) => {
    // field doesn't show "???" as I assume it should due to the chunk above,
    // but the request is sent with the mocked data correctly and I get the expected results (response)
    let field = request.body.getJson().field; 
})

TL;DR: Is it possible to edit the request (and/or response) data from the EventEmitter emission?

The RunKit example is broken

The readme suggests to try mockttp on RunKit

Want to play with this yourself? Try running a standalone version live on RunKit: https://npm.runkit.com/mockttp

When I go there and click "run", an error pops up:

Error: Cannot find module 'ws'
Require stack:
- /app/available_modules/1586791592000/mockttp/dist/server/websocket-handler.js
- /app/available_modules/1586791592000/mockttp/dist/server/mockttp-server.js
- /app/available_modules/1586791592000/mockttp/dist/main.js
- /app/index.js

Can't use mockttp in the browser without a CommonJS bundler

In the Readme, you have an in-depth tutorial that gives an example of the browser code in the format const mockttp = require('mockttp').getLocal(); which would work in Node.js but not in Chrome.

I know that AMD works in the browser, but the commonJS fashion of var = require('package') isn't browser-friendly. The guide shows that the browser and nodeJS code are of the same kind.

Is there a way to load commonJS properly in a browser like that? RequireJS vomits when I attempt that. Or can I simply rebuild the project to AMD?

What's missing?

Integrating with Cypress

This question is mostly about Cypress, so if you feel it's totally irrelevant - feel free to close. If you can help - that would be great!

I have backend-for-frontend that does SSR (and all the necessary requests to the upstream backends in the course of it). Cypress can mock requests, but only those that leave browser, and that's not helpful in my case. I'm interested in mocking the requests that leave BFF, towards upstream backends.

I found a relevant SO thread https://stackoverflow.com/questions/47631821/ but it still doesn't completely click for me how to practically integrate Mockttp and Cypress. A small example would be very helpful.

Forward requests without mocks to a different "fallback" server

We are considering migrating from MockServer to mockttp and one of the requirements we have is to forward requests without mocks to a different "fallback" server.

When the mock server receives a request, if there is no mock defined for this request, we would like to forward the request on to another server.

In MockServer this is possible using the following CLI flags:

        -proxyRemotePort <port>                 Optionally enables port forwarding mode.
                                                When specified all requests received will
                                                be forwarded to the specified port, unless
                                                they match an expectation.

        -proxyRemoteHost <hostname>             Specified the host to forward all proxy
                                                requests to when port forwarding mode has
                                                been enabled using the proxyRemotePort
                                                option.  This setting is ignored unless
                                                proxyRemotePort has been specified. If no
                                                value is provided for proxyRemoteHost when
                                                proxyRemotePort has been specified,
                                                proxyRemoteHost will default to "localhost".

Is this possible with mockttp, or is it something you would consider adding?

I read some stuff about proxies in the mockttp docs but as far as I can tell this is a different type of proxy.

Issue with latest version of jest with the jsdom environment

Hi,

Not so long ago the Jest folks removed setImmediate and clearImmediate from the jsdom environment.

Having upgraded to the latest version of Jest and set testEnvironment to jsdom I am now seeing:

ReferenceError: setImmediate is not defined

import { getLocal } from 'mockttp';
^

      at Object.<anonymous> (node_modules/vm2/lib/main.js:1277:2)                                                                           
      at Object.<anonymous> (node_modules/vm2/index.js:3:18)                                                                                
      at Object.<anonymous> (node_modules/degenerator/src/index.ts:6:1)                                                                     
      at Object.<anonymous> (node_modules/pac-resolver/src/index.ts:3:1)                                                                    
      at Object.<anonymous> (node_modules/pac-proxy-agent/src/agent.ts:13:1)                                                                
      at Object.<anonymous> (node_modules/pac-proxy-agent/src/index.ts:8:1)                                                                 
      at Object.<anonymous> (node_modules/proxy-agent/index.js:16:21)                                                                       
      at Object.<anonymous> (node_modules/mockttp/src/util/http-agents.ts:3:1)                                                              
      at Object.<anonymous> (node_modules/mockttp/src/rules/requests/request-handlers.ts:54:1)                                              
      at Object.<anonymous> (node_modules/mockttp/src/rules/requests/request-rule-builder.ts:7:1)

Is there a suggested solution for this? Do I need to polyfill setImmediate?

Thanks!

Is ignoreHostCertificateErrors the recommended way to ignore certificate errors?

Let's say that I'm using mockttp to proxy requests to example.local, which uses a self-signed certificate.

During testing, the requests fail with HTTP code 502 and I receive the following message in the Node console:

Failed to handle request: unable to verify the first certificate

I tried using workarounds like running Node with environment variables set - for example:

NODE_EXTRA_CA_CERTS='../ssl/example.local.pem' node index.js

and

NODE_TLS_REJECT_UNAUTHORIZED=0 node index.js

Neither worked. In fact, while using the latter approach (NODE_TLS_REJECT_UNAUTHORIZED), Node did provide a warning which confirmed that the env setting was being set appropriately but that it was simply not working:

(node:43294) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.

Fortunately, in the code for mockttp, I was able to find an example of how to ignore host certificate errors. This led me to the following approach:

server.thenPassThrough({
  ignoreHostCertificateErrors: ['example.local']
});

This does seem to work ๐ŸŽ‰, but I'm confused.

  1. Why didn't the other general Node environment variable approaches work? Are those settings overridden by mockttp?
  2. Is this approach (using ignoreHostCertificateErrors) the recommended solution?

Thank you! :)

Feature Request: Add ability to customize the order in which rules are matched

Right now in MockttpServer.findMatchingRule() rule matching seems to always progress from the top of the array to the bottom of the array. The first rule always gets top priority for matching.

        const rulesMatches = rules.map((r) => ({ rule: r, match: r.matches(request) }));

        // Evaluate the matches one by one, and immediately use the first
        for (let { rule, match } of rulesMatches) {
            if (await match && rule.isComplete() === false) {
                // The first matching incomplete rule we find is the one we should use
                return rule;
            }
        }

I would like the ability to rotate the rule priority.

For example with these rules:

  await server.forGet('/users').thenJson(200, [ 'u1', u2' ]); // (A)
  await server.forPut('/users').thenJson(200, { message: 'User added' }); // (B)
  await server.forGet('/users').thenJson(200, [ 'u1', u2', 'u3' ]); // (C)
  • The first request to GET /users would match rule (A) and return ['u1', 'u2']
  • Rule matching would then start on Rule (B) going forward
  • A request to 'PUT /users' would match rule (B)
  • Rule matching would then start on Rule (C) going forward
  • The second request to GET /users would match rule (C) and return ['u1', 'u2', 'u3] (as if the user was added)

Is this currently possible?

If not are there plans to allow this?

I realize the caller could rotate the rules in the array and continually call setRequestRules() after each match, but that is more expensive as there is the overhead of disposing the previous rules and constructing new RequestRule objects in that method.

If there is no solution planned for this then I can just fork the mockttp repo and change findMatchingRule() to use a custom iterator, e.g. a rotating iterator.

How to ignore/bypass android apps's certificate pinning

Hello,

The android apps have a certificate pinning that block mockttp.
Here is the debug output:

TLS client error: {"failureCause":"cert-rejected","hostname":"api.twitter.com","remoteIpAddress":"::ffff:10.3.141.91","remotePort":45686,"tags":[],"timingEvents":{"startTime":1641902289465,"connectTimestamp":12868.375694,"failureTimestamp":12923.67577}}

I know that there is no way to bypass without jailbreaking the phone.
So, i would love to find a way to ignore these requests from the proxy.
If we can detect the header of the request coming from the apps, we can ignore the request then and make the app work without the proxy.

There is the code i have written so far:

http-combo-server.js

server.addListener('connect', function (req, resOrSocket) {
            if (resOrSocket instanceof net.Socket) {

               // if it's not a webbrowser, we can't proxy the request, ignore it
                if (!req.headers['user-agent'] || !req.headers['user-agent'].match("Mozilla")) {
                    var host = req.url.split(":")[0];
                    var port = req.url.split(":")[1];
    
                    var conn = net.connect({
                        port: port,
                        host: host,
                        allowHalfOpen: true
                    }, function(){
                        conn.on('finish', () => {
                          socket.destroy();
                        });
                        socket.on('close', () => {
                          conn.end();
                        });
                        socket.write('HTTP/1.1 200 OK\r\n\r\n', 'UTF-8', function(){
                          conn.pipe(socket);
                          socket.pipe(conn);
                        });
                    });
                    return false;
                }

                handleH1Connect(req, resOrSocket);
            }
            else {
                handleH2Connect(req, resOrSocket);
            }
        });

But it's not working, the TLS error happens before the connect.

If someone can help me on this i would be really gratefull

Jest detects 1 open handle after test run

We're using Mockttp with Jest, with the --detectOpenHandles option set, and after our tests complete we're seeing the following warning:

Jest has detected the following 1 open handle potentially keeping Jest from exiting:
  โ—  Timeout
      at Object.<anonymous> (node_modules/mockttp/src/util/socket-util.ts:68:5)

Taking a look at the code in question it seems clear why this is happening, but is there a suggested workaround? We'd rather avoid the false-negative.

Happy to raise a PR if needed.

Add option to match relative URLs without computing isIndirectPathRequest()

The following commit prevents us from upgrading: ef2e0a8

This may be a breaking change if you are sending requests to a
Mockttp server directly, using a hostname for the server that
isn't 'localhost' or one of its ip addresses. That traffic will
now be treated as having an absolute URL.

We will be able to get around the issue, but I thought that describing our use case could help you if you wanted to change the design.

Our use case is system testing of an app container which sometimes makes requests to an external_webservice.
Our tests are run by another container named tester, which makes requests to the app container and checks the response. We have been using mockttp to mock external_webservice. A typical test inside tester would be:

describe('The APP container on /route1', () => {
  before(async () => {
    await mockServer.start(process.env.MOCK_PORT);
    await mockServer.get('/external_api').thenReply(200, "something that external_webservice should respond");
  });
  after(async () => {
    await mockServer.stop();
  });
  it('always calls the external_api and returns OK', async () => {
    const response = await request(`${process.env.APP_URL}/route1`);
    expect(response).to.equal('OK');
    const externalRequests = await mockServer.getSeenRequests();
    expect(externalRequests.length).to.equal(1);
  });
}

Our containers run with docker-compose, with something like this;

app:
  environment:
    EXTERNAL_API_URL: http://tester:7500/external_api
tester:
  environment:
    MOCK_PORT: 7500

As you can see, the host that mockttp will receive is tester not localhost.
After upgrading, this is the error message:

No rules were found matching this request.
This request was: GET request to http://tester:7500/external_api with headers: ...
The configured rules are:
Match requests making GETs for /external_api, and then respond with status 200 and body "something that external_webservice should respond".
You can fix this by adding a rule to match this request, for example:
mockServer.get("/external_api").thenReply(200, "your response");

Note that the suggestion is incorrect, because this is precisely the route that we specified.

We can get around the issue in multiple ways. But maybe mockttp could be improved in one of the following ways:

  • add a disableProxy option to MockttpOptions
  • add a noHostChecking option to MockttpOptions
  • create a mockServer.proxyUrl, which would be different from mockServer.url (maybe appending a fingerprint like /.well-kown/mockttp-proxy)

getSeenRequests never completing due to rule.requests never resolving promise.

I've got a mocked endpoint:

    const mockedEndpoint = mockServer.post("/id/endpoint").thenJson(200 , { total: 3 });

I can see with the logging it's being added okay:

Handling request for /id/endpoint
Request matched rule: Match requests making POSTs for /id/endpoint, and then respond with status 200, headers {"Content-Type":"application/json","Content-Length":"40"} and body "{"total":3}".

The endpoint is called in a browser test, and it does respond with the correct reply, within 6ms, not stuck pending.

Then I later check it's been called with the correct info:

log.debug("Got mocked endpoint", mockedEndpoint);
const requests = await mockedEndpoint.getSeenRequests();

The problem is this times out. The promise never completes. I added some logging to ensure I've got the right endpoint:

Got mocked endpoint Mocked endpoint: Match requests making POSTs for /id/endpoint, and then respond with status 200, headers {"Content-Type":"application/json","Content-Length":"40"}
and body "{"total":3}".

Then I added some logging to the library itself to check the requests promises:

    getSeenRequests() {
        // Wait for all completed running requests to have all their details available
        console.log(this.rule.requests);
        return Promise.all(this.rule.requests);
    }

Which reports the single expected request that's stuck: [ Promise { <pending> } ]

I've no idea why this particular endpoint is hanging, it works with all the others (more complex ones with body and query matchers). The response does come through in the browser tests where I'm calling it. It responds with the correct reply, within 6ms. It's just the call to getSeenRequests.

Have you seen this before? Is there anything that would case it to get stuck unresolved?

How to check if server is already running on port

I'm trying to integrate mockttp with cypress.
From the cypress test I start and stop the server at port 8001 like this.

import { getRemote } from 'mockttp'
const server = getRemote()

before(async () => {
  await server.start(8001)
})

after(async () => {
  await server.stop()
})

Now the problem is that whenever a code change is made cypress will restart the test at any moment in time so it's not possible to stop the server. At this moment the test restarts and mockttp throws an error because port 8001 is already in use.

How can I check if a port is already in use and if so restart the server?
I tried this and its not working:

  await server.start(8001).catch(() => {
    server.reset()
  })

Allow overriding mocks

It often happens through the lifecycle of a test that the same route must return two different result.
For example:

GET a list
POST a new item
GET a list (with the new item)

We want two different output for the list on the same route.

Currently, I handle that by using the times, once, etc... methods but they imply you know exactly how many times the route must be called which is limiting.
Knowing how many times a route is called inside the test is very technical and I want to stay "functional".

So what I want to do is:

GET a list
POST a new item
  THEN override the list mock
GET a list

That way if for some reason my list is called multiple times before the POST I don't have to manually change the times and the test won't necessarily break.

The simple solution is to reverse the array of matchingRules so the last one added is always the one chosen instead of always using the first one declared. LIFO > FIFO

https://github.com/pimterry/mockttp/blob/master/src/server/mockttp-server.ts#L229

let nextRule = last(matchingRules.filter((r) => !this.isComplete(r, matchingRules)));

beforeResponse and transformResponse acting differently

Hello,

I am using mockttp in order to retrieve specific responses, modify them, then pass them through to the original requestor.

However, I am finding that I am having issues using the beforeResponse PassThroughHandlerOptions but I am able to successfully use the transformResponse property to change the JSON body. The issue with me using the transformResponse property instead, is that I don't have access to the original response body and cannot programmatically change it, rather, I am reading a json file into an object which I pass to the transformResponse.

  const requestLogger = (request: CompletedRequest) => {
    console.log(`Request for: ${request.url}`);
    return;
  };

  const fileContents = fs.readFileSync(
    path.resolve(__dirname, '../../config/mockttp/info.json'),
    'utf8'
  );
  
  const fileToJson = JSON.parse(fileContents);

  Object.entries(fileToJson).forEach((item) => {
    const key = item[1]['key'];
    item[1]['value'] =
      key == 'value1'
        ? 'false'
        : key == 'value2'
        ? 'true'
        : key == 'value3'
        ? 'false'
        : key == 'value4'
        ? 'true'
        : item[1]['value'];
  });

  const transform: ResponseTransform = {
    updateJsonBody: fileToJson,
  };

  const customResponse = (response: CompletedResponse) => {
    console.log(response);
    return { ...response, body: fileToJson };
  };

The below works:

    await Promise.all([
      this.mockServer.get('/info').always().thenPassThrough({
        transformResponse: transform,
        beforeRequest: requestLogger,
      }),
      this.mockServer.anyRequest().thenPassThrough({
        beforeRequest: requestLogger,
      }),
    ]);

But this fails

    await Promise.all([
      this.mockServer.get('/info').always().thenPassThrough({
        beforeRequest: requestLogger,
        beforeResponse: customResponse,
      }),
      this.mockServer.anyRequest().thenPassThrough({
        beforeRequest: requestLogger,
      }),
    ]);

I've tried using the body and json return properties of beforeResponse all with strings, uint8 buffers, or json object and still no success.

Any idea what is going on?

Parse Error: Expected HTTP/

On mockttp 0.20.0, 0.20.1, and 0.20.2 I get a weird http parse error. I think it is something to do with response encoding.

Node version is 12.18.0

tested the request with request-promise, axios, and fetch with the same results each time

{
  "config": {
    "url": "https://localhost:1234/oauth/access_token.php",
    "method": "post",
    "data": {
      "_overheadLength": 432,
      "_valueLength": 150,
      "_valuesToMeasure": [],
      "writable": false,
      "readable": true,
      "dataSize": 0,
      "maxDataSize": 2097152,
      "pauseStreams": true,
      "_released": true,
      "_streams": [],
      "_currentStream": null,
      "_insideLoop": false,
      "_pendingNext": false,
      "_boundary": "--------------------------229731192039541199026626",
      "_events": {},
      "_eventsCount": 1
    },
    "headers": {
      "Accept": "application/json, text/plain, */*",
      "Content-Type": "multipart/form-data; boundary=--------------------------229731192039541199026626",
      "User-Agent": "axios/0.19.2"
    },
    "transformRequest": [
      null
    ],
    "transformResponse": [
      null
    ],
    "timeout": 0,
    "xsrfCookieName": "XSRF-TOKEN",
    "xsrfHeaderName": "X-XSRF-TOKEN",
    "maxContentLength": -1
  },
  "code": "HPE_INVALID_CONSTANT"
}

Negate matchers/function predicates

I think it would nice to be able to allow matching based on negation. In my case I would like to match when a header is not present, but I think it would make sense to allow it on the other parts of the requests as well. More specifically I would like to model when the user is not logged in and and therefore has no cookie.

Alternatively function predicates in the same style the nock supports would probably be more flexible and also cover this scenario.

Security vulnerability from `ws`

The vulnerability comes via mockhttp > universal-websocket-client > ws.

$ npm audit

                       === npm audit security report ===

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                Manual Review                                 โ”‚
โ”‚            Some vulnerabilities require your attention to resolve            โ”‚
โ”‚                                                                              โ”‚
โ”‚         Visit https://go.npm.me/audit-guide for additional guidance          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ High          โ”‚ Denial of Service                                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Package       โ”‚ ws                                                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Patched in    โ”‚ >= 1.1.5 <2.0.0 || >=3.3.1                                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Dependency of โ”‚ mockttp [dev]                                                โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Path          โ”‚ mockttp > universal-websocket-client > ws                    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ More info     โ”‚ https://nodesecurity.io/advisories/550                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
found 1 high severity vulnerability in 3113 scanned packages
  1 vulnerability requires manual review. See the full report for details.

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.