Skip to content
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

fix: resolve segfault issue caused by "node:events" import #1885

Merged
merged 11 commits into from
Nov 24, 2023

Conversation

mattcosta7
Copy link
Contributor

@mattcosta7 mattcosta7 commented Nov 23, 2023

A 3rd attempt which uses a subclass to implement the node specific behavior, instead of the methods in:

I think this is my favorite implementation, and by far the least leaky, while still allowing control of the imports outside of the class definition, which allows us to better utilize this in only the node export

I still haven't managed to recreate a proper test environment that actually throws, but we're at least avoidng the codepath here

@mattcosta7 mattcosta7 marked this pull request as ready for review November 23, 2023 04:43
import * as path from 'node:path'
import { defineConfig } from 'vitest/config'

export default defineConfig({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be the exact copy of the existing vitest config for node tests. Cannot we just reference to it for native tests, which I assume is the intention here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we probably can. I was separating this to try and get a test environment that worked properly for react-native but failed to do so, and kept this to provide a path to doing that in the future. I think it's probably ok to duplicate here, but we could also nest the native test inside of the node folder and just run it there, since it's fairly small.

No strong preferences, although a working native setup would be ideal. I couldn't even get vi.mock to throw for builtins here, which I also tried

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the vi.mock() work but it requires a module alias hack in Vitest.

import { SetupServer } from './glossary'
import { isNodeExceptionLike } from './utils/isNodeExceptionLike'

export class SetupNodeServerApi extends SetupServerApi implements SetupServer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach. A couple of thoughts to make it stellar:

  1. Don’t introduce a new class.
  2. Add a protected onRequest method to the existing SetupServerApi class. Do nothing in that method.
  3. In src/node/index.ts, create a new subclass from SetupServerApi. In that subclass, invoke the abort listener logic directly (no need to abstract to a method). This way, the import to node:events will be scoped to node/index.ts and won’t leak to /native on SetupServerApi.ts imports there.
  4. No changes are necessary for the React Native setup API.

So, this is basically identical to what you did just inlining the new derived class directly in src/node/index.ts. What do you think about this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main concern here is that SetupApi classes are meant to cover functionality. Here, we sort of address the extension issue that's import-specific (if we import node:events in the base SetupApi, any consumer automatically gets that import, which is not what we want). An internal issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, makes sense.

1e44a5b might be what you're suggesting (just keeping from a separate file?)

@kettanaito kettanaito changed the title fix: dependency injection for node events, via subclassing fix: resolve segfault issue caused by "node:events" import Nov 24, 2023
* The root-level package.json is still CJS, which, I suspects,
* resolves any subsequent in-build imports to their CJS counterparts.
*/
expect(() => setupServer()).not.toThrow()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a very basic test that due to the lack of proper testing environment, tests implementation detail of the node:events import (or its lack) in the msw/native build.

@@ -14,6 +14,6 @@ test('throws an error given an Array of request handlers to setupServer', () =>
}

expect(createServer).toThrow(
`[MSW] Failed to construct "SetupServerApi" given an Array of request handlers. Make sure you spread the request handlers when calling the respective setup function.`,
`[MSW] Failed to construct "SetupNodeServerApi" given an Array of request handlers. Make sure you spread the request handlers when calling the respective setup function.`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the subclass name leaking to the consumer. We should somehow keep this as SetupServerApi.

* the root-level "package.json" is not "module".
*/
'msw/node': path.resolve(LIB_DIR, 'node/index.mjs'),
'msw/native': path.resolve(LIB_DIR, 'native/index.mjs'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattcosta7, this is the hack that makes vi.mock() work with overriding the standard node modules.

kettanaito
kettanaito previously approved these changes Nov 24, 2023
Copy link
Member

@kettanaito kettanaito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Thanks for fixing this, @mattcosta7! I've addressed the remaining feedback here and it should be ready for merge.

@kettanaito kettanaito merged commit f188d77 into main Nov 24, 2023
10 checks passed
@kettanaito kettanaito deleted the v3-node-events-dependency-injection branch November 24, 2023 15:10
@kettanaito
Copy link
Member

Released: v2.0.9 🎉

This has been released in v2.0.9!

Make sure to always update to the latest version (npm i msw@latest) to get the newest features and bug fixes.


Predictable release automation by @ossjs/release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

segfault in jest with [email protected]
2 participants