Protractor encounters an error stating "No element found with specified locator" after attempting to switch to an

I've been attempting to download an embedded PDF from a webpage using Protractor selenium. However, I seem to be stuck when it comes to actually downloading the file as I always encounter the following error:

  • Failed: No element found using locator: By(css selector, *[id="download"])

Even after switching to the iframe, the button cannot be located.

I have also tried the solution mentioned in this answer, where it extracts the src attribute value and directly goes to the URL, but the same issue persists. The download button (icon) remains elusive.

We both have identical requirements, simply needing to click the download icon embedded within the PDF inside an iframe. An example page can be seen here.

Below is the code snippet I am currently using:

        const iframe = $('#printFrame'),            
              downloadBtn = $('#download'),
              content = $('#content');

        await this.disableWaitForAngular();
        await browser.wait(EC.visibilityOf(iframe), waitTimeout);
        console.log("Switching to iframe...");
        await browser.switchTo().frame(iframe.getWebElement());

        await browser.wait(EC.visibilityOf(content), waitTimeout);
        await browser.actions().mouseMove(content).perform();

        console.log("Waiting for download button.");
        await browser.wait(EC.visibilityOf(downloadBtn), waitTimeout);

        await downloadBtn.click();

        await browser.switchTo().defaultContent();
        await this.enableWaitForAngular();

UPDATE:

I attempted to inject the following code as suggested in one of the previous answers before and after switching frames, but it resulted in an error.

const downloadIcon: WebElement = await browser.executeScript('return document.querySelector("#viewer").shadowRoot.querySelector("#toolbar").shadowRoot.querySelector("#downloads").shadowRoot.querySelector("#download").shadowRoot.querySelector("#icon > iron-icon");');
    
    await downloadIcon.click();

Error:

 - Failed: javascript error: Cannot read property 'shadowRoot' of null
(Session info: chrome=87.0.4280.66)
(Driver info: chromedriver=87.0.4280.20 (c99e81631faa0b2a448e658c0dbd8311fb04ddbd-refs/branch-heads/4280@{#355}), platform=Windows NT 10.0.14393 x86_64)

Reference image of the download icon: https://i.sstatic.net/8Zd7g.png

Answer №1

Upon reviewing the example page you shared, it appears that there is no direct "Download" button present as it is a function of the browser rather than the webpage itself. This means that traditional selectors cannot be used to locate this button.

However, since we have the PDF loaded within an iframe, we can create our own custom download button using the following code:

a = document.createElement('a'); a.href = $('iframe').src; a.download = "hello.pdf"; a.click();

To implement this solution, simply copy the code provided, navigate to your page, paste it into the console, and execute it. This will initiate the download process for the file.

While this example serves as a demonstration, feel free to modify and adapt this concept to suit your specific requirements.

UPDATE

For those interested in the technical details, I have included screenshots of the same page displayed in various browsers such as Chrome, Firefox, Edge, and IE.

https://i.sstatic.net/J6pwa.png

https://i.sstatic.net/cyj8B.png

https://i.sstatic.net/M5TmC.png

https://i.sstatic.net/7qPBE.png

It is evident from these images that the actual content of the PDF page varies across browsers due to the control exerted by the browser and its plugins.

Attempting to interact with the "download" icon/button is equivalent to interacting with elements within the plugin itself, making it impossible to directly manipulate.

In reality, the webpage only contains the PDF object without any visible controls for downloading.

As demonstrated in IE, while the "download" button may not be visually accessible on the page, it is still possible to trigger the action through the browser interface, as shown here:

https://i.sstatic.net/LFaiX.png

Answer №2

It seems like the root of your issue is related to the shadow-root feature.

  1. Consider utilizing Protractor's by.deepCss(selector) method. If that doesn't work, check out this workaround here.

  2. You can extract the src attribute from the iframe and open it in a new window. Then use Ctrl+S with sendKeys.

  3. Another option is to execute JavaScript code in Protractor:

    document.querySelector("#viewer").shadowRoot.querySelector("#toolbar").shadowRoot.querySelector("#downloads").shadowRoot.querySelector("#download").shadowRoot.querySelector("#icon > iron-icon").click();

I discovered these steps while inspecting the element and choosing "Copy JS Path" in Chrome DevTools.

For more information:
Interacting with elements within #shadow-root (open) when Clearing Browsing Data in Chrome Browser using cssSelector
Troubleshooting deepCss failure to identify an element inside a shadow root in Protractor
Difficulty selecting input element inside a shadow DOM (Polymer) in Protractor using by.deepCss('input')
https://www.protractortest.org/#/api?view=ProtractorBy.prototype.deepCss
Keyboard shortcuts for Chrome PDF Viewer

Answer №3

Using a combination of chaining and awaiting in Protractor is not recommended:

isPDFDownloadSuccess: () => Promise <boolean> = async() => {        
        await this.disableWaitForAngular(); //equivalent to browser.waitForAngularEnabled(false);
        const pdfIframe = await element(by.tagName("iframe"));
        console.log("Switching to PDF iFrame...");        
        await browser.switchTo().frame(element(by.tagName('iframe')).getWebElement());
        await element(by.id("download")).click()
     
        //Actions to validate successful download can be inserted here 
       
         return true;    
    };

Answer №4

The following code successfully completed the task:

await browser.waitForAngularEnabled(false);
await browser.get('https://www.sebi.gov.in/enforcement/orders/jun-2019/adjudication-order-in-respect-of-three-entities-in-the-matter-of-prism-medico-and-pharmacy-ltd-_43323.html');
let $iFrame = $('iframe[src*="sebi"]'),
    $downloadButton = $('#download');
await browser.wait(ExpectedConditions.presenceOf($iFrame), 5000);
await browser.switchTo().frame($iFrame.getWebElement());
await browser.wait(ExpectedConditions.presenceOf($downloadButton), 2000);
await $downloadButton.click();
await browser.sleep(2500);
await browser.switchTo().defaultContent();
await browser.waitForAngularEnabled(true);

If the code does not work for you, there may be an issue with your configuration. Please update your question with more details.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What benefits does using blocking code offer compared to non-blocking code?

Currently, I am diving into the world of JavaScript and Node. The concept of asynchronous operations makes sense to me, as I can see how it greatly improves efficiency. However, I've noticed that some languages such as Ruby and Java are inherently bl ...

[Using Selenium] Tips for invoking overridden methods on web elements

I have implemented an override method called click() in the BaseElement class, which implements the WebElement interface. I want to be able to use this overridden method on all web elements where applicable. WebElement ele = driver.findElement(By.id("but ...

`Changing drop-down menu to display the previously selected item upon page refresh in a Django application`

Is there a way to retain the selected filter in a Django/Python application when a page refreshes after using an HTML drop-down form? Here is the current form I am using: <form name="portfolio_filter" action="" method="get"> <select class="o ...

sending functions into angular as opposed to using 'function()'

Lately, I've been immersing myself in Angular development. One thing that caught my interest was the idea of using a declared function instead of a generic "function() {}" placeholder, particularly in scenarios like handling promise callbacks. I encou ...

How can you integrate Dygraph into your React project alongside redux?

Lately, I've been facing some challenges while trying to integrate Dygraph into React (utilizing Redux). The Dygraph wrapper packages available on NPM don't seem to cooperate. Furthermore, the conventional method of using: <div id="graph"> ...

Using gulp to compile TypeScript is resulting in a directory being generated that we do not want

My goal is to use Gulp to transpile my .ts files located in the /dev directory, and then move the transpiled .js file to a /build directory. The ideal folder structure I am aiming for is as follows: /dev - index.ts /build - index.js However, the curre ...

The page you are looking for cannot be located using Jquery AJAX JSON PHP POST -

Whenever I attempt to POST some JSON data to a local host, I consistently encounter a 404 Not Found error. Strangely enough, the php file is positioned precisely where it should be according to the script instructions. If anyone has dealt with this issue b ...

Can a linked checkbox be created?

Is it possible to create a switch type button that automatically redirects to a webpage when turned on by clicking a checkbox? I'm working on implementing this feature and would like to know if it's feasible. ...

Inserting a script tag with an external source and waiting for it to run

Is there a way to dynamically inject a <script src="https://remote.com/"></script> element into my page, wait for it to run, and then access the functions it defines? Just to note, the script will handle credit card processing in certain cases ...

Effective Strategies for Preventing Javascript Injection Attacks

My main concern is distinguishing between client-side messages originating from my code and those coming from a potential hacker. Despite researching JavaScript injection and reading various responses on StackOverflow, the consistent advice is to never tru ...

What is the best way to navigate and map through an array of objects, especially when encountering an empty object?

I am currently in the process of developing a bootleg version of Amazon with a focus on creating the Questions & Answers component. The issue I have encountered is that in my dummyData, there are instances where a product may not have any questions, lead ...

Utilize regular expressions to substitute a specific string of text with an HTML tag

My task is to transform this text: let text = "#Jim, Start editing to see some magic happen!"; into this format: text = "<span style="color:red">#Jim</span>, Start editing to see some magic happen!"; Here is my ...

Explore various date formats using the datepicker functionality

I'm dealing with the code below: <script type="text/javascript" language="javascript" src="~/Scripts/bootstrap-datepicker.min.js"></script> <script type="text/javascript" language="javascript" src="~/Scripts/locales/bootst ...

Error: You forgot to include a name after the dot operator

I am facing an issue where I am unable to use YUIcompressor to compress a file. The script is running smoothly, but I am encountering the error missing name after . operator on line 3 of this script: Specifically at: "+ source.response.chars[k].name +" I ...

Is it possible for the width of the table to exceed the width of the

I am working on creating a table that will have a varying number of cells in each row generated dynamically. My goal is to ensure that the width of the table exceeds the width of the page so that each cell's inner HTML content remains on a single line ...

What is the process for retrieving a value from JSON utilizing JavaScript?

Unfortunately, I am completely stumped when it comes to Javascript. I'm attempting a few solutions based on online resources. If anyone could offer some assistance, that would be greatly appreciated. Below is the JSON data provided. It has been conde ...

Is it possible that JavaScript isn't functioning properly?

My current issue involves echoing JavaScript from a PHP file to an HTML page using AJAX. Strangely, the JavaScript does not run when dynamically echoed, even though it appears in the Inspect Element tool. On the other hand, purely textual content echoes su ...

Adjusting the size of MUI StaticDatePicker

Struggling to resize the MUI staticDatePicker component. It seems the only way is to adjust the sub-components individually, but I can't locate all of them. Here's what I've managed so far: <Field as={StaticDatePicker} id='bookin ...

I'm trying to find the official documentation for the Mongoose save() method. Can

When it comes to working with Mongoose, saving data is a common task. However, the official documentation for the save method seems to be elusive. A quick Google search brings up: https://mongoosejs.com/docs/models.html and https://mongoosejs.com/docs/d ...

Customizing the language parameter for the apply button script on LinkedIn

Our company's website features the AWLI button which allows users to apply for jobs using their LinkedIn profile. <div name="widget-holder"> <script type="text/javascript" src="https://www.linkedin.com/mj ...