cypress之实现文件上传下载以及操作iframe下页面元素

前面讲解了使用cypress框架如何定位、操作页面元素以及校验测试结果,此次课程将介绍如何实现文件上传、操作iframe下面的页面原因以及操作shadow dom下的页面元素。为了完成此次课程目标,拆分了3个task。

  • 实现文件上传和下载
  • 定位操作iframe下的页面元素
  • 定位操作shadow dom下的页面元素

接下来我们就从第一个taks开始吧。

实现文件上传和下载

Cypress框架自身没有提供直接的方法完成文件的上传,如果要实现文件上传操作,可以引入第三方包“cypress-file-upload”,该包封装了cypress的自定义命令,故安装此包后,还需在command.js文件中引入该包。command.js中引入该包后,通过调用cy.get('elementSelector').attachFile(filePath)即可完成文件上传。需要注意一点,这里传入的filePath是相对于cypress/fixture的相对路径,具体可看下面的演示脚本。Test Runner中选择“uploadFile_spec.js”即可运行下面的脚本。

describe("upload file demo", () => {
    Cypress.on('uncaught:exception', (err, runnable) => {
        return false
    });
   //Cypress.on(....)作用是如果出现uncaught:exception的error时,继续运行测试案例不失败。添加此脚本是因为测试案例使用的被测页面有一些错误。
   //实际项目不应该添加此语句忽略这样的异常信息,因为console界面的错误也属于issue

    it("should upload file successfully", () => {
        cy.visit("https://chercher.tech/practice/popups");
   //打开被测页面,如下图所示

        cy.get('input[type="file"]').attachFile('testData/dev/user.json');
   //上传文件,首先通过cy.get(selector)定位上传文件按钮,然后调用attachFile(filePath)上传目标文件

        cy.wait(3000);
    //添加等待语句,主要是为了调试时查看是否真的上传了文件

        cy.visit("https://chercher.tech/practice/popups");
        cy.get('input[type="file"]')
            .attachFile('testData/dev/user.json')
            .attachFile('profile.json', {force: true, encoding: 'utf-8'});
    //还支持一次上传多个文件,且attachFile()方法还支持一些可选参数输入

        cy.wait(3000)
    });
});

下图是被测页面,可以看到打开该页面时,console中有错误信息,这是因为被测页面脚本问题,故上面的测试脚本中需要添加Cypress.on(.....)语句忽略掉这些错误。默认情况下,cypress会监听这些异常信息,如果发现异常信息,测试案例会失败。运行上面的案例,应该能在页面上看到被上传的文件。

可以看到通过引入“cypress-file-upload”能非常方便的实现文件上传,除文件上传外还有文件下载场景,因为文件下载基本都是点击某个按钮或者链接完成文件下载,和普通的点击操作无区别,故这里不再做额外的介绍。接下来我们看看如何定位和操作iframe下的页面元素。

定位操作iframe下的页面元素

Cypress框架没有提供直接操作iframe下元素的的方法,如果被测应用中包含iframe,如何才能操作iframe下的元素呢?下面的内容将给大家演示如何定位和操作iframe下的页面元素。

如下图所示,打开的web页面中包含iframe。

下面的脚本演示了获取iframe下的" </h1/> " 元素的值以及点击iframe中的submit按钮。实现的思路是获取iframe下document对象,然后获取document对象的body,在body基础上查找需要的页面元素并进行点击操作。同样,Test Runner中选择“iframe_spec.js”即可运行下面的脚本。运行完成后Test Runner中可以看到点击submit后的页面,说明整个脚本运行与期望一致。

describe("control iframe", () => {
    it("should access element in iframe successfully", ()=> {
        cy.visit("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_file");
        getIframeBody('iframe[name="iframeResult"]').find('h1').should('contain','Show File-select Fields');
        getIframeBody('iframe[name="iframeResult"]').find('input[type="submit"]').first().click();
        cy.wait(3000);
    })
});

const getIframeDocument = (iframeSelector) => { 
    //参数传入需要查找的iframe selector,利于方法的复用

    return cy
        .get(iframeSelector)
        .its('0.contentDocument').should('exist')
        //通过0.conentDocument属性获取document对象。这里添加should校验,保证iframe加载完成后才继续运行后面的脚本,保证脚本稳定性
};

const getIframeBody = (iframeSelector) => {
    return getIframeDocument(iframeSelector)
        .its('body').should('not.be.empty')
        //获取document的body对象,并校验body内容不为空,保证iframe加载完成后才继续运行后面的脚本,保证脚本稳定性

        .then(cy.wrap)
       //cy.wrap是cypress提供的一个命令,调用cy.warp,后面才能继续添加链式命令,例如.find(selector).click()等
};

 上面的脚本中把getIframeDocument()和getIframeBody()与测试用例脚本放在一起,但这两个方法属于共用方法,涉及iframe的地方都需要调用这两个方法,故这里可以优化一下。下面脚本把getIframeBody设置为cypress的自定义用户命令,这样在任何需要获取iframeBody的地方调用命令即可。support/command.js文件中添加getIframeBody的脚本。

Cypress.Commands.add('getIframe',(iframeSelector)=> {   //定义的command名称是getIframe
    return cy
        .get(iframeSelector)
        .its('0.contentDocument').should('exist')
        .its('body').should('not.be.empty')
        .then(cy.wrap)
})

 修改测试案例脚本,通用使用cy.getIframe()命令操作iframe里面的页面元素。同样,Test Runner上选择“iframeWithCommand_spec.js”即可运行下面的脚本。

it('should control element in iframe with command',()=> {
    cy.visit("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_file");
    cy.getIframe('iframe[name="iframeResult"]').find('h1').should('contain','Show File-select Fields');
    //调用cy.getIframe(iframeSelector).find(elementSelector)定位iframe下的页面元素

    cy.getIframe('iframe[name="iframeResult"]').find('input[type="submit"]').first().click();
    cy.wait(3000);
    //这里添加等待是方便调试时查看点击iframe下button后的效果,确保确实点击了submit button
});

执行结果如下图所示,Test Runner中可以看到点击了submit后打开了新的页面。

关于cypress中封装自定义命令的内容后面章节还会单独进行详细讲解。接下来我们看看如果页面元素包含在shadow dom中,如何定位操作shadow dom下的页面元素。

定位操作shadow dom下的页面元素

Cypress框架自身并没有直接提供定位操作shadow dom下页面元素的方法,但可以通过引入第三方包“cypress-shadow-dom”实现定位shadow dom下的页面元素。该包添加了cypress自定义命令,故安装此包后,还需在command.js文件中引入该包。下图是一个包含shdow dom的web页面。

下面是定位操作shadow dom下页面元素的demo脚本,同样,Test Runner中选择“shadowDom_spec.js”即可运行下面的脚本。

describe("shadow dom demo", () => {
    it("should control dom in shadow successfully", () => {
        cy.visit("https://radogado.github.io/shadow-dom-demo/");
        cy.shadowGet('#app')   
        //获取shadow dom对象
            .shadowFind('p')   
        //在shadow dom对象基础上通过elementSelector定位页面元素
            .its('length')     
            .should('eq', 1);  
        //获取定位的页面元素个数并校验个数是否等于1

        cy.shadowGet('#app')
            .shadowFind('p')
            .shadowContains('Dynamically generated content');
        //定位shadow dom下的页面元素p,并校验p的innerText等于“Dynamically generated content”    

        cy.shadowGet('#app')
            .shadowFind('p')
            .shadowClick()
        //定位shadow dom下的页面元素p,并点击p元素 
    })
});

 可以看到通过引入“cypress-shadow-dom”可以方便的定位和操作shadow dom下的页面元素。除上面脚本用的方法外,该包还提供了其他一些api,这里汇总整理了“cypress-shadow-dom”目前提供的所有api。

cy.shadowGet('selector')
//这里传入的selector和普通web页面上定位元素的selector一致,需要注意一点是,selector定位到shadow-root的位置

cy.shadowGet('selector').find('selector')
cy.shadowGet('selector').find('selector').shadowFirst()
cy.shadowGet('selector').find('selector').shadowLast()
//定位到shadow dom后,在此基础上继续查找shadow dom下的页面元素,如果获取到了多个页面元素,那么可以通过shadowFirst()或者shadowLast()定位期望的页面元素

cy.shadowGet('selector').find('selector').shadowClick()
//点击定位的页面元素

cy.shadowGet('selector').find('selector').shadowType()
//输入内容到shadow dom下的输入框中

cy.shadowGet('selector').find('selector').shadowContain(contentText)
//校验定位的元素的innerText是否包含contentText

cy.shadowGet('selector').find('selector').trigger(eventName)
//这里的event指mousedown,mouseup,mouseleave等等

 上面列举了“cypress-shadow-dom”包对外提供的api,这些api除接受必填参数外,还接受可选参数输入。例如:shadowClick({force:true})接受可选参数force,即是否强制进行点击操作。如果想了解每个api可以接受哪些可选参数可查看github上介绍

GitHub - abramenal/cypress-shadow-dom: Extend Cypress commands with shadow DOM supporticon-default.png?t=M4ADhttps://github.com/abramenal/cypress-shadow-dom

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Cypress 中打开 PDF 文件需要使用第三方库 `pdfjs-dist` 来解析 PDF 文件,并且需要将 PDF 文件转化为二进制流。具体实现可以参考下面的代码示例: ```javascript import pdfjsLib from 'pdfjs-dist' describe('Open PDF file', () => { it('should open PDF file', () => { cy.request({ url: 'http://example.com/example.pdf', method: 'GET', responseType: 'arraybuffer' }).then(response => { const data = new Uint8Array(response.body) return pdfjsLib.getDocument({ data }).promise }).then(pdf => { return pdf.getPage(1) }).then(page => { const viewport = page.getViewport({ scale: 1.0 }) const canvas = document.createElement('canvas') const context = canvas.getContext('2d') canvas.height = viewport.height canvas.width = viewport.width return page.render({ canvasContext: context, viewport }).promise }).then(() => { const canvas = document.querySelector('canvas') const dataUrl = canvas.toDataURL('image/png') cy.visit(dataUrl) }) }) }) ``` 在上面的示例中,我们使用 `cy.request()` 命令获取 PDF 文件的二进制流数据,并使用 `pdfjsLib.getDocument()` 命令将二进制流数据解析成 PDF 文件。接着我们使用 `pdf.getPage()` 命令获取 PDF 文件的第一页,并使用 `page.getViewport()` 命令获取页面的视图大小。然后我们创建一个 `canvas` 元素,并使用 `page.render()` 命令将页面渲染到 `canvas` 上。最后我们使用 `canvas.toDataURL()` 命令将 `canvas` 转换成 `data URL`,并使用 `cy.visit()` 命令打开该 `data URL`。 需要注意的是,由于 PDF 文件解析需要时间,所以我们需要使用 `then()` 命令来处理异步操作。在测试用例中,我们使用 `cy.request()` 命令获取 PDF 文件的二进制流数据是因为 Cypress 无法直接访问本地文件系统。因此,我们需要将 PDF 文件上传到服务器上并通过 URL 访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

taoli-qiao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值