Custom spec types with RSpec

We use RSpec as our testing framework at Modern Message. And I learned something new about RSpec today.

You know those types that you can pass into RSpec specs? For example:

Or

Starting from RSpec 3+, we have to specifically define these spec types. And it turns out that these spec types provide RSpec specific methods that you can use like post, expect, and etc that you use to write your tests. Also, it turns out that you can define your custom spec types as well.

Why am I writing about custom spec types?

At Modern Message, I’m currently working on a feature where I have to have common before and after hooks for multiple specs. To be specific, I’m currently using the stripe-ruby-mock library to stub out external requests made to Stripe in my tests.

For each test that utilizes the stripe-ruby-mock gem, we need a before and after hook that starts and stops the StripeMock class. You can read through the docs in the GitHub page for the library, but essentially it looks something like this.

In my specific circumstance, I am writing tests for webhook events that Stripe sends out. For example, Stripe has a webhook event called invoice.payment_succeeded. To create a corresponding model in my Rails app, I created a folder called stripe_service in my models folder and a corresponding ruby class file app/models/stripe_service/invoice_payment_succeeded.rb.

Do note that Stripe does have multiple webhook events and in my specific case (and probably in most Rails applications), you would have multiple classes and files in the stripe_service folder that represents different webhook events. And that means more spec files in spec/models/stripe_service/ folder with more repetitive before and after hooks starting and stopping the StripeMock class.

While I’m one of those people who believe that there’s nothing wrong with a little bit of duplication (especially in my case where we only have three webhook event classes), we can remove this before and after hook duplication with a custom spec type. Thus, if we create a custom spec type, our Stripe::InvoicePaymentSucceeded spec will look like this.

To create this custom stripe_service type, we need to go into our spec/spec_helper.rb file and define this new type. Here’s an example.

Here, the first thing we do is that we specify that all of the specs in the spec/models/stripe_service folder to have the type stripe_service. And in the following lines of the configuration, we use our new strip_service metadata type, we specify that before and after hooks both start and stop the StripeMock classes. With this configuration, each time we specify our specs to have the type stripe_service, it’ll automatically run the before and after hooks automatically, reducing duplication in our specs.