Organizing Cucumber Steps - ruby

I am dealing with huge code base where features are grouped by domain in and are kept in separate packages.
+ServicesDomain
    |---+features
         |+step_definitions
+SalesDomain
    |---+features
         |+step_definitions
But there are always some common steps and I could not find a way to keep the common step definitions in some common steps package.
What I would like to know is that, if there is way to keep all the generic steps in some common package and make my domain package depend on generic steps package to leverage the generic steps.

One way of doing it would be to set up a file called features/support/env.rb and add a 'require' statement to this file to include your common steps each time. For instance, the file could contain:
require File.join(File.dirname(__FILE__), ​'..'​, ​'common'​, ​'common_steps'​)
That way your common_steps.rb would be loaded each time.
env.rb is the first file to be run on each Cucumber run.
Have you also heard of the Pickle gem? That might be worth a look as it does something similar by putting common steps into a file called 'pickle_steps.rb'. This comes with handy step definitions for testing models but there would be nothing stopping you editing that file and adding your own.
Hope that is of some help?

Cucumber has a command line option -r that allows you to include specific files. If you run cucumber --help, you can get more information about all the command line options. In ruby you can combine this with a config.yml file to setup globally how cucumber is run in the project. However I suspect you are using java, and I don't know if that applies. You could ask on the cucumber mailing list if thats the case.
An alternative would be to place a file in each support directory e.g. ServicesDomain/features/support and SalesDomian/features/support that just has a require statement that pulls in all the common steps. Cucumber automatically loads all the files in features/support (when it is run from features/..).

Related

In a gem or lib, where should I create a sub-project that's closely related to a gem?

Let's say, I want to add a code-autogenerator for my gem/library. A code generator won't be a single executive cli file, but it'll contain source code as well as a cli file, and I'll be working on it too along with the main gem. Besides, it'll be written in a different language. I could move it into a different repository, but for now I've chosen to use a single repository. According to the convention, in what sub-directory in the main repository should I create that sub-project? opt, var, extra, tools....?
There is more likely no convention for a such situation and I think you already know the actually good solution: use a separate repository.
If this solution is not acceptable for now, a good option would be to put it in the folder with a name explaining its purpose. E.g. if it's a code generator, it could be inside "code_generator" or "tools/code_generator".

how can I ignore certain directories when initializing sorbet?

The summary: As far as I can tell, when I run srb init, it requires every single file. Is there a way to disable or customize this behavior before the config is generated in sorbet/?
I run into some trouble with this since my team keeps gems in a non-standard location (it's a polyglot monorepo.) In particular, I'd like to tell Sorbet to ignore things in _build, db, and script—short of adding a typed: ignore to every file (apparently this won't work for us due to how gems are being set up) how can I make Sorbet ignore these?
(some background: we tried to adopt Sorbet's static checks when it first came out and could not because we use Rails and the tooling was not working well enough yet. We found the runtime checks really useful, however, and so we've been using those extensively. I've been re-evaluating the static side every couple of months, and have been consistently gotten stuck when trying to create the sorbet directory!)
I believe you can start by creating and modifying the config file accordingly and then running the whole process. You can acomplish this by running srb rbi config first, and then adding a line like --ignore=db/ to the newly created file at ./sorbet/config.
For multiple directories you can put one on each line:
--dir
.
--ignore=db/
--ignore=vendor/

Cucumber step definition folder naming

I have just started using cucumber and am seeking clarification whether the folder having my step definitions must be named exactly as step_defnitions or can it be anything (e.g. my_defs). I tried renaming in my local machine but sometimes it works and sometimes doesn't.
features/
|
|-- step_definitions/
Cucumber will automatically load any files within the features folder. This means that your step definition files can be located in any folder name/structure as long as they are in the features folder.
Note that it is possible to override this setting and explicitly state the location of your steps by doing:
cucumber -r your/steps/folder/location
For more details you can see the help - cucumber -h:
-r: Require files before executing the features. If this option is not specified, all *.rb files that are siblings or
below the features will be loaded auto-matically. Automatic loading is
disabled when this option is specified, and all loading becomes
explicit. Files under directories named "support" are always loaded
first. This option can be specified multiple times.
In every reference I've seen (including the RSpec Book), they always have a "step_definitions" folder for definitions. A lot of things in Ruby (and especially Rails) utilize a "convention over configuration" philosophy, and I believe this is one of those things. I think it'd be less hassle for you to just make the "step_definitions" folder inside the "features" folder and know that it should work than to try and figure out how to change the configuration.

rspec require spec_helper in .rspec file

I've noticed that projects such as bundler do a require spec_helper in each spec file
I've also noticed that rspec takes the option --require, which allows you to require a file when rspec is bootstrapped. You can also add this to the .rspec file, so it is added whenever you run rspec with no arguments.
Are there any disadvantages to using the above method which might explain why projects such as bundler choose to require spec_helper in each spec file?
I don't work on Bundler so I can't speak directly about their practices. Not all projects check-in the .rspec file. The reason is this file, generally by current convention, only has personal configuration options for general output / runner preferences. So if you only required spec_helper there, others wouldn't load it, causing tests to fail.
Another reason, is not all tests may need the setup performed by spec_helper. More recently there have been groups of Rubyists who are trying to move away from loading too many dependencies into the test. By making it explicit when spec_helper is required in the test people have an idea what may be going on. Also, running a single test file or directory that doesn't need that setup will be faster.
In reality, if all of your tests are requiring spec_helper and you've make it a clear convention on the project there's no technical reason you can't or shouldn't do it. It just may be an initial surprise for new people who join the project.
With a proper setup, there's no downside at all.
The .rspec file is meant to be project related (and should be commited like any other project source file).
Meanwhile, the .rspec-local is for overriding with personalized settings (and it will let the user override some options only).
(see: https://www.relishapp.com/rspec/rspec-core/v/3-2/docs/configuration/read-command-line-configuration-options-from-files)
Rails projects even use a separate --require rails_helper for Rails-specific RSpec settings.
Both the .rspec and --require options have existed since 2011 at least (which is ages ago).
And, RSpec is especially not a tool for people needing training wheels - you want people to understand how RSpec works and what the options are, because you want people to know e.g. when and where to temporarily set the --seed option, how to change the formatter, switch on --fail-fast, use specific tags to work on a feature, etc.
The test environment also has to have a consistent configuration, so you do not want people tweaking the spec_helper file or the .rspec file (for the same reason).
In short: if it doesn't apply to every spec in the project, it shouldn't be in the spec_helper file. Which is why you should make sure it is included by every spec file. And the .rspec file is the best way to do that.
The only reason to not to switch to this is when the project is being actively maintained by many people (and any project wide change just creates annoyances by e.g. forcing people to rebase their work for no reason related to what they were working on).
Bundler fits into this category - to many people potentially working concurrently.
P.S. I also recommend using rspec --init on an empty project and checking out the generated config.

How do I get my ruby source in the load path when invoking with thin?

I'm playing around with a combination of Thin, Sinatra and Bundler. I'm trying to understand how I get Thin to include the path to my source code in the load path? I have looked for introductory tutorials to this setup, but none of them seem to answer my question.
Mucking around with the rackup file or Thin config file feels wrong. Assume I have a directory structure with something like:
bin/my-application-entry.rb # The entry point to my sinatra application
lib/myapp/mylibs.rb
thin/config.ru # rackup config
thin/dev.yaml # thin config
Gemfile # for my dependencies
The contents of the rackup file is essentially
require 'sinatra'
# I'd like to require 'my-application-entry' around here somewhere (I think?)
run Sinatra.application
I invoke the application with
thin -C thin/dev.yaml -R thin/config.ru start
I noticed that thin takes a command-line argument to require a specific library, but surely there is a better place where you can define all the load paths?
So my question is really, how do I tell thin/rack/bundler which directories to include? (such as bin/ and lib/)
Edit: For clarity, I'd really like to know how this is generally done with Thin specifically. I am reluctant to modify $: in my main application, but if I am forced to use $:, where is the best place (in a Thin/Rack/Sinatra context) to do so?
$: is a global variable describing the load path, represented as an array. You can add ".", then if you care, eliminate duplicates, as follows:
$:.unshift(".").uniq!
Or you can push it to the end of the list:
$:.push(".").uniq!
It's often omitted by default because it's a potential security hazard.
I'm wondering the same thing. I'll tell you what I'm doing and try to justify it. Perhaps in the process of writing this, I'll have figured something out.
I have decided, for now, to add to $LOAD_PATH in config.ru, because I'm using config.ru as the entry point of my application. I can get away with this because I intend to leave this file in the root of the project. I don't like making that assumption, but it seems pretty safe for now. Of course, I'll leave a comment saying "Ew. Assumes that this file is the only entry point of the application and that it will always be in the root of the project."
I chose this because I want to add to $LOAD_PATH as high up in the call stack as possible (Dependency Inversion Principle), but doing so in the commands that run the app (Procfile running thin in production; command line running shotgun in development) duplicates the directories that I want to add to the load path. Do I classify this duplication as essential (worth removing) or coincidental (worth duplicating)? For now, it looks like an essential aspect of the app, at least as I've decided to organise it, because the app integrates the various services into a single request/response/routing engine. Also, config.ru describes the app, so it makes sense to treat it as the app.
If the situation changes and I notice that I want a different $LOAD_PATH in development than in production, then I'll move the directories up the call stack into the command that runs config.ru.
I feel comfortable with this choice, not because I consider it "the right choice", but because I think I know how and why I'd change my mind. Good enough for me.
I hope this helps.

Resources