-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Executing mockttp remotes from a Cypress test suite broken since [email protected] #188
Comments
I was able to hack my way to a running test case, aiming at the minimum intervention, but it's definitely a hack. You can see the changes required at... https://github.com/cefn/cypress-mockttp/pull/3/files Since Ideally mockttp would have a browser-oriented build which includes only getRemote and its requirements. Suggestion, create a separate package or a separate export intended for remote, which maybe people could consume like...
WorkaroundThis section provides more detail about the workaround at https://github.com/cefn/cypress-mockttp/pull/3/files I needed to explicitly configure webpack by adding This enables the single test case to run, but I don't know how errored Given all the intercepted resolutions, I take this to mean that the browser-targeted build (or the build that cypress believes is the browser build) is incorrectly composed right now, and contains much of the infrastructure required for the admin server and local server, when by definition these flows are impossible within a browser. const webpackOptions = {
resolve: {
extensions: [".ts", ".js", ".wasm"],
fallback: {
"stream": require.resolve("stream-browserify"),
"zlib": false,
"querystring": false,
"path": false,
"fs": false
}
},
module: {
rules: [
{
test: /\.wasm$/,
type: "asset/resource", // Ensures WebAssembly files are handled correctly
},
],
},
experiments: {
asyncWebAssembly: true, // Enable WebAssembly
syncWebAssembly: true, // (Optional) Enable synchronous WASM
},
plugins: [
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
process: "process/browser",
}),
]
} as const; |
Mockttp already has built-in configuration for a separate browser entrypoint at main.browser.ts, see the configuration in package.json: Lines 5 to 51 in b19499f
This entrypoint excludes the vast majority of Node-specific code. There are still a few dependencies on node built-in modules still used like stream & buffer, but there's standard polyfills available for those (quite a few bundlers will handle that automatically - although not Webpack v5 specifically, which you're using here). Regarding brotli-wasm, the main challenge is that it is actually required in the browser for quite a few modern Mockttp use cases, so it can't be excluded. That module allows you to inspect & mock Brotli-compressed traffic, and brotli is a popular compression algorithm nowadays that's widely used. You need to use brotli-wasm in the browser if you try to read any brotli-encoded body. Wasm is supported by all modern browsers and so it's quite possible to use this in the browser (Mockttp itself has a complete suite of browsers tests that run in Chrome) and brotli-wasm has a specific browser-compatible entrypoint to support this, generated with a standard wasm-pack setup. The issue is just when a bundler gets involved, and webpack v5 specifically which needs special configuration for wasm in general. Your solution (configuring webpack explicitly to support wasm) is roughly the right approach here if you want to include brotli-wasm, although there's a few bits that are surprising:
For the wasm configuration specifically, as a workaround you could just add |
This is incredibly detailed and useful thanks, Tim. I'll look if the In summary for our use case the scenario of mockttp needing special manipulation at the bundler level is the thing that then takes the extra work and creates the complexity, so knowing that e.g. the polyfills are explicit dependencies and that (De)CompressionStream and URLSearchParams fulfil those requirements and therefore no bundling is needed is the crucial threshold. Before mockttp was in the mix we had no webpack config at all. If there's any bundle configuration needed, we've already stepped into the lava, and 6 packages versus 1 package is not a big difference (excepting the runtime exceptions we might potentially see). I think I may have misunderstood the architecture in that I expected calls via getRemote to have no logic of their own, but just mirror a node-side API which did all the actual implementation. From your commentary the boundary isn't as clear as this. Perhaps it could be? Our choice will be probably to retire Cypress in favour of Playwright (which will effectively run in Node) so I'll see how that policy change goes down with the team before putting more effort in this direction. |
Mostly things do happen on the server side, but that's not always possible. The main challenge is when the client directly handles request or response data itself - this is where all the compression algorithms come in. Any time the server needs to give the client request or response data, it sends the data as received in its original raw still-encoded form, and the client decodes it dynamically when you try to read it if required. There's a few reasons for this:
The relevant stuff happens here: mockttp/src/util/request-utils.ts Lines 187 to 269 in df40d1f
That code we can store/transfer just a buffer of the raw received request body, and when you call There's a few places where bodies like this are accessible on the client side:
In all these cases, the client needs to access the request/response body. If that's compressed, it needs to be able to decompress it, which currently uses I guess there's a few alternatives I can see:
Any of these would be large tricky changes I think, but it's possible. The last is definitely easiest (we already use an async API for decoding here - we just create a server API for this, and then call that instead of decoding the content for ourselves). So, just to recap:
PRs towards any of those welcome if you're interested. Removing all these completely is non-trivial but probably a good general direction of travel for us to aim for nowadays (most of these were added back when Webpack v4 automatically handled all these polyfills for you). |
Since
[email protected]
the package cannot successfully load and executegetRemote()
in any Cypress test out of the box. The error seems to arise from the (incorrect?) export configuration ofbrotli-wasm
which was a new dependency since2.0.0
.This is a real shame as the mockttp design is exactly what's needed to work around the limitation that Cypress tests all execute within a browser context, so if you want to control mocks, mockttp remoting is a perfect solution.
Is it still possible to run mockttp in a browser with a typical bundling process (I assume that cypress has a mainstream bundling process that we can consider canonical) ?
Is there any obvious workaround to prevent
brotli-wasm
bundling issues being fatal for all Cypress tests?Repro
I started to investigate by forking the the original cypress+mockttp working reference from @mvasin from 2020 linked at #35 (comment)
You can see my fork at https://github.com/cefn/cypress-mockttp/tree/283ce5e2facf0c166907c4abb0ca7cd9df7bf072
In my fork I upgraded all dependencies except mockttp to get it to function in modern Chrome and Cypress, then I upgraded to latest
[email protected]
which remained functional.However, upgrading to
[email protected]
ormockttp@latest
were both failures. I know there are API changes needed also to align with latest mockttp, but this failure is profound and immediate to do with the fact the newermockttp
includes elements which can't be bundled for the browser at all, so we never get that far. Aligning with the new API makes no difference.Instructions
You can prove the repro runs correctly in
1.x.x
by running......then clicking on the Cypress E2E Testing button that appears, then click on
Start E2E Testing in Chrome
in the next screen choose the exampledummy.spec.ts
in the eventually-loaded Chrome instance. It correctly showsexpected this is a mocked response to equal this is a mocked response
.After proving that it's functional with
[email protected]
you can recreate the error within the project by running......or...
The failure presents in the UI like this...
Looking at debug logs the issue shows more detail about the module load failure which fingers loading
brotli-wasm
as the cause.The text was updated successfully, but these errors were encountered: