httptoolkit / mockttp

Powerful friendly HTTP mock server & proxy library
https://httptoolkit.com
Apache License 2.0
786 stars 88 forks source link

Using MockHttp for Angular Testing #133

Closed lukevd closed 1 year ago

lukevd commented 1 year ago

Is this package intended to be used for testing an angular application (https://angular.io/guide/testing)? If yes, then the documentation should be improved in my oppinion.

I created an angular application by typing in the following command

ng new my-application

(as described here: https://angular.io/guide/setup-local). Then, i typed in the following commands as described in the getting started section in the readme of mockttp:

cd my-application
npm install --save-dev mockttp

I created the test as described in the section Get Testing in the readme of mockttp:

import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
const superagent = require("superagent");
const mockServer = require("mockttp").getLocal();

describe('AppComponent', () => {
    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [
                AppComponent
            ],
        }).compileComponents();

        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).toEqual("A mocked response");
    });
});

Running the tests by executing the command ng test produced the following error:

Error: src/app/app.component.spec.ts:3:20 - error TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.

3 const superagent = require("superagent");

Therefore, i installed node (npm i --save-dev @types/node) and added node to the file tsconfig.spec.json (which is not documented in the readme of mockttp):

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": [
      "jasmine", "node"
    ]
  },
  "include": [
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

I also installed superagent:

npm install superagent

Running the tests by executing the command ng test produces the following output:

- Generating browser application bundles (phase: setup)...
√ Browser application bundle generation complete.

./node_modules/http-encoding/dist/index.js:34:13-28 - Error: Module not found: Error: Can't resolve 'zlib' in 'C:\UData\learn\learnAngular\my-application\node_modules\http-encoding\dist'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "zlib": require.resolve("browserify-zlib") }'
        - install 'browserify-zlib'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "zlib": false }

./node_modules/mockttp/dist/rules/matchers.js:9:12-26 - Error: Module not found: Error: Can't resolve 'url' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\rules'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
        - install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "url": false }

./node_modules/mockttp/dist/rules/requests/request-handler-definitions.js:9:12-26 - Error: Module not found: Error: Can't resolve 'url' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\rules\requests'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
        - install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "url": false }

./node_modules/mockttp/dist/rules/requests/request-handler-definitions.js:11:17-34 - Error: Module not found: Error: Can't resolve 'stream' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\rules\requests'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

./node_modules/mockttp/dist/rules/websockets/websocket-handler-definitions.js:7:12-26 - Error: Module not found: Error: Can't resolve 'url' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\rules\websockets'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
        - install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "url": false }

./node_modules/mockttp/dist/serialization/serialization.js:9:17-34 - Error: Module not found: Error: Can't resolve 'stream' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\serialization'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

./node_modules/mockttp/dist/util/buffer-utils.js:7:15-32 - Error: Module not found: Error: Can't resolve 'stream' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\util'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

./node_modules/mockttp/dist/util/normalize-url.js:7:12-26 - Error: Module not found: Error: Can't resolve 'url' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\util'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
        - install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "url": false }

./node_modules/mockttp/dist/util/request-utils.js:12:15-32 - Error: Module not found: Error: Can't resolve 'stream' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\util'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

./node_modules/mockttp/dist/util/request-utils.js:13:20-42 - Error: Module not found: Error: Can't resolve 'querystring' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\util'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "querystring": require.resolve("querystring-es3") }'
        - install 'querystring-es3'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "querystring": false }

./node_modules/mockttp/dist/util/request-utils.js:15:12-26 - Error: Module not found: Error: Can't resolve 'url' in 'C:\UData\learn\learnAngular\my-application\node_modules\mockttp\dist\util'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "url": require.resolve("url/") }'
        - install 'url'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "url": false }

./node_modules/native-duplexpair/index.js:3:15-39 - Error: Module not found: Error: Can't resolve 'stream' in 'C:\UData\learn\learnAngular\my-application\node_modules\native-duplexpair'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }

./node_modules/zstd-codec/lib/zstd-codec-binding-wasm.js:45:32-45 - Error: Module not found: Error: Can't resolve 'fs' in 'C:\UData\learn\learnAngular\my-application\node_modules\zstd-codec\lib'

./node_modules/zstd-codec/lib/zstd-codec-binding-wasm.js:46:36-51 - Error: Module not found: Error: Can't resolve 'path' in 'C:\UData\learn\learnAngular\my-application\node_modules\zstd-codec\lib'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
        - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "path": false }

./node_modules/zstd-codec/lib/zstd-codec-binding.js:45:32-45 - Error: Module not found: Error: Can't resolve 'fs' in 'C:\UData\learn\learnAngular\my-application\node_modules\zstd-codec\lib'

./node_modules/zstd-codec/lib/zstd-codec-binding.js:46:36-51 - Error: Module not found: Error: Can't resolve 'path' in 'C:\UData\learn\learnAngular\my-application\node_modules\zstd-codec\lib'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
        - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "path": false }

24 02 2023 11:11:54.406:WARN [karma]: No captured browser, open http://localhost:9876/
24 02 2023 11:11:54.419:INFO [karma-server]: Karma v6.4.1 server started at http://localhost:9876/
24 02 2023 11:11:54.420:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
24 02 2023 11:11:54.436:INFO [launcher]: Starting browser Chrome
Chrome 110.0.0.0 (Windows 10) ERROR
  Disconnected Client disconnected from CONNECTED state (transport close)
Chrome 110.0.0.0 (Windows 10): Executed 0 of 0 SUCCESS (0.01 secs / 0 secs)
Chrome 110.0.0.0 (Windows 10) ERROR
  Disconnected Client disconnected from CONNECTED state (transport close)
24 02 2023 11:19:05.100:ERROR [launcher]: Chrome crashed.

DevTools remote debugging is disallowed by the system admin.
[15336:17012:0224/111157.053:ERROR:device_event_log_impl.cc(218)] [11:11:57.053] USB: usb_device_handle_win.cc:1046 Failed to read descriptor from node connection: Ein an das System angeschlossenes Ger�t funktioniert nicht. (0x1F)

24 02 2023 11:19:05.101:ERROR [launcher]: Chrome stdout:
24 02 2023 11:19:05.101:ERROR [launcher]: Chrome stderr:
DevTools remote debugging is disallowed by the system admin.
[15336:17012:0224/111157.053:ERROR:device_event_log_impl.cc(218)] [11:11:57.053] USB: usb_device_handle_win.cc:1046 Failed to read descriptor from node connection: Ein an das System angeschlossenes Ger�t funktioniert nicht. (0x1F)

24 02 2023 11:19:05.192:INFO [launcher]: Trying to start Chrome again (1/2).
√ Browser application bundle generation complete.
√ Browser application bundle generation complete.
pimterry commented 1 year ago

Is this package intended to be used for testing an angular application

Not specifically, but yes it's quite possible to test Angular applications with Mockttp.

Error: src/app/app.component.spec.ts:3:20 - error TS2591: Cannot find name 'require'. Do you need to install type definitions for node? Try npm i --save-dev @types/node and then add 'node' to the types field in your tsconfig.

This message is because you're using ESM modules (import ... from ...) but you've used require in your test file. This isn't really a Mockttp issue - it applies to using any JS library.

You shouldn't need to import the node types for that specifically (I'm not sure if they're required for other reasons) instead you should import all libraries using ESM syntax instead of require, e.g:

import * as superagent from 'superagent';
import * as mockttp from 'mockttp';
const mockServer = mockttp.getLocal();

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default...

This is because you're using Webpack v5 - as noted in each of those messages, this means you need to explicitly include libraries for features that older webpack (and most other bundlers) would normally include automatically.

Mockttp's own browser test suite is tested against Webpack v5, and you can find the config here which may be useful. I think the important part is the resolve.fallback section, which in Mockttp's tests looks like:

assert: require.resolve('assert/'),
buffer: require.resolve('buffer/'),
crypto: require.resolve('crypto-browserify'),
zlib: require.resolve('browserify-zlib'),
stream: require.resolve('stream-browserify'),
path: require.resolve('path-browserify'),
querystring: require.resolve('querystring-es3'),
util: require.resolve('util/'),
url: require.resolve('url/')

You may not need all of those, in Mockttp's case there's quite a few additional modules that are used only because they're helpful in the tests, not within Mockttp itself.

You'll also need to install each of the modules listed from npm, if you don't have them already.

mockServer.start(8080)

This line in your beforeEach should have an await, to ensure the tests don't start before the server is running.


It would be useful to remove some of these node dependencies in future, although using them does make life much easier for non-browser use cases, and most bundlers (except Webpack v5+) do handle this transparently. I'm also open to documenting all this more clearly. In both cases, PRs are very welcome!

lukevd commented 1 year ago

Thank's. I decided to not integrate mockttp directly in my angular tests but to use it in a pure node.js application.