-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: add infrastructure for cucumber/aruba features
cucumber allows us to express test cases in gherkin given/when/then syntax and the aruba library lets us take our features to Kokomo, adding step definitions for common actions when testing a command-line application.
- Loading branch information
1 parent
51f73f8
commit 37a7698
Showing
11 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Feature: Available Aruba Steps | ||
# # uncomment me to describe available aruba step phrases | ||
# # see step implementations: https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber | ||
# # see step documentation: https://relishapp.com/cucumber/aruba/v/0-11-0/docs/getting-started | ||
|
||
# @announce-stdout | ||
# Scenario: 'available aruba steps' | ||
# Given an executable named "bin/cli" with: | ||
# """ | ||
# #!/bin/bash | ||
# git clone https://github.com/cucumber/aruba.git | ||
# cd aruba | ||
# grep -E "When|Given|Then" lib/aruba/cucumber/*.rb | awk -F ":" '{ $1 = ""; print $0}' |sort | ||
# """ | ||
# When I run `bin/cli` | ||
# Then the exit status should be 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Feature: usage | ||
Background: | ||
Given I have installed "goconfig" locally into the path | ||
|
||
# @announce-stdout @announce-stderr | ||
Scenario: help | ||
When I run `goconfig` | ||
Then the stdout should show usage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
Then(/(the )?(\w+) from `([^`]*)` should (not )?contain "([^"]*)"/) do |_, channel, cmd, negated, content| | ||
run_command_and_validate_channel( | ||
cmd: cmd, | ||
fail_on_error: true, | ||
channel: channel, | ||
negated: negated, | ||
match_as_regex: false, | ||
content: content | ||
) | ||
end | ||
|
||
Then(/(the )?(\w+) from `([^`]*)` should (not )?match "([^"]*)"/) do |_, channel, cmd, negated, content| | ||
run_command_and_validate_channel( | ||
cmd: cmd, | ||
fail_on_error: true, | ||
channel: channel, | ||
negated: negated, | ||
match_as_regex: true, | ||
content: content | ||
) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'fileutils' | ||
|
||
Given('I have installed {string} into {string} within the current directory') do |app, path| | ||
install_binary_and_add_to_path(app, path) | ||
end | ||
|
||
Given('I have installed {string} locally into the path') do |app| | ||
install_binary_and_add_to_path(app, 'bin') | ||
end | ||
|
||
def install_binary_and_add_to_path(app, path) | ||
exe = File.join(aruba.root_directory, path, app) | ||
raise "'#{exe}' not found; did you run 'make build'?" unless File.exist?(exe) | ||
|
||
expanded_path = expand_path(path) | ||
|
||
create_directory(path) | ||
FileUtils.cp(exe, expanded_path) | ||
|
||
# TODO: find a way to assert the dest path exists without listing the folder contents to stdoout | ||
# run_command_and_stop("ls -la #{path}", fail_on_error: true) | ||
|
||
unless ENV['PATH'].split(File::PATH_SEPARATOR).include?(path) | ||
prepend_environment_variable "PATH", expand_path(path) + File::PATH_SEPARATOR | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# frozen_string_literal: true | ||
|
||
Given('I clear the screen') do | ||
aruba.command_monitor.clear | ||
end | ||
|
||
# Then(/(the )?(\w+) should (not )?show usage/) do |_, channel, negated| | ||
Then(/the (\w+) should show usage/) do |channel| | ||
negated = false | ||
validate_channel( | ||
channel: channel, | ||
negated: negated, | ||
match_as_regex: false, | ||
content: "Usage:" | ||
) | ||
end | ||
|
||
When('I sleep for {int} seconds') do |n_seconds| | ||
sleep(n_seconds) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'aruba' | ||
require 'aruba/cucumber' | ||
|
||
# Aruba ------------------------------------------------ | ||
|
||
# aruba file matchers: https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber/file.rb | ||
# aruba command matchers: https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber/command.rb | ||
|
||
# Step Helpers ----------------------------------------------- | ||
|
||
module Command | ||
# syntax wrappers around arub commands | ||
module StepHelpers | ||
|
||
# this helper provides some common logic around running a specific | ||
# command using Aruba's environment and path resolution, then | ||
# inspecting that output and matching it either as a regex match | ||
# or a string contains | ||
def run_command_and_validate_channel(cmd: '', fail_on_error: true, channel: 'stdout', negated: false, match_as_regex: false, content: '') | ||
run_command_and_stop(cmd, fail_on_error: fail_on_error) | ||
|
||
command = aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)) | ||
|
||
matcher = case channel | ||
when 'output'; then :have_output | ||
when 'stderr'; then :have_output_on_stderr | ||
when 'stdout'; then :have_output_on_stdout | ||
end | ||
|
||
output_string_matcher = if match_as_regex | ||
:an_output_string_matching | ||
else | ||
:an_output_string_including | ||
end | ||
|
||
if negated | ||
expect(command).not_to send(matcher, send(output_string_matcher, content)) | ||
else | ||
expect(command).to send(matcher, send(output_string_matcher, content)) | ||
end | ||
end | ||
|
||
def validate_channel(channel: 'stdout', negated: false, match_as_regex: false, content: '') | ||
output = send("all_#{channel}") | ||
|
||
matcher = case channel | ||
when 'output'; then :have_output | ||
when 'stderr'; then :have_output_on_stderr | ||
when 'stdout'; then :have_output_on_stdout | ||
end | ||
|
||
output_string_matcher = if match_as_regex | ||
:match_output_string | ||
else | ||
:include_output_string | ||
end | ||
|
||
if negated | ||
expect(output).not_to send(output_string_matcher, content) | ||
else | ||
expect(output).to send(output_string_matcher, content) | ||
end | ||
end | ||
end | ||
end | ||
|
||
# rubocop:disable Style/MixinUsage | ||
# this extend is at the global scope deliberately, to make these helpers available in step definitions | ||
include Command::StepHelpers | ||
# rubocop:enable Style/MixinUsage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require_relative 'os_helper' | ||
|
||
Before('@announce-paths') do | ||
aruba.announcer.activate :paths | ||
end | ||
|
||
Before('@windows-only') do | ||
pending unless ProjectUtils::OS.windows? | ||
end | ||
|
||
Before('@not-windows') do | ||
pending if ProjectUtils::OS.windows? | ||
end | ||
|
||
Before('@pending') do | ||
pending | ||
end | ||
|
||
Before do | ||
aruba.announcer.announce(:paths, "aruba - root_directory: #{aruba.root_directory}") | ||
aruba.announcer.announce(:paths, "aruba - working_directory: #{File.join(aruba.root_directory, aruba.config.working_directory)}") | ||
aruba.announcer.announce(:paths, "aruba - current_directory: #{File.join(aruba.root_directory, aruba.current_directory)}") | ||
|
||
# ensure that git, when run by aruba, does not accidentally discover | ||
# any of the parent repo's git config | ||
ceiling_dir = File.dirname(expand_path('.')) | ||
set_environment_variable('GIT_CEILING_DIRECTORIES', ceiling_dir) | ||
aruba.announcer.announce(:paths, "git ceiling set to: #{ceiling_dir} (git won't look for config or .git/ in this folder or above)") | ||
end | ||
|
||
After do | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
require "rspec/expectations/version" | ||
|
||
RSpec::Matchers.define :match_string do |expected| | ||
match do |actual| | ||
actual.force_encoding("UTF-8") | ||
@expected = Regexp.new(unescape_text(expected), Regexp::MULTILINE) | ||
@actual = sanitize_text(actual) | ||
|
||
values_match? @expected, @actual | ||
end | ||
|
||
diffable | ||
|
||
description { "string matches: #{description_of expected}" } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
module ProjectUtils | ||
# syntax helpers for OS platform detection | ||
# adapted from: https://stackoverflow.com/a/171011/8997 | ||
module OS | ||
def OS.windows? | ||
(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil | ||
end | ||
|
||
def OS.mac? | ||
(/darwin/ =~ RUBY_PLATFORM) != nil | ||
end | ||
|
||
def OS.unix? | ||
!OS.windows? | ||
end | ||
|
||
def OS.linux? | ||
OS.unix? and not OS.mac? | ||
end | ||
|
||
def OS.jruby? | ||
RUBY_ENGINE == 'jruby' | ||
end | ||
end | ||
end | ||
|
||
# rubocop:disable Style/MixinUsage | ||
# this extend is at the global scope deliberately, to make these helpers available in step definitions | ||
include ProjectUtils::OS | ||
# rubocop:enable Style/MixinUsage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'aruba' | ||
require 'aruba/cucumber' | ||
require_relative 'matchers/match_string' | ||
require 'yaml' | ||
|
||
# Aruba ------------------------------------------------ | ||
|
||
# aruba file matchers: https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber/file.rb | ||
# aruba command matchers: https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber/command.rb | ||
|
||
Aruba.configure do |config| | ||
config.exit_timeout = 1 # seconds | ||
config.command_search_paths = [] # don't automatically include {project}/bin in the PATH during scenario runs | ||
end | ||
|
||
# Step Helpers ----------------------------------------------- | ||
|
||
Given(/PENDING/) do | ||
pending | ||
end | ||
|
||
module ProjectUtils | ||
# syntax wrappers around arub commands | ||
module StepHelpers | ||
# def goconfig_bin | ||
# bin = File.join(aruba.root_directory, 'bin', 'goconfig') | ||
# raise "'#{bin}' not found; did you run 'make build'?" unless File.exist?(bin) | ||
# | ||
# bin | ||
# end | ||
|
||
def home_dir | ||
relative_dir('~/') | ||
end | ||
|
||
def current_dir | ||
relative_dir('.') | ||
end | ||
|
||
def relative_dir(path) | ||
abs_dir(path).delete_prefix(aruba.root_directory)[1..-1] | ||
end | ||
|
||
def relative_dir_from_abs(path) | ||
path.delete_prefix(aruba.root_directory)[1..-1] | ||
end | ||
|
||
def abs_dir(path) | ||
expanded = path | ||
with_environment do | ||
expanded = expand_path(path) | ||
end | ||
expanded | ||
end | ||
|
||
# TODO: this syntax will break with aruba 2.1.0 | ||
def all_output_includes(s, negated: false) | ||
if negated | ||
expect(all_commands) | ||
.to_not include_an_object have_output an_output_string_including(s) | ||
else | ||
expect(all_commands) | ||
.to include_an_object have_output an_output_string_including(s) | ||
end | ||
end | ||
|
||
# TODO: this syntax will break with aruba 2.1.0 | ||
def all_output_matches(s, negated: false) | ||
if negated | ||
expect(all_commands) | ||
.to_not include_an_object have_output an_output_string_matching(s) | ||
else | ||
expect(all_commands) | ||
.to include_an_object have_output an_output_string_matching(s) | ||
end | ||
end | ||
end | ||
end | ||
|
||
# rubocop:disable Style/MixinUsage | ||
# this extend is at the global scope deliberately, to make these helpers available in step definitions | ||
include ProjectUtils::StepHelpers | ||
# rubocop:enable Style/MixinUsage |