cucumber_testrail 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|