问题描述
我正在使用 Mocha/JSDOM 编写功能规范并使用“chai”进行断言。
当我在服务器上运行时,这工作正常,但问题是当我尝试编写规范时,无法看到更新的 DOM。我通过放置控制台语句检查了 updateContent 函数,我看到了更新的内容,但是一旦控制转移到 spec 函数,我就会看到添加到 JSDOM 的原始 DOM。
这是使用Typescript、js组合、JQuery编写的DOM操作
你能帮我解决我在这里遗漏的问题吗?任何建议/信息都会有所帮助。 我尝试在访问时使用 global
updateContent 函数在 helper.js 文件中可用
function updateContent(year,fetchAge) {
Promise.all([fetchAge("age")]).then((data) => {
console.log("DOM before update ="+$('html').html());
data = data[0].replace(/{{age}}/g,year);
$('.mybenifits .content').html(data);
console.log("DOM after update ="+$('html').html());//Able to see the updated DOM
console.log("$('.mybenifits .content').html="+global.$('.mybenifits .content').html());
}).catch((error) => {
console.log(" ******* Error while fetching age info");
});
}
规范代码片段:helper.test.js
const expect = require('chai').expect;
const assert = require('chai').assert;
const sinon = require('sinon');
const { JSDOM } = require('jsdom');
const { updateContent } = require('../../main/webpack/common/helper.js');
describe('Helper - Example',() => {
it('should update the content',() => {
let htmlStr = '<!doctype html><html><body><div class="mybenifits"><div class="content"></div></div></body></html>';
const jsdom = new JSDOM(htmlStr,{
url: 'http://localhost/',});
//Setting Global variables - start
global.window = jsdom.window;
global.document = jsdom.window.document;
global.$ = require('jquery');
//Setting GLobal variables - end
//Mocking fetchAge function
function fetchAge(featurename) {
return '<p id="fcontent">Current Age is {{age}}</p>';
}
updateContent("2020",fetchAge);
console.log("Total html file ="+$('html').html());
//expect($('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');
//expect(global.$('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');//Not working even if I use global
});
});
解决方法
您的错误可能是因为您的 updateContent
函数异步执行其操作,而其余代码继续运行。这可能意味着 expect
断言在 updateContent
完成规范更新之前被调用。
首先,我再怎么强调都不过分 - 充分了解 Promises
及其工作原理以及 async/await
关键字将非常有用(并且可能是必不可少的)从长远来看。
这是未经测试,但应该让您走上正确的道路。我假设您的 fetchAge()
函数正在返回一个 Promise - 即调用 API 来检索年龄 - 或类似的?。
// Since you're only resolving one promise,you don't need `Promise.all`. `fetchAge` returns a promise and so you can chain `then` directly onto it.
// Also,we can `return` the promise here in case you want to do `updateContent().then(...)` later
function updateContent(year,fetchAge) {
return fetchAge("age")
.then((data) => {
// ...
data = data[0].replace(/{{age}}/g,year);
$('.mybenifits .content').html(data);
// ...
})
.catch(/* ... */);
}
进行上述更改应该允许您像这样进行测试
此外,由于我们正在使用 then
链测试异步代码,因此您需要确保使用 done
参数,以便我们可以在测试运行完成时告诉 jest。见https://jestjs.io/docs/en/asynchronous
it('should update the content',(done) => {
// ...
// Since you're mocking a function that returns a promise,your mock function needs to aswell
function fetchAge(featurename) {
return Promise.resolve('<p id="fcontent">Current Age is {{age}}</p>');
}
updateContent("2020",fetchAge)
.then(() => {
console.log("Total html file ="+$('html').html());
expect($('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');
expect(global.$('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');
done();
})
.catch(error => done(e));
});
编辑:
仅供参考,这是关于如何使用 updateContent
(使用内联类型)重写 async/await
函数的建议。同样,未在本地进行测试,因此可能需要进行一两次调整:)
// Note the `async` keyword
async function updateContent(year: string,fetchAge: () => Promise<string>): Promise<void> {
// Using async/await,we can now use `try/catch` blocks
// instead of `<Promise>.catch()`!
try {
// Note `await`. Since `fetchAge` returns a Promise,we can `await` it!
const data = await fetchAge("age");
const htmlData = data[0].replace(/{{age}}/g,year);
$('.mybenifits .content').html(htmlData);
} catch (error) {
// Add your error handling / logging here
console.error(error);
}
}
然后在您的测试中,您可以在断言 DOM 值匹配之前简单地等待 updateContent
完成!
it('should update the content',async () => {
// ...
await updateContent("2020",fetchAge);
expect($('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');
expect(global.$('.mybenifits .content').html()).to.be.equal('<p id="fcontent">Current Age is 2020</p>');
// ...
});