Nightwatch从页面对象返回选项值到测试文件的实现方法
问题根因
你遇到的optionSelected始终为undefined的问题,本质是混淆了Nightwatch异步命令队列的执行逻辑。Nightwatch所有和浏览器交互的方法(click、getText、setValue等)都是异步入队的,不会按照同步代码的书写顺序立即执行完成,原写法是在异步回调执行前就同步返回变量,自然拿不到实际值。
原写法的失效原因
看你定义的selectAndStoreOption函数执行流:
- 声明空变量
optionSelected - 依次将click下拉框、getText取选项文本、click选中选项三个动作加入命令队列,此时三个动作都没有实际执行
- 同步执行
return optionSelected——这行代码跑的时候,getText的回调函数根本没被触发,optionSelected还是初始的空值undefined - 等队列里的命令真正执行完,getText的回调给
optionSelected赋值的时候,函数的返回动作早就结束了,拿到的值永远是初始的undefined
具体修改方案
1. 改造页面对象的selectAndStoreOption方法
Nightwatch 2.x及以上版本原生支持命令链返回Promise,只要把原来的同步返回逻辑改成基于命令链完成后再传值的模式,就能拿到真实的选项文本:
selectAndStoreOption: function(selector, value) { return this .click(selector) // 入队:点击打开筛选下拉框 .getText(`li[value='${value}']`) // 入队:获取目标选项的文本 .then((result) => { const optionText = result.value; // 拿到文本后,再入队点击选中目标选项 return this.click(`li[value="${value}"]`) .then(() => optionText); // 命令全部执行完成后,把拿到的文本作为返回值传递出去 }) }
2. 改造测试用例的取值逻辑
因为改造后的selectAndStoreOption返回的是Promise对象,原来的同步赋值方式拿不到值,需要用Nightwatch测试上下文原生支持的async/await语法等待命令执行完成:
"Google Advanced Search Test": async function(browser) { const googleSearchPage = browser.page.googleSearchPage(); const resultPage = browser.page.resultPage(); const data = browser.globals; // 依次执行基础搜索配置动作,等每个动作完成再往下走 await googleSearchPage .setQuery(data.googleAdvancedSearch.textToSearch) .selectFilter('@languageBox','lang_pl') .selectFilter('@regionButton','countryPH'); // 等待selectAndStoreOption执行完成,拿到真实的选项文本 const optionSelec = await googleSearchPage.selectAndStoreOption('@lastUpdateBtn','m'); console.log(optionSelec); // 此时会正常打印出"upto a month ago"的文本值 await googleSearchPage.clickSubmit(); // 把拿到的真实值传入结果页校验方法 await resultPage.verifyCorrectResultDisplayed(optionSelec, data.googleAdvancedSearch.textToSearch); }
3. 修复结果页的校验逻辑顺序
原来的verifyCorrectResultDisplayed方法没有等前面的断言完成就执行分支判断,同样存在队列执行顺序的问题,需要调整为按队列顺序执行的模式:
verifyCorrectResultDisplayed: async function(optionSelected, textToSearch) { // 依次执行基础断言,等所有断言完成再往下走 await this .assert.urlContains("as_q=Elon+Musk","Elon Musk searched") .assert.urlContains("lr=lang_pl","Language polish set") .assert.visible(`input[title='Search'][value='${textToSearch}']`,"Search result visible on UI"); // 等基础断言完成后,再获取时间筛选栏的文本做分支判断 const monthBoxText = await this.getText('@monthBox'); if(optionSelected === "upto a month ago") { await this.assert.containsText('@monthBox',"Past month","Past month result displayed"); } return this; }
适配低版本Nightwatch的替代方案
如果你使用的是Nightwatch 1.x版本,不支持原生async/Promise的命令链返回,可以用内置的perform方法把取值逻辑插到命令队列末尾:
- 在测试用例作用域声明全局变量存储取值
- 在
selectAndStoreOption的命令链最后追加一个.perform(() => { storedOption = optionText; }),等队列走到这一步时再给变量赋值
注:这种写法是低版本的兼容方案,长期建议升级到最新稳定版Nightwatch,避免队列顺序混乱导致的断言失效。
内容的提问来源于stack exchange,提问作者Sonal
相关产品推荐
相关产品推荐

