需Jasmine测试帮助:如何为嵌套each循环的jQuery逻辑编写测试
如何为嵌套jQuery $.each循环编写Jasmine测试并使用afterEach?
我来帮你一步步搞定这个测试的写法,顺便讲清楚afterEach的用法。首先先把你的代码补全(看起来你没写完判断逻辑,我先按常见的过滤场景补全),然后再写测试用例。
你的原始代码(补全后):
HTML结构
<div id="mj"> <div class="commonclass"> Item 1 </div> <div class="commonclass"> Item 2 </div> <div class="commonclass"> Item 3 </div> </div>
jQuery逻辑(补全过滤逻辑)
var filterArray = ['Item', 'Block', 'Item 3']; $.each($('.commonclass'), function(i, v) { var matching = false; $.each(filterArray, function(j, w) { // 判断元素文本是否包含filter项 if ($(v).text().trim().includes(w)) { matching = true; return false; // 找到匹配就跳出内层循环,提升效率 } }); // 根据匹配结果控制元素显示/隐藏 matching ? $(v).show() : $(v).hide(); });
第一步:把业务逻辑封装成函数
为了方便测试,最好把这段过滤逻辑封装成一个可调用的函数,而不是直接写在全局作用域里:
function filterItems(filterArray) { $.each($('.commonclass'), function(i, v) { var matching = false; $.each(filterArray, function(j, w) { if ($(v).text().trim().includes(w)) { matching = true; return false; } }); matching ? $(v).show() : $(v).hide(); }); }
第二步:编写Jasmine测试用例
核心思路
- 用
beforeEach在每个测试前挂载干净的DOM结构 - 用
afterEach在每个测试后清理DOM,避免污染后续测试 - 针对不同的过滤条件,验证元素的显示/隐藏状态是否符合预期
- 可以用Jasmine的spy来验证循环的执行次数,确保逻辑覆盖完整
完整测试代码
describe('嵌套$.each的元素过滤逻辑', function() { // 每个测试前准备DOM环境和函数引用 beforeEach(function() { // 把测试用的HTML插入到页面中 $('body').append(` <div id="mj"> <div class="commonclass"> Item 1 </div> <div class="commonclass"> Item 2 </div> <div class="commonclass"> Item 3 </div> </div> `); // 把过滤函数绑定到this上,方便在测试用例中调用 this.filterItems = filterItems; }); // 每个测试结束后清理DOM afterEach(function() { // 移除我们挂载的测试DOM,保证下一个测试的环境是干净的 $('#mj').remove(); }); // 测试过滤逻辑的正确性 it('应该正确显示匹配过滤条件的元素,隐藏不匹配的', function() { // 测试场景1:过滤包含"Item"或"Block"的元素 this.filterItems(['Item', 'Block']); expect($('.commonclass:eq(0)').is(':visible')).toBe(true); // Item1包含Item expect($('.commonclass:eq(1)').is(':visible')).toBe(true); // Item2包含Item expect($('.commonclass:eq(2)').is(':visible')).toBe(true); // Item3包含Item // 测试场景2:只过滤"Block",所有元素都不匹配 this.filterItems(['Block']); expect($('.commonclass:eq(0)').is(':visible')).toBe(false); expect($('.commonclass:eq(1)').is(':visible')).toBe(false); expect($('.commonclass:eq(2)').is(':visible')).toBe(false); // 测试场景3:精确匹配"Item 3" this.filterItems(['Item 3']); expect($('.commonclass:eq(0)').is(':visible')).toBe(false); expect($('.commonclass:eq(1)').is(':visible')).toBe(false); expect($('.commonclass:eq(2)').is(':visible')).toBe(true); }); // 测试循环的执行情况,确保逻辑覆盖完整 it('应该遍历所有外层元素,找到匹配后跳出内层循环', function() { // 监听$.each方法,同时保留原函数功能 spyOn($, 'each').and.callThrough(); this.filterItems(['Item', 'Block']); // 外层$.each调用1次(处理3个.commonclass元素) // 内层每个元素找到匹配后就跳出,所以内层调用3次(每个元素各1次) // 总调用次数是1 + 3 = 4次 expect($.each.calls.count()).toBe(4); }); });
关于afterEach的说明
这里的afterEach函数会在每个测试用例执行完毕后自动运行,它的作用是清理我们在beforeEach中挂载的DOM元素。如果没有这一步,前一个测试留下的#mj元素会留在页面里,可能导致下一个测试的DOM环境混乱,比如重复选择元素、状态污染等问题。简单来说,它就是用来保证每个测试用例都在独立、干净的环境中运行。
内容的提问来源于stack exchange,提问作者Mahendran
相关产品推荐
相关产品推荐

