Bug 210162 - Web Automation: timeout underneath Automation.evaluateJavaScriptFunction in Selenium test frame_switching_tests.py::testShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs[Safari]
Summary: Web Automation: timeout underneath Automation.evaluateJavaScriptFunction in S...
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebDriver (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: BJ Burg
Keywords: InRadar
Depends on:
Reported: 2020-04-07 15:22 PDT by BJ Burg
Modified: 2020-04-24 10:50 PDT (History)
9 users (show)

See Also:

Patch (24.42 KB, patch)
2020-04-07 16:11 PDT, BJ Burg
no flags Details | Formatted Diff | Diff
Patch (24.00 KB, patch)
2020-04-24 09:57 PDT, BJ Burg
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description BJ Burg 2020-04-07 15:22:50 PDT
Comment 1 BJ Burg 2020-04-07 15:23:10 PDT
Comment 2 BJ Burg 2020-04-07 16:11:53 PDT
Created attachment 395756 [details]
Comment 3 Devin Rousso 2020-04-08 14:30:14 PDT
Comment on attachment 395756 [details]

View in context: https://bugs.webkit.org/attachment.cgi?id=395756&action=review

r=me, the overall idea seems solid, but I do have lots of comments 😅

> Source/WebKit/ChangeLog:35
> +        (WebKit::WebAutomationSessionProxy::ensureObserverForFrame): For non-main frames,

NIT: for multi-line explanations, I prefer to start it on the next line, as that's where my eye naturally thinks the explanation starts 😅

> Source/WebKit/WebKit.xcodeproj/project.pbxproj:10822
> +				990D39F5243BE64800199388 /* WebAutomationDOMWindowObserver.h in Headers */,

This should be sorted.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:27
> +#include "WebAutomationDOMWindowObserver.h"

Please make sure all necessary includes are in this file, such that if unified sources get shuffled around this file doesn't cause build breakages due to previously implicit includes.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:36
> +    ASSERT(this->frame());

Is the `this` necessary?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:37
> +    if (m_window)

When would we ever want to create a `WebAutomationDOMWindowObserver` with an invalid `DOMWindow`?  Why not pass a `DOMWindow&` instead?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:47
> +Frame* WebAutomationDOMWindowObserver::frame() const

It seems like all this is used for is inside `ASSERT`.  Perhaps we could remove this and just `ASSERT(m_window && m_window->frame())` in those places instead?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:62
> +    if (m_window)

Is this really necessary?  This function is called by `DOMWindow`, so we should be guaranteed to have a `m_window`.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:73
> +    if (!m_wasDetached) {

Given my comment on +95, I don't think it's possible for this to be called if `m_wasDetached`.  I'm not sure we'd need the member variable in that case either.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:75
> +        Frame* frame = this->frame();
> +        ASSERT_UNUSED(frame, frame);

Why not just `ASSERT(frame());`?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:80
> +    if (m_window)

Ditto (+62)

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:93
> +    Frame* frame = this->frame();
> +    ASSERT_UNUSED(frame, frame);

Ditto (+74)

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:94
> +    m_callback(*this);

Shouldn't we also `m_window->unregisterObserver(*this)` here too, given that `m_callback(*this)` removes this object from `m_observers`, therefore causing it to be destroyed, meaning that no further callbacks should be run?  Or is this because it's possible/allowed/valid for the frame to be re-attached and continue to be used?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.cpp:96
> +    m_wasDetached = true;

NIT: should this be set earlier to prevent reentrancy (using the `ASSERT(!m_wasDetached)`) via `m_callback`?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:28
> +#import <WebCore/DOMWindow.h>

Please add
    #include <wtf/Forward.h>

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:31
> +class Element;

This doesn't seem needed.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:47
> +    // All of these observer callbacks are interpreted as a signal that a frame has been detached and
> +    // can no longer accept new commands nor finish pending commands (eg, evaluating JavaScript).

Wouldn't the same apply to `suspendForBackForwardCache`, or are frames that have been navigated away from still considered valid?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:53
> +    WebCore::DOMWrapperWorld& world() const { return m_world; }

We should forward declare or include `WebCore::DOMWrapperWorld` too.

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:59
> +    Ref<WebCore::DOMWrapperWorld> m_world;

Why is this needed?  It doesn't seem like it's used anywhere.  Is it just to keep it alive?

> Source/WebKit/WebProcess/Automation/WebAutomationDOMWindowObserver.h:60
> +    RefPtr<WebCore::Frame> m_disconnectedFrame;

When is this set?

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:68
> +using namespace WebCore;

Shouldn't this be inside the `namespace WebKit {`?

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:310
> +    if (!frame.coreFrame()->window() || !frame.coreFrame()->window()->frame())

Shouldn't we also check that `frame.coreFrame()` exists?

If `frame.coreFrame()` exists, then wouldn't it be equal to `frame.coreFrame()->window()->frame()`, or can they be different objects?

Als, since you access `frame.coreFrame()->window()` three different times, perhaps it's worth pulling out into a variable?

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:316
> +    FrameIdentifier frameID = frame.frameID();


> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:317
> +    m_frameObservers.set(frameID, WebAutomationDOMWindowObserver::create(frame.coreFrame()->window(), WebCore::mainThreadNormalWorld(), [this, frameID] (WebAutomationDOMWindowObserver&) {

We should have an include for `DOMWrapperWorld`.

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:318
> +        this->willDestroyGlobalObjectForFrame(frameID);

NIT: is the `this->` needed?

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:350
> +    if (!frame || !frame->coreFrame()->window() || !frame->coreFrame()->window()->frame()) {

Ditto (+310)

> Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:-738
> -        String invalidNodeIdentifierrrorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::InvalidNodeIdentifier);


Part of me want's to keep this for the lols :P
Comment 4 BJ Burg 2020-04-24 09:57:29 PDT
Created attachment 397463 [details]
Comment 5 EWS 2020-04-24 10:50:45 PDT
Committed r260653: <https://trac.webkit.org/changeset/260653>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 397463 [details].