How do I organize my RSpec files

How do I organize my RSpec files

rspec-rails.png

In many projects I worked, I always have the same issue, big and giant RSpec files that ends up with a stress and mess that can't event let you read the file comfortable, having too many lines in one file is really a nightmare. So I decided to organize my specs in multiple files organizing them in folders and files per action, context, describe, validations etc…

By this way I have a separated file per case, obviously we will have repeated code and for this we should create a shared context to handle the code in one place and follow the DRY pattern.

Example: lets say we have ArticlesControllerand we want to test the API CRUD actions index, create, show, update, destroy, so we have five actions to be tested in one file, after doing all those specs, your file will become a giant file and will be hard to navigate between the actions to reach the code, so I prefer to divide this file and create a file per action:

- specs/requests/articles/index_spec.rb
- specs/requests/articles/create_spec.rb
- specs/requests/articles/show_spec.rb
- specs/requests/articles/update_spec.rb
- specs/requests/articles/destroy_spec.rb

Another example, lets say that the article can be draft and published, so if we have 5 published articles and 2 draft articles we need to be sure that the index action returns the publishedarticles by default and if we send the draft parameter will return the draft articles:

# frozen_string_literal: true

require "rails_helper"

RSpec.describe("Articles", type: :request) do
  before do
    create_list(:article, 2, status: :draft)
    create_list(:article, 5, status: :published)
  end

  describe "GET /api/articles" do
    context "without draft param" do
      befor do
        get("/api/articles")
      end

      it 'returns only published articles' do
        expect(json_response.count).to(eq(5))
      end
    end

    context "with draft param" do
      befor do
        get("/api/articles", params: { draft: true })
      end

      it 'returns only draft articles' do
        expect(json_response.count).to(eq(2))
      end
    end
  end
end

Imagine if you have more specs per context, your file will become a giant spec file, for me I feel more comfortable read small files rather than big files, so I prefer to divide the file into two files, one per context grouping them in one folder name as the action:

- specs/requests/articles/index/published_spec.rb
- specs/requests/articles/index/draft_spec.rb

Same thing can be done for Models and Service Objects, this helps me to keep files organized in correct folders as namespaces.

Thanks for reading.