Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Jest模拟JavaScript窗口对象?_Javascript_Mocking_Jestjs - Fatal编程技术网

如何使用Jest模拟JavaScript窗口对象?

如何使用Jest模拟JavaScript窗口对象?,javascript,mocking,jestjs,Javascript,Mocking,Jestjs,我需要测试在浏览器中打开新选项卡的功能 openStatementsReport(contactIds) { window.open(`a_url_${contactIds}`); } 我想模拟窗口的open函数,以便验证是否将正确的URL传递给open函数 使用玩笑,我不知道如何模拟窗口。我试图设置窗口。用模拟函数打开,但这种方法不起作用。下面是测试用例 it('correct url is called', () => { window.open = jest.fn();

我需要测试在浏览器中打开新选项卡的功能

openStatementsReport(contactIds) {
  window.open(`a_url_${contactIds}`);
}
我想模拟窗口的
open
函数,以便验证是否将正确的URL传递给
open
函数

使用玩笑,我不知道如何模拟
窗口
。我试图设置
窗口。用模拟函数打开
,但这种方法不起作用。下面是测试用例

it('correct url is called', () => {
  window.open = jest.fn();
  statementService.openStatementsReport(111);
  expect(window.open).toBeCalled();
});
但它给了我一个错误

expect(jest.fn())[.not].toBeCalled()
jest.fn()值必须是模拟函数或间谍。
收到:
函数:[函数匿名]

我应该如何处理测试用例?

而不是
窗口
使用
全局

it('correct url is called', () => {
  global.open = jest.fn();
  statementService.openStatementsReport(111);
  expect(global.open).toBeCalled();
});
你也可以试试

const open = jest.fn()
Object.defineProperty(window, 'open', open);
您可以尝试以下方法:

import * as _Window from "jsdom/lib/jsdom/browser/Window";

window.open = jest.fn().mockImplementationOnce(() => {
    return new _Window({ parsingMode: "html" });
});

it("correct url is called", () => {
    statementService.openStatementsReport(111);
    expect(window.open).toHaveBeenCalled();
});

我们还可以在
setupTests

// setupTests.js
global.open = jest.fn()
并在实际测试中使用
global
调用它:

// yourtest.test.js
it('correct url is called', () => {
    statementService.openStatementsReport(111);
    expect(global.open).toBeCalled();
});

在Jest配置中,添加setupfileafterenv:[“/setupTests.js”],创建该文件,并添加要在测试之前运行的代码:

// setupTests.js
window.crypto = {
   .....
};

参考资料:

以下方法对我有效。这种方法允许我测试一些应该在浏览器和Node.js中都能工作的代码,因为它允许我将
window
设置为
undefined

这是玩笑24.8(我相信):


如果类似于上的窗口位置问题,您可以尝试(调整):


有两种方法可以开玩笑地模仿globals:

  • 使用
    mockImplementation
    方法(最滑稽的方式),但它只适用于那些由
    jsdom
    提供默认实现的变量<代码>窗口。打开
  • 是其中之一:

    test('it work',()=>{
    //设置
    const mockedOpen=jest.fn();
    //如果不制作副本,将出现循环依赖性问题
    常量originalWindow={…window};
    const windowSpy=jest.spyOn(全局,“窗口”、“获取”);
    windowSpy.mockImplementation(()=>({
    …originalWindow,//以防需要其他窗口属性
    打开:mockedOpen
    }));
    //测验
    statementService.openStatementsReport(111)
    expect(mockedOpen).toBeCalled();
    //清理
    windowSpy.mockRestore();
    });
    
  • 将该值直接指定给全局属性。这是最简单的,但它可能会触发某些
    window
    变量的错误消息,例如
    window.href

    test('it work',()=>{
    //设置
    const mockedOpen=jest.fn();
    const originalOpen=window.open;
    window.open=mockedOpen;
    //测验
    statementService.openStatementsReport(111)
    expect(mockedOpen).toBeCalled();
    //清理
    window.open=originalOpen;
    });
    
  • 不要直接使用全局变量(需要一些重构)

    与直接使用全局值不同,从另一个文件导入它可能更干净,因此使用Jest进行模拟将变得微不足道

  • 文件./test.js
    jest.mock('./fileWithGlobalValueExported.js');
    从“/fileWithGlobalValueExported.js”导入{windowOpen};
    从“/testedFile.js”导入{statementService};
    //测验
    测试('it works',()=>{
    statementService.openStatementsReport(111)
    expect(windowOpen).toBeCalled();
    });
    
    文件。/fileWithGlobalValueExported.js
    export const windowOpen=window.open;
    
    文件./testedFile.js
    从“/fileWithGlobalValueExported.js”导入{windowOpen};
    导出常量语句服务={
    OpenStatementReport(联系人ID){
    windowOpen(`a_url_${contactIds}`);
    }
    }
    
    我找到了一个简单的方法:删除并替换

    description('testcase',()=>{
    const{open}=窗口;
    以前(()=>{
    //删除现有的
    删除窗口。打开;
    //替换为自定义值
    window.open=jest.fn();
    //也为“地点”工作,例如:
    //window.location={origin:'http://localhost:3100' };
    });
    毕竟(()=>{
    //还原原始
    window.open=打开;
    });
    它('调用了正确的url',()=>{
    openStatementsReport(111);
    期待(窗口.打开).toBeCalled();//快乐,快乐
    });
    });
    
    在我的组件中,我需要访问
    窗口.位置.搜索
    。这就是我在玩笑测试中所做的:

    Object.defineProperty(global, "window", {
      value: {
        location: {
          search: "test"
        }
      }
    });
    
    如果不同测试中的窗口属性必须不同,我们可以将窗口模拟放入函数中,并使其可写,以便覆盖不同测试:

    function mockWindow(search, pathname) {
      Object.defineProperty(global, "window", {
        value: {
          location: {
            search,
            pathname
          }
        },
        writable: true
      });
    }
    
    并在每次测试后重置:

    afterEach(() => {
      delete global.window.location;
    });
    

    我直接将
    jest.fn()
    分配给
    窗口。打开

    window.open=jest.fn()
    //…代码
    期望(窗口打开)。已被调用时间(1)
    预期(window.open).toHaveBeenCalledWith('/new tab','\u blank'))
    
    可以测试它:

    describe('TableItem Components', () => {
        let open_url = ""
        const { open } = window;
        beforeAll(() => {
            delete window.open;
            window.open = (url) => { open_url = url };
        });
        afterAll(() => {
            window.open = open;
        });
        test('string type', async () => {
            wrapper.vm.openNewTab('http://example.com')
            expect(open_url).toBe('http://example.com')
        })
    })
    

    试过了,但对我不起作用。我的情况很奇怪,嘲弄在本地有效,但不适用于特拉维斯的公关合并。。。知道吗?@AlexJM你也有同样的问题吗?介意分享一下你是如何模拟窗口对象的吗?我只是在我的测试中定义了window.property@Andreas有没有办法将窗口模拟为未定义的谢谢!几个小时后,我只需要为
    全局
    更改
    窗口
    ,这比
    对象要好得多。定义属性
    ,因为这允许在模拟时不影响其他测试。这应该是可接受的答案,因为它模拟/间谍,而不是更改实际的全局属性。这是最好的方法!
    afterEach(() => {
      delete global.window.location;
    });
    
    describe('TableItem Components', () => {
        let open_url = ""
        const { open } = window;
        beforeAll(() => {
            delete window.open;
            window.open = (url) => { open_url = url };
        });
        afterAll(() => {
            window.open = open;
        });
        test('string type', async () => {
            wrapper.vm.openNewTab('http://example.com')
            expect(open_url).toBe('http://example.com')
        })
    })