如何在完成加载之前在iframe中覆盖JavaScript警报功能?

时间:2019-01-11 17:42:49

标签: javascript html google-chrome iframe override

我正在使用无头chrome浏览器和幽灵(https://github.com/BBC-News/wraith)。 问题是当我有一个页面打开警报失败失败

ERROR: unexpected alert open: {Alert text : Bla bla bla.}
  (Session info: headless chrome=71.0.3578.98)
  (Driver info: chromedriver=71.0.3578.33 (269aa0e3f0db08097f0fe231c7e6be200b6939f7),platform=Mac OS X 10.13.6 x86_64)

这是我尝试过的,但到目前为止失败了:

const BACKEND_USERNAME = "";
const BACKEND_PASSWORD = "";

function resizeIFrameToFitContent(iFrame) {
    iFrame.width = iFrame.contentWindow.document.body.scrollWidth;
    iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
}


var original_url_asked = document.referrer;
if (typeof jQuery !== 'undefined') {//maybe 500 or 404 page
    $(document).ready(function () {
        //we ended up on login page, let's login
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="password"]:nth-child(3)').prop('value', BACKEND_PASSWORD);
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="text"]:nth-child(1)').prop('value', BACKEND_USERNAME);
        $('body > div:nth-child(23) > div.backend_right_content > div > div > form > input[type="submit"]:nth-child(5)').click();//submit form

        //we are logged in
        $('body').empty();//clear all the stuff
        //since we can't redirect, we'll open a full page iframe with the url we wanted to see initially
        $('body').append('<iframe id="ifr" width="100%" height="100%" frameborder="0" src="" ></iframe>');

        //load the original_url finally
        $("#ifr").attr("src", original_url_asked);//cannot redirect or wraith complains


        //hide the menu and other elements, for smaller screenshots
        $('#ifr').on('load', function () {
            $('#ifr').contents().find('div.backend_left, div.backend_right_top').remove();
            resizeIFrameToFitContent(document.getElementById('ifr'));
        });
    });
}

//important or wraith will not understand it is ready to take a screenshot
var callback = arguments[arguments.length - 1];
setTimeout(callback, 20000);//wait for page to load

2 个答案:

答案 0 :(得分:2)

您无法使用JavaScript来阻止警报窗口,因为wraith执行before_capture脚本时,警报弹出窗口已经存在。因此,当wraith尝试执行JavaScript并使警报弹出窗口保持打开状态时,webdriver会引发您遇到的错误。

您可以切换到phantomjs来解决此问题,但是如果您要坚持使用无硒硒鼓和wraith,则必须修补wraith才能正确处理模式弹出窗口。

  

文件:{Ruby安装目录} \ lib \ ruby​​ \ gems \ 2.6.0 \ gems \ wraith-4.2.3 \ lib \ wraith \ save_images.rb
  :129

driver.navigate.to url
# patch to handle rogue alert popups at page load
while true
  begin
    driver.switch_to.alert.dismiss
  rescue
    break
  end
end
# patch end
driver.execute_async_script(File.read(global_before_capture)) if global_before_capture

while循环将消除页面导航到您的URL并运行before_capture脚本时发现的警报弹出窗口。

答案 1 :(得分:1)

如果您可以访问跨域iframe,则可以覆盖原生alert函数,如下所示:

<iframe id="ifr" src="about:blank"></iframe>
<script type="text/javascript">
var iframe = document.getElementById('ifr');

iframe.addEventListener('load', function(event)
{
    iframe.contentWindow.alert = function(s){console.log(s)};
});

iframe.src = 'iframe.html';
</script>

来自iframe.html的代码

<script type="text/javascript">
alert('iframe'); // this will always native function and you can not override it
</script>

<!-- BUT the following message you will get in console: -->
<input type="button" value="try it" onclick="alert('Your native alert was overriden!')">

现在,您可以在此iframe中单击按钮,然后在控制台中收到消息'Your native alert was overriden!'

换句话说:您可以覆盖本机alert函数,但是在加载iframe window之前不能覆盖它。对于这种情况,我们没有任何事件。只有在加载iframe window之后,您才能使用覆盖功能。如果您足够使用它,就可以使用它。

但是您不能做的其他事情。

需要了解的重要内容:

总是在从新的src设置iframe后,iframe会加载原始(本机)alert函数。因此,在加载iframe中的新网站后,您必须始终覆盖它。

替代解决方案

感谢用户Munim Munna在评论中的提示,我们提供了一个完美的解决方案: 您可以将 sandbox="allow-forms allow-same-origin allow-scripts" 作为属性添加到iframe中,如下所示:

<iframe id="ifr" src="about:blank" sandbox="allow-forms allow-same-origin allow-scripts"></iframe>

,除非您将allow-modals添加到此列表,否则所有警报框将被忽略。在这种情况下,在控制台中,您将收到错误消息:

  

忽略了对'alert()'的呼叫。该文档已被沙箱化,并且未设置'allow-modals'关键字。

如果有人不喜欢它,那么他可以像我回答的第一部分一样覆盖alert函数。