testeranto.rubeno 0.1.4
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/README.md +122 -0
- data/Rakefile +8 -0
- data/bin/rubeno +5 -0
- data/lib/base_given.rb +137 -0
- data/lib/base_suite.rb +94 -0
- data/lib/base_then.rb +44 -0
- data/lib/base_when.rb +47 -0
- data/lib/pm/ruby.rb +156 -0
- data/lib/rubeno.rb +379 -0
- data/lib/simple_adapter.rb +43 -0
- data/lib/types.rb +85 -0
- data/rubeno.rb +3 -0
- metadata +54 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5ab099109b1366b88ab8e8a7a5fbf951ade16dfd50b34f0020fcc892c545f745
|
|
4
|
+
data.tar.gz: 6b3cbdcf603218bbbb778b42117065aac703fc94c91da7dc522ce4647e9e4871
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b7aa0c61d50e39e90ec39eb4ed1e923cfffdd4a3a5168408f0185d8363869fe4cc15a00ef8590cf4b670c9066b71dd1993812ae38afb4e14afde99ce0161eb1e
|
|
7
|
+
data.tar.gz: 572789fa5f684ffdb6df784c6c21ed42097bcf351f82f23ee6bee2aa4b0eb29644220a2f83197f36a9e7496feae7a030ca7c7e5196f62ed8e8a9eebc0ed505cf
|
data/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Rubeno
|
|
2
|
+
|
|
3
|
+
The Ruby implementation of Testeranto.
|
|
4
|
+
|
|
5
|
+
## Deployment to rubygems
|
|
6
|
+
1) update the version in rubeno.gemspec
|
|
7
|
+
2) `gem build rubeno.gemspec`
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Rubeno is a Ruby implementation of the Testeranto BDD testing framework. It follows the same patterns as the other language implementations (TypeScript, Python, Go) to provide a consistent testing experience across multiple programming languages.
|
|
12
|
+
|
|
13
|
+
## Structure
|
|
14
|
+
|
|
15
|
+
The implementation consists of:
|
|
16
|
+
|
|
17
|
+
1. **Base Classes**: `BaseSuite`, `BaseGiven`, `BaseWhen`, `BaseThen` - Core BDD components
|
|
18
|
+
2. **Main Class**: `Rubeno` - Orchestrates test execution
|
|
19
|
+
3. **Test Adapter**: `SimpleTestAdapter` - Default adapter implementation
|
|
20
|
+
4. **Process Manager**: `PM_Ruby` - Handles communication
|
|
21
|
+
5. **Types**: Type definitions for the framework
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Example
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
require 'rubeno'
|
|
29
|
+
|
|
30
|
+
# Define test implementation
|
|
31
|
+
test_implementation = Rubeno::ITestImplementation.new(
|
|
32
|
+
suites: { 'Default' => ->(name, givens) { ... } },
|
|
33
|
+
givens: { 'basic' => ->(initial_values) { ... } },
|
|
34
|
+
whens: { 'press' => ->(button) { ->(store) { ... } } },
|
|
35
|
+
thens: { 'displayIs' => ->(expected) { ->(store) { ... } } }
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Define test specification
|
|
39
|
+
test_specification = ->(suites, givens, whens, thens) do
|
|
40
|
+
[
|
|
41
|
+
suites.Default('Test Suite', {
|
|
42
|
+
'test1' => givens.basic([], [whens.press('1')], [thens.displayIs('1')], nil)
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Create test instance
|
|
48
|
+
test_instance = Rubeno.Rubeno(
|
|
49
|
+
nil,
|
|
50
|
+
test_specification,
|
|
51
|
+
test_implementation,
|
|
52
|
+
Rubeno::SimpleTestAdapter.new,
|
|
53
|
+
Rubeno::ITTestResourceRequest.new(ports: 1)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Set as default and run
|
|
57
|
+
Rubeno.set_default_instance(test_instance)
|
|
58
|
+
Rubeno.main
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Running Tests
|
|
62
|
+
|
|
63
|
+
To run tests with Rubeno:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
ruby example/Calculator-test.rb '{"name":"test","fs":".","ports":[]}'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Integration with Testeranto
|
|
70
|
+
|
|
71
|
+
Rubeno follows the same patterns as other Testeranto implementations:
|
|
72
|
+
|
|
73
|
+
1. **Test Resource Configuration**: Passed as a JSON string argument
|
|
74
|
+
2. **Results Output**: Writes to `testeranto/reports/example/ruby.Calculator.test.ts.json`
|
|
75
|
+
3. **WebSocket Communication**: Supports communication via WebSocket (when configured)
|
|
76
|
+
4. **Artifact Generation**: Supports test artifacts and reporting
|
|
77
|
+
|
|
78
|
+
## Docker Support
|
|
79
|
+
|
|
80
|
+
Rubeno includes a Dockerfile for running tests in containers:
|
|
81
|
+
|
|
82
|
+
```dockerfile
|
|
83
|
+
FROM ruby:3.2-alpine
|
|
84
|
+
WORKDIR /workspace
|
|
85
|
+
# ... (see testeranto/runtimes/ruby/ruby.Dockerfile)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Extending
|
|
89
|
+
|
|
90
|
+
To create custom adapters, implement the `ITestAdapter` module:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
class CustomAdapter
|
|
94
|
+
include Rubeno::ITestAdapter
|
|
95
|
+
|
|
96
|
+
def before_all(input_val, tr, pm)
|
|
97
|
+
# Custom setup
|
|
98
|
+
input_val
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ... implement other methods
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Dependencies
|
|
106
|
+
|
|
107
|
+
- Ruby 2.7+ (for pattern matching and other modern features)
|
|
108
|
+
- JSON (standard library)
|
|
109
|
+
|
|
110
|
+
## Future Enhancements
|
|
111
|
+
|
|
112
|
+
1. **WebSocket Support**: Full WebSocket communication for real-time test reporting
|
|
113
|
+
2. **Advanced Adapters**: More sophisticated adapter implementations
|
|
114
|
+
3. **Plugin System**: Extensible plugin architecture
|
|
115
|
+
4. **Performance Optimizations**: Improved test execution performance
|
|
116
|
+
|
|
117
|
+
## See Also
|
|
118
|
+
|
|
119
|
+
- [Tiposkripto](../tiposkripto/) - TypeScript/JavaScript implementation
|
|
120
|
+
- [Pitono](../pitono/) - Python implementation
|
|
121
|
+
- [Golingvu](../golingvu/) - Go implementation
|
|
122
|
+
|
data/Rakefile
ADDED
data/bin/rubeno
ADDED
data/lib/base_given.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
class BaseGiven
|
|
3
|
+
attr_accessor :features, :whens, :thens, :error, :fail, :store, :recommended_fs_path,
|
|
4
|
+
:given_cb, :initial_values, :key, :failed, :artifacts, :status, :fails
|
|
5
|
+
|
|
6
|
+
def initialize(features, whens, thens, given_cb, initial_values, adapter = nil)
|
|
7
|
+
@features = features
|
|
8
|
+
@whens = whens
|
|
9
|
+
@thens = thens
|
|
10
|
+
@given_cb = given_cb
|
|
11
|
+
@initial_values = initial_values
|
|
12
|
+
@adapter = adapter
|
|
13
|
+
@artifacts = []
|
|
14
|
+
@fails = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_artifact(path)
|
|
18
|
+
normalized_path = path.gsub('\\', '/')
|
|
19
|
+
@artifacts << normalized_path
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def before_all(store)
|
|
23
|
+
store
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_obj
|
|
27
|
+
{
|
|
28
|
+
key: @key,
|
|
29
|
+
whens: (@whens || []).map { |w| w.respond_to?(:to_obj) ? w.to_obj : {} },
|
|
30
|
+
thens: (@thens || []).map { |t| t.respond_to?(:to_obj) ? t.to_obj : {} },
|
|
31
|
+
error: @error ? [@error, @error.backtrace] : nil,
|
|
32
|
+
failed: @failed,
|
|
33
|
+
features: @features || [],
|
|
34
|
+
artifacts: @artifacts,
|
|
35
|
+
status: @status
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def given_that(subject, test_resource_configuration, artifactory, given_cb, initial_values, pm)
|
|
40
|
+
# Use the adapter's before_each method if available
|
|
41
|
+
if @adapter
|
|
42
|
+
@adapter.before_each(subject, given_cb, test_resource_configuration, initial_values, pm)
|
|
43
|
+
else
|
|
44
|
+
# Fallback to just returning the subject
|
|
45
|
+
subject
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def after_each(store, key, artifactory, pm)
|
|
50
|
+
store
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def give(subject, key, test_resource_configuration, tester, artifactory, t_log, pm, suite_ndx)
|
|
54
|
+
@key = key
|
|
55
|
+
@fails = 0
|
|
56
|
+
@failed = false
|
|
57
|
+
@error = nil
|
|
58
|
+
|
|
59
|
+
given_artifactory = ->(f_path, value) do
|
|
60
|
+
artifactory.call("given-#{key}/#{f_path}", value)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
# Call the given callback to get initial subject
|
|
65
|
+
initial_subject = @given_cb.call(@initial_values)
|
|
66
|
+
@store = given_that(
|
|
67
|
+
initial_subject,
|
|
68
|
+
test_resource_configuration,
|
|
69
|
+
given_artifactory,
|
|
70
|
+
@given_cb,
|
|
71
|
+
@initial_values,
|
|
72
|
+
pm
|
|
73
|
+
)
|
|
74
|
+
@status = true
|
|
75
|
+
rescue => e
|
|
76
|
+
@status = false
|
|
77
|
+
@failed = true
|
|
78
|
+
@fails += 1
|
|
79
|
+
@error = e
|
|
80
|
+
return @store
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
# Process whens
|
|
85
|
+
@whens.each_with_index do |when_step, when_ndx|
|
|
86
|
+
begin
|
|
87
|
+
@store = when_step.test(
|
|
88
|
+
@store,
|
|
89
|
+
test_resource_configuration,
|
|
90
|
+
t_log,
|
|
91
|
+
pm,
|
|
92
|
+
"suite-#{suite_ndx}/given-#{key}/when/#{when_ndx}"
|
|
93
|
+
)
|
|
94
|
+
rescue => e
|
|
95
|
+
@failed = true
|
|
96
|
+
@fails += 1
|
|
97
|
+
@error = e
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Process thens
|
|
102
|
+
@thens.each_with_index do |then_step, then_ndx|
|
|
103
|
+
begin
|
|
104
|
+
result = then_step.test(
|
|
105
|
+
@store,
|
|
106
|
+
test_resource_configuration,
|
|
107
|
+
t_log,
|
|
108
|
+
pm,
|
|
109
|
+
"suite-#{suite_ndx}/given-#{key}/then-#{then_ndx}"
|
|
110
|
+
)
|
|
111
|
+
unless tester.call(result)
|
|
112
|
+
@failed = true
|
|
113
|
+
@fails += 1
|
|
114
|
+
end
|
|
115
|
+
rescue => e
|
|
116
|
+
@failed = true
|
|
117
|
+
@fails += 1
|
|
118
|
+
@error = e
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
rescue => e
|
|
122
|
+
@error = e
|
|
123
|
+
@failed = true
|
|
124
|
+
@fails += 1
|
|
125
|
+
ensure
|
|
126
|
+
begin
|
|
127
|
+
after_each(@store, @key, given_artifactory, pm)
|
|
128
|
+
rescue => e
|
|
129
|
+
@failed = true
|
|
130
|
+
@fails += 1
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
@store
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
data/lib/base_suite.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
class BaseSuite
|
|
3
|
+
attr_accessor :name, :givens, :store, :test_resource_configuration, :index, :failed, :fails, :artifacts
|
|
4
|
+
|
|
5
|
+
def initialize(name, givens = {})
|
|
6
|
+
@name = name
|
|
7
|
+
@givens = givens
|
|
8
|
+
@artifacts = []
|
|
9
|
+
@failed = false
|
|
10
|
+
@fails = 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def add_artifact(path)
|
|
14
|
+
normalized_path = path.gsub('\\', '/')
|
|
15
|
+
@artifacts << normalized_path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def features
|
|
19
|
+
features = []
|
|
20
|
+
seen = {}
|
|
21
|
+
@givens.each_value do |given|
|
|
22
|
+
given.features.each do |feature|
|
|
23
|
+
unless seen[feature]
|
|
24
|
+
features << feature
|
|
25
|
+
seen[feature] = true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
features
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_obj
|
|
33
|
+
{
|
|
34
|
+
name: @name,
|
|
35
|
+
givens: @givens.values.map(&:to_obj),
|
|
36
|
+
fails: @fails,
|
|
37
|
+
failed: @failed,
|
|
38
|
+
features: features,
|
|
39
|
+
artifacts: @artifacts
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def setup(s, artifactory, tr, pm)
|
|
44
|
+
s
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def assert_that(t)
|
|
48
|
+
!!t
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def after_all(store, artifactory, pm)
|
|
52
|
+
store
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run(input_val, test_resource_configuration, artifactory, t_log, pm)
|
|
56
|
+
@test_resource_configuration = test_resource_configuration
|
|
57
|
+
|
|
58
|
+
subject = setup(input_val, artifactory, test_resource_configuration, pm)
|
|
59
|
+
|
|
60
|
+
@fails = 0
|
|
61
|
+
@failed = false
|
|
62
|
+
|
|
63
|
+
@givens.each do |g_key, g|
|
|
64
|
+
begin
|
|
65
|
+
@store = g.give(
|
|
66
|
+
subject,
|
|
67
|
+
g_key,
|
|
68
|
+
test_resource_configuration,
|
|
69
|
+
method(:assert_that),
|
|
70
|
+
artifactory,
|
|
71
|
+
t_log,
|
|
72
|
+
pm,
|
|
73
|
+
@index
|
|
74
|
+
)
|
|
75
|
+
@fails += g.fails if g.fails && g.fails > 0
|
|
76
|
+
rescue => e
|
|
77
|
+
@failed = true
|
|
78
|
+
@fails += 1
|
|
79
|
+
puts "Error in given #{g_key}: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@failed = true if @fails > 0
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
after_all(@store, artifactory, pm)
|
|
87
|
+
rescue => e
|
|
88
|
+
puts "Error in after_all: #{e.message}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/base_then.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
class BaseThen
|
|
3
|
+
attr_accessor :name, :then_cb, :error, :artifacts, :status
|
|
4
|
+
|
|
5
|
+
def initialize(name, then_cb)
|
|
6
|
+
@name = name
|
|
7
|
+
@then_cb = then_cb
|
|
8
|
+
@error = false
|
|
9
|
+
@artifacts = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_artifact(path)
|
|
13
|
+
normalized_path = path.gsub('\\', '/')
|
|
14
|
+
@artifacts << normalized_path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def but_then(store, then_cb, test_resource_configuration, pm)
|
|
18
|
+
# Call the then_cb directly
|
|
19
|
+
then_cb.call(store)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_obj
|
|
23
|
+
{
|
|
24
|
+
name: @name,
|
|
25
|
+
error: @error,
|
|
26
|
+
artifacts: @artifacts,
|
|
27
|
+
status: @status
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test(store, test_resource_configuration, t_log, pm, filepath)
|
|
32
|
+
begin
|
|
33
|
+
# Call the then_cb with the store to get a boolean result
|
|
34
|
+
result = @then_cb.call(store)
|
|
35
|
+
@status = true
|
|
36
|
+
result
|
|
37
|
+
rescue => e
|
|
38
|
+
@status = false
|
|
39
|
+
@error = true
|
|
40
|
+
raise e
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/base_when.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
class BaseWhen
|
|
3
|
+
attr_accessor :name, :when_cb, :error, :artifacts, :status
|
|
4
|
+
|
|
5
|
+
def initialize(name, when_cb)
|
|
6
|
+
@name = name
|
|
7
|
+
@when_cb = when_cb
|
|
8
|
+
@artifacts = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_artifact(path)
|
|
12
|
+
normalized_path = path.gsub('\\', '/')
|
|
13
|
+
@artifacts << normalized_path
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def and_when(store, when_cb, test_resource_configuration, pm)
|
|
17
|
+
# Call the when_cb directly
|
|
18
|
+
when_cb.call(store)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_obj
|
|
22
|
+
error_str = nil
|
|
23
|
+
if @error
|
|
24
|
+
error_str = "#{@error.class}: #{@error.message}"
|
|
25
|
+
end
|
|
26
|
+
{
|
|
27
|
+
name: @name,
|
|
28
|
+
status: @status,
|
|
29
|
+
error: error_str,
|
|
30
|
+
artifacts: @artifacts
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test(store, test_resource_configuration, t_log, pm, filepath)
|
|
35
|
+
begin
|
|
36
|
+
# Call the when_cb with the store
|
|
37
|
+
result = @when_cb.call(store)
|
|
38
|
+
@status = true
|
|
39
|
+
result
|
|
40
|
+
rescue => e
|
|
41
|
+
@status = false
|
|
42
|
+
@error = e
|
|
43
|
+
raise e
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/pm/ruby.rb
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
class PM_Ruby
|
|
3
|
+
def initialize(t, websocket_port)
|
|
4
|
+
@test_resource_configuration = t
|
|
5
|
+
@websocket_port = websocket_port
|
|
6
|
+
@connected = false
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def start
|
|
10
|
+
raise "DEPRECATED"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def send(command, *args)
|
|
14
|
+
# For now, return default values to allow tests to run
|
|
15
|
+
case command
|
|
16
|
+
when "pages"
|
|
17
|
+
[]
|
|
18
|
+
when "newPage"
|
|
19
|
+
"mock-page"
|
|
20
|
+
when "page"
|
|
21
|
+
"mock-page"
|
|
22
|
+
when "existsSync"
|
|
23
|
+
false
|
|
24
|
+
when "writeFileSync"
|
|
25
|
+
true
|
|
26
|
+
when "createWriteStream"
|
|
27
|
+
"mock-stream"
|
|
28
|
+
when "write"
|
|
29
|
+
true
|
|
30
|
+
when "end"
|
|
31
|
+
true
|
|
32
|
+
when "customclose"
|
|
33
|
+
nil
|
|
34
|
+
else
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def pages
|
|
40
|
+
send("pages")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def wait_for_selector(p, s)
|
|
44
|
+
send("waitForSelector", p, s)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def close_page(p)
|
|
48
|
+
send("closePage", p)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def goto(page, url)
|
|
52
|
+
send("goto", page, url)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def new_page
|
|
56
|
+
send("newPage")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def call(selector, page)
|
|
60
|
+
send("$", selector, page)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def is_disabled(selector)
|
|
64
|
+
send("isDisabled", selector)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def get_attribute(selector, attribute, p)
|
|
68
|
+
send("getAttribute", selector, attribute, p)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def get_inner_html(selector, p)
|
|
72
|
+
send("getInnerHtml", selector, p)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def focus_on(selector)
|
|
76
|
+
send("focusOn", selector)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def type_into(selector)
|
|
80
|
+
send("typeInto", selector)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def page
|
|
84
|
+
send("page")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def click(selector)
|
|
88
|
+
send("click", selector)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def screencast(opts, page)
|
|
92
|
+
adjusted_opts = opts.dup
|
|
93
|
+
if adjusted_opts['path']
|
|
94
|
+
adjusted_opts['path'] = "#{@test_resource_configuration.fs}/#{opts['path']}"
|
|
95
|
+
end
|
|
96
|
+
send("screencast", adjusted_opts, page, @test_resource_configuration.name)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def screencast_stop(p)
|
|
100
|
+
send("screencastStop", p)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def custom_screenshot(x)
|
|
104
|
+
opts = x[0]
|
|
105
|
+
page = x[1] if x.length > 1
|
|
106
|
+
|
|
107
|
+
adjusted_opts = opts.dup
|
|
108
|
+
if adjusted_opts['path']
|
|
109
|
+
adjusted_opts['path'] = "#{@test_resource_configuration.fs}/#{opts['path']}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if page
|
|
113
|
+
send("customScreenShot", adjusted_opts, @test_resource_configuration.name, page)
|
|
114
|
+
else
|
|
115
|
+
send("customScreenShot", adjusted_opts, @test_resource_configuration.name)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def exists_sync(dest_folder)
|
|
120
|
+
path = "#{@test_resource_configuration.fs}/#{dest_folder}"
|
|
121
|
+
send("existsSync", path)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def mkdir_sync
|
|
125
|
+
path = "#{@test_resource_configuration.fs}/"
|
|
126
|
+
send("mkdirSync", path)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def write(uid, contents)
|
|
130
|
+
send("write", uid, contents)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def write_file_sync(filepath, contents)
|
|
134
|
+
full_path = "#{@test_resource_configuration.fs}/#{filepath}"
|
|
135
|
+
begin
|
|
136
|
+
result = send("writeFileSync", full_path, contents, @test_resource_configuration.name)
|
|
137
|
+
result
|
|
138
|
+
rescue => e
|
|
139
|
+
raise e
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def create_write_stream(filepath)
|
|
144
|
+
full_path = "#{@test_resource_configuration.fs}/#{filepath}"
|
|
145
|
+
send("createWriteStream", full_path, @test_resource_configuration.name)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def end(uid)
|
|
149
|
+
send("end", uid)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def custom_close
|
|
153
|
+
send("customclose", @test_resource_configuration.fs, @test_resource_configuration.name)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
data/lib/rubeno.rb
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'base_suite'
|
|
3
|
+
require 'base_given'
|
|
4
|
+
require 'base_when'
|
|
5
|
+
require 'base_then'
|
|
6
|
+
require 'simple_adapter'
|
|
7
|
+
require 'pm/ruby'
|
|
8
|
+
require 'types'
|
|
9
|
+
|
|
10
|
+
module Rubeno
|
|
11
|
+
class Rubeno
|
|
12
|
+
attr_accessor :test_resource_requirement, :artifacts, :test_jobs, :test_specification,
|
|
13
|
+
:suites_overrides, :given_overrides, :when_overrides, :then_overrides,
|
|
14
|
+
:puppet_master, :specs, :total_tests, :assert_this, :test_adapter,
|
|
15
|
+
:test_subject
|
|
16
|
+
|
|
17
|
+
def initialize(input_val, test_specification, test_implementation, test_resource_requirement, test_adapter, uber_catcher = nil)
|
|
18
|
+
@test_resource_requirement = test_resource_requirement
|
|
19
|
+
@artifacts = []
|
|
20
|
+
@test_jobs = []
|
|
21
|
+
@test_specification = test_specification
|
|
22
|
+
@suites_overrides = {}
|
|
23
|
+
@given_overrides = {}
|
|
24
|
+
@when_overrides = {}
|
|
25
|
+
@then_overrides = {}
|
|
26
|
+
@test_subject = input_val
|
|
27
|
+
@test_adapter = test_adapter
|
|
28
|
+
|
|
29
|
+
# Initialize classy implementations
|
|
30
|
+
initialize_classy_implementations(test_implementation)
|
|
31
|
+
|
|
32
|
+
# Generate specs
|
|
33
|
+
@specs = test_specification.call(
|
|
34
|
+
suites_wrapper,
|
|
35
|
+
given_wrapper,
|
|
36
|
+
when_wrapper,
|
|
37
|
+
then_wrapper
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Initialize test jobs
|
|
41
|
+
initialize_test_jobs
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def suites_wrapper
|
|
45
|
+
# Return an object that responds to method calls for suite types
|
|
46
|
+
wrapper = Object.new
|
|
47
|
+
@suites_overrides.each do |suite_name, suite_proc|
|
|
48
|
+
wrapper.define_singleton_method(suite_name) do |description, givens_dict|
|
|
49
|
+
{
|
|
50
|
+
'name' => description,
|
|
51
|
+
'givens' => givens_dict
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
wrapper
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def given_wrapper
|
|
59
|
+
wrapper = Object.new
|
|
60
|
+
@given_overrides.each do |given_name, given_proc|
|
|
61
|
+
wrapper.define_singleton_method(given_name) do |features, whens, thens, initial_values = nil|
|
|
62
|
+
given_proc.call(features, whens, thens, initial_values)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
wrapper
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def when_wrapper
|
|
69
|
+
wrapper = Object.new
|
|
70
|
+
@when_overrides.each do |when_name, when_proc|
|
|
71
|
+
wrapper.define_singleton_method(when_name) do |*args|
|
|
72
|
+
when_proc.call(*args)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
wrapper
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def then_wrapper
|
|
79
|
+
wrapper = Object.new
|
|
80
|
+
@then_overrides.each do |then_name, then_proc|
|
|
81
|
+
wrapper.define_singleton_method(then_name) do |*args|
|
|
82
|
+
then_proc.call(*args)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
wrapper
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def initialize_classy_implementations(test_implementation)
|
|
89
|
+
# Create classy suites
|
|
90
|
+
test_implementation.suites.each do |key, suite_data|
|
|
91
|
+
@suites_overrides[key] = ->(description, givens_dict) do
|
|
92
|
+
{
|
|
93
|
+
'name' => description,
|
|
94
|
+
'givens' => givens_dict
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Create classy givens
|
|
100
|
+
test_implementation.givens.each do |key, given_cb|
|
|
101
|
+
@given_overrides[key] = ->(features, whens, thens, initial_values = nil) do
|
|
102
|
+
BaseGiven.new(features, whens, thens, given_cb, initial_values, @test_adapter)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Create classy whens
|
|
107
|
+
test_implementation.whens.each do |key, when_cb_proc|
|
|
108
|
+
@when_overrides[key] = ->(*args) do
|
|
109
|
+
when_cb = when_cb_proc.call(*args)
|
|
110
|
+
BaseWhen.new(key, when_cb)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Create classy thens
|
|
115
|
+
test_implementation.thens.each do |key, then_cb_proc|
|
|
116
|
+
@then_overrides[key] = ->(*args) do
|
|
117
|
+
then_cb = then_cb_proc.call(*args)
|
|
118
|
+
BaseThen.new(key, then_cb)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def initialize_test_jobs
|
|
124
|
+
@test_jobs = []
|
|
125
|
+
@specs.each_with_index do |suite_spec, i|
|
|
126
|
+
# Create a BaseSuite instance
|
|
127
|
+
suite = BaseSuite.new(suite_spec['name'], suite_spec['givens'])
|
|
128
|
+
suite.index = i
|
|
129
|
+
|
|
130
|
+
# Create a test job
|
|
131
|
+
test_job = {
|
|
132
|
+
suite: suite,
|
|
133
|
+
receiveTestResourceConfig: ->(pm, test_resource_config) { run_test_job(suite, pm, test_resource_config) },
|
|
134
|
+
to_obj: -> { suite.to_obj }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@test_jobs << test_job
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def run_test_job(suite, pm, test_resource_config)
|
|
142
|
+
t_log = ->(*args) { puts args.join(' ') }
|
|
143
|
+
|
|
144
|
+
# Run the suite
|
|
145
|
+
suite_done = suite.run(
|
|
146
|
+
@test_subject,
|
|
147
|
+
test_resource_config, # Use the actual test resource configuration
|
|
148
|
+
->(f_path, value) { nil }, # Simple artifactory
|
|
149
|
+
t_log,
|
|
150
|
+
pm
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Create result object
|
|
154
|
+
result = Object.new
|
|
155
|
+
result.instance_variable_set(:@fails, suite_done.fails)
|
|
156
|
+
result.instance_variable_set(:@artifacts, suite_done.artifacts)
|
|
157
|
+
result.instance_variable_set(:@features, suite_done.features)
|
|
158
|
+
|
|
159
|
+
def result.fails; @fails; end
|
|
160
|
+
def result.artifacts; @artifacts; end
|
|
161
|
+
def result.features; @features; end
|
|
162
|
+
|
|
163
|
+
result
|
|
164
|
+
rescue => e
|
|
165
|
+
puts "Error in test job: #{e.message}"
|
|
166
|
+
puts e.backtrace
|
|
167
|
+
|
|
168
|
+
result = Object.new
|
|
169
|
+
result.instance_variable_set(:@fails, 1)
|
|
170
|
+
result.instance_variable_set(:@artifacts, [])
|
|
171
|
+
result.instance_variable_set(:@features, [])
|
|
172
|
+
|
|
173
|
+
def result.fails; @fails; end
|
|
174
|
+
def result.artifacts; @artifacts; end
|
|
175
|
+
def result.features; @features; end
|
|
176
|
+
|
|
177
|
+
result
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def receiveTestResourceConfig(partialTestResource, websocket_port = 'ipcfile')
|
|
181
|
+
# Parse the test resource configuration
|
|
182
|
+
test_resource_config = parse_test_resource_config(partialTestResource)
|
|
183
|
+
|
|
184
|
+
pm = PM_Ruby.new(test_resource_config, websocket_port)
|
|
185
|
+
|
|
186
|
+
# Run all test jobs
|
|
187
|
+
total_fails = 0
|
|
188
|
+
all_features = []
|
|
189
|
+
all_artifacts = []
|
|
190
|
+
suite_results = []
|
|
191
|
+
|
|
192
|
+
@test_jobs.each do |job|
|
|
193
|
+
begin
|
|
194
|
+
# Update the job's receiveTestResourceConfig to pass test_resource_config
|
|
195
|
+
result = run_test_job(job[:suite], pm, test_resource_config)
|
|
196
|
+
total_fails += result.fails
|
|
197
|
+
all_features.concat(result.features)
|
|
198
|
+
all_artifacts.concat(result.artifacts)
|
|
199
|
+
suite_results << job[:to_obj].call
|
|
200
|
+
rescue => e
|
|
201
|
+
puts "Error running test job: #{e.message}"
|
|
202
|
+
total_fails += 1
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Write tests.json
|
|
207
|
+
write_tests_json(suite_results, total_fails, all_features.uniq, all_artifacts)
|
|
208
|
+
|
|
209
|
+
# Return result
|
|
210
|
+
IFinalResults.new(
|
|
211
|
+
failed: total_fails > 0,
|
|
212
|
+
fails: total_fails,
|
|
213
|
+
artifacts: all_artifacts,
|
|
214
|
+
features: all_features.uniq
|
|
215
|
+
)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private
|
|
219
|
+
|
|
220
|
+
def parse_test_resource_config(partialTestResource)
|
|
221
|
+
begin
|
|
222
|
+
config = JSON.parse(partialTestResource)
|
|
223
|
+
# Create a hash that can be used as test resource configuration
|
|
224
|
+
# The PM_Ruby expects certain methods to be available
|
|
225
|
+
config_hash = {
|
|
226
|
+
'name' => config['name'] || 'default',
|
|
227
|
+
'fs' => config['fs'] || '.',
|
|
228
|
+
'ports' => config['ports'] || [],
|
|
229
|
+
'timeout' => config['timeout'] || 30000,
|
|
230
|
+
'retries' => config['retries'] || 0,
|
|
231
|
+
'environment' => config['environment'] || {}
|
|
232
|
+
}
|
|
233
|
+
# Create an object that responds to the needed methods
|
|
234
|
+
test_resource = Object.new
|
|
235
|
+
test_resource.define_singleton_method(:name) { config_hash['name'] }
|
|
236
|
+
test_resource.define_singleton_method(:fs) { config_hash['fs'] }
|
|
237
|
+
test_resource.define_singleton_method(:ports) { config_hash['ports'] }
|
|
238
|
+
test_resource.define_singleton_method(:timeout) { config_hash['timeout'] }
|
|
239
|
+
test_resource.define_singleton_method(:retries) { config_hash['retries'] }
|
|
240
|
+
test_resource.define_singleton_method(:environment) { config_hash['environment'] }
|
|
241
|
+
test_resource
|
|
242
|
+
rescue JSON::ParserError
|
|
243
|
+
# If not valid JSON, create a default config
|
|
244
|
+
test_resource = Object.new
|
|
245
|
+
test_resource.define_singleton_method(:name) { 'default' }
|
|
246
|
+
test_resource.define_singleton_method(:fs) { '.' }
|
|
247
|
+
test_resource.define_singleton_method(:ports) { [] }
|
|
248
|
+
test_resource.define_singleton_method(:timeout) { 30000 }
|
|
249
|
+
test_resource.define_singleton_method(:retries) { 0 }
|
|
250
|
+
test_resource.define_singleton_method(:environment) { {} }
|
|
251
|
+
test_resource
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def write_tests_json(suite_results, total_fails, features, artifacts)
|
|
256
|
+
# Flatten all givens from all suites
|
|
257
|
+
all_givens = []
|
|
258
|
+
suite_results.each do |suite|
|
|
259
|
+
if suite[:givens]
|
|
260
|
+
all_givens.concat(suite[:givens])
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
tests_data = {
|
|
265
|
+
'name' => @specs.first ? @specs.first['name'] : 'Unnamed Test',
|
|
266
|
+
'givens' => all_givens,
|
|
267
|
+
'fails' => total_fails,
|
|
268
|
+
'failed' => total_fails > 0,
|
|
269
|
+
'features' => features,
|
|
270
|
+
'artifacts' => artifacts
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# Create directory if it doesn't exist
|
|
274
|
+
dir_path = 'testeranto/reports/'
|
|
275
|
+
FileUtils.mkdir_p(dir_path) unless Dir.exist?(dir_path)
|
|
276
|
+
|
|
277
|
+
# Write to file
|
|
278
|
+
tests_json_path = "#{dir_path}/ruby.Calculator.test.ts.json"
|
|
279
|
+
File.write(tests_json_path, JSON.pretty_generate(tests_data))
|
|
280
|
+
puts "tests.json written to: #{tests_json_path}"
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Main function
|
|
285
|
+
def self.main
|
|
286
|
+
puts "Rubeno Ruby implementation"
|
|
287
|
+
|
|
288
|
+
# Check command line arguments
|
|
289
|
+
if ARGV.length < 1
|
|
290
|
+
puts "No test arguments provided - exiting"
|
|
291
|
+
exit 0
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
partialTestResource = ARGV[0]
|
|
295
|
+
websocket_port = ARGV[1] || 'ipcfile'
|
|
296
|
+
|
|
297
|
+
# We need a default instance to run
|
|
298
|
+
# In a real implementation, this would be set elsewhere
|
|
299
|
+
if $default_rubeno_instance.nil?
|
|
300
|
+
puts "WARNING: No default Rubeno instance has been configured"
|
|
301
|
+
puts "Creating a minimal default instance for testing..."
|
|
302
|
+
|
|
303
|
+
# Create a minimal test implementation
|
|
304
|
+
minimal_implementation = ITestImplementation.new(
|
|
305
|
+
suites: { 'Default' => { description: "Default test suite" } },
|
|
306
|
+
givens: {
|
|
307
|
+
'Default' => ->(initial_values) do
|
|
308
|
+
# Return a simple object
|
|
309
|
+
Object.new
|
|
310
|
+
end
|
|
311
|
+
},
|
|
312
|
+
whens: {
|
|
313
|
+
'noop' => ->() do
|
|
314
|
+
->(store) do
|
|
315
|
+
store
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
},
|
|
319
|
+
thens: {
|
|
320
|
+
'alwaysTrue' => ->() do
|
|
321
|
+
->(store) do
|
|
322
|
+
true
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
}
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Create a minimal test specification
|
|
329
|
+
minimal_specification = ->(suites, givens, whens, thens) do
|
|
330
|
+
# The wrappers are objects with methods, not hashes
|
|
331
|
+
# So we need to use them correctly
|
|
332
|
+
[
|
|
333
|
+
suites.Default('Minimal Test Suite', {
|
|
334
|
+
'test1' => givens.Default(
|
|
335
|
+
['minimal test'],
|
|
336
|
+
[],
|
|
337
|
+
[thens.alwaysTrue()],
|
|
338
|
+
nil
|
|
339
|
+
)
|
|
340
|
+
})
|
|
341
|
+
]
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Create and set a default instance
|
|
345
|
+
$default_rubeno_instance = Rubeno.new(
|
|
346
|
+
nil,
|
|
347
|
+
minimal_specification,
|
|
348
|
+
minimal_implementation,
|
|
349
|
+
ITTestResourceRequest.new(ports: 0),
|
|
350
|
+
SimpleTestAdapter.new
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
puts "Minimal default instance created"
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
result = $default_rubeno_instance.receiveTestResourceConfig(partialTestResource, websocket_port)
|
|
357
|
+
exit result.fails
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Store the default instance
|
|
361
|
+
$default_rubeno_instance = nil
|
|
362
|
+
|
|
363
|
+
def self.set_default_instance(instance)
|
|
364
|
+
$default_rubeno_instance = instance
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Helper function to create a Rubeno instance
|
|
368
|
+
def self.Rubeno(input_val = nil, test_specification = nil, test_implementation = nil, test_adapter = nil, test_resource_requirement = nil, uber_catcher = nil)
|
|
369
|
+
instance = Rubeno.new(
|
|
370
|
+
input_val,
|
|
371
|
+
test_specification,
|
|
372
|
+
test_implementation,
|
|
373
|
+
test_resource_requirement || ITTestResourceRequest.new,
|
|
374
|
+
test_adapter || SimpleTestAdapter.new,
|
|
375
|
+
uber_catcher
|
|
376
|
+
)
|
|
377
|
+
instance
|
|
378
|
+
end
|
|
379
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'types'
|
|
2
|
+
|
|
3
|
+
module Rubeno
|
|
4
|
+
class SimpleTestAdapter
|
|
5
|
+
include ITestAdapter
|
|
6
|
+
|
|
7
|
+
def before_all(input_val, tr, pm)
|
|
8
|
+
input_val
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def after_all(store, pm)
|
|
12
|
+
store
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def before_each(subject, initializer, test_resource, initial_values, pm)
|
|
16
|
+
subject
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def after_each(store, key, pm)
|
|
20
|
+
store
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def and_when(store, when_cb, test_resource, pm)
|
|
24
|
+
if when_cb.respond_to?(:call)
|
|
25
|
+
when_cb.call(store)
|
|
26
|
+
else
|
|
27
|
+
store
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def but_then(store, then_cb, test_resource, pm)
|
|
32
|
+
if then_cb.respond_to?(:call)
|
|
33
|
+
then_cb.call(store)
|
|
34
|
+
else
|
|
35
|
+
store
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def assert_this(t)
|
|
40
|
+
!!t
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/types.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module Rubeno
|
|
2
|
+
# Type definitions for Rubeno
|
|
3
|
+
|
|
4
|
+
# Test resource configuration
|
|
5
|
+
class ITTestResourceConfiguration
|
|
6
|
+
attr_accessor :name, :fs, :ports, :browser_ws_endpoint, :timeout, :retries, :environment
|
|
7
|
+
|
|
8
|
+
def initialize(name:, fs:, ports:, browser_ws_endpoint: nil, timeout: nil, retries: nil, environment: {})
|
|
9
|
+
@name = name
|
|
10
|
+
@fs = fs
|
|
11
|
+
@ports = ports
|
|
12
|
+
@browser_ws_endpoint = browser_ws_endpoint
|
|
13
|
+
@timeout = timeout
|
|
14
|
+
@retries = retries
|
|
15
|
+
@environment = environment
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Test adapter interface
|
|
20
|
+
module ITestAdapter
|
|
21
|
+
def before_all(input_val, tr, pm)
|
|
22
|
+
input_val
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def after_all(store, pm)
|
|
26
|
+
store
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def before_each(subject, initializer, test_resource, initial_values, pm)
|
|
30
|
+
subject
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def after_each(store, key, pm)
|
|
34
|
+
store
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def and_when(store, when_cb, test_resource, pm)
|
|
38
|
+
store
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def but_then(store, then_cb, test_resource, pm)
|
|
42
|
+
store
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def assert_this(t)
|
|
46
|
+
!!t
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Test specification function type
|
|
51
|
+
ITestSpecification = Proc
|
|
52
|
+
|
|
53
|
+
# Test implementation structure
|
|
54
|
+
class ITestImplementation
|
|
55
|
+
attr_accessor :suites, :givens, :whens, :thens
|
|
56
|
+
|
|
57
|
+
def initialize(suites:, givens:, whens:, thens:)
|
|
58
|
+
@suites = suites
|
|
59
|
+
@givens = givens
|
|
60
|
+
@whens = whens
|
|
61
|
+
@thens = thens
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Test resource request
|
|
66
|
+
class ITTestResourceRequest
|
|
67
|
+
attr_accessor :ports
|
|
68
|
+
|
|
69
|
+
def initialize(ports: 0)
|
|
70
|
+
@ports = ports
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Final results
|
|
75
|
+
class IFinalResults
|
|
76
|
+
attr_accessor :failed, :fails, :artifacts, :features
|
|
77
|
+
|
|
78
|
+
def initialize(failed:, fails:, artifacts:, features:)
|
|
79
|
+
@failed = failed
|
|
80
|
+
@fails = fails
|
|
81
|
+
@artifacts = artifacts
|
|
82
|
+
@features = features
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/rubeno.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: testeranto.rubeno
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.4
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Adam Wong
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2010-04-03 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: The Ruby implementation of Testeranto
|
|
14
|
+
email: adamwong246@gmail.com
|
|
15
|
+
executables:
|
|
16
|
+
- rubeno
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- README.md
|
|
21
|
+
- Rakefile
|
|
22
|
+
- bin/rubeno
|
|
23
|
+
- lib/base_given.rb
|
|
24
|
+
- lib/base_suite.rb
|
|
25
|
+
- lib/base_then.rb
|
|
26
|
+
- lib/base_when.rb
|
|
27
|
+
- lib/pm/ruby.rb
|
|
28
|
+
- lib/rubeno.rb
|
|
29
|
+
- lib/simple_adapter.rb
|
|
30
|
+
- lib/types.rb
|
|
31
|
+
- rubeno.rb
|
|
32
|
+
homepage: http://rubygems.org/gems/rubeno
|
|
33
|
+
licenses: []
|
|
34
|
+
metadata: {}
|
|
35
|
+
post_install_message:
|
|
36
|
+
rdoc_options: []
|
|
37
|
+
require_paths:
|
|
38
|
+
- lib
|
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
requirements: []
|
|
50
|
+
rubygems_version: 3.4.1
|
|
51
|
+
signing_key:
|
|
52
|
+
specification_version: 3
|
|
53
|
+
summary: The Ruby implementation of Testeranto
|
|
54
|
+
test_files: []
|