Unit testing 模具、传单、单元测试组件,给出类型错误:无法读取属性';设备xdpi';未定义的

Unit testing 模具、传单、单元测试组件,给出类型错误:无法读取属性';设备xdpi';未定义的,unit-testing,leaflet,jestjs,jsdom,stenciljs,Unit Testing,Leaflet,Jestjs,Jsdom,Stenciljs,因此,我们正在开发一个Stenciljs组件,该组件包装传单地图并添加一些附加功能 现在很明显,我们不想或不需要测试传单,而是只测试包装器组件中的部分 因此,使用测试示例,我们创建了我们的测试 import { LeMap } from "./le-map"; describe("Map component tests", () => { it("Should build the map component", async () => { const map

因此,我们正在开发一个Stenciljs组件,该组件包装传单地图并添加一些附加功能

现在很明显,我们不想或不需要测试传单,而是只测试包装器组件中的部分

因此,使用测试示例,我们创建了我们的测试

import { LeMap } from "./le-map";

describe("Map component tests", () => {
    it("Should build the map component", async () => {
        const map = new LeMap();
        expect(map).not.toBeNull();
    });     
});
尝试加载组件并测试公共函数,但我们得到

TypeError: Cannot read property 'deviceXDPI' of undefined

> 1 | import {Component, Element, Listen, Method, Prop, Watch} from 
'@stencil/core';
> 2 | import L from 'leaflet';
    | ^
  3 |
  4 | @Component({
  5 |       shadow: false,
我们认为这条消息是因为测试试图呈现传单,并且因为它不是真正的浏览器,它无法检测到视图,因此抛出此错误,因此我们尝试在测试中模拟传单,但仍然遇到相同的问题

我们尝试使用笑话模拟来模拟传单模块

jest.genMockFromModule('leaflet');
但这没有任何区别

我唯一的想法是将逻辑从组件中分离出来,但这感觉是错误的,因为我们这样做只是为了测试

使用的版本有:传单:1.3.4、@stencil:0.15.2、笑话:23.4.2

还有其他建议吗

感谢@skyboyer的建议,通过进一步的调查,我找到了这行传单核心浏览器.js文件

export var retina = (window.devicePixelRatio || (window.screen.deviceXDPI/window.screen.logicalXDPI)) > 1;
这一行是传单core browser.js文件

export var retina = (window.devicePixelRatio || (window.screen.deviceXDPI/window.screen.logicalXDPI)) > 1;
但是我无法模拟window的screen属性,因为我得到了以下错误

[ts] Cannot assign to 'screen' because it is a constant or a read-only property, 
因此,我尝试以下方法

const screen =  {
    deviceXDPI:0,
    logicalXDPI:0
}

Object.defineProperty(window, 'screen', screen);
Object.defineProperty(window, 'devicePixelRatio', 0);
同样的错误,完全忽略了这一点,所以我尝试跳过导出

jest.spyOn(L.Browser,'retina').mockImplementation(() => false);
也没有快乐,所以努力了

L.Browser.retina = jest.fn(() => false); 
但get it告诉我它是一个常量,不能更改(但其含义是这样的)_(ツ)_/”)

还有什么我可以试试的吗

进一步更新, 我试图模仿窗户,但不幸的是,这并不能解决它

const screenMock = {            
    deviceXDPI: 0,
    logicalXDPI: 0          
}

const windowMock = {
    value: {
        'devicePixelRatio': 0,
        'screen': screenMock
    }
}
Object.defineProperty(global, 'window', windowMock);
如果我将此记录在控制台日志中,我将获得正确的属性,但只要我测试组件的实例化,它就会失败

  TypeError: Cannot read property 'deviceXDPI' of undefined
阅读传单似乎并没有检查DOM,只是尝试渲染,我看不到这一点,我看到了一个传单无头包,但我不知道如何将它们交换出来只是为了测试


我想我需要考虑另一种测试策略,可能是量角器。

找到了一个解决方案,尚未完全测试,但测试通过。 我通过创建一个

__mocks__ 
与节点\模块目录处于同一级别的目录。 在其中创建了一个名为传单.js的文件。它只是包含一个简单的文件

'use strict';

const leaflet = jest.fn();

module.exports = leaflet;
然后在我的测试文件(le map.spec.ts)中,我刚刚添加了

jest.mock('leaflet')
进口前

现在我的考试通过了

我试着在测试本身中这样做,但这只是给了我同样的错误,它必须是加载序列中的某个东西,这意味着它必须事先手动模拟


希望这对其他人有帮助,这几周来一直让我发疯。

你可以从模仿这个方法开始:但我不确定你需要模仿多少方法来运行测试