如何模拟用户创建的窗口属性?

时间:2019-02-06 20:10:57

标签: javascript mocking

我有一个发出API请求的javascript实用程序文件。它的顶部有两个条件依赖于window.VarA和window.VarB。其中VarA和VarB是我们的软件赋予窗口的变量。如果设置了它们,则将运行条件代码中的代码。由于此文件实际上并未渲染窗口,因此我无法将这些属性设置为任何值,也无法在条件内获取代码覆盖率。

我尝试渲染默认窗口,但这似乎不起作用。我有Jest和酶。

我正在测试的对象中的代码如下所示:

let param = "";
let url = "";
if(window.VarA !== underfined){
     param = window.VarA; <<--need coverage here
}
if(window.VarB !== underfined){
     url = window.VarB; <<--need coverage here
}

有什么方法可以模拟这些窗口属性以进行测试?

2 个答案:

答案 0 :(得分:1)

<!DOCTYPE html> <html> <head> <title>Track your favorite websites</title> <meta name="author" content="791894" > <meta name="date" content="2019-03-01T16:33:43-0700" > <script type="text/javascript" src="partA.js"></script> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h2>Please Complete the Following Registration</h2> <form id="register" onsubmit="addToArray();return false"> <table> <tr><td>Enter Your URL Here</td><td><input type="text" id="url" size="25" required="true"></td></tr> </table> <input type="submit" value="Submit"> </form> <h3><span id="showlist"></span></h3> </body> </html>的默认test environment是使用Jest的类似浏览器的环境,它提供了jsdom对象。

如果测试环境为window,则jsdom对象可以作为windowwindow访问。

global上设置变量就像执行以下操作一样容易:

window

棘手的部分是在代码运行之前 设置这些变量。

考虑以下window.VarA = 'foo'; // global.VarA works as well window.VarB = 'bar'; // global.VarB works as well 模块:

config.js

如果您使用let param = ""; let url = ""; if (window.VarA !== undefined) { param = window.VarA; } if (window.VarB !== undefined) { url = window.VarB; } export const config = { param, url } ,则代码将不会运行,直到需要该模块为止。允许进行如下测试:

require

另一方面,如果您使用test('setting window variables', () => { window.VarA = 'foo'; // global.VarA works as well window.VarB = 'bar'; // global.VarB works as well const { config } = require('./config'); // now require the module expect(config.param).toBe('foo'); // SUCCESS expect(config.url).toBe('bar'); // SUCCESS }); ,则变量必须在import之前 进行定义,测试从imports are hoisted开始运行,并在测试代码运行:

window

因此,如果您使用的是import { config } from './config'; // this runs first test('setting window variables', () => { window.VarA = 'foo'; // <= this doesn't affect config window.VarB = 'bar'; // <= this doesn't affect config expect(config.param).toBe('foo'); // FAIL expect(config.url).toBe('bar'); // FAIL }); ,那么在测试开始运行之前,您需要使用类似setupFilesAfterEnv的方法来设置import变量:

window

答案 1 :(得分:1)

Brian Adams的回答很好。作为setupFilesAfterEnv的替代方案,您还可以在测试主体中动态导入模块:

test('setting window variables', async () => {
  window.VarA = 'foo';
  window.VarB = 'bar';
  const { config } = await import('./config');
  expect(config.param).toBe('foo');  // SUCCESS
  expect(config.url).toBe('bar');  // SUCCESS
});

请注意,window变量无法重新分配-进一步的测试仍将首先引用原始分配的值,否则会产生副作用。例如:

test('setting window variables', async () => { ... });

test('setting a different window variable A', async () => {
  window.VarA = 'baz';
  const { config } = await import('./config');
  expect(config.param).toBe('baz');  // FAIL, it's still 'foo'
});

因此,为了避免精神错乱,值得将window的作业移至beforeAllbeforeEach中:

beforeAll(() => {
  window.VarA = 'foo';
  window.VarB = 'bar';
});

test('setting window variables', async () => {
  const { config } = await import('./config');
  expect(config.param).toBe('foo');
  expect(config.url).toBe('bar');   
});