[英]How do I run a test in Jest when the file I'm testing starts by grabbing an element from the unloaded DOM?
I am new to testing and Jest.我是测试和开玩笑的新手。 I am trying to run a test in app6.test.js.我正在尝试在 app6.test.js 中运行测试。 It's my first one.这是我的第一个。
The expectation is that my test either passes or fails after running correctly .期望是我的测试在正确运行后通过或失败。 Currently, it's failing.目前,它正在失败。 I am confident that I know why.我有信心知道为什么。 I'll get to that in a sec.我会在几秒钟内解决这个问题。
Here is the error I get when the test fails:这是测试失败时我得到的错误:
FAIL maze/app6.test.js
● Test suite failed to run
TypeError: Cannot read property 'style' of null
6 | const yRows = height / cube;
7 | const cols = width / cube;
> 8 | maze.style.width = width + 'px';
| ^
9 | maze.style.height = height + 'px';
10 |
11 | const trees = [];
at Object.<anonymous> (maze/app6.js:8:6)
at Object.<anonymous> (maze/app6.test.js:7:37)
Test Suites: 1 failed, 1 total
So, I believe it's failing because, as I understand it, Jest goes into the file containing the to-be-tested code, and tries to run the file.所以,我相信它失败了,因为据我了解,Jest 进入包含待测试代码的文件,并尝试运行该文件。 But in my case it can't do that because my file tries to load a DOM element, and there is no DOM loaded by any browser.但在我的情况下,它不能这样做,因为我的文件试图加载一个 DOM 元素,并且任何浏览器都没有加载 DOM。
The closest thing I have to a solution is trying to open the webpage which runs the script using Puppeteer, and then running the function:我最接近解决方案的方法是尝试打开使用 Puppeteer 运行脚本的网页,然后运行 function:
/**
* @jest-environment jsdom
*/
const puppeteer = require("puppeteer")
const { checkIfCellsAreAdjacent } = require("./app6");
test("should output true or false", async () => {
const browser = await puppeteer.launch({
headless: false,
})
const page = await browser.newPage();
await page.goto(`C:\\Users\\myName\\2020-Coding-Projects\\mentoring\\kruskel\\maze\\maze-4.html`)
const boolean = checkIfCellsAreAdjacent({ x: 29, y: 30 }, { x: 30, y: 30 });
expect(boolean).toBe(true);
});
But whatever I did there, it didn't work.但无论我在那里做什么,它都没有奏效。
Now, I could go through app6.js and surgically remove the line that says let maze = document.getElementById('maze');
现在,我可以通过 app6.js 删除 go 并通过手术删除let maze = document.getElementById('maze');
的行。 and everything that references it afterwards.以及之后引用它的所有内容。 But that requires going thru a lot of code that I'd rather leave integrated.但这需要通过大量我宁愿保持集成的代码。 There must be an alternative.必须有替代方案。
Re: research, I've been to about 6-7 different sites that I found by googling "jest typeerror cannot read property 'style' of null".回复:研究,我去过大约 6-7 个不同的网站,通过谷歌搜索“开玩笑的 typeerror 无法读取 null 的属性 'style'”。 These links talk about, eeeh, not particularly similar problems (though they are in the same language at least).这些链接谈论,eeeh,不是特别相似的问题(尽管它们至少使用相同的语言)。 They lead me to the concept of "mocking" an element but apparently I didn't do it correctly...他们把我引向了“嘲笑”一个元素的概念,但显然我没有正确地做到这一点......
Help.帮助。 Please and thank you.谢谢,麻烦您了。
Edit: so no one has to ask... the top 8 lines of app6.js:编辑:所以没有人要问... app6.js 的前 8 行:
let maze = document.getElementById('maze');
const height = 900;
const width = 1500;
const cube = 50 // cell size = 20px by 20px. Hence cube
const yRows = height / cube;
const cols = width / cube;
maze.style.width = width + 'px';
Jest DOM and Puppeteer tests are orthogonal. Jest DOM 和 Puppeteer 测试是正交的。 If it's the implementation that is tested, everything that involves puppeteer
doesn't belong to this test.如果是被测试的实现,所有涉及puppeteer
的东西都不属于这个测试。
It appears that the problem with app6.js is that it accesses DOM on top level rather than functions that need it, this requires mocks to be set up before the module is imported, so it needs to be imported inside a test rather that on top level.看来 app6.js 的问题在于它访问顶层的 DOM 而不是需要它的函数,这需要在导入模块之前设置模拟,因此需要在测试中导入它而不是在顶层等级。 jest.isolateModules
or a combination of require
and jest.resetModules
is appropriate to test a module without interfering with other tests. jest.isolateModules
或require
和jest.resetModules
的组合适用于在不干扰其他测试的情况下测试模块。
maze
element needs to be mocked, either by mocking document.getElementById
call or by putting it to DOM. maze
元素需要通过 mocking document.getElementById
调用或将其放入 DOM 来模拟。 The former option requires to reset the mock after a test;前一个选项需要在测试后重置模拟; this should be preferably done always with restoreMocks
configuration option.最好始终使用restoreMocks
配置选项来完成此操作。 The latter requires to clean up after a test:后者需要在测试后进行清理:
let maze;
let app6;
beforeEach(() => {
maze = document.createElement('div');
maze.setAttribute('id', 'maze');
document.body.appendChild(maze);
jest.isolateModules(() => {
app6 = require('./app6');
});
});
test("should output true or false", () => {
const boolean = app6.checkIfCellsAreAdjacent({ x: 29, y: 30 }, { x: 30, y: 30 });
expect(boolean).toBe(true);
});
afterEach(() => {
document.body.removeChild(maze);
});
I found a less-than-perfect solution to my problem.我找到了一个不太完美的解决方案来解决我的问题。
The solution was to move all my functions from app6.js to a separate file, then import the function I want to test from that separate file.解决方案是将我的所有函数从 app6.js 移到一个单独的文件中,然后从那个单独的文件中导入我想测试的 function。 That way I avoid running the code that reaches out to the DOM entirely.这样我就可以避免运行完全触及 DOM 的代码。
Ideally someone will tell me how to run the code without moving code around in my files: in other words, I want it all to run in one file.理想情况下,有人会告诉我如何运行代码而不在我的文件中移动代码:换句话说,我希望它全部在一个文件中运行。 However this solution is OK for now.但是,此解决方案目前还可以。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.