1

We have an RSpec test we want to run that uses selenium running with js: true. i.e. as you run the test it will literally launch firefox in front of you and go through the test itself.

Our test is policing a single page angular application and needs to do a combination of navigating around the app and then manipulating the database directly to see how the front end responds to it.

context "in my single page Angular application" do
  context "given I go to a user's profile page" do
    it "should contain the user's profile photo" do
      visit profile_page_url
      expect(page).to have_text(profile_photo_url)
    end
    
    context "and then I go to the homepage, remotely destroy the photo and return to the profile page" do
      before :each do
        visit homepage_url
        profile_photo.destroy
        visit profile_page_url
      end
      
      it "expects the profile photo to be gone" do
        expect(page).not_to have_text(profile_photo_url)
      end
    end
  end
end

In the example above you can see that we go to a user's profile page, check that their photo is there then go to the homepage. Whilst we're on the homepage we destroy the user's profile photo (directly using the script rather than the interface) and then return to the original page to see whether it's gone. Or at least this is what we do in theory.

It looks like the two processes are in different threads / transactions

In practice everything hangs once we've deleted the photo. Reading up on this it seems like this might be due to the console and selenium running two different DB transactions in parallel in different processes (threads?). The console is waiting for Selenium to finish before it can execute its DB query.

So superficially it seems like we're stuck. Anecdotally it looks like we can't do direct DB maniupulation at the same time as Selenium is running as one transaction is waiting for the other to finish.

It is possible to do this if we put a binding.pry debugger statement in. But it doesn't work in the test suite.

Is it possible to manipulate the DB synchronously with a Selenium session

We need to be able to alter the DB directly via the console and Selenium during the same session. Is this possible?

Community
  • 1
  • 1
Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • You are correct in that your tests and the rails server that selenium is browsing run in different processes. Usually when using factories it is a very good idea to use `database_cleaner` to wipe the database between specs - as residual state can lead to false positives and flapping tests. – max Oct 17 '16 at 15:05
  • Even as so that spec is pretty useless - you're merely testing that your test works... Instead destroy the record via the frontend. – max Oct 17 '16 at 15:06
  • It's not useless @max, it's testing that given that the photo is destroyed via another means (a mobile app for instance), that the app correctly removes it from the interface. Since it's a SPA the risk is that it will still show the photo even though it no longer exists in the back end. We don't want to clean the DB, we just need to manipulate it to mimick that – Peter Nixey Oct 17 '16 at 15:06
  • If you have an API route where the profile picture can be removed you may be able to get the [Capybara driver to send a DELETE request](http://stackoverflow.com/questions/4084212/how-do-you-post-to-a-url-in-capybara). However it is driver specific and I don't know if it is possible with selenium-webdriver. That would avoid the hanging DB issue. – max Oct 17 '16 at 15:28

1 Answers1

0

Is it possible to manipulate the DB synchronously with a Selenium session

Sure, there a couple of ways.

But first, please let me clarify - Selenium doesn't interact with your database at all. all it does, is automates the web application that is connected to your database. Selenium doesn't care what's in the back.

That being said, to these solutions - don't try and use "Selenium" to automate your database.

Possible solution #1

Use your Python scripts to manually connect to your database. Maybe have a global variable called db that you can interface with. In your Selenium test, just call something like db.put("something", "something")

Possible solution #2

As @max stated in the comments section, you can also directly invoke endpoints. But remember... Selenium won't do this. You can use a standard python HTTP call, or use an http request library.

ddavison
  • 28,221
  • 15
  • 85
  • 110