Jest.js 错误: “ Recected: 序列化为同一个字符串”

我对这个测试有一个奇怪的问题:

交易,测试,交易

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);
});
});
});

一言为定

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)是否与函数相等方面,我似乎有些不理解的地方。

另外,你可能会建议使用 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 | });


118566 次浏览

当比较一个数组中有一个设置了 -1索引的元素的数组时,出现了这个问题(想象一下,除了从0到 N 的数字之外,还要设置其他任何键)。 因此,在下面的场景中可能会出现这个错误:

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

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

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

当我开始测试时,我得到了以下信息:

screenshot of jest results

所以我替换了 toBe方法

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

toStrictEqual进行深入的等式比较

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

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

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

在我的情况下,检查一个代理对象和一个普通对象是一样的。

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({})

当我试图比较数组时遇到了这个问题,其中一个数组从 Graphql 的解析器返回,另一个数组从测试的输入返回。
所有字段都是相同的,只是来自 Graphql 的数组中的条目没有任何 __proto__,而来自我的测试输入的条目有 __proto__: Object,这会导致 严格平等失败,即 因为它检查结构之外的类型。因此,在我的例子中,类型导致失败。把它改成 toEqual解决了这个问题。

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


我开玩笑的时候也遇到过同样的问题。在我的例子中,我是在比较对象数组(基本上是一个模型类)。在那个类中,我将一个函数定义为一个箭头函数。

问题是,在比较它的时候,还要检查箭头函数。由于箭头函数为所有对象创建不同的实例,而普通函数只有一个类范围的实例,因此箭头函数的比较结果为 false。

因此,一个简单的解决方案是将箭头函数转换为类中的普通函数。

用途:

class ClassName {
yourFunc(){
// your code here
}
};

而不是:

class ClassName {
yourFunc = () => {
// your code here
};
};

因此,一旦转换为普通函数,您可以简单地使用 toEqual()进行比较。

如果不能转换成普通函数,可以使用 JSON.stringify()先将它们转换成字符串,然后再使用 toEqual()toBe()

我在比较两个 MongoDb ObjectID 时遇到了类似的问题

expect(`${thisObject._id}`).toEqual(`${thatObject._id}`);