cucumber_testrail 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +4 -0
- data/cucumber_testrail.gemspec +30 -0
- data/lib/cucumber_testrail.rb +7 -0
- data/lib/cucumber_testrail/external_reporting.rb +106 -0
- data/lib/cucumber_testrail/reopen_scenario.rb +58 -0
- data/lib/cucumber_testrail/testrail.rb +108 -0
- data/lib/cucumber_testrail/testrail_extensions.rb +139 -0
- data/lib/cucumber_testrail/version.rb +3 -0
- data/report.log +2 -0
- data/spec/cucumber_ast_scenario_spec.rb +15 -0
- data/spec/cucumber_testrail_spec.rb +103 -0
- data/spec/fixtures/vcr_cassettes/create_a_test_case.yml +39 -0
- data/spec/fixtures/vcr_cassettes/create_a_test_result.yml +38 -0
- data/spec/fixtures/vcr_cassettes/title_is_found.yml +45 -0
- data/spec/fixtures/vcr_cassettes/title_not_found.yml +45 -0
- data/spec/spec_helper.rb +11 -0
- data/tasks/rspec.rake +4 -0
- metadata +188 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ecd80cf8e65a0501a6682cbf5dc0d3673711927
|
4
|
+
data.tar.gz: 2ff6834a864a02c9e85ea4c0a27be6af917dcb18
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96c2ea59b4b6b57a8d94b73a928e06660cdd23f67ceb53b5f37d0c251eb9679a5b551ae3dde621fc9da4c04aef3b0dbfe79a6e51cd704b3bb247bbc2c55db4d4
|
7
|
+
data.tar.gz: e369fa2f42664c73d8de0f94dc5e85fa020ad0979799c99dc3abcb698da5eef6d994a998285ea524130a474be3a0cf3d9d613c6a6264090b480ed62f27439d37
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
*.swp
|
24
|
+
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cuke_rail
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 John Small
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# CucumberTestrail
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
This gem helps you synchronise your Cucumber test suites into Testrail. It uses tags to link Testrail projects, test suites, testcases
|
6
|
+
and write reports for testruns into Testrail. It will also create new testcases if it can't find them in Testrail and update your feature files
|
7
|
+
to add the tag to the scenario. It writes the step definition into the testcase and keeps it updated.
|
8
|
+
|
9
|
+
The central idea is that tags in the features files are used to link your scenarios to Testrail. The identifiers used are 'project','suite','testcase','testrun' they are all looked up
|
10
|
+
from tags on the scenario, tags on the feature or environment variables. E.g. on the scenario you might have a tag **@testcase_99**, this will link to the Testrail tescase
|
11
|
+
with id=99.
|
12
|
+
|
13
|
+
In Testrail, tests are instances of testcases within the context of a testrun. Therefore to report on a test instance you need a combination of testcase
|
14
|
+
and testrun. The testrun can be one of a tag at scenario level, a tag at feature level or and environment level, e.g. a tag **@testrun_5** or
|
15
|
+
environment variable **TESTRUN=5**. The combination of testcase and testrun form a Testrail test and the result of the senario is add to a list of results for the Testrail test. How you allocate test suites, testcases and testruns is entirely up to you.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
The gem is hosted our own gemserver at http://ec2-54-77-102-63.eu-west-1.compute.amazonaws.com:9292 so you need to add these lines to your Gemfile
|
19
|
+
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
source "http://ec2-54-77-102-63.eu-west-1.compute.amazonaws.com:9292"
|
24
|
+
gem 'cucumber_testrail',"~>1.1.0" #whatever is the latest version
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
### Basic usage
|
29
|
+
|
30
|
+
Once you've installed the gem and bundled it, you need to add the methods in the gem to the World object. In **env.rb** add
|
31
|
+
|
32
|
+
World CucumberTestrail
|
33
|
+
|
34
|
+
Then you need to add the code to After scenario hooks
|
35
|
+
|
36
|
+
send_result(scenario)
|
37
|
+
|
38
|
+
Then state which testrun you're operating in. This can be either a tag e.g. **@testrun_5** at the scenario or feature level, or in the environment **TESTRUN=5**
|
39
|
+
|
40
|
+
Set up environment variables for the Testrail URL, username and password
|
41
|
+
|
42
|
+
export TESTRAIL__USER="your-testrail-user"
|
43
|
+
export TESTRAIL_PASSWORD="your-testrail-password"
|
44
|
+
export TESTRAIL_BASE_URL="your-testrail-server"
|
45
|
+
|
46
|
+
|
47
|
+
#### What if I don't have a testcase id?
|
48
|
+
|
49
|
+
The gem will try to find one that matches the title and if it can't it'll create a new testcase. It then takes the testcase id and adds a tag to your
|
50
|
+
feature file. That requires at least one line in between each scenario, but you do that anyway.
|
51
|
+
|
52
|
+
To create the testcase it needs to know the project id suite id and the sub section id.
|
53
|
+
Those should be added as a tags at feature level e.g. **@project_2 @suite_10 @sub_section_14**
|
54
|
+
|
55
|
+
#### Outlines!!
|
56
|
+
|
57
|
+
Each line in the Examples section of a Scenario Outline will be mapped to a unique testcase using the scenario title, and the named variables in the
|
58
|
+
examples. e.g.
|
59
|
+
|
60
|
+
Scenario Outline: A title
|
61
|
+
Given some steps
|
62
|
+
Examples: some example lines
|
63
|
+
|heading 1 | heading 2 |
|
64
|
+
| ex1 | ex2 |
|
65
|
+
|
66
|
+
Will be mapped to a testcase with title "A title : heading 1='ex1', heading 2='ex2'". Because we will have many testcases for a single scenario outline
|
67
|
+
then the gem doesn't add testcase tags
|
68
|
+
|
69
|
+
#### What if I don't want to send a report to Testrail
|
70
|
+
|
71
|
+
There's a special tag **@ignore_testrail** and environment variable **IGNORE_TESTRAIL=true**. So you can specify one scenario should not be linked to Testrail,
|
72
|
+
one feature file, or the whole run.
|
73
|
+
|
74
|
+
#### What if I want to tag it with a jira ticket number?
|
75
|
+
|
76
|
+
Add the tag **@jira_STORE-123** for example. This will then appear in the defect section of the test report as STORE-123. You can add multiple jira tags to a scenario
|
77
|
+
|
78
|
+
|
79
|
+
### Synchronising Testrail testcases to Cucumber scenarios?
|
80
|
+
|
81
|
+
The gem relies first and foremost on the tag **@testcase_id**. If that tag is present it will use that id without further checks. When it writes the result of the
|
82
|
+
test it also updates the title of the testcase to match the title of the scenario and the contents of the testcase steps to match the scenario steps. It overwrites
|
83
|
+
these without any checks. That means if you have a Testrail testcase 5, with title 'Check that the sun comes up in the morning' and you give a tag **@testcase_5**
|
84
|
+
to a scenario titled 'The user should be logged in', then at the end of the run that Testrail testcase will now have the title taken from the scenario.
|
85
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cucumber_testrail/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cucumber_testrail"
|
8
|
+
spec.version = CucumberTestrail::VERSION
|
9
|
+
spec.authors = ["John Small"]
|
10
|
+
spec.email = ["john.small@bbc.com"]
|
11
|
+
spec.summary = %q{Sync Cucumber specs and results to TestRail}
|
12
|
+
spec.description = %q{Call cucumber_testrail.send_result(scenario) in an After hook. It will match existing testcases by scenario title or add new testcases
|
13
|
+
and then add the result of the run to TestRail. See the README.md}
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "cucumber","~>1.3"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
+
spec.add_development_dependency "rake","~>10.3"
|
25
|
+
spec.add_development_dependency "rspec","~>3.0"
|
26
|
+
spec.add_development_dependency "vcr","~>2.9"
|
27
|
+
spec.add_development_dependency "webmock","~>1.18"
|
28
|
+
spec.add_development_dependency "rdoc","~>4.1"
|
29
|
+
spec.add_development_dependency "geminabox","~>0.12"
|
30
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'fileutils'
|
3
|
+
module Report
|
4
|
+
|
5
|
+
##
|
6
|
+
# allows access to an instance of the testrail object. If it's not set then it will be created on the first read
|
7
|
+
# most useful when testing because you can put a spy in place of the testrail api to check the expected calls are being made
|
8
|
+
attr_accessor :testrail
|
9
|
+
|
10
|
+
## The only entry point from your Cucumber After scenario hooks.
|
11
|
+
# You need to have this code ;-
|
12
|
+
#
|
13
|
+
# After do |scenario|
|
14
|
+
# send_result(scenario)
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# It returns true if it wrote to Testrail and false if it didn't. I.e. if you set *ignore_testrail* then it won't send results to Testrail and it will return false
|
18
|
+
#
|
19
|
+
def send_result(scenario)
|
20
|
+
if scenario.ignore_testrail?
|
21
|
+
result = false
|
22
|
+
else
|
23
|
+
external_reference = get_an_external_reference(scenario)
|
24
|
+
raise 'duff external reference' unless external_reference.to_i > 0
|
25
|
+
#p "external reference #{external_reference}"
|
26
|
+
send_test_result_to_testrail(scenario,external_reference) unless scenario.skip_result?
|
27
|
+
update_test_case(scenario,external_reference)
|
28
|
+
# only write the testcase tag if it's a scenario, not a scenario outline
|
29
|
+
update_source_file(scenario,"testcase_#{external_reference}") if scenario.is_a?(Cucumber::Ast::Scenario)
|
30
|
+
result = true
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
##
|
37
|
+
# This method takes an external reference, e.g. testcase_119 and adds it as a tag before the scenario
|
38
|
+
#
|
39
|
+
def update_source_file(scenario, external_reference)
|
40
|
+
#this could be done on one line with sed. But the format is different on Mac OS and GNU Linux version and it definitely won't work on a Windows machine
|
41
|
+
path = scenario.file
|
42
|
+
lines = IO.readlines(scenario.file)
|
43
|
+
lines[scenario.tag_line].gsub!(/@testcase_(\d*)|\n/," @#{external_reference}") unless lines[scenario.tag_line] =~/#{external_reference}/
|
44
|
+
temp_file = Tempfile.new('foo')
|
45
|
+
begin
|
46
|
+
File.open(path, 'r') do |file|
|
47
|
+
lines.each do |line|
|
48
|
+
temp_file.puts line
|
49
|
+
end
|
50
|
+
end
|
51
|
+
temp_file.close
|
52
|
+
FileUtils.mv(temp_file.path, path)
|
53
|
+
ensure
|
54
|
+
temp_file.close
|
55
|
+
temp_file.unlink
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# If we don't have a tag testcase id then we need to find one. Either by matching a testcase by title, or by creating a new testcase
|
61
|
+
# The input is a scenario and the result is a testcase id
|
62
|
+
def get_an_external_reference(scenario)
|
63
|
+
(check_if_a_test_case_id_exists(scenario) || locate_a_test_case_by_name(scenario) || create_a_test_case_from_scenario(scenario)['id']).to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_a_test_case_from_scenario(scenario)
|
67
|
+
testrail.send_post("add_case/#{scenario.sub_section || scenario.suite}",scenario.testrail_testcase)
|
68
|
+
end
|
69
|
+
|
70
|
+
def locate_a_test_case_by_name(scenario)
|
71
|
+
if scenario.sub_section
|
72
|
+
restrict_by ="#{scenario.project}&suite_id=#{scenario.suite}§ion_id=#{scenario.sub_section}"
|
73
|
+
else
|
74
|
+
restrict_by ="#{scenario.project}&suite_id=#{scenario.suite}"
|
75
|
+
end
|
76
|
+
matches = testrail.send_get("get_cases/#{restrict_by}").select{|m| m['title'] == scenario.title}
|
77
|
+
unless matches.empty?
|
78
|
+
matches.first['id']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_if_a_test_case_id_exists(scenario)
|
83
|
+
if scenario.testcase
|
84
|
+
matches = testrail.send_get("get_cases/#{scenario.project}&suite_id=#{scenario.suite}").select{|m| m['id'].to_i == scenario.testcase.to_i}
|
85
|
+
ref = matches.first['id']
|
86
|
+
end
|
87
|
+
ref
|
88
|
+
end
|
89
|
+
|
90
|
+
def send_test_result_to_testrail(scenario,external_reference=nil)
|
91
|
+
testcase = external_reference || scenario.testcase
|
92
|
+
testrail.send_post("add_result_for_case/#{scenario.testrun}/#{testcase}",scenario.testrail_test_report)
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_test_case(scenario,external_reference)
|
96
|
+
testcase = external_reference || scenario.testcase
|
97
|
+
testrail.send_post("update_case/#{testcase}",scenario.testrail_testcase)
|
98
|
+
end
|
99
|
+
|
100
|
+
def testrail
|
101
|
+
raise 'TESTRAIL_BASE_URL must be set up in your environment' unless ENV['TESTRAIL_BASE_URL']
|
102
|
+
raise 'TESTRAIL_USER must be set up in your environment' unless ENV['TESTRAIL_USER']
|
103
|
+
raise 'TESTRAIL_PASSWORD must be set up in your environment' unless ENV['TESTRAIL_PASSWORD']
|
104
|
+
@testrail ||= TestRail::APIClient.new(ENV['TESTRAIL_BASE_URL'],ENV['TESTRAIL_USER'],ENV['TESTRAIL_PASSWORD'])
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'testrail_extensions'
|
2
|
+
module Cucumber #:nodoc:
|
3
|
+
module Ast #:nodoc:
|
4
|
+
class Scenario
|
5
|
+
include Testrail::Scenario
|
6
|
+
##
|
7
|
+
# return the steps and as strings ready to write to the testcase
|
8
|
+
def steps_as_string
|
9
|
+
to_sexp.select{|a| a[0]==:step_invocation}.map do |s|
|
10
|
+
if s[4]
|
11
|
+
["#{s[2]}#{s[3]}"]+s[4].select{|e| e.is_a?(Array) && e[0]==:row}.map do |l|
|
12
|
+
"| #{l.select{|e| e.is_a?(Array)}.map{|e| e[1]}.join(' | ')} |"
|
13
|
+
end
|
14
|
+
else
|
15
|
+
"#{s[2]}#{s[3]}"
|
16
|
+
end
|
17
|
+
end.flatten.join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def tag_line
|
21
|
+
line - 2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ScenarioOutline
|
26
|
+
def my_steps
|
27
|
+
@steps ||= @background.step_collection(step_invocations)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class OutlineTable
|
32
|
+
class ExampleRow
|
33
|
+
include Testrail::Scenario
|
34
|
+
|
35
|
+
def feature_tags
|
36
|
+
scenario_outline.feature_tags
|
37
|
+
end
|
38
|
+
|
39
|
+
def title
|
40
|
+
line = self.to_hash.to_a.map{|a| "#{a[0]}='#{a[1]}'"}.join(', ')
|
41
|
+
"#{scenario_outline.title} :: #{line}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def steps_as_string
|
45
|
+
#example rows in an outline table don't respond to steps so we have to check the scenario_outline
|
46
|
+
scenario_outline.raw_steps.map{|s| "#{s.keyword} #{s.name}"}.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
def tag_line
|
50
|
+
scenario_outline.file_colon_line.split(':')[1].to_i - 2
|
51
|
+
end
|
52
|
+
def file
|
53
|
+
scenario_outline.file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#
|
2
|
+
# TestRail API binding for Ruby (API v2, available since TestRail 3.0)
|
3
|
+
#
|
4
|
+
# Learn more:
|
5
|
+
#
|
6
|
+
# http://docs.gurock.com/testrail-api2/start
|
7
|
+
# http://docs.gurock.com/testrail-api2/accessing
|
8
|
+
#
|
9
|
+
# Copyright Gurock Software GmbH
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'net/http'
|
13
|
+
require 'net/https'
|
14
|
+
require 'uri'
|
15
|
+
require 'json'
|
16
|
+
|
17
|
+
module TestRail
|
18
|
+
class APIClient
|
19
|
+
@url = ''
|
20
|
+
@user = ''
|
21
|
+
@password = ''
|
22
|
+
|
23
|
+
attr_accessor :user
|
24
|
+
attr_accessor :password
|
25
|
+
|
26
|
+
def initialize(base_url,user,password)
|
27
|
+
if !base_url.match(/\/$/)
|
28
|
+
base_url += '/'
|
29
|
+
end
|
30
|
+
@url = base_url + 'index.php?/api/v2/'
|
31
|
+
@user ||=user
|
32
|
+
@password ||=password
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Send Get
|
37
|
+
#
|
38
|
+
# Issues a GET request (read) against the API and returns the result
|
39
|
+
# (as Ruby hash).
|
40
|
+
#
|
41
|
+
# Arguments:
|
42
|
+
#
|
43
|
+
# uri The API method to call including parameters
|
44
|
+
# (e.g. get_case/1)
|
45
|
+
#
|
46
|
+
def send_get(uri)
|
47
|
+
_send_request('GET', uri, nil)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Send POST
|
52
|
+
#
|
53
|
+
# Issues a POST request (write) against the API and returns the result
|
54
|
+
# (as Ruby hash).
|
55
|
+
#
|
56
|
+
# Arguments:
|
57
|
+
#
|
58
|
+
# uri The API method to call including parameters
|
59
|
+
# (e.g. add_case/1)
|
60
|
+
# data The data to submit as part of the request (as
|
61
|
+
# Ruby hash, strings must be UTF-8 encoded)
|
62
|
+
#
|
63
|
+
def send_post(uri, data)
|
64
|
+
_send_request('POST', uri, data)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def _send_request(method, uri, data)
|
69
|
+
url = URI.parse(@url + uri)
|
70
|
+
if method == 'POST'
|
71
|
+
request = Net::HTTP::Post.new(url.path + '?' + url.query)
|
72
|
+
request.body = JSON.dump(data)
|
73
|
+
else
|
74
|
+
request = Net::HTTP::Get.new(url.path + '?' + url.query)
|
75
|
+
end
|
76
|
+
request.basic_auth(@user, @password)
|
77
|
+
request.add_field('Content-Type', 'application/json')
|
78
|
+
|
79
|
+
conn = Net::HTTP.new(url.host, url.port)
|
80
|
+
if url.scheme == 'https'
|
81
|
+
conn.use_ssl = true
|
82
|
+
conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
83
|
+
end
|
84
|
+
response = conn.request(request)
|
85
|
+
|
86
|
+
if response.body && !response.body.empty?
|
87
|
+
result = JSON.parse(response.body)
|
88
|
+
else
|
89
|
+
result = {}
|
90
|
+
end
|
91
|
+
|
92
|
+
if response.code != '200'
|
93
|
+
if result && result.key?('error')
|
94
|
+
error = '"' + result['error'] + '"'
|
95
|
+
else
|
96
|
+
error = 'No additional error message received'
|
97
|
+
end
|
98
|
+
raise APIError.new('TestRail API returned HTTP %s (%s)' %
|
99
|
+
[response.code, error])
|
100
|
+
end
|
101
|
+
|
102
|
+
result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class APIError < StandardError
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Testrail
|
2
|
+
module Scenario
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.set_testrail_configuration(:status_map,{'passed'=>1,'failed'=>5,'undefined'=>7,'pending'=>6})
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
@@testrail_configuration={}
|
11
|
+
|
12
|
+
##
|
13
|
+
# set a configuration property at the class level. Initially used to set the mapping between Cucumber test results and Testrail result ids
|
14
|
+
def set_testrail_configuration(property_name,property_value)
|
15
|
+
@@testrail_configuration[property_name] = property_value
|
16
|
+
end
|
17
|
+
##
|
18
|
+
# get a named Testrail configuration property. Currenly only used for the results status map
|
19
|
+
def get_testrail_configuration(property_name)
|
20
|
+
@@testrail_configuration[property_name]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# * Looks for a tagname at scenario, feature file and environment levels in that order
|
27
|
+
# * Unless the tagname == 'ignore_testrail' it will return the id of the tag. e.g. input tagname 'testcase' output '5'
|
28
|
+
# * If the tagname == 'ignore_testrail' then it will return nil or true depeneding if it can find the tag or the environment variable
|
29
|
+
def testrail_tag(tagname)
|
30
|
+
#check scenario, feature, environment in that order
|
31
|
+
result = nil
|
32
|
+
unless tagname =~ /ignore_testrail|manual|skip_result/
|
33
|
+
[source_tag_names,feature_tags.tags.map{|t| t.name}].each do | tags |
|
34
|
+
extracted_tag = tags.map{|tag| /^@#{tagname}_(\d+)$|^@#{tagname}_(.*)$/.match(tag)}.compact
|
35
|
+
if extracted_tag
|
36
|
+
if tagname=='jira'
|
37
|
+
result = extracted_tag.map{|e| e.to_a.compact[1]}.join(', ')
|
38
|
+
else
|
39
|
+
result = extracted_tag.first.to_a.compact[1] # we compact it because there are two possible matches, if it hits the second then the first will be nil so after compacting
|
40
|
+
# the result is always the first second element. Try it in irb to convince yourself
|
41
|
+
end
|
42
|
+
break
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
[source_tag_names,feature_tags.tags.map{|t| t.name}].each do | tags |
|
47
|
+
extracted_tag = tags.map{|tag| /#{tagname}/.match(tag)}.compact.first
|
48
|
+
if extracted_tag
|
49
|
+
result = true
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
result ||=ENV[tagname.upcase]
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# returns true if the tag @ignore_testrail or environment variable IGNORE_TESTRAIL=true are found
|
59
|
+
# OR the suite and project id cannot be found
|
60
|
+
def ignore_testrail?
|
61
|
+
testrail_tag('ignore_testrail') || !suite || !project
|
62
|
+
end
|
63
|
+
##
|
64
|
+
# is this a manual scenario?
|
65
|
+
def is_manual?
|
66
|
+
testrail_tag('manual')
|
67
|
+
end
|
68
|
+
##
|
69
|
+
# skip sending the result - useful for simply loading the testcases into Testrail
|
70
|
+
def skip_result?
|
71
|
+
testrail_tag('skip_result')
|
72
|
+
end
|
73
|
+
##
|
74
|
+
# return the project id
|
75
|
+
def project
|
76
|
+
testrail_tag('project')
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# return the suite id
|
81
|
+
def suite
|
82
|
+
testrail_tag('suite')
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# return the sub_section id
|
87
|
+
def sub_section
|
88
|
+
testrail_tag('sub_section')
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# return the testcase id
|
93
|
+
def testcase
|
94
|
+
testrail_tag('testcase')
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# return the tesrun id
|
99
|
+
def testrun
|
100
|
+
testrail_tag('testrun')
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# return test results if it failed, ready to write into the testcase test result
|
105
|
+
def test_result
|
106
|
+
if status =~ /failed/
|
107
|
+
"#{status} #{exception} line #{backtrace_line}"[0..249]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
##
|
111
|
+
#return the jira ticket number if there is one
|
112
|
+
def jira
|
113
|
+
testrail_tag('jira')
|
114
|
+
end
|
115
|
+
##
|
116
|
+
# translate the scenario status into a testrail id using the configured status map. This can be changed in your set up env.rb
|
117
|
+
# but by default it maps
|
118
|
+
# * passed to 1
|
119
|
+
# * failed to 5
|
120
|
+
# * undefined to 2
|
121
|
+
# * pending to 2
|
122
|
+
def testrail_status
|
123
|
+
self.class.get_testrail_configuration(:status_map)[status.to_s]
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# returns a hash of status_id and comment to write into Testrail test report
|
128
|
+
def testrail_test_report
|
129
|
+
{status_id:testrail_status,comment:test_result,defects:jira}
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# returns a hash of :title, :type_id and :custom_steps to create or update a Testrail testcase
|
134
|
+
# [TODO] parameterize the mapping of type_id to manual, in other installations it might be different
|
135
|
+
def testrail_testcase
|
136
|
+
{'title'=>title,'type_id'=>(is_manual? ? 7 : 1 ),'custom_steps'=>steps_as_string}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/report.log
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
[webmock] Handling request: [get https://john.small%40bbc.com:314Sukra%21@paulokikiade.testrail.com/index.php?/api/v2/get_cases/1&suite_id=1] (disabled: false)
|
2
|
+
[webmock] Identified request type (unhandled) for [get https://john.small%40bbc.com:314Sukra%21@paulokikiade.testrail.com/index.php?/api/v2/get_cases/1&suite_id=1]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require "spec_helper"
|
4
|
+
require 'rspec'
|
5
|
+
require 'rspec/mocks'
|
6
|
+
|
7
|
+
describe Cucumber::Ast::Scenario do
|
8
|
+
# let(:world) do
|
9
|
+
# world = class_double('Funky')
|
10
|
+
# world.extend subject
|
11
|
+
# world
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require "spec_helper"
|
4
|
+
require 'rspec'
|
5
|
+
require 'rspec/mocks'
|
6
|
+
describe CucumberTestrail do
|
7
|
+
before(:each) do
|
8
|
+
ENV['TESTRAIL_BASE_URL']='https://paulokikiade.testrail.com'
|
9
|
+
ENV['TESTRAIL_USER'] ='test.rail@bbc.com'
|
10
|
+
ENV['TESTRAIL_PASSWORD']='a_password'
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:world) do
|
14
|
+
world = class_double('Funky')
|
15
|
+
world.extend subject
|
16
|
+
world
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#testrail" do
|
20
|
+
it "should raise an exception if any of the environment variables are not set up" do
|
21
|
+
['TESTRAIL_BASE_URL','TESTRAIL_USER','TESTRAIL_PASSWORD'].each do | var |
|
22
|
+
save_env = ENV[var]
|
23
|
+
begin
|
24
|
+
ENV[var] = nil
|
25
|
+
expect{world.testrail}.to raise_exception(RuntimeError,/#{var}/)
|
26
|
+
ensure
|
27
|
+
ENV[var] = save_env
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#send result" do
|
34
|
+
it 'should not send the result if scenario.ignore_testrail is true' do
|
35
|
+
scenario = instance_double('Scenario',ignore_testrail?: true)
|
36
|
+
expect(world.send_result(scenario)).to be_falsey
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#locate_a_test_case_by_name" do
|
41
|
+
it "doesn't find a phoney test" do
|
42
|
+
VCR.use_cassette('title_not_found') do
|
43
|
+
scenario = instance_double("Scenario",title:'A silly title',project:1,suite:1,sub_section:2)
|
44
|
+
expect(world.locate_a_test_case_by_name(scenario)).to be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "does find a real test" do
|
49
|
+
VCR.use_cassette('title_is_found') do
|
50
|
+
scenario = instance_double("Scenario",title:'Carousel - Test Case 1',project:1,suite:1,sub_section:2)
|
51
|
+
expect(world.locate_a_test_case_by_name(scenario)).not_to be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#create_a_test_case_from_scenario' do
|
57
|
+
let(:testrail_testcase) {{'title'=>'A test scenario','type_id'=>1,'custom_steps'=>'Given some steps'}}
|
58
|
+
let(:scenario) {instance_double("Scenario",suite:2,sub_section:2,testrail_testcase:testrail_testcase)}
|
59
|
+
it "should get a testcase id" do
|
60
|
+
VCR.use_cassette('create_a_test_case') do
|
61
|
+
expect(world.create_a_test_case_from_scenario(scenario)['id']).not_to be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should put the steps into custom steps" do
|
66
|
+
VCR.use_cassette('create_a_test_case') do
|
67
|
+
expect(world.create_a_test_case_from_scenario(scenario)['custom_steps']).to eq('Given some steps')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
it "should add the test case to the test suite" do
|
71
|
+
VCR.use_cassette('create_a_test_case') do
|
72
|
+
expect(world.create_a_test_case_from_scenario(scenario)['section_id']).to eq(2)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
it "should set the testcase title" do
|
76
|
+
VCR.use_cassette('create_a_test_case') do
|
77
|
+
expect(world.create_a_test_case_from_scenario(scenario)['title']).to eq('A test scenario')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#send_test_result_to_testrail' do
|
83
|
+
let(:testrail_test_report) { {status_id:1,defects:'none',comment:'comment'}}
|
84
|
+
let(:scenario) {instance_double("Scenario",testcase:10,testrun:5,testrail_test_report:testrail_test_report)}
|
85
|
+
it 'should return a valid test result' do
|
86
|
+
VCR.use_cassette('create_a_test_result') do
|
87
|
+
expect(world.send_test_result_to_testrail(scenario)['id']).not_to be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should set the defects' do
|
92
|
+
VCR.use_cassette('create_a_test_result') do
|
93
|
+
expect(world.send_test_result_to_testrail(scenario)['defects']).to eq('none')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should set the comment' do
|
98
|
+
VCR.use_cassette('create_a_test_result') do
|
99
|
+
expect(world.send_test_result_to_testrail(scenario)['comment']).to eq('comment')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://test.rail%40bbc.com:a_password@paulokikiade.testrail.com/index.php?/api/v2/add_case/2
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"title":"A test scenario","type_id":1,"custom_steps":"Given some steps"}'
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Content-Type:
|
17
|
+
- application/json
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Date:
|
24
|
+
- Mon, 07 Jul 2014 09:51:06 GMT
|
25
|
+
Server:
|
26
|
+
- Apache
|
27
|
+
Content-Length:
|
28
|
+
- '322'
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
Set-Cookie:
|
32
|
+
- gr_sid=2f527; path=/
|
33
|
+
body:
|
34
|
+
encoding: UTF-8
|
35
|
+
string: '{"id":13,"title":"A test scenario","section_id":2,"type_id":1,"priority_id":4,"milestone_id":null,"refs":null,"created_by":2,"created_on":1404726666,"updated_by":2,"updated_on":1404726666,"estimate":null,"estimate_forecast":null,"suite_id":2,"custom_preconds":null,"custom_steps":"Given
|
36
|
+
some steps","custom_expected":null}'
|
37
|
+
http_version:
|
38
|
+
recorded_at: Mon, 07 Jul 2014 09:51:11 GMT
|
39
|
+
recorded_with: VCR 2.9.2
|
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://test.rail%40bbc.com:a_password@paulokikiade.testrail.com/index.php?/api/v2/add_result_for_case/5/10
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"status_id":1,"defects":"none","comment":"comment"}'
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Content-Type:
|
17
|
+
- application/json
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Date:
|
24
|
+
- Mon, 07 Jul 2014 12:35:24 GMT
|
25
|
+
Server:
|
26
|
+
- Apache
|
27
|
+
Content-Length:
|
28
|
+
- '163'
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
Set-Cookie:
|
32
|
+
- gr_sid=2f527; path=/
|
33
|
+
body:
|
34
|
+
encoding: UTF-8
|
35
|
+
string: '{"id":51,"test_id":25,"status_id":1,"created_by":2,"created_on":1404736525,"assignedto_id":null,"comment":"comment","version":null,"elapsed":null,"defects":"none"}'
|
36
|
+
http_version:
|
37
|
+
recorded_at: Mon, 07 Jul 2014 12:35:29 GMT
|
38
|
+
recorded_with: VCR 2.9.2
|
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://test.rail%40bbc.com:a_password@paulokikiade.testrail.com/index.php?/api/v2/get_cases/1§ion_id=2&suite_id=1
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Content-Type:
|
17
|
+
- application/json
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Date:
|
24
|
+
- Mon, 07 Jul 2014 09:26:34 GMT
|
25
|
+
Server:
|
26
|
+
- Apache
|
27
|
+
Content-Length:
|
28
|
+
- '1057'
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
Cache-Control:
|
32
|
+
- private
|
33
|
+
Set-Cookie:
|
34
|
+
- gr_sid=b7690; path=/
|
35
|
+
body:
|
36
|
+
encoding: UTF-8
|
37
|
+
string: '[{"id":1,"title":"Carousel - Test Case 1","section_id":1,"type_id":2,"priority_id":5,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122853,"updated_by":1,"updated_on":1403122853,"estimate":"2m","estimate_forecast":"2m","suite_id":1,"custom_preconds":"Ensure
|
38
|
+
hope page is present","custom_steps":"test homepage renders in 1 sec","custom_expected":"Homepage
|
39
|
+
renders in 1 sec"},{"id":2,"title":"Ensure test is tested","section_id":1,"type_id":6,"priority_id":4,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122907,"updated_by":1,"updated_on":1403122907,"estimate":null,"estimate_forecast":null,"suite_id":1,"custom_preconds":"test
|
40
|
+
test test","custom_steps":"test test test test","custom_expected":"test test"},{"id":3,"title":"3rd
|
41
|
+
test","section_id":1,"type_id":6,"priority_id":4,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122925,"updated_by":1,"updated_on":1403122925,"estimate":null,"estimate_forecast":null,"suite_id":1,"custom_preconds":"test
|
42
|
+
","custom_steps":"test ","custom_expected":"test again"}]'
|
43
|
+
http_version:
|
44
|
+
recorded_at: Mon, 07 Jul 2014 09:26:39 GMT
|
45
|
+
recorded_with: VCR 2.9.2
|
@@ -0,0 +1,45 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://test.rail%40bbc.com:a_password@paulokikiade.testrail.com/index.php?/api/v2/get_cases/1§ion_id=2&suite_id=1
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Content-Type:
|
17
|
+
- application/json
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Date:
|
24
|
+
- Mon, 07 Jul 2014 09:21:56 GMT
|
25
|
+
Server:
|
26
|
+
- Apache/2.2.14 (Ubuntu)
|
27
|
+
Content-Length:
|
28
|
+
- '1057'
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
Cache-Control:
|
32
|
+
- private
|
33
|
+
Set-Cookie:
|
34
|
+
- gr_sid=dba88; path=/
|
35
|
+
body:
|
36
|
+
encoding: UTF-8
|
37
|
+
string: '[{"id":1,"title":"Carousel - Test Case 1","section_id":1,"type_id":2,"priority_id":5,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122853,"updated_by":1,"updated_on":1403122853,"estimate":"2m","estimate_forecast":"2m","suite_id":1,"custom_preconds":"Ensure
|
38
|
+
hope page is present","custom_steps":"test homepage renders in 1 sec","custom_expected":"Homepage
|
39
|
+
renders in 1 sec"},{"id":2,"title":"Ensure test is tested","section_id":1,"type_id":6,"priority_id":4,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122907,"updated_by":1,"updated_on":1403122907,"estimate":null,"estimate_forecast":null,"suite_id":1,"custom_preconds":"test
|
40
|
+
test test","custom_steps":"test test test test","custom_expected":"test test"},{"id":3,"title":"3rd
|
41
|
+
test","section_id":1,"type_id":6,"priority_id":4,"milestone_id":null,"refs":null,"created_by":1,"created_on":1403122925,"updated_by":1,"updated_on":1403122925,"estimate":null,"estimate_forecast":null,"suite_id":1,"custom_preconds":"test
|
42
|
+
","custom_steps":"test ","custom_expected":"test again"}]'
|
43
|
+
http_version:
|
44
|
+
recorded_at: Mon, 07 Jul 2014 09:22:01 GMT
|
45
|
+
recorded_with: VCR 2.9.2
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require "cucumber_testrail"
|
4
|
+
require 'vcr'
|
5
|
+
require 'rspec/mocks'
|
6
|
+
|
7
|
+
VCR.configure do |c|
|
8
|
+
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
9
|
+
c.hook_into :webmock # or :fakeweb
|
10
|
+
#c.debug_logger = File.open('report.log', 'w')
|
11
|
+
end
|
data/tasks/rspec.rake
ADDED
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cucumber_testrail
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Small
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cucumber
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: vcr
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.9'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.9'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: webmock
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.18'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.18'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rdoc
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4.1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: geminabox
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.12'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.12'
|
125
|
+
description: |-
|
126
|
+
Call cucumber_testrail.send_result(scenario) in an After hook. It will match existing testcases by scenario title or add new testcases
|
127
|
+
and then add the result of the run to TestRail. See the README.md
|
128
|
+
email:
|
129
|
+
- john.small@bbc.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- ".gitignore"
|
135
|
+
- ".ruby-gemset"
|
136
|
+
- ".ruby-version"
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- cucumber_testrail.gemspec
|
142
|
+
- lib/cucumber_testrail.rb
|
143
|
+
- lib/cucumber_testrail/external_reporting.rb
|
144
|
+
- lib/cucumber_testrail/reopen_scenario.rb
|
145
|
+
- lib/cucumber_testrail/testrail.rb
|
146
|
+
- lib/cucumber_testrail/testrail_extensions.rb
|
147
|
+
- lib/cucumber_testrail/version.rb
|
148
|
+
- report.log
|
149
|
+
- spec/cucumber_ast_scenario_spec.rb
|
150
|
+
- spec/cucumber_testrail_spec.rb
|
151
|
+
- spec/fixtures/vcr_cassettes/create_a_test_case.yml
|
152
|
+
- spec/fixtures/vcr_cassettes/create_a_test_result.yml
|
153
|
+
- spec/fixtures/vcr_cassettes/title_is_found.yml
|
154
|
+
- spec/fixtures/vcr_cassettes/title_not_found.yml
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
- tasks/rspec.rake
|
157
|
+
homepage:
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
metadata: {}
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 2.2.2
|
178
|
+
signing_key:
|
179
|
+
specification_version: 4
|
180
|
+
summary: Sync Cucumber specs and results to TestRail
|
181
|
+
test_files:
|
182
|
+
- spec/cucumber_ast_scenario_spec.rb
|
183
|
+
- spec/cucumber_testrail_spec.rb
|
184
|
+
- spec/fixtures/vcr_cassettes/create_a_test_case.yml
|
185
|
+
- spec/fixtures/vcr_cassettes/create_a_test_result.yml
|
186
|
+
- spec/fixtures/vcr_cassettes/title_is_found.yml
|
187
|
+
- spec/fixtures/vcr_cassettes/title_not_found.yml
|
188
|
+
- spec/spec_helper.rb
|