Javascript 开玩笑地嘲笑全球人
是否有任何方式可以模拟全局对象,例如Javascript 开玩笑地嘲笑全球人,javascript,unit-testing,dependencies,jestjs,babel-jest,Javascript,Unit Testing,Dependencies,Jestjs,Babel Jest,是否有任何方式可以模拟全局对象,例如navigator,或Image*?我基本上已经放弃了这一点,并将其留给了一系列可模仿的实用工具方法。例如: // Utils.js export isOnline() { return navigator.onLine; } 测试这个微小的函数很简单,但很粗糙,根本不确定。我可以得到75%的路,但这是我能做到的: // Utils.test.js it('knows if it is online', () => { const {
navigator
,或Image
*?我基本上已经放弃了这一点,并将其留给了一系列可模仿的实用工具方法。例如:
// Utils.js
export isOnline() {
return navigator.onLine;
}
测试这个微小的函数很简单,但很粗糙,根本不确定。我可以得到75%的路,但这是我能做到的:
// Utils.test.js
it('knows if it is online', () => {
const { isOnline } = require('path/to/Utils');
expect(() => isOnline()).not.toThrow();
expect(typeof isOnline()).toBe('boolean');
});
另一方面,如果我不介意这个间接寻址,我现在可以通过以下实用程序访问navigator
:
// Foo.js
import { isOnline } from './Utils';
export default class Foo {
doSomethingOnline() {
if (!isOnline()) throw new Error('Not online');
/* More implementation */
}
}
…然后像这样进行决定性的测试
// Foo.test.js
it('throws when offline', () => {
const Utils = require('../services/Utils');
Utils.isOnline = jest.fn(() => isOnline);
const Foo = require('../path/to/Foo').default;
let foo = new Foo();
// User is offline -- should fail
let isOnline = false;
expect(() => foo.doSomethingOnline()).toThrow();
// User is online -- should be okay
isOnline = true;
expect(() => foo.doSomethingOnline()).not.toThrow();
});
在我使用过的所有测试框架中,Jest感觉是最完整的解决方案,但每当我编写笨拙的代码只是为了使其可测试时,我感觉我的测试工具让我失望
这是唯一的解决方案还是我需要重新布线
*不要傻笑<代码>图像非常适合ping远程网络资源。由于每个测试套件都运行自己的环境,您可以通过覆盖全局来模拟全局。所有全局变量都可以通过
global
命名空间访问:
global.navigator = {
onLine: true
}
覆盖仅对当前测试有效,不会影响其他测试。这也是处理
Math.random
或Date.now
的好方法
请注意,通过对其进行一些更改,您可能不得不像这样模拟全局变量:
Object.defineProperty(globalObject, key, { value, writable: true });
Jest可能在编写接受的答案后发生了更改,但Jest似乎不会在测试后重置全局设置。请参阅附件中的测试用例 据我所知,解决这个问题的唯一方法是使用
afterEach()
或afterAll()
来清理分配给global
的任务
let originalGlobal = global;
afterEach(() => {
delete global.x;
})
describe('Scope 1', () => {
it('should assign globals locally', () => {
global.x = "tomato";
expect(global.x).toBeTruthy()
});
});
describe('Scope 2', () => {
it('should not remember globals in subsequent test cases', () => {
expect(global.x).toBeFalsy();
})
});
如果有人需要用静态属性模拟全局,那么我的示例应该会有所帮助:
beforeAll(() => {
global.EventSource = jest.fn(() => ({
readyState: 0,
close: jest.fn()
}))
global.EventSource.CONNECTING = 0
global.EventSource.OPEN = 1
global.EventSource.CLOSED = 2
})
如果您使用的是
react testing library
,并且使用了该库提供的cleanup
方法,则一旦文件中的所有测试运行完毕,它将删除该文件中的所有全局声明。这将不会继续进行任何其他测试
例如:
import { cleanup } from 'react-testing-library'
afterEach(cleanup)
global.getSelection = () => {
}
describe('test', () => {
expect(true).toBeTruthy()
})
正确的方法是使用。这里的其他答案,即使它们工作,也不要考虑清理和污染全局范围。< /P>
//以前
开玩笑
.spyOn(窗口“导航器”、“获取”)
.mockImplementation(()=>{…})
//毕竟
开玩笑。恢复记忆();
如果需要在window.navigator
上分配和重新分配属性值,则需要:
window.navigator
上的值时出错,因为这些值大多是只读的
let mockUserAgent = "";
beforeAll(() => {
Object.defineProperty(global.navigator, "userAgent", {
get() {
return mockUserAgent;
},
});
});
it("returns the newly set attribute", () => {
mockUserAgent = "secret-agent";
expect(window.navigator.userAgent).toEqual("secret-agent");
});
global
是否与浏览器中的window
相同?是的,您可以在那里设置内容。但可能并非所有出现在窗口中的内容也出现在全局中。这就是为什么我不使用global.navigator.onLine
的原因,因为我不确定global
中是否有navigator
对象。请注意,作为一般做法,现在并非所有全局属性都是可覆盖的。有些测试为可写false,将忽略值更改尝试。“覆盖仅对您当前的测试有效,不会影响其他测试。”-是否有记录在案?@JamesPlayer我可以肯定地确认,一个测试中的覆盖将影响其他测试。至少在一个测试套件中。我经历了相同的行为,在每次测试运行后,我的全局变量没有重置。调用jest.clearAllMocks()代码>在afterEach()
帮助我。。。从'@angular/compiler/src/util'导入{global}我相信这是自@testing library/react
v9.0以来的默认行为,并且在v10.0中删除每个功能后的清理——您说“一旦文件中的所有测试都运行完毕”,但每次之后都使用,这与我所说的相反“属性导航器没有访问类型get”-这应该是哪个版本的Jest工作?