Jest.js 错误:“已接收:序列化为相同的字符串”

Posted

技术标签:

【中文标题】Jest.js 错误:“已接收:序列化为相同的字符串”【英文标题】:Jest.js error: "Received: serializes to the same string" 【发布时间】:2019-11-12 08:29:53 【问题描述】:

我在这个测试中遇到了一个奇怪的问题:

deal.test.js

import Deal from "../src/models/Deal";
import apiProducts from "../__mocks__/api/products";

describe("Deal", () => 
  describe("Deal.fromApi", () => 
    it("takes an api product and returns a Deal", () => 
      const apiDeal = apiProducts[0];
      const newDeal = Deal.fromApi(apiDeal);
      const expected = expectedDeal();
      expect(newDeal).toEqual(expected);
    );
  );
);

Deal.js

export default class Deal 
  // no constructor since we only ever create a deal from Deal.fromApi

  static fromApi(obj: Object): Deal 
    const deal = new Deal();
    deal.id = obj.id;
    deal.name = obj.name;
    deal.slug = obj.slug;
    deal.permalink = obj.permalink;
    deal.dateCreated = obj.date_created;
    deal.dateModified = obj.date_modified;
    deal.status = obj.status;
    deal.featured = obj.featured;
    deal.catalogVisibility = obj.catalog_visibility;
    deal.descriptionhtml = obj.description;
    deal.shortDescriptionHTML = obj.short_description;
    deal.price = Number(obj.price);
    deal.regularPrice = Number(obj.regular_price);
    deal.salePrice = Number(obj.sale_price);
    deal.dateOnSaleFrom = obj.date_on_sale_from;
    deal.dateOnSaleTo = obj.date_on_sale_to;
    deal.onSale = obj.on_sale;
    deal.purchasable = obj.purchasable;
    deal.relatedIds = obj.related_ids;
    deal.upsellIds = obj.upsell_ids;
    deal.crossSellIds = obj.cross_sell_ids;
    deal.categories = obj.categories;
    deal.tags = obj.tags;
    deal.images = obj.images;
    return deal;
  

 descriptionWithTextSize(size: number): string 
    return this.descriptionWithStyle(`font-size:$size`);
  

  descriptionWithStyle(style: string): string 
    return `<div style="$style">$this.description</div>`;
  

  distanceFromLocation = (
    location: Location,
    unit: unitOfDistance = "mi"
  ): number => 
    return distanceBetween(this.location, location);
  ;

  distanceFrom = (otherDeal: Deal, unit: unitOfDistance = "mi"): number => 
    return distanceBetween(this.location, otherDeal.location);
  ;

  static toApi(deal: Deal): Object 
    return  ...deal ;
  

测试失败并出现以下错误:

  ● Deal › Deal.fromApi › takes an api product and returns a Deal

    expect(received).toEqual(expected) // deep equality

    Expected: "catalogVisibility": "visible", "categories": ["id": 15, "name": "New York", "slug": "new-york"], "crossSellIds": [34, 31], "dateCreated": "2019-05-18T17:36:14", "dateModified": "2019-05-18T17:39:02", "dateOnSaleFrom": null, "dateOnSaleTo": null, "descriptionHTML": "<p>Pete's Tavern<br />
    129 E 18th St<br />
    New York, NY 10003</p>
    <p>Weekdays from 4 p.m. to 7 p.m.<br />
    $5 wines and beers</p>
    ", "distanceFromLocation": [Function anonymous], "featured": false, "id": 566, "images": ["alt": "", "date_created": "2019-05-18T17:38:52", "date_created_gmt": "2019-05-18T17:38:52", "date_modified": "2019-05-18T17:38:52", "date_modified_gmt": "2019-05-18T17:38:52", "id": 567, "name": "wine and beers2", "src": "https://tragodeals.com/wp-content/uploads/2019/05/wine-and-beers2.jpg"], "name": "Wines and beers", "onSale": true, "permalink": "https://tragodeals.com/product/wines-and-beers/", "price": 5, "purchasable": true, "regularPrice": 11, "relatedIds": [552, 564, 390, 37, 543], "salePrice": 5, "shortDescriptionHTML": "<p>$5 wines and beers</p>
    ", "slug": "wines-and-beers", "status": "publish", "tags": ["id": 58, "name": "beers", "slug": "beers", "id": 54, "name": "Cocktails", "slug": "cocktails", "id": 45, "name": "drink", "slug": "drink", "id": 57, "name": "wine", "slug": "wine"], "upsellIds": [53]
    Received: serializes to the same string

    > 15 |       expect(newDeal).toEqual(expected);
         |                       ^
      16 |     );
      17 |   );
      18 | );

      at Object.toEqual (__tests__/deal.test.js:15:23)

我插入了这个循环来调查:

for (let key in expected) 
  expect(expected[key]).toEqual(newDeal[key]);

我发现问题出在函数上。所以我把整个测试改成这样:

      for (let key in expected) 
        if (typeof expected[key] === "function") continue;
        expect(expected[key]).toEqual(newDeal[key]);
      
     // expect(newDeal).toEqual(expected);

它通过了,并且在它应该失败的时候也失败了。 (如果您阅读了这个问题的旧版本,我在其中通过了我不理解的测试,那是因为我在循环中是 returning 而我应该是 continueing)。

但我希望能够使用标准断言expect(newDeal).toEqual(expected) 来做到这一点。关于检查类对象 (Deal) 是否与函数相等,我似乎有些不理解。

PS。您可能会建议使用toMatchObject。但是,很遗憾:

  ● Deal › Deal.fromApi › takes an api product and returns a Deal

    expect(received).toMatchObject(expected)

    - Expected
    + Received

    @@ -1,6 +1,6 @@
    - Deal 
    + Object 
        "address": "129 E 18th St New York, NY 10003",
        "catalogVisibility": "visible",
        "categories": Array [
          Object 
            "id": 15,

      13 |         expect(expected[key]).toEqual(newDeal[key]);
      14 |       
    > 15 |       expect(newDeal).toMatchObject(expected);
         |                       ^
      16 |     );
      17 |   );
      18 | );

【问题讨论】:

嗨,乔纳森,您是否可以传递一个 apiProducts 样本来重现此错误?您能否提供您在控制台中遇到的确切错误? 我注意到你的构造函数 Object.assign(this, obj: Object) 【参考方案1】:

与其他同事类似,我在数组比较中遇到了这个问题,我基本上是在测试一个函数,它可以获取数组中最大的字符串,此外,如果超过 1 个字符串与可能的最大长度匹配,它应该返回一个数组。

当我开始测试时,我收到以下消息:

所以我替换了toBe方法

expect(function(array1)).toBe('one result')

toStrictEqual 进行深度相等比较

expect(function(array2)).toStrictEqual(['more than one', 'more than one']);

【讨论】:

【参考方案2】:

当尝试比较一个数组中存在一个索引为 -1 的元素的数组时遇到了这个问题(想象一下要设置的任何其他键,除了从 0 到 N 的数字)。 所以你可能会在以下场景中出现这个错误:

const arr = [1, 2]
arr[-1] = 'foo'
expect(arr).toEqual([1, 2])

它们都序列化为相同的字符串,但它们不相等。

【讨论】:

我的问题是我们在数组上放置了一个静态属性,类似于这个【参考方案3】:

我有一个类似的情况,对象有一个 base64 编码的字符串,我管理测试以使用 JSON.stringify 比较对象的序列化:

expect(JSON.stringify(newDeal)).toMatchObject(JSON.stringify(expected));

【讨论】:

expect(newDeal).toMatchObject(expected) 可以。无需转换为字符串。 @AVC 你确定这是正确的吗?开玩笑说这是关于expect(newDeal).toMatchObject(expected)It will match received objects with properties that are not in the expected object.。当我尝试它时,它对我不起作用。为了使toEqual() 比较成功,我必须在等式两边都做JSON.stringify()【参考方案4】:

在我的情况下,我在检查代理对象和常规对象时非常平等。

const proxyObject = new Proxy(, 
    get: function(target, prop) 
        return Object.hasOwnProperty.call(target, prop) ? target[prop] : '';
    
)
expect(proxyObject).toEqual()
// Expected: 
// Received: serializes to the same string

应该是:

expect(proxyObject).toMatchObject()

【讨论】:

【参考方案5】:

当我尝试比较一个数组从 Graphql 的解析器返回而另一个数组来自我的测试输入的数组时,我遇到了这个问题。 所有字段都是相同的,除了来自 Graphql 的数组中的条目没有任何 __proto__ 而来自我的测试输入的条目有 __proto__: Object 并且导致 toStrictEqual 失败,因为它检查结构以外的类型。所以,在我的情况下,类型导致失败。将其更改为 toEqual 即可解决问题。

                expect(res.data.myMutation.values).toEqual(
                    testInput.values,
                );

【讨论】:

以上是关于Jest.js 错误:“已接收:序列化为相同的字符串”的主要内容,如果未能解决你的问题,请参考以下文章

Jest.js 强制窗口未定义

观看并重新运行 Jest JS 测试

Jest.js强制窗口未定义。

当预期/接收的值是对象时,Jest.js 测试不通过

如何模拟 ES6 超类并用 jest.js 监视它?

是否有忽略 jest.js 中元素位置的数组相等匹配函数?