yordi_tests 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 783043661bdec27c6adf4c9f4d3b1d545d675ef4
4
- data.tar.gz: 64fc1f61a1a524e3e61aaedc4931c6dce74523b7
3
+ metadata.gz: 4208c9db4dd2f22a7c88dce21e4f6250139efe13
4
+ data.tar.gz: 0a7442b43e80119ea70d342601566a4d298545a5
5
5
  SHA512:
6
- metadata.gz: 7784cb732fcd3cb3794b3058d39efa00cace7d44dca2778f3a2c09549831997dffa5ce058063f553af65d476f34de4fe7334bb4bf0c2394a61efe5fbead0119f
7
- data.tar.gz: 4a2b864d577a4d56f762ca2d57d62226c5e83fa08cee69aeb68f2dc35b0078c7f511621d5961670ab75bf4a8d30f62ed35f385cba8ccf714325079e5af65d002
6
+ metadata.gz: 5fb1e59529a9fa1e73f6149f35d74a2afec07a1e91627226badd23b9f467a22c3706814740f6b84adaf4b835e1c4f61aae84a96c1af7edc55fa5e70ee5b6a715
7
+ data.tar.gz: b03cf1c995ddf5c78385eaad2d403deefb3b84cf3fbf436a8d1ab66fa25a99d5d430616eb1d21ee41b013594fde857da05fb277388e88b3c4d1c1fe8245933e6
data/.gitignore CHANGED
@@ -10,4 +10,5 @@
10
10
  /.idea/
11
11
  /test/fixtures/
12
12
  /test/fixtures/benchmarks/
13
+ /.yordi_tests/
13
14
  /test/fixtures/screenshots/
@@ -13,14 +13,22 @@ module YordiTests
13
13
 
14
14
 
15
15
  YORDI_DIR = ENV['YORDI_DIR'].freeze || '.yordi_tests'.freeze
16
- BENCHMARKS_PATH = YORDI_DIR + '/benchmarks'.freeze
17
- SCREENS_PATH = YORDI_DIR + '/screenshots'.freeze
18
- CONFIG_FILE = YORDI_DIR + '/config.json'.freeze
19
- REPORT_FILE = YORDI_DIR + '/report.json'.freeze
20
- REPORT_HTML = YORDI_DIR + '/report.html'.freeze
16
+ BENCHMARKS_PATH = File.join(YORDI_DIR, 'benchmarks').freeze
17
+ SCREENS_PATH = File.join(YORDI_DIR, 'screenshots').freeze
18
+ CONFIG_FILE = File.join(YORDI_DIR, 'config.json').freeze
19
+ REPORT_FILE = File.join(YORDI_DIR, 'report.json').freeze
20
+ REPORT_HTML = File.join(YORDI_DIR, 'report.html').freeze
21
+
22
+ # set default value
23
+ @client = Client
24
+ @verbose = true
21
25
 
22
26
  module_function
23
27
 
28
+ def verbose=(v)
29
+ @verbose = v
30
+ end
31
+
24
32
  def client=(v)
25
33
  @client = v
26
34
  end
@@ -29,8 +37,9 @@ module YordiTests
29
37
  @client
30
38
  end
31
39
 
32
- # set default value
33
- @client = Client
40
+ def safe_puts(message)
41
+ puts message if @verbose
42
+ end
34
43
 
35
44
  def new_client(apikey)
36
45
  client = new
@@ -7,22 +7,21 @@ module YordiTests
7
7
 
8
8
  desc 'init --api_key', 'Initializes a Yordi test directory at .yordi_tests relative to where you execute the command'
9
9
  method_option :api_key, type: :string, aliases: '-k', desc: 'APIKEY from YordiTest.com if you want to sync results online'
10
+ method_option :force, type: :boolean, aliases: '-f', desc: 'Force re-initialization'
11
+ method_option :verbose, type: :boolean, default: false, aliases: '-v', desc: 'Suppress console output'
10
12
 
11
13
  def init
12
- puts 'init'
13
- if Dir.exist?(YORDI_DIR)
14
+ YordiTests.verbose = options.verbose
15
+ YordiTests.safe_puts 'init'
16
+
17
+ if DataManager.store? && !options.force
14
18
  puts 'Already initialized'
15
19
  exit(1)
16
20
  end
17
- puts "Creating #{YORDI_DIR} directory"
18
- DataManager.create_store
19
21
 
20
- store = DataManager.default_store(options.api_key)
21
- puts "Saving store #{CONFIG_FILE}"
22
- DataManager.save_store store
22
+ DataManager.create_store(options.api_key)
23
23
 
24
24
  return unless options.api_key
25
- puts 'Fetching remote store.'
26
25
  DataManager.fetch(true, true, nil)
27
26
  end
28
27
 
@@ -34,16 +33,19 @@ module YordiTests
34
33
  method_option :sync_failures, type: :boolean, default: false, aliases: '-f', desc: 'Push only failed screens to YordiTests.com for evaluation.'
35
34
  method_option :filenames, type: :array, aliases: '-i', desc: 'Only test these specific files'
36
35
  method_option :screens, type: :array, aliases: '-s', desc: 'Give the files a name other than there filename in the report (best used with -i option)'
36
+ method_option :verbose, type: :boolean, default: false, aliases: '-v', desc: 'Suppress console output'
37
37
 
38
38
  def test(path_to_screens)
39
- puts "Testing #{path_to_screens} name: #{options.name}, clean_dir: #{options.clean_dir}, sync_all: #{options.sync_all}, sync_failures: #{options.sync_failures}, filenames: #{options.filenames}, screens: #{options.screens}"
40
-
39
+ YordiTests.verbose = options.verbose
40
+ YordiTests.safe_puts "Testing #{path_to_screens} name: #{options.name}, clean_dir: #{options.clean_dir}, sync_all: #{options.sync_all}, sync_failures: #{options.sync_failures}, filenames: #{options.filenames}, screens: #{options.screens}"
41
41
  DataManager.run_test(path_to_screens, options.name, options.clean_dir, options.sync_all, options.sync_failures, options.filenames, options.screens)
42
42
  end
43
43
 
44
44
  desc 'make_report', 'Regenerate a Yordi report based on json report'
45
45
 
46
+ method_option :verbose, type: :boolean, default: false, aliases: '-v', desc: 'Suppress console output'
46
47
  def make_report
48
+ YordiTests.verbose = options.verbose
47
49
  DataManager.generate_report
48
50
  end
49
51
 
@@ -51,9 +53,11 @@ module YordiTests
51
53
  method_option :benchmarks, type: :boolean, default: false, aliases: '-b', desc: 'Fetch benchmarks'
52
54
  method_option :masks, type: :boolean, default: false, aliases: '-m', desc: 'Fetch masks'
53
55
  method_option :screens, type: :array, aliases: '-s', desc: 'Only fetch items associated with this list of screen names'
56
+ method_option :verbose, type: :boolean, default: false, aliases: '-v', desc: 'Suppress console output'
54
57
 
55
58
  def fetch
56
- puts "Fetching with options benchmarks: #{options.benchmarks}, masks: #{options.masks}, screens: #{options.screens}"
59
+ YordiTests.verbose = options.verbose
60
+ YordiTests.safe_puts "Fetching with options benchmarks: #{options.benchmarks}, masks: #{options.masks}, screens: #{options.screens}"
57
61
  DataManager.fetch(options.benchmarks, options.masks, options.screens)
58
62
  end
59
63
 
@@ -61,9 +65,11 @@ module YordiTests
61
65
  method_option :benchmarks, type: :boolean, default: false, aliases: '-b', desc: 'Push benchmarks'
62
66
  method_option :masks, type: :boolean, default: false, aliases: '-m', desc: 'Push masks'
63
67
  method_option :screens, type: :array, aliases: '-s', desc: 'Only push items associated with this list of screen names'
68
+ method_option :verbose, type: :boolean, default: false, aliases: '-v', desc: 'Suppress console output'
64
69
 
65
70
  def push(path_to_screens)
66
- puts "test #{path_to_screens}"
71
+ YordiTests.verbose = options.verbose
72
+ YordiTests.safe_puts "test #{path_to_screens}"
67
73
  end
68
74
 
69
75
 
@@ -1,74 +1,89 @@
1
1
  require 'yordi_tests'
2
- require 'yordi_tests/local_store'
2
+ require 'yordi_tests/data_store'
3
3
  require 'yordi_tests/image_compare'
4
4
  require 'yordi_tests/generators/report'
5
5
  module YordiTests
6
6
  module DataManager
7
7
  module_function
8
8
 
9
- def default_store(apikey)
10
- {title: 'YordiTests', apikey: apikey, test_benchmarks: []}
9
+ # Create Store
10
+ #
11
+ # Called during init process on the CLI
12
+ #
13
+ def create_store(apikey)
14
+ YordiTests.safe_puts "Initializing #{YORDI_DIR} "
15
+ verify_directories
16
+ store = {title: 'YordiTests', apikey: apikey, test_benchmarks: []}
17
+ YordiTests.safe_puts "Saving store #{CONFIG_FILE}"
18
+ save_store store
11
19
  end
12
20
 
13
- def create_store
14
- Dir.mkdir(YORDI_DIR) unless Dir.exist? YORDI_DIR
15
- end
21
+ # Fetch
22
+ #
23
+ # used in the fetch command from the CLI
24
+ #
25
+ def fetch(get_benchmarks, get_masks, screens)
26
+ verify_directories
27
+ local_store = DataStore.new(read_store)
16
28
 
17
- def read_store
18
- read_json(CONFIG_FILE)
19
- end
29
+ ## no api key
30
+ return unless local_store.apikey
20
31
 
21
- def read_report
22
- read_json(REPORT_FILE)
23
- end
32
+ client = YordiTests.client
33
+ client.apikey = local_store.apikey
24
34
 
25
- def read_json(path)
26
- if File.exist? path
27
- file = File.read path
28
- JSON(file)
29
- else
30
- puts "No file at: #{path} did you call initialize this directory"
31
- end
35
+ YordiTests.safe_puts 'Fetching remote store.'
36
+ remote_data = client.fetch_application
32
37
 
38
+ ## no remote store
39
+ return unless remote_data
40
+
41
+ remote_store = DataStore.new(remote_data)
42
+
43
+ local_store.update_root_data(remote_store.title, remote_store.apikey)
44
+ replace_benchmarks(client, local_store, remote_store, screens) if get_benchmarks
45
+ replace_masks(local_store, remote_store, screens) if get_masks
46
+
47
+ save_store local_store.data
33
48
  end
34
49
 
35
- def save_store(store_hash)
36
- File.open(CONFIG_FILE, 'w') {|file| file.write(store_hash.to_json)}
50
+ # Generate a report
51
+ #
52
+ # Used in the make_report command from the CLI
53
+ #
54
+ def generate_report
55
+ YordiTests::Generators::Report.start([REPORT_HTML, read_report])
37
56
  end
38
57
 
39
- # Test entry from the CLI
58
+ # RunTest
59
+ #
60
+ # Used in the test command from the CLI
40
61
  def run_test(path_to_screens, name, clean_dir, sync_all, sync_failures, filenames, screens)
41
- local_store = LocalStore.new(read_store)
62
+ verify_directories
63
+ store = DataStore.new(read_store)
42
64
  if filenames
43
65
  files = []
44
66
  filenames.each do |filename|
45
- files << path_to_screens + '/' + filename
67
+ files << File.join(path_to_screens, filename)
46
68
  end
47
69
  else
48
- files = Dir.glob(path_to_screens + '/*.png').sort
70
+ files = Dir.glob(File.join(path_to_screens, '*.png')).sort
49
71
  end
50
-
51
- Dir.mkdir(BENCHMARKS_PATH) unless Dir.exist? BENCHMARKS_PATH
52
- Dir.mkdir(SCREENS_PATH) unless Dir.exist? SCREENS_PATH
53
72
  responses = []
54
73
  files.each_with_index do |item, index|
55
- puts "Testing #{item}"
56
- screenname = (!screens.nil? && screens.size > index) ? screens[index] : File.basename(item, '.*')
57
- benchmark = local_store.benchmark_by_screenname(screenname)
74
+ YordiTests.safe_puts "Testing #{item}"
75
+ screenname = !screens.nil? && screens.size > index ? screens[index] : File.basename(item, '.*')
76
+ benchmark = store.benchmark_by_screenname(screenname)
58
77
  local_name = benchmark.nil? ? sanitize(screenname) + File.extname(item) : benchmark[LOCAL_FILENAME]
59
- benchmark_path = BENCHMARKS_PATH + '/' + local_name
60
- screenshot_path = SCREENS_PATH + '/' + local_name
78
+ benchmark_path = File.join(BENCHMARKS_PATH, local_name)
79
+ screenshot_path = File.join(SCREENS_PATH, local_name)
61
80
  FileUtils.copy item, screenshot_path
62
81
  if benchmark.nil?
63
82
  FileUtils.copy item, benchmark_path
64
- benchmark = {SCREENNAME => screenname,
65
- MASKED_AREA => nil,
66
- FILENAME => local_name,
67
- LOCAL_FILENAME => local_name}
68
- local_store.update_benchmark(benchmark)
69
- save_store local_store.data
83
+ benchmark = store.add_benchmark(screenname, local_name)
84
+ save_store store.data
70
85
  end
71
- global_mask = local_store.get(MASKED_AREA)
86
+ global_mask = store.get(MASKED_AREA)
72
87
  screen_mask = benchmark.nil? ? nil : benchmark[MASKED_AREA]
73
88
  response = ImageCompare.perform(benchmark_path, screenshot_path, global_mask, screen_mask)
74
89
  response[SCREENNAME] = screenname
@@ -77,80 +92,80 @@ module YordiTests
77
92
  File.delete item if clean_dir
78
93
  end
79
94
  report_hash = {name: name, tests: responses}
80
- File.open(REPORT_FILE, 'w') {|file| file.write(report_hash.to_json)}
95
+ save_report(report_hash)
81
96
 
82
97
  # sync with yorditests.com if desired
83
- sync_with_yordi local_store, sync_all, sync_failures if sync_all || sync_failures
98
+ sync_with_yordi store, sync_all, sync_failures if sync_all || sync_failures
84
99
  generate_report
85
100
  end
86
101
 
87
- def generate_report
88
- # generate report
89
- YordiTests::Generators::Report.start([REPORT_HTML, read_report])
102
+ # helper functions
90
103
 
104
+ def store?
105
+ Dir.exist? YORDI_DIR
91
106
  end
92
107
 
93
- def sync_with_yordi(store, sync_all, sync_failures)
94
- # sync with remote
95
- puts 'Syncing with YordiTests'
96
- report = read_report
97
- client = YordiTests.client
98
- client.apikey = store.apikey if store.apikey
99
- if !report.nil? && !report['tests'].empty?
100
- reports = report['tests']
101
- failures = 0
102
- if sync_failures
103
- reports.each do |item|
104
- failures += 1 unless item['passed']
105
- end
106
- end
108
+ def read_store
109
+ read_json(CONFIG_FILE)
110
+ end
107
111
 
108
- if sync_all || failures > 0
109
- client.start report['name']
110
- reports.each do |item|
111
- next unless sync_all || !item['passed']
112
- puts item[SCREENNAME]
113
- benchmark = store.benchmark_by_screenname(item[SCREENNAME])
114
- filename = SCREENS_PATH + '/' + benchmark[LOCAL_FILENAME]
115
- client.upload filename, item[SCREENNAME]
116
- end
117
- client.stop
118
- end
112
+ def read_report
113
+ read_json(REPORT_FILE)
114
+ end
115
+
116
+ def read_json(path)
117
+ if File.exist? path
118
+ file = File.read path
119
+ JSON(file)
120
+ else
121
+ YordiTests.safe_puts "No file at: #{path} did you call initialize this directory"
119
122
  end
123
+
120
124
  end
121
125
 
122
- # Fetch entry from the CLI
123
- def fetch(get_benchmarks, get_masks, screens)
124
- local_store = LocalStore.new(read_store)
125
- ## no api key
126
- return unless local_store.apikey
126
+ def save_report(store_hash)
127
+ save_data(REPORT_FILE, store_hash)
128
+ end
127
129
 
128
- client = YordiTests.client
129
- client.apikey = local_store.apikey
130
- remote_data = client.fetch_application
130
+ def save_store(store_hash)
131
+ save_data(CONFIG_FILE, store_hash)
132
+ end
131
133
 
132
- ## no remote store
133
- return unless remote_data
134
+ def save_data(file_path, hash)
135
+ File.open(file_path, 'w') {|file| file.write(hash.to_json)}
136
+ end
134
137
 
135
- remote_store = LocalStore.new(remote_data)
136
138
 
137
- update_store_base(local_store, remote_store)
138
- replace_benchmarks(client, local_store, remote_store, screens) if get_benchmarks
139
- replace_masks(local_store, remote_store, screens) if get_masks
139
+ def sync_with_yordi(store, sync_all, sync_failures)
140
+ # sync with remote
141
+ return unless store.apikey
142
+ YordiTests.safe_puts 'Syncing with YordiTests'
143
+ report = read_report
144
+ return if report.nil? || report['tests'].empty?
145
+ reports = report['tests']
140
146
 
141
- save_store local_store.data
142
- end
147
+ client = YordiTests.client
148
+ client.apikey = store.apikey
143
149
 
144
- def update_store_base(local_store, remote_store)
145
- local_store.put(TITLE, remote_store.get(TITLE))
146
- local_store.put(APIKEY, remote_store.apikey)
150
+ # filter out passed tests if failures syncing is on
151
+ if sync_failures && !sync_all
152
+ reports = reports.reject {|item| item['passed']}
153
+ end
154
+
155
+ return unless sync_all || !reports.empty?
156
+
157
+ client.start report['name']
158
+ reports.each do |item|
159
+ YordiTests.safe_puts "Uploading #{item[SCREENNAME]}"
160
+ benchmark = store.benchmark_by_screenname(item[SCREENNAME])
161
+ filename = File.join(SCREENS_PATH, benchmark[LOCAL_FILENAME])
162
+ client.upload filename, item[SCREENNAME]
163
+ end
164
+ client.stop
147
165
  end
148
166
 
149
167
  def replace_benchmarks(client, local_store, remote_store, screens)
150
- # no api key
151
- screens = remote_store.all_screens unless screens
152
-
153
- Dir.mkdir(BENCHMARKS_PATH) unless Dir.exist? BENCHMARKS_PATH
168
+ screens ||= remote_store.all_screens
154
169
 
155
170
  screens.each do |screen|
156
171
  benchmark = remote_store.benchmark_by_screenname(screen)
@@ -159,11 +174,11 @@ module YordiTests
159
174
  benchmark[LOCAL_FILENAME] = sanitize(screen) + File.extname(benchmark[FILENAME])
160
175
 
161
176
  # download benchmark
162
- puts "Downloading #{screen}"
177
+ YordiTests.safe_puts "Downloading #{screen}"
163
178
  benchmark_image = client.fetch_benchmark(screen)
164
179
 
165
180
  # update store to reflex file name of benchmark
166
- file_path = "#{BENCHMARKS_PATH}/#{benchmark[LOCAL_FILENAME]}"
181
+ file_path = File.join(BENCHMARKS_PATH, benchmark[LOCAL_FILENAME])
167
182
  File.open(file_path, 'w') {|file| file.write(benchmark_image)}
168
183
  local_store.update_benchmark(benchmark)
169
184
  end
@@ -172,15 +187,20 @@ module YordiTests
172
187
  def replace_masks(local_store, remote_store, screens)
173
188
  # global mask
174
189
  local_store.put(MASKED_AREA, remote_store.get(MASKED_AREA))
175
- screens = remote_store.all_screens unless screens
190
+ screens ||= remote_store.all_screens
176
191
  screens.each do |screen|
177
192
  benchmark = remote_store.benchmark_by_screenname(screen)
178
193
  # download benchmark
179
- puts "Update mask for #{screen}"
194
+ YordiTests.safe_puts "Update mask for #{screen}"
180
195
  local_store.update_mask(benchmark) if benchmark
181
196
  end
182
197
  end
183
198
 
199
+ def verify_directories
200
+ Dir.mkdir(YORDI_DIR) unless Dir.exist? YORDI_DIR
201
+ Dir.mkdir(BENCHMARKS_PATH) unless Dir.exist? BENCHMARKS_PATH
202
+ Dir.mkdir(SCREENS_PATH) unless Dir.exist? SCREENS_PATH
203
+ end
184
204
 
185
205
  def sanitize(filename)
186
206
  # Remove any character that aren't 0-9, A-Z, or a-z
@@ -8,7 +8,7 @@ module YordiTests
8
8
  LOCAL_FILENAME = 'local_filename'.freeze
9
9
  TITLE = 'title'.freeze
10
10
 
11
- class LocalStore
11
+ class DataStore
12
12
 
13
13
  def initialize(json_store)
14
14
  @store = json_store
@@ -17,6 +17,9 @@ module YordiTests
17
17
  def apikey
18
18
  get(APIKEY)
19
19
  end
20
+ def title
21
+ get(TITLE)
22
+ end
20
23
 
21
24
  def data
22
25
  @store
@@ -27,7 +30,8 @@ module YordiTests
27
30
  end
28
31
 
29
32
  def get(key)
30
- @store[key]
33
+ return @store[key].dup unless @store[key].nil?
34
+ nil
31
35
  end
32
36
 
33
37
  def all_screens
@@ -37,6 +41,10 @@ module YordiTests
37
41
  end
38
42
  screens
39
43
  end
44
+ def update_root_data(title, apikey)
45
+ put(TITLE, title)
46
+ put(APIKEY, apikey)
47
+ end
40
48
 
41
49
  def update_benchmark(benchmark)
42
50
  benchmark_pos = benchmark_pos_by_screenname(benchmark[SCREENNAME])
@@ -49,12 +57,21 @@ module YordiTests
49
57
  end
50
58
  end
51
59
 
60
+ def add_benchmark(screenname, local_name)
61
+ benchmark = {SCREENNAME => screenname,
62
+ MASKED_AREA => nil,
63
+ FILENAME => local_name,
64
+ LOCAL_FILENAME => local_name}
65
+ @store[BENCHMARKS] << benchmark.dup
66
+ benchmark
67
+ end
68
+
52
69
  def update_mask(benchmark)
53
70
  benchmark_pos = benchmark_pos_by_screenname(benchmark[SCREENNAME])
54
71
  if benchmark_pos < 0
55
72
  @store[BENCHMARKS] << benchmark.dup
56
73
  else
57
- @store[BENCHMARKS][benchmark_pos][MASKED_AREA] = benchmark[MASKED_AREA]
74
+ @store[BENCHMARKS][benchmark_pos][MASKED_AREA] = benchmark[MASKED_AREA].dup unless benchmark[MASKED_AREA].nil?
58
75
  end
59
76
  end
60
77
 
@@ -89,7 +89,7 @@
89
89
 
90
90
  <td>
91
91
  <b>Result</b><br/>
92
- <img style="width:100%" src="benchmarks/<%= item['local_filename'] %>"/>
92
+ <img style="width:100%" src="screenshots/<%= item['local_filename'] %>"/>
93
93
 
94
94
  </td>
95
95
  </tr>
@@ -1,7 +1,6 @@
1
1
  require 'yordi_tests'
2
2
  require 'mini_magick'
3
3
  require 'securerandom'
4
- require 'yordi_tests/local_store'
5
4
  module YordiTests
6
5
  module ImageCompare
7
6
  module_function
@@ -1,3 +1,3 @@
1
1
  module YordiTests
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yordi_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian OQR
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-10 00:00:00.000000000 Z
11
+ date: 2017-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -115,10 +115,10 @@ files:
115
115
  - lib/yordi_tests/cli.rb
116
116
  - lib/yordi_tests/client.rb
117
117
  - lib/yordi_tests/data_manager.rb
118
+ - lib/yordi_tests/data_store.rb
118
119
  - lib/yordi_tests/generators/report.html.erb
119
120
  - lib/yordi_tests/generators/report.rb
120
121
  - lib/yordi_tests/image_compare.rb
121
- - lib/yordi_tests/local_store.rb
122
122
  - lib/yordi_tests/version.rb
123
123
  - yordi_tests.gemspec
124
124
  homepage: https://www.yorditests.com