I would love to understand more about how capybara-webkit works and provide contributions to capybara-webkit. However the contributor's guide does not provide a high-level view of how Capybara Webkit works. In particular how capybara-webkit is initialised from the context of Capybara, and how a developer without intimate knowledge of the QT ecosystem could begin to contribute / look at relevant reading resources.
To try to help with this initial documentation, I have investigated the source code and this is what I believe to be true.
Capybara-Webkit
There are two important aspects to Capybara-Webkit. Firstly the Capybara-webkit DSL implementation which allows for a developer to call methods such as page.findCss('#foo'), and a running C++ Webkit-server which the Ruby Capybara-webkit DSL will react out to.
Webkit Server
When Capybara-webkit is installed, it creates a custom webkit binary which directly interacts with a browser. This binary hosts a server which listens for commands sent to it, in this case via capyara-webkit.
When capybara-webkit is bundled via bundle install, it creates a new webkit server binary as part of extconf.rb, which calls CapybaraWebkitBuilder.build_all. This CapybaraWebkitBuilder relies on qmake to create the webkit server binary. A top level file called webkit_server.pro is used as part of the qmake build, where .pro is a file extension used to represent project.
It is within webkit_server.pro that specifies the configuration of various various custom capybara C++ header files to be injected into the custom webkit-server build, as seen here here
Additionally within this webkit_server.pro file there is a RESOURCES = webkit_server.qrc line which injects two custom resources:
It is the Capybara.js file which injects in a global JavaScript helper object called Capybara. This helper contains various function to find and interact with particular elements on the page, such as findXpath etc. For instance, when the capybara-webkit server is called, it will reach out to this custom JavaScript helper embedded on to the page to evaluate its scripts. This JavaScript helper will be injected on to the page when a new webpage is visited.
All of this is required to build a webkit server which is built under bin/webkit_server, which will later be run by the capybara-webkit Ruby process.
Capybara Webkit
Capybara Webkit is a driver for Capybara, and it implements Capybara's Domain Specific Language (DSL). When running an rspec project with feature tests; Capybara will request for the currently configured driver (i.e. capybara-webkit) to initialize. When this Capybara driver is initialized, the previously built webkit server bin/webkit_server will be started, and a connection from Ruby will be opened to this new server.
As a high level example of how the interaction of capybara-webkit works:
A Capybara DSL method such as page.find_css('#foo') is called within an RSpec test
The Capybara-webkit library needs to reach out to the running webkit server
Capybara webkit communicates with the webkit server with 'command' calls. For instance invoke("findXpathWithin", xpath), which will result in a command being sent to the previously opened webkit-server connection, as shown here
The webkit-server receives and parses this sent string command into a C++ command object, which contains the logic of how to handle this particular request. The full list can be seen here:
In this case the FindCss.cpp command object will be matched, and the particular implementation will invoke page()->invokeCapybaraFunction(...).
invokeCapybaraFunction is a function call which will attempt to make the request to call findCss within the browser. It does this in two steps. First, it first injects a global CapybaraInvocation object on the current QWebFrame, which contains the request object information. With this helper object injected on to the web page, it will call the previously embedded JavaScript helper Capybara.invoke. The implementation of invoke will look at injected CapybaraInvocation object and decide what function to call:
QT - The C++ library used to create applications with widgets. Capybara-webkit uses this and qmake to create a custom qtwebkit binary
QT_WebKit - Describes how to integrate QT Webkit in a .pro file, as used within webkit_server.proqmake project files - Describes the overall structure of qmake .pro files
I am unsure if the above knowledge is correct; And I would appreciate additional insight into this :+1:
If it seems appropriate, I can go ahead and create a PR to add this into the codebase too.
At a high-level I would like to also add additional information into debugging race conditions/other issues with capybara webkit.
For instance, how a developer should approach a problem such as:
Currently I am unsure how to document the debugging issues, due to my unfamiliarity with the codebase, but I would definitely appreciate thoughts on this :+1:
I would love to understand more about how capybara-webkit works and provide contributions to capybara-webkit. However the contributor's guide does not provide a high-level view of how Capybara Webkit works. In particular how capybara-webkit is initialised from the context of Capybara, and how a developer without intimate knowledge of the QT ecosystem could begin to contribute / look at relevant reading resources.
To try to help with this initial documentation, I have investigated the source code and this is what I believe to be true.
Capybara-Webkit
There are two important aspects to Capybara-Webkit. Firstly the
Capybara-webkit
DSL implementation which allows for a developer to call methods such aspage.findCss('#foo')
, and a running C++ Webkit-server which the Ruby Capybara-webkit DSL will react out to.Webkit Server
When Capybara-webkit is installed, it creates a custom webkit binary which directly interacts with a browser. This binary hosts a server which listens for commands sent to it, in this case via capyara-webkit.
When capybara-webkit is bundled via
bundle install
, it creates a new webkit server binary as part ofextconf.rb
, which callsCapybaraWebkitBuilder.build_all
. This CapybaraWebkitBuilder relies onqmake
to create the webkit server binary. A top level file calledwebkit_server.pro
is used as part of the qmake build, where.pro
is a file extension used to representproject
.It is within
webkit_server.pro
that specifies the configuration of various various custom capybara C++ header files to be injected into the custom webkit-server build, as seen here hereAdditionally within this
webkit_server.pro
file there is aRESOURCES = webkit_server.qrc
line which injects two custom resources:It is the Capybara.js file which injects in a global JavaScript helper object called
Capybara
. This helper contains various function to find and interact with particular elements on the page, such asfindXpath
etc. For instance, when the capybara-webkit server is called, it will reach out to this custom JavaScript helper embedded on to the page to evaluate its scripts. This JavaScript helper will be injected on to the page when a new webpage is visited.All of this is required to build a webkit server which is built under
bin/webkit_server
, which will later be run by the capybara-webkit Ruby process.Capybara Webkit
Capybara Webkit is a driver for Capybara, and it implements Capybara's Domain Specific Language (DSL). When running an rspec project with feature tests; Capybara will request for the currently configured driver (i.e. capybara-webkit) to initialize. When this Capybara driver is initialized, the previously built webkit server
bin/webkit_server
will be started, and a connection from Ruby will be opened to this new server.As a high level example of how the interaction of capybara-webkit works:
page.find_css('#foo')
is called within an RSpec testinvoke("findXpathWithin", xpath)
, which will result in a command being sent to the previously opened webkit-server connection, as shown herepage()->invokeCapybaraFunction(...)
.invokeCapybaraFunction
is a function call which will attempt to make the request to callfindCss
within the browser. It does this in two steps. First, it first injects a globalCapybaraInvocation
object on the current QWebFrame, which contains the request object information. With this helper object injected on to the web page, it will call the previously embedded JavaScript helperCapybara.invoke
. The implementation ofinvoke
will look at injectedCapybaraInvocation
object and decide what function to call:Useful Resources
QT - The C++ library used to create applications with widgets. Capybara-webkit uses this and
qmake
to create a custom qtwebkit binary QT_WebKit - Describes how to integrate QT Webkit in a.pro
file, as used within webkit_server.pro qmake project files - Describes the overall structure of qmake.pro
filesI am unsure if the above knowledge is correct; And I would appreciate additional insight into this :+1: If it seems appropriate, I can go ahead and create a PR to add this into the codebase too.
At a high-level I would like to also add additional information into debugging race conditions/other issues with capybara webkit.
For instance, how a developer should approach a problem such as:
Currently I am unsure how to document the debugging issues, due to my unfamiliarity with the codebase, but I would definitely appreciate thoughts on this :+1: