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

Do not exhaust one-time handlers with custom predicate in resolver #2399

Open
1 task
YunYouJun opened this issue Dec 20, 2024 · 4 comments
Open
1 task

Do not exhaust one-time handlers with custom predicate in resolver #2399

YunYouJun opened this issue Dec 20, 2024 · 4 comments
Labels
feature good first issue Good for newcomers

Comments

@YunYouJun
Copy link

Scope

Improves an existing behavior

Compatibility

  • This is a breaking change

Feature description

Background

As stated on https://mswjs.io/docs/best-practices/custom-request-predicate, we can implement predicate filtering by wrapping the resolver.

export const handlers = [
  http.get(
    '/user',
    withPredicate(
      // Only match "GET /user" requests that have
      // the "userId" query parameter present.
      (params) => params.has('userId'),
      ({ request, params, cookies }) => {
        return HttpResponse.json({
          name: 'John Maverick',
        })
      }
    )
  ),
  { once: true }
]

However, if we want to use options.once at this point, it will result in the once being consumed even if the predicate is not passed.

This makes it hard for our implemented predicate to support both once with predicate simultaneously.


restoreHandlers() can restore once.
But it will also reset all the handlers.


Solution

So I think Custom request predicate function is very important. It gives us more control.

#1804

I would like to know when we can expect to have this feature available, or if there are any alternative solutions to address the current issue?

@YunYouJun
Copy link
Author

YunYouJun commented Dec 20, 2024

One of my temporary solutions:

/**
 * reset isUsed by myself
 */
function resetIsUsed(fn: MSWHttpResponseResolver, handler?: HttpHandler): MSWHttpResponseResolver {
  return async (args) => {
    const res = await fn(args)
    if (handler) {
      if (a) // custom logic
        handler.isUsed = false
    }
    return res
  }
}

@kettanaito
Copy link
Member

Hi, @YunYouJun. That's a good point, thanks for bringing it up.

This is related to #1804 I raised some time ago. Response resolver function is, technically, not the best place for custom predicates because the resolver phase happens after the predicate phase internally.

I wouldn't go into shipping that new API to address your use case though. I think a far more incremental approach would be this:

  • Only mark the request handler as used once its resolver function returned something.

For resolvers that trigger, do their predicate, but return nothing (don't handle the request), keep that resolver as non-exhausted (new behavior). For those that handle the request, exhaust them (current behavior).

What do you think?

@kettanaito
Copy link
Member

Currently, we mark the handler as used immediately if the internal predicate phase has matched:

this.isUsed = true

But that won't work for handlers where the user defines a custom predicate within the response resolver, as you've pointed out.

Instead, we could move this update after the execution result is known:

const executionResult = this.createExecutionResult({

And do something like:

if (executionResult != null) {
  this.isUsed = true
}

If you wish to give this a try, please start with a test case! test/node/msw-api/setup-server/once.test.ts looks like a good place to put it.

@kettanaito kettanaito added the good first issue Good for newcomers label Dec 25, 2024
@kettanaito kettanaito changed the title allow predicate before once Do not exhaust one-time handlers with custom predicate in resolver Dec 25, 2024
@YunYouJun
Copy link
Author

YunYouJun commented Dec 25, 2024

Hi, @YunYouJun. That's a good point, thanks for bringing it up.你好, 。这是一个很好的观点,谢谢你提出来。

This is related to #1804 I raised some time ago. Response resolver function is, technically, not the best place for custom predicates because the resolver phase happens after the predicate phase internally.这与 #1804 我前段时间养过。从技术上讲,响应解析器函数并不是自定义谓词的最佳位置,因为解析器阶段发生在内部谓词阶段_之后_。

I wouldn't go into shipping that new API to address your use case though. I think a far more incremental approach would be this:不过,我不会发布新的 API 来解决您的用例。我认为一种更加渐进的方法是这样的:

  • Only mark the request handler as used once its resolver function returned something.仅当其解析器函数_返回某些内容_时,才将请求处理程序标记为已使用。

For resolvers that trigger, do their predicate, but return nothing (don't handle the request), keep that resolver as non-exhausted (new behavior). For those that handle the request, exhaust them (current behavior).对于触发的解析器,执行其谓词,但不返回任何内容(不处理请求),使该解析器保持未耗尽状态(新行为)。对于那些处理请求的人,耗尽他们(当前行为)。

What do you think?  你怎么认为?

I think it looks good.

But is there a case where the user's internal resolver returns null, but also wants to consume once?

So I thought that allowing the user to return a specific function or Symbol would satisfy more situations without breaking past behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

2 participants