当前位置: 首页 > 工具软件 > TestCafe > 使用案例 >

使用TestCafe时如何模拟常见的web应用操作

卫博
2023-12-01

前面介绍了使用TestCafe时如何定位、操作页面元素以及校验执行结果,此次课程将介绍使用TestCafe时如何完成拖动页面元素、模拟鼠标键盘、文件上传下载等操作。在介绍Cypress和Puppeteer时也详细讲解过如何模拟这些操作,故此章节对于这些场景只会简单介绍并给出demo脚本。为了完成此次课程拆分了7个task,接下来将逐个进行简单介绍。

  • 模拟拖动页面元素
  • 模拟键盘和鼠标操作
  • 操作iframe下的页面元素
  • 操作shadow dom下页面元素
  • 实现文件上传和下载
  • 弹框处理
  • 实现浏览器前进、后退以及模拟hover操作

拖动页面元素

Testcafe框架自身提供了拖动页面元素的api,调用t.dragToElement(fromElementSelector,targetSelector)即可,调用时传入拖动元素的开始位置和结束位置的页面元素selector即可。具体可看下面的案例脚本。同样,执行“npm run test:dragElement”即可运行下面的脚本。

import {Selector} from 'testcafe'
fixture('drag element demo');
test('should drag element successfully', async (t) => {
    await t.navigateTo("http://devexpress.github.io/testcafe/example/");
    await t.click('#tried-test-cafe');
    const toAreaElement = Selector('.slider-container .slider-value').withText('5');
    //定位拖动的目标位置元素

    await t.dragToElement('.slider-container #slider span', toAreaElement);
    //调用testcafe提供的拖动元素api完成拖动操作。

    await t.wait(3000);
   //此处添加等待命令,方便看到拖动的结果  
});

模拟键盘或者鼠标操作

调用t.pressKey(keyname)即可模拟键盘输入操作,下面脚本写了几个常见键值输入,更多可输入的键值可查看官网资料“ Redirecting… ”。对于模拟鼠标操作,框架提供了click、doubleClick、rightClick、hover、dragToElement5个api完成常见的鼠标操作,这几个api使用方式非常简单,前面也分别做过介绍,这里不再重复说明。同样,执行“npm run test:keyBoard”即可运行下面的脚本。

fixture('simulate keyboard action');
test('should simulate keyboard action successfully', async (t) => {
    await t.navigateTo('https://devexpress.github.io/testcafe/example/');
    await t.typeText('#developer-name','test')
        .pressKey('shift+a');
        //模拟在输入框中输入大写字母A,这里是通过按住shift+a完成大写字母输入,主要是为了演示模拟键盘键值输入

    await t.pressKey('enter');
    //模拟输入enter键

    await t.pressKey('tab');
    //模拟输入tab键
});

操作iframe下的页面元素

TestCafe框架提供了t.switchToIframe(iframeSelector)跳转到iframe上,同时也提供t.switchToMainWindow()跳回主窗口。通过调用这两个方法可以方便定位iframe和非iframe上的页面元素。 具体看下面的demo脚本,同样,执行“npm run test:iframeTest”即可运行下面的测试案例。

import {Selector, t} from 'testcafe'
fixture('control element in iframe demo');
test('should select and click element in iframe successfully', async () => {
    await t.navigateTo('https://www.w3schools.com/TAgs/tryit.asp?filename=tryhtml_button_test');
    await t.switchToIframe('#iframeResult');
    //通过调用switchToIframe切换到iframe上,这样后面的脚本即可定位iframe下的页面元素

    await t.expect(Selector('h1').innerText).contains("The button Element");
    await t.setNativeDialogHandler(() => true)
        .click('button');
    await t.switchToMainWindow();
    //通过调用switchToMainWindow切换到主窗口上,这样后面的脚本即可定位非iframe下的页面元素

    const button= Selector('div button').withText('Run »');
    await t.click(button);
});

操作shadow dom下的页面元素

TestCafe框架没有提供直接的api定位shadow dom下的页面元素,但使用testcafe时可以调用document对象,document对象可以很方便的定位shadow dom下的页面元素。具体看下面的demo脚本,同样,执行“npm run test:shadowDomTest”即可运行下面的测试案例。

import {t,Selector} from 'testcafe'
fixture('shadow dom element demo');
test('should control element in shadow dom successfully', async () => {
    await t.navigateTo('https://radogado.github.io/shadow-dom-demo/');
    const elementInShadowDom = Selector(()=>document.querySelector('#app').shadowRoot.querySelector('#container p'));
    //Selector(()=>document.xxxx)中可以调用document对象,通过document对象定位到shadow dom下的页面元素,然后再操作或者获取页面元素的值

    await t.expect(elementInShadowDom.textContent).eql('Dynamically generated content');
    //获取页面元素的值并校验是否与期望的值相等
});

文件上传、下载

TestCafe框架提供了api完成文件上传,且一次还可以上传多个文件。下载文件实际是完成点击操作,和模拟页面点击操作无区别。具体看下面的demo脚本,同样,执行“npm run test:uploadFile”和"npm run test:downloadFile"即可运行下面的测试案例。

//下面是下载文件demo脚本

fixture `Example`
    .page `https://js.devexpress.com/Demos/WidgetsGallery/Demo/FileUploader/FileSelection/jQuery/Light/`;
test('Upload Files test', async t => {
    await t
        .switchToIframe('.demo-frame')
        .setFilesToUpload('.dx-fileuploader-input', ['./testFile/test.jpeg'
        ]);
        //调用setFileToUpload(selector,[fileList])即可完成文件上传操作,filelist中可以传入多个文件地址,用逗号隔开。
        //需要注意一点,这里的文件路径是相对于测试案例脚本的路径,例如上面脚本中,和测试脚本同一层中存在目录testFile目录,该目录下存在test.jpeg测试文件
});
//下面是下载文件的脚本,下载文件实际模拟的是点击页面元素操作

import {Selector} from 'testcafe'
fixture("download file demo");
test('should download file successfully',async (t)=> {
   await t.navigateTo("https://file-examples.com/index.php/sample-documents-download/sample-doc-download/");
   const downLoadElement = Selector('td a').withText('Download sample DOC file');
   await t.click(downLoadElement);
});

弹框处理

TestCafe提供了api处理弹框。调用" t.setNativeDialogHandler(type,text)=>{} "即可模拟点击弹框中的确认、取消或者关闭按钮。Type指弹框类型,包含alert、confirm、prompt三种类型。 具体使用规则,请看下面的demo代码,同样,执行“npm run test:handleDialog”即可运行下面的脚本。

fixture`handel dialog demo`
    .page`http://devexpress.github.io/testcafe/example/`;
test('should handel confirm dialog successfully', async t => {
    await t
        .setNativeDialogHandler((type, text) => {
            switch (type) {
                case 'confirm':
                    switch (text) {
                        case 'Do you want to subscribe?':
                            return false;
                            //返回false,等同于模拟点击confirm类型弹框的取消按钮

                        case 'Reset information before proceeding?':
                            return true;
                            //返回true,等同于模拟点击confirm类型弹框的确认按钮

                        default:
                            throw 'Unexpected confirm dialog!';
                         //假设弹框的message不等于上面两类message,那么抛异常信息,这样运行的案例会失败,并显示定义的异常信息“Unexpected confirm dialog!”   
                    }
                case 'prompt':
                    return 'Hi there';
                    //如果是prompt类型弹框,模拟输入“Hi there”,然后点击确认按钮

                case 'alert':
                    throw 'An alert was invoked!';
                  //如果是alert弹框,这里模拟抛出异常。实际场景中,可以根据项目情况模拟处理结果。  
            }
        })
        .click('#populate');
    //在会出现弹框的方法前面调用.setNativeDialogHandler(),可以根据type类型和text的值确定处理结果

    await t.click('#remote-testing');
});

一个应用中,如果某些页面会显示弹框,那么可以把处理弹框的代码封装到page对象中,这样便于测试脚本的复用。这里总结下对于各类弹框返回值的含义。

  • 对于confirm类型的弹框,返回false表示模拟点击确认框的取消按钮,返回true表示模拟点击确认框的确认按钮;不返回值框架模拟点击confirm框的取消按钮关闭弹框。
  • 对于alert类型的弹框,框架会忽略返回值,即不管return true或者return false或者调用.setNativeDialogHandler(()=>{})时不返回任何值,框架都会模拟点击alert框的取消按钮关闭弹框。
  • 对于prompt类型的弹框,返回输入的message信息,框架模拟点击prompt的取消按钮关闭弹框。

可以看到,使用testcafe时必须提前能确定出现弹框的位置,例如点击某个按钮时会出现弹框,那么在click操作前调用setNativeDialogHandler方法。如果页面会出现随机弹框,testcafe无法进行处理。puppeteer中通过监听处理弹框,可以处理页面随机弹出的弹框,故如果被测应用中会出现大量随机的弹框,那么建议选择puppeteer测试框架。上面讲解了如何处理不同类型的弹框,接来下看看如何模拟点击浏览器前进和后退按钮。

浏览器前进、后退以及模拟hover操作

TestCafe框架没有直接提供api模拟浏览器前进和后退操作,但可以调用window对象实现前进、后退,且可以获取当前页面的地址,校验当前页面是否是期望的页面。具体请看下面的demo脚本,同样,执行“npm run test:pageBackForward”即可运行下面的案例。

import {ClientFunction,t,Selector} from "testcafe";
fixture("page back forward demo");
test("should browser back or forward successfully", async()=> {
    const goBack = ClientFunction(() => window.history.back());
    //调用window对象,实现浏览器后退操作,这里还使用了用户自定义脚本,这样,在需要后退操作的脚本中调用goBack即可。

    const forward = ClientFunction(() => window.history.forward());
    //调用window对象,实现浏览器前进操作。

    const getLocation = ClientFunction(() => window.location.href);
    //获取当前页面的地址
    //实际项目中可以把这三个方法封装到util一类的公共脚本中,方便所有测试脚本复用。

    await t.navigateTo("https://chercher.tech/practice/popups");
    await t.expect(getLocation()).contains('chercher.tech');
    await t.hover('#sub-menu');
    const googleLink=Selector('div a').withText('Google');
    await t.click(googleLink);
    await t.expect(getLocation()).contains('google');
    await goBack();
    await t.expect(getLocation()).contains('chercher.tech');
    await forward();
    await t.expect(getLocation()).contains('google');
});

TestCafe框架直接提供了hover()方法完成hover操作,使用起来很简单,具体请看下面的脚本,执行“npm run test:hoverTest”即可运行下面的脚本。

import {Selector, t} from 'testcafe'
fixture("hover demo");
test('should hover successfully', async()=> {
   await t.navigateTo("https://chercher.tech/practice/popups");
   await t.hover('#sub-menu');
   //调用hover(selector)完成模拟hover操作

   const googleLink=Selector('div a').withText('Google');
   await t.click(googleLink)
});
 类似资料: