Short version of my question:
In Cucumber tests written for an Angular single page web application, how do I accomplish the tasks usually performed in the "given" section of a scenario (such as setting up test data, defining database record associations, and ensuring a clean database state between tests) when testing the full-stack, both the front-end application and its back-end? The application source code is stored in two separate Git repositories, one for the front-end application and one for the back-end. The back-end is written in Ruby using the Rails API gem. The challenge in testing this application full-stack comes from the fact that it's actually two applications, in contrast with a more traditional Ruby on Rails application not implemented as a single page application.
Full version of my question:
I'm looking to write a series of Cucumber tests for a web application. The application consists of a front-end single page application written in Angular, and a back-end API written using Rails API. The source code for the front-end and the source code for the back-end each reside in their own Git repositories, providing a clean separation between the two codebases. Furthermore, the application uses MySQL and Elasticsearch.
I've used Cucumber in the past on previous Ruby on Rails projects. These projects were not developed as single page applications. In these projects it was easy to create Ruby objects as test data in Cucumber step definitions. For example, consider the following feature file from a Rails project that was not a single page application:
# features/home_page.feature
Feature: Home page
Scenario: Viewing application's home page
Given there's a post titled "My first" with "Hello, BDD world!" content
When I am on the homepage
Then I should see the "My first" post
The steps in this feature file can be implemented with the following step definitions:
# features/step_definitions/home_page_steps.rb
Given(/^there's a post titled "(.*?)" with "(.*?)" content$/) do |title, content|
@post = FactoryGirl.create(:post, title: title, content: content)
end
When(/^I am on the homepage$/) do
visit root_path
end
Then(/^I should see the "(.*?)" post$/) do |title|
@post = Post.find_by_title(title)
page.should have_content(@post.title)summary of the question
page.should have_content(@post.content)
end
In Ruby on Rails projects that were not developed as single page applications, testing tools can be included into the project as Ruby gems. For me, these tools would include:
group :test do
gem 'shoulda-matchers'
gem 'cucumber-rails', require: false
gem 'database_cleaner'
gem 'selenium-webdriver'
end
group :development, :test do
gem 'factory_girl_rails'
end
As you can see, this includes Factory Girl, used for setting up Ruby objects as test data and defining database record associations, and Database Cleaner, used to ensure a clean database state between tests. The inclusion of Selenium WebDriver is required for Cucumber scenarios which use JavaScript.
The situation is different in the case of my single page application. As described above, the application is broken into two separate code bases, one for the Angular front-end single page application and the other for the Rails API back-end interface.
However, single page applications such as my project still have the same testing requirements as more traditional Rails applications not built as single page applications. It's necessary to test the application full-stack to ensure each component, both front and backend, work together as expected. There will need to be Cucumber steps defined which create the "given" preconditions prior to a test, and it will be necessary to ensure a clean database between tests.
How do I test with Cucumber an application such as this, one with two code bases, implemented as a single page application? There's a version of Cucumber available for JavaScript called CucumberJS. However, I don't know how to create fixtures, record associations, and to ensure a clean database between tests using CucumberJS. There's also a tool for testing JavaScript written with Angular called Protractor. I imagine this tool taking the place of Selenium WebDriver.
Answer to the short version question.
What you describe is tipical to single page apps. I have a number of spa examples (covered with E2E) where the backend is a RESTful API in PHP, Dot.net or ever a cloud web-service (parse.com). To my point of view, it is best to treat such apps, to qoute you agin, as 2 different apps and write 2 different sets of test for each. I believe that is the only way to write stable, scalable and fast e2e tests.
Basically what we do is create a local non-persistent mock api (in javascript) especially for testing. Here's a list of requirements/guidelines for such an api:
How does that look in practice. Let's say we are testing a Login feature of the website and it has 3 scenarios:
To satisfy these tests all we have to do is implement an api for the POST /login request: