javascript integration testing

鲍国兴
2023-12-01

Questions


1. what is

Headless browser?

headless browser is a web browser without a graphical user interfaceThey are particularly useful for testing web pages as they are able to render and understand HTML the same way a browser would, including styling elements


2. what is 

Capybara?


Capybara is a web-based automation framework used for creating functional tests that simulate how users would interact with your application.

2. what is 

Rack_test?

Without JavaScript, Capybara uses rack-test as a driver by default and looks something like this:

  • +
  • You trigger user action by invoking one of Capybara’s DSL methods, such as visit.
    +
  • Capybara tells its driver (rack-test) to load the requested URL.
    +
  • rack-test uses the URL to generate a fake Rack request and passes it directly to the in-memory instance of your Rails application.
    +
  • The Rack response is parsed by rack-test and saved as the current page.
3. what is

Selenium, capybara-webkit, and Poltergeist?

browser tools like WebKit are difficult to load inside of a Ruby process, these drivers boot up an external process which can interact with the browser engine. Because the external process doesn’t have access to the in-memory instance of your Rails application, they must make actual HTTP requests.
  • You trigger user action by invoking one of Capybara’s DSL methods, such as visit.
    +
  • Capybara tells its driver (such as capybara-webkit) to load the requested URL.
    +
  • The driver starts its external process to hold the browser engine.
    +
  • In order to serve actual HTTP requests, Capybara boots a new instance of your Rails application in a background thread.
    +
  • The driver’s browser process uses the URL to create a real HTTP request which is passed to your application server, such as Thin.
    +
  • Thin translates the HTTP request into a Rack request, which is passed to your Rails application in the background thread.
    +
  • Thin also translates your Rack response into a real HTTP response, which is accepted by the browser process.
There’s a lot of extra machinery in here to make this work: process forking, HTTP requests, and background threads. However, there’s really only one bump which frequently affects users: that pesky background thread.
If requests are served in a background thread, that means that your tests keep running while your application responds to simulated interactions. This provides for an endless number of race conditions, where your tests look for elements on the page which have not appeared yet

Capybara is smart enough to understand that a page may not have loaded by the time you try to interact with it.

Test Thread Application Thread
Your test invokes visit. Waiting for a request.
Capybara tells the driver to load the page. Waiting for a request.
The driver performs a request. Waiting for a request.
Your test invokes click_link. Your application receives the request.
Capybara looks for the link on the page, but it isn’t there. Your application sends a response.
Capybara tries to find the element again, but it’s not there. The driver receives the response.
Capybara successfully finds the element from the response. Waiting for a request.

Find the first matching element

+

Bad:

+
first(".active").click
+

If there isn’t an .active element on the page yet, first will return nil and the click will fail.

+

Good:

+
# If you want to make sure there's exactly one
find(".active").click

# If you just want the first element
find(".active", match: :first).click

Interact with all matching elements

+

Bad:

+
all(".active").each(&:click)
+

If there are no matching elements yet, an empty array will be returned, and no elements will be affected.

+

Good:

+
find(".active", match: :first)
all(".active").each(&:click)

Directly interacting with JavaScript

+

Bad:

+
execute_script("$('.active').focus()")
+

JavaScript expressions may be evaluated before the action is complete, and the wrong element or no element may be affected.

+

Good:

+
find(".active")
execute_script("$('.active').focus()")
+

Capybara will wait until a matching element is on the page, and then dispatch a JavaScript command which interacts with it.

+

Note: execute_script should only be used as a last resort when running into driver limitations or other issues which make it impossible to use other Capybara methods.

Checking a field’s value

+

Bad:

+
expect(find_field("Username").value).to eq("Joe")
+

Capybara will wait for the matching element and then immediately return its value. If the value changes from a page load or Ajax request, it will be too late.

+

Good:

+
expect(page).to have_field("Username", with: "Joe")
+

Capybara will wait for a matching element and then wait until its value matches, up to two seconds.

Checking an element’s attribute

+

Bad:

+
expect(find(".user")["data-name"]).to eq("Joe")
+

Capybara will wait for the matching element and then immediately return the requested attribute.

+

Good:

+
expect(page).to have_css(".user[data-name='Joe']")
+

Capybara will wait for the element to appear and have the correct attribute.

Looking for matching CSS

+

Bad:

+
it "doesn't have an active class name" do
  expect(has_active_class).to be_false
end

def has_active_class
  has_css?(".active")
end
+

Capybara will immediately return true if the element hasn’t been removed from the page yet, causing the test to fail. It will also wait two seconds before returning false, meaning the test will be slow when it passes.

+

Good:

+
it "doesn't have an active class name" do
  expect(page).not_to have_active_class
end

def have_active_class
  have_css(".active")
end
+

Capybara will wait up to two seconds for the element to disappear before failing, and will pass immediately when the element isn’t on the page as expected.

Summary

+

When interacting with the page, use action methods like click_on instead of finder methodslike find whenever possible. Capybara knows the most about what you’re doing with those methods, and can more intelligently handle odd edge cases.

+

When verifying that elements are on the page as expected, use RSpec matchers likehave_css instead of node methods like text whenever possible. Capybara can wait for the result you want with a matcher, but doesn’t know what text you’re expecting when you invoke methods on a node.









references

https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara

 类似资料:

相关阅读

相关文章

相关问答