Puppeteer之处理弹框、实现文件上传下载以及操作iframe下页面元素

前面博客介绍了定位、操作页面元素以及如何校验执行结果。此篇博客将介绍如何处理页面弹框、文件上传下载、操作iframe里面页面元素,为了完成课程目标,分了3个task

  • 处理页面弹框
  • 实现文件上传和下载操作
  • 操作iframe中的元素

接下来就开始第一个task的学习,同样执行“npm run handle-dialog”即可运行下面讲解的案例。

处理页面弹框

弹框主要分为三种类型:alertbox、confirmbox、promptbox。alterbox主要用于给用户显示一些提示信息,通常会带一个OK按钮,点击OK按钮即可关闭alterbox。confirmbox主要让用户输入确认或者取消信息,confirmbox通常会带OK和CANCEL按钮,点击OK或者CANCEL都可以关闭confirmbox。promptbox主要让用户输入一些信息,通常会带一个text输入框和OK、CANCEL按钮,点击OK或者CANCEL都可以关闭promptbox。

如下图所示,当点击页面的populate按钮时,页面弹出了alertbox。

 如果不关闭上面的弹框,页面上其他element都不可点击。对于这类弹框,处理的机制是实时监听页面上是否显示了弹框,如果有即可关闭,防止其影响正常的自动化脚本运行。那么使用puppeteer框架时如何处理弹框呢?请看下面的案例。同样,执行“npm run handle-dialog”即可运行下面的案例。

describe("dialog demo", () => {
    it("simulate click close on alert dialog", async () => {
        await page.on('dialog', async dialog => {
            switch (dialog.type()) {
                case 'alert':
                    await dialog.dismiss();
                    break;
                case 'confirm':
                    await dialog.accept();
                    break;
                case 'prompt':
                    await dialog.accept("type things");
                    break;
                default :
                    throw "can't get dialog type"
            }
        //自动化脚本最前面通过page.on()添加对页面的监听操作,如果出现弹框,调用dialog.dismiss()方法关闭弹框
        //dialog.dismiss()相当于点击弹框右上角的关闭按钮
        //dialog.accept()相当于点击弹框的OK按钮,如果是prompt类型的弹框,调用dialog.accept('conent')模拟在prompt弹框中输入conent
        //dialog.type()返回监听到的dialog类型,类型包含:alert,confirm,prompt和beforeunload
        });
        await page.goto('https://devexpress.github.io/testcafe/example/');
        await expect(page).toClick('#populate');
    });
    it("simulate click ok button on alert dialog", async () => {
        await page.goto("https://chercher.tech/practice/popups");
        await expect(page).toClick('input[name="alert"]');
    });

    it("simulate click ok button on confirm dialog", async () => {
        await page.goto("https://chercher.tech/practice/popups");
        await expect(page).toClick('input[name="confirmation"]');
    });

    it("simulate input text on promote dialog", async () => {
        await page.goto("https://chercher.tech/practice/popups");
        await expect(page).toClick('input[name="prompt"]');
    })
});

看了上面的案例,你掌握了如何处理dialog框了么?这里我们总结下dialog框常用方法。

  • 1.dialog.message()获取dialog框中的message信息,当一个测试流程中可能出现多个dialog框,那么可以获取message信息,然后根据信息进行下一步操作。
  • 2.dialog.dismiss()等同于点击dialog框右上角的关闭按钮,如果实际场景中你只是想关闭dialog框,不影响正常的自动化脚本,那么可以用此方法。注意,这里即便弹出的dialog框中右上角没有关闭按钮,仍然可以调用此方法关闭dialog。
  • 3.dialog.accept()等同于点击dialog框中的确认按钮,如果方法中传入参数值,那么当监听到prompt弹框时会把accept()中参数值输入到prompt弹框中。
  • 4.dialog.defaultValue(),如果是prompt的弹框会返回prompt弹框中的值,如果不是prompt弹框,返回空字符串。
  • 5.dialog.type()获取弹框的类型,实际项目中可以根据弹框类型进行不同的处理逻辑。

以上就是关于dialog弹框的所有常用方法,掌握了这些方法,处理dialog弹框不再是难事。接下来我们学习如何利用puppeteer框架实现文件的上传和下载。

实现文件上传操作

Puppeteer框架中已经封装了文件上传方法,在需要文件上传的页面调用该方法即可完成文件上传。同样,执行“npm run upload-file”即可运行下面讲解的案例。案例的代码如下所示

const path = require('path');
// 引入path,供后面使用

describe("upload  file demo", () => {
    it("should upload file successfully", async () => {
        page.goto("https://chercher.tech/practice/popups");
        await page.waitForSelector('input[type="file"]');
        //添加等待语句,保证上传文件的元素已显示在页面上后,再进行下一步操作

        const uploadFileHandle = await page.$('input[type="file"]');
        await uploadFileHandle.uploadFile('./testdata/test.txt');
        //上传文件,这里文件地址是基于代码根目录的相对地址

        await page.waitFor(3000);
        //这里调用了包好的一个固定时间等待方法,方便查看文件是否真正已上传成功
    });

    it("should upload file with puppeteer-expect", async () => {
        page.goto("https://chercher.tech/practice/popups");
        await page.waitFor(3000);
        await expect(page).toUploadFile(
            'input[type="file"]',
            path.join('./testdata/', 'test.txt'),
        );
        //puppeteer-expect提供了上传文件的方法,按官方文档提示此方法可以实现自动等待,但经过验证发现,在调用上传文件的方法前需要写入等待语句,否则案例会运行失败
       await page.waitFor(3000);

    })
});

总结而言,要完成文件上传,首选需要添加等待语句,保证“上传文件”页面元素已显示在web应用页面上,接着调用puppeteer提供的方法或者puppeteer-expect提供的上传文件方法上传即可,传入的文件地址写相对地址即可。这里需要注意一点,真实项目中,如果有上传文件场景,需要把上传的文件和代码放在一起。例如案例中在代码根目录下创建了testdata目录,在此目录存放需要上传的文件。不要放自己电脑的其他目录,否则脚本在持续集成平台上运行时,会因为找不到文件而报错。

上面演示了如何上传文件,接下来我们看看如何实现文件下载。Web应用中往往是点击某个链接、图片等完成下载操作,总的来说都是点击页面某个元素。所以,实现文件下载实际就是点击页面的目标元素,和之前讲过的点击操作相同,唯一的差别是:可以指定下载的文件存放位置。下面是案例代码,同样,执行“npm run download-file”即可运行下面的案例。

describe('download file demo',()=> {
    it('should download file successfully', async()=> {
        await page.goto('https://file-examples.com/index.php/sample-documents-download/sample-doc-download/');
        //打开一个存在文件下载链接的web页面

        await page._client.send('Page.setDownloadBehavior', {behavior: 'allow', downloadPath: './'});
       //如果无此行代码,下载的文件存放到默认下载路径中,如果添加此语句,可以通过downloadPath指定下载的文件存放路径,这里指定为./,那么下载的文件会存放到代码根目录下

        await expect(page).toClick('td a',{text:'Download sample DOC file'});
        //点击目标元素,完成下载操作

        await page.waitFor(8000);
        //等待语句,方便查看是否下载过程
    })
});

介绍完文件的上传和下载后,下面介绍如何操作iframe里面的页面元素。

操作iframe中的元素

Iframe上元素的操作实际也很简单,如何使用请看下面的案例,同样执行“npm run iframe-action”即可运行下面的案例。

describe("iframe demo", () => {
    it("should control element in iframe successfully", async() => {
        page.on('dialog', async dialog => {
            await dialog.dismiss()});
        //这个场景当下面点击button按钮的时候,会弹出一个dialog框,这里通过添加page.on的方式关闭弹出的dialog框

        await page.goto('https://www.w3schools.com/TAgs/tryit.asp?filename=tryhtml_button_test');
        //打开页面

        const frame = await page.frames().find(f => f.name() === 'iframeResult');
         //通过名字获取需要的iframe对象,当一个页面有多个iframe时,可以通过名字匹配到需要的iframe

        await frame.waitForSelector('button');
        await frame.click('button');
        //如果需要获取iframe上的元素,使用frame.$即可,所有在page对象上能调用的方法,iframe对象上也可调用
    });

通过上面的案例可以看到,对于在iframe里面的页面元素,首选是获取iframe对象,然后基于iframe对象查找、操作页面元素即可。在page对象上能调用的方法,在iframe上基本都可以使用。

接下来我们再看看iframe和文件上传结合的案例,如下图所示,可以看到该页面上的文件上传元素是在iframe里面。

上面的web页面上,如果要实现上传文件,首先必须先获取iframe对象,如果直接基于page对象调用上传文件方法,无法成功上传文件,但脚本不会报错,因为定位元素的时候,确实存在这个元素。实际项目中,如果你调用方法对页面元素进行操作时始终无法成功,可查看下该元素是否在iframe里面。iframe下实现文件上传案例代码如下所示。


    it("should upload file in iframe successfully ", async() => {
        await page.goto("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_file");

        const elementHandle = await page.$('iframe[name="iframeResult"]');
        const frame = await elementHandle.contentFrame();
       //获取iframe对象的另外一种写法,两种方式都可以获取到iframe对象

        await frame.waitForSelector('input[type="file"]');
        const uploadFileHandle =  await frame.$('input[type="file"]');
        await uploadFileHandle .uploadFile('./testdata/test.txt')
        //这个web应用上,上传文件的元素在iframe上,故这里获取iframe对象后,再通过iframe.$方式获取文件上传对象,完成文件上传操作
    })
});

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taoli-qiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值