是否可以向 jest Expect 断言添加自定义修饰符?

Tak*_*shi 5 javascript jestjs

您可能知道,可以添加修饰符来期望诸如.not, 或 之类的断言.resolves

我想知道是否可以添加自定义期望修饰符,我找不到有关该主题的任何资源。

我的用例是对字符串化的 http 响应进行断言。为了简化我的测试工作流程,我为一些断言制作了一些自定义匹配器:

  toHaveJsonBodyIncludingSameMembers(members: any[]): R;
  toHaveJsonBodyIncludingAllMembers(members: any[]): R;
  toHaveJsonBodyIncludingAllPartialMembers(members: any[]): R;
  toHaveJsonBodyIncludingAnyMembers(members: any): R;
  toHaveJsonBodySatisfying<E = any>(predicate: (actual: E) => boolean): R;
Run Code Online (Sandbox Code Playgroud)

实现起来有点麻烦,对于所有这些匹配器,我总是以相同的方式实现它:

  • 我解析 JSON 正文
  • 然后我从 jest-extend 调用现有的匹配器

如果我可以制作一个自定义修饰符,而不是编写:

expect(someStringResponse).toHaveJsonBodyIncludingSameMembers(['a', 'b'])
Run Code Online (Sandbox Code Playgroud)

我可以写:

expect(someStringResponse).jsonBody.toIncludeSameMembers(['a', 'b']);
Run Code Online (Sandbox Code Playgroud)

主要好处是我不需要实现所有匹配器,而只需要实现一个修饰符,其职责是解开 JSON 主体,即。解析它。使用此修饰符,可以在展开的值上访问所有现有的匹配器。

关于如何做到这一点有任何线索吗?或者如果有可能的话?

Dub*_*ubl 0

TL;DR:使用目前的库并不容易。

查看源代码,我在方法中发现了以下内容expect

Object.keys(allMatchers).forEach(name => {
    const matcher = allMatchers[name];
    const promiseMatcher = getPromiseMatcher(name, matcher) || matcher;
    expectation[name] = makeThrowingMatcher(matcher, false, '', actual);
    expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual);

    expectation.resolves[name] = makeResolveMatcher(
      name,
      promiseMatcher,
      false,
      actual,
      err,
    );
    expectation.resolves.not[name] = makeResolveMatcher(
      name,
      promiseMatcher,
      true,
      actual,
      err,
    );

    expectation.rejects[name] = makeRejectMatcher(
      name,
      promiseMatcher,
      false,
      actual,
      err,
    );
    expectation.rejects.not[name] = makeRejectMatcher(
      name,
      promiseMatcher,
      true,
      actual,
      err,
    );
  });
Run Code Online (Sandbox Code Playgroud)

看起来 jest 中可用的每个修饰符实际上只是结果期望对象的一个​​属性。每个都是它自己的期望,无论属性设置如何表达修饰符的意图(例如,.not修饰符设置属性以表明它已被否定)。所有匹配器都需要复制到所有这些对象上。

添加自己的修饰符的唯一方法是编写与此类似的代码。您需要循环遍历所有匹配器并根据期望提供您自己的属性。目前没有一种好方法可以针对应用程序中的所有期望执行此操作,因为修改测试应用程序时将创建的所有期望的唯一真正的内置方法是使用扩展方法,它只接受新匹配器。

据我所知,有两种方法可以解决您的问题。您在问题中列出的一个是创建您自己的匹配器。这并不理想,因为您需要在解包 json 对象时创建您想要使用的所有匹配器的新版本。

另一种方法是将展开逻辑移到生产线的前面。我建议您可能会包装该expect函数,大致如下:

Object.keys(allMatchers).forEach(name => {
    const matcher = allMatchers[name];
    const promiseMatcher = getPromiseMatcher(name, matcher) || matcher;
    expectation[name] = makeThrowingMatcher(matcher, false, '', actual);
    expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual);

    expectation.resolves[name] = makeResolveMatcher(
      name,
      promiseMatcher,
      false,
      actual,
      err,
    );
    expectation.resolves.not[name] = makeResolveMatcher(
      name,
      promiseMatcher,
      true,
      actual,
      err,
    );

    expectation.rejects[name] = makeRejectMatcher(
      name,
      promiseMatcher,
      false,
      actual,
      err,
    );
    expectation.rejects.not[name] = makeRejectMatcher(
      name,
      promiseMatcher,
      true,
      actual,
      err,
    );
  });
Run Code Online (Sandbox Code Playgroud)

这使您可以轻松地包含自定义展开逻辑,同时能够使用所有内置修饰符/匹配器等。

您还可以创建一个在 Expect 调用内部调用的函数,例如:

export function expectJson(json: MyCustomJsonType) {
    // Add JSON unwrapping logic here

    return expect(jsonResult);
}
Run Code Online (Sandbox Code Playgroud)