Nightwatch中.element()始终获取数组最后值的问题求助
解决Nightwatch循环中异步回调的变量引用问题
我太懂你这种头疼的感觉了——明明循环里依次填对了每个RSS链接,结果所有回调里的URL全变成数组最后一个,测试报告根本分不清哪个链接是好是坏。其实这是JavaScript里典型的闭包作用域陷阱:你用var声明的urlToTest是函数级作用域,所有异步回调(也就是.element()的那个回调函数)共享同一个变量引用,等回调真正执行的时候,循环早就跑完了,urlToTest自然就停在最后一个元素上了。
下面给你几个靠谱的解决方案,按从简单到兼容旧环境的顺序排列:
方案1:用ES6的let替代var(最省心)
把循环里的变量声明改成let就行,因为let是块级作用域,每次循环迭代都会创建一个独立的urlToTest实例,回调会绑定当前迭代的变量:
// RSS Feeds for (let i = 0; i < rssFeeds.length; i++) { let urlToTest = rssFeeds[i].toString(); // 用let声明,每次迭代生成独立变量 browser .url('https://validator.w3.org/feed/') .waitForElementVisible('body', 'W3C RSS Validator page loaded... https://validator.w3.org/feed/ \n') .setValue('#url', urlToTest) .click('a[class="submit"]') .element('css selector', 'img[title="Valid RSS"]', function (result) { if (result.value && result.value.ELEMENT) { console.log('valid RSS...') browser.verify.ok(1 == 1, `${urlToTest} valid RSS...`) } else { console.log('invalid RSS...') browser.verify.ok(1 != 1, `${urlToTest} invalid RSS...`) } }) }
方案2:用forEach遍历数组(更清爽)
forEach的每次迭代都会创建独立的作用域,天然避开闭包问题,代码也更简洁:
// RSS Feeds rssFeeds.forEach(function(urlToTest) { urlToTest = urlToTest.toString(); browser .url('https://validator.w3.org/feed/') .waitForElementVisible('body', 'W3C RSS Validator page loaded... https://validator.w3.org/feed/ \n') .setValue('#url', urlToTest) .click('a[class="submit"]') .element('css selector', 'img[title="Valid RSS"]', function (result) { if (result.value && result.value.ELEMENT) { console.log('valid RSS...') browser.verify.ok(1 == 1, `${urlToTest} valid RSS...`) } else { console.log('invalid RSS...') browser.verify.ok(1 != 1, `${urlToTest} invalid RSS...`) } }) })
方案3:用立即执行函数(IIFE)创建独立作用域(兼容旧环境)
如果你的项目还不支持ES6,就用立即执行函数把每次迭代的URL封装到独立作用域里:
// RSS Feeds for (var i = 0; i < rssFeeds.length; i++) { // 立即执行函数,把当前迭代的URL作为参数传入,创建独立作用域 (function(currentUrl) { browser .url('https://validator.w3.org/feed/') .waitForElementVisible('body', 'W3C RSS Validator page loaded... https://validator.w3.org/feed/ \n') .setValue('#url', currentUrl) .click('a[class="submit"]') .element('css selector', 'img[title="Valid RSS"]', function (result) { if (result.value && result.value.ELEMENT) { console.log('valid RSS...') browser.verify.ok(1 == 1, `${currentUrl} valid RSS...`) } else { console.log('invalid RSS...') browser.verify.ok(1 != 1, `${currentUrl} invalid RSS...`) } }) })(rssFeeds[i].toString()) }
这几个方案都能解决你的问题,个人优先推荐方案1或2,代码更简洁易读。测试的时候你会发现,测试报告终于能正确显示每个URL的验证结果了!
内容的提问来源于stack exchange,提问作者Beau D'Amore
相关产品推荐
相关产品推荐

