Protractor调用callback报错not a function及多函数顺序执行咨询
问题原因分析
1. callback报错的直接原因
你调用inputFeild时传入的第二个参数是epatRateIntlPagePo.dropDwnField("13227300 - OAQ DALLAS"),这行代码会立即执行dropDwnField方法,把方法执行后的返回值(默认是undefined)传给callback参数,自然会报"callback is not a function"的错误。如果要用回调写法,需要传函数本身,比如包一层箭头函数:() => epatRateIntlPagePo.dropDwnField("13227300 - OAQ DALLAS")。
2. 执行顺序混乱、click报错的根本原因
Protractor基于WebDriverJS,自带异步控制流,你混用浏览器侧的sleep、Node侧的setTimeout,会打破控制流的执行顺序,经常出现元素还没渲染完成、还没处于可交互状态就触发操作,自然会报click intercepted错误。
最佳实践方案:用async/await + 显式等待实现顺序调用
完全不需要回调写法,把两个方法改造为异步方法,用Protractor自带的ExpectedConditions做显式等待替代硬sleep,既稳定又能保证执行顺序:
改造后的页面对象方法
import { ExpectedConditions as EC } from 'protractor'; // 输入框方法,改为async异步方法 inputFeild = async (empId: number) => { const input = element(by.css('input#employeeid')); // 等待输入框可见再操作,替代硬sleep await browser.wait(EC.visibilityOf(input), 10000, '员工ID输入框未加载完成'); await input.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, 'a')); await input.sendKeys(empId.toString()); // 可根据页面实际响应速度调整等待时长,不需要固定20s await browser.sleep(1000); } // 下拉框方法,改为async异步方法,去掉setTimeout dropDwnField = async (propId: any) => { const drpDwn = element(by.xpath("//b[text()='Assigned Proposals:']//parent::div//following-sibling::p-dropdown")); // 等待下拉框可点击再点击 await browser.wait(EC.elementToBeClickable(drpDwn), 10000, '下拉框不可点击'); await drpDwn.click(); const search = element(by.xpath("//input[contains(@class,'p-dropdown-filter p-inputtext ')]")); await browser.wait(EC.visibilityOf(search), 10000, '下拉搜索框未加载完成'); await browser.wait(EC.elementToBeClickable(search), 10000, '下拉搜索框不可点击'); await search.click(); await search.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, 'a')); await search.sendKeys(propId.toString()); const targetOption = element(by.xpath(`//span[text()='${propId}']`)); await browser.wait(EC.elementToBeClickable(targetOption), 10000, `未找到选项${propId}`); await targetOption.click(); }
改造后的spec用例
直接按顺序await两个方法即可保证执行顺序:
it('顺序调用方法测试', async () => { // 先等输入方法执行完成 await epatRateIntlPagePo.inputFeild(5001096); // 输入完成后再执行下拉框方法 await epatRateIntlPagePo.dropDwnField("13227300 - OAQ DALLAS"); await browser.sleep(3000); })
补充说明
- 显式等待的超时时间可以根据你的页面加载速度调整,比固定时长的sleep稳定性高很多,能解决90%以上的元素交互报错问题
- 如果你的Protractor版本开启了SELENIUM_PROMISE_MANAGER控制流,也可以直接链式调用方法,不过async/await是目前官方更推荐的写法,可读性更高
内容的提问来源于stack exchange,提问作者krishna sai
相关产品推荐
相关产品推荐

