golden_silk 0.0.3.cardboard → 0.0.4.builders
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/golden_silk +38 -3
- data/lib/golden_silk/result/diff.rb +5 -3
- data/lib/golden_silk/result/no_effect.rb +1 -1
- data/lib/golden_silk/spinner.rb +56 -40
- data/lib/golden_silk/step/button_click.rb +20 -0
- data/lib/golden_silk/step/click.rb +3 -3
- data/lib/golden_silk/step/visit.rb +2 -2
- data/lib/golden_silk/version.rb +1 -1
- data/lib/golden_silk.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 126e16c8f9f102e4822151c6f325316430b1f441
|
4
|
+
data.tar.gz: 8fd0d2c891234ae8be26681d755b5fe3138eb71f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50fc6ebeb33b7966711d9ac51be11da1112e09d0b69615132ff0e96566827e1019f3298ec05ed31cb1766c9a1d095d97a2f593305fdaa57d0471494a300a692e
|
7
|
+
data.tar.gz: 6165461801b143f4c15698c9de5f21c4752e8f9ad6a9bbe9bccfa65942e1acf456d42ce147712481493b9a8f913ed1a8d56a7e139e7e68ecd2644f93ae6f3483
|
data/bin/golden_silk
CHANGED
@@ -1,7 +1,42 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'golden_silk'
|
4
|
+
require 'optparse'
|
4
5
|
|
5
|
-
# TODO:
|
6
|
-
|
7
|
-
|
6
|
+
# TODO: Add a pretty progress bar when verbose is off
|
7
|
+
options = {}
|
8
|
+
|
9
|
+
opt_parser = OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: golden_silk [options] starting_url"
|
11
|
+
|
12
|
+
opts.separator ""
|
13
|
+
opts.separator "Options:"
|
14
|
+
|
15
|
+
opts.on("-v", "--verbose", "Run verbosely. Default is no output.") do |v|
|
16
|
+
options[:verbose] = true
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-d", "--depth NUM", Integer, "The maximum depth (number of steps) from the starting URL that should be explored. Default is 3.") do |d|
|
20
|
+
options[:depth] = d
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
24
|
+
puts opts
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on_tail("--version", "Show version") do
|
29
|
+
puts GoldenSilk::VERSION
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
opt_parser.parse!(ARGV)
|
35
|
+
|
36
|
+
starting_url = ARGV.first
|
37
|
+
if starting_url
|
38
|
+
GoldenSilk::Spinner.new(starting_url, options).run
|
39
|
+
else
|
40
|
+
puts "Starting URL is required."
|
41
|
+
exit
|
42
|
+
end
|
@@ -15,10 +15,12 @@ module GoldenSilk
|
|
15
15
|
#{@steps.last}
|
16
16
|
sleep 2
|
17
17
|
html_after = html
|
18
|
-
diff = Diffy::Diff.new(html_before, html_after, context:
|
19
|
-
expect(diff).to eql('#{@diff.gsub("'", "\\\\'")}')
|
20
|
-
end
|
18
|
+
diff = Diffy::Diff.new(html_before, html_after, context: 0).each_chunk.to_a
|
21
19
|
RSPEC
|
20
|
+
@diff.each_chunk do |chunk|
|
21
|
+
s << " expect(diff).to include('#{chunk.gsub("'", "\\\\'")}')\n"
|
22
|
+
end
|
23
|
+
s << " end\n"
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/golden_silk/spinner.rb
CHANGED
@@ -6,39 +6,39 @@ module GoldenSilk
|
|
6
6
|
class Spinner
|
7
7
|
include Capybara::DSL
|
8
8
|
|
9
|
-
# TODO: configurable depth
|
10
|
-
MAX_DEPTH = 3
|
11
|
-
|
12
9
|
# TODO: configurable capybara driver
|
13
10
|
Capybara.default_driver = :webkit
|
14
11
|
|
15
12
|
Diffy::Diff.default_format = :text
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
# TODO: allow for the thing we start with to be calling a method in your test_helper? Maybe?
|
15
|
+
# If the interesting part to test requires you to do a few steps like visit and log in...
|
16
|
+
def initialize(root_url, options = {})
|
17
|
+
@root_url = root_url
|
18
|
+
@verbose = options.fetch(:verbose, false)
|
19
|
+
@max_depth = options.fetch(:depth, 3)
|
20
|
+
|
21
|
+
# TODO: configurable click selector
|
22
|
+
# TODO: have the default take into account disabled states
|
20
23
|
@click_selector = 'button, .store-accessory'
|
24
|
+
|
21
25
|
@results = []
|
22
26
|
@queue = []
|
23
27
|
end
|
24
28
|
|
25
29
|
def run
|
26
|
-
|
27
|
-
page.driver.allow_url(
|
30
|
+
host = URI(@root_url).host
|
31
|
+
page.driver.allow_url(host)
|
28
32
|
page.driver.block_unknown_urls
|
29
33
|
|
30
34
|
visit @root_url
|
31
35
|
# TODO: configurable wait time
|
32
36
|
sleep 2
|
33
|
-
|
34
|
-
|
35
|
-
Step::Visit.new(url: @root_url, on: self),
|
36
|
-
Step::Click.new(xpath: node.path, text: node.text, on: self)
|
37
|
-
]
|
38
|
-
}
|
39
|
-
stuff(@queue, @results)
|
37
|
+
enqueue_clickables([Step::Visit.new(url: @root_url, on: self)])
|
38
|
+
crawl
|
40
39
|
|
41
40
|
# TODO: configurable output dir, test file(s), preamble
|
41
|
+
# TODO: provide helper methods so that diffy doesn't have to be required explicitly
|
42
42
|
# TODO: stream results so that all is not lost if you have to kill the generation
|
43
43
|
FileUtils.mkdir_p("test/integration")
|
44
44
|
File.open('test/integration/golden_silk_spec.rb', 'w') do |f|
|
@@ -49,51 +49,67 @@ module GoldenSilk
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
def output(str)
|
53
|
+
puts str if @verbose
|
54
|
+
end
|
55
|
+
|
52
56
|
private
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
+
def enqueue_clickables(previous_steps)
|
59
|
+
all(@click_selector).each { |node|
|
60
|
+
steps_to_queue = previous_steps.clone
|
61
|
+
# TODO: check for Ambiguous matches that may need more identification
|
62
|
+
if node.tag_name == 'button'
|
63
|
+
steps_to_queue << Step::ButtonClick.new(text: node.text, on: self)
|
64
|
+
else
|
65
|
+
steps_to_queue << Step::Click.new(xpath: node.path, text: node.text, on: self)
|
66
|
+
end
|
67
|
+
@queue << steps_to_queue
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def crawl
|
72
|
+
if @queue.empty?
|
73
|
+
output "Queue is empty, we're done!"
|
58
74
|
return
|
59
75
|
end
|
60
76
|
|
61
|
-
current_action_set = queue.shift
|
77
|
+
current_action_set = @queue.shift
|
62
78
|
depth = current_action_set.length
|
63
79
|
|
64
|
-
|
80
|
+
all_but_the_last_action = current_action_set[0...-1]
|
81
|
+
last_action = current_action_set.last
|
65
82
|
|
66
|
-
|
83
|
+
all_but_the_last_action.each { |a| a.execute }
|
67
84
|
sleep 2
|
68
85
|
before_snapshot = html
|
69
86
|
last_action.execute
|
70
87
|
sleep 2
|
71
88
|
after_snapshot = html
|
72
|
-
diff = Diffy::Diff.new(before_snapshot, after_snapshot, context: 1).to_s
|
73
89
|
|
74
|
-
if
|
75
|
-
|
76
|
-
|
90
|
+
# Do a (quicker?) simple string comparison to see if there was a change in the page
|
91
|
+
if before_snapshot == after_snapshot
|
92
|
+
output "No change, adding to results but not queue."
|
93
|
+
@results << Result::NoEffect.new(steps: current_action_set)
|
77
94
|
else
|
78
|
-
|
79
|
-
|
95
|
+
# If there is a change, try and get the smallest change we can
|
96
|
+
before_html = before_snapshot.gsub(/>\s+</, "><").gsub("<", "\n<").gsub(">", ">\n").gsub(/\n\n+/, "\n")
|
97
|
+
after_html = after_snapshot.gsub(/>\s+</, "><").gsub("<", "\n<").gsub(">", ">\n").gsub(/\n\n+/, "\n")
|
98
|
+
diff = Diffy::Diff.new(before_html, after_html, context: 0)
|
99
|
+
|
100
|
+
output "Change, adding to results."
|
101
|
+
@results << Result::Diff.new(diff: diff, steps: current_action_set)
|
80
102
|
|
81
|
-
if depth ==
|
82
|
-
|
103
|
+
if depth == @max_depth
|
104
|
+
output "Hit max depth."
|
83
105
|
else
|
84
|
-
|
85
|
-
|
86
|
-
all(@click_selector).map { |node|
|
87
|
-
queue << current_action_set + [
|
88
|
-
last_action,
|
89
|
-
Step::Click.new(xpath: node.path, text: node.text, on: self)
|
90
|
-
]
|
91
|
-
}
|
106
|
+
output "Looking for more steps to take."
|
107
|
+
enqueue_clickables(current_action_set)
|
92
108
|
end
|
93
109
|
end
|
94
110
|
|
95
|
-
|
96
|
-
|
111
|
+
output "Recursing. Queue length: #{@queue.length}, Results length: #{@results.length}"
|
112
|
+
crawl
|
97
113
|
end
|
98
114
|
end
|
99
115
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GoldenSilk
|
2
|
+
module Step
|
3
|
+
class ButtonClick
|
4
|
+
def initialize(options = {})
|
5
|
+
@text = options[:text]
|
6
|
+
@tag = options[:tag]
|
7
|
+
@object = options[:on]
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
@object.output "Following instructions to click button #{@text}"
|
12
|
+
@object.click_button @text
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"click_button \"#{@text}\""
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -2,13 +2,13 @@ module GoldenSilk
|
|
2
2
|
module Step
|
3
3
|
class Click
|
4
4
|
def initialize(options = {})
|
5
|
-
@xpath
|
6
|
-
@text
|
5
|
+
@xpath = options[:xpath]
|
6
|
+
@text = options[:text]
|
7
7
|
@object = options[:on]
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute
|
11
|
-
|
11
|
+
@object.output "Following instructions to click #{@text}"
|
12
12
|
@object.find(:xpath, @xpath).click
|
13
13
|
end
|
14
14
|
|
@@ -2,12 +2,12 @@ module GoldenSilk
|
|
2
2
|
module Step
|
3
3
|
class Visit
|
4
4
|
def initialize(options = {})
|
5
|
-
@url
|
5
|
+
@url = options[:url]
|
6
6
|
@object = options[:on]
|
7
7
|
end
|
8
8
|
|
9
9
|
def execute
|
10
|
-
|
10
|
+
@object.output "Visiting #{@url}"
|
11
11
|
@object.visit @url
|
12
12
|
end
|
13
13
|
|
data/lib/golden_silk/version.rb
CHANGED
data/lib/golden_silk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: golden_silk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4.builders
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carol (Nichols || Goulding)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/golden_silk/result/diff.rb
|
102
102
|
- lib/golden_silk/result/no_effect.rb
|
103
103
|
- lib/golden_silk/spinner.rb
|
104
|
+
- lib/golden_silk/step/button_click.rb
|
104
105
|
- lib/golden_silk/step/click.rb
|
105
106
|
- lib/golden_silk/step/visit.rb
|
106
107
|
- lib/golden_silk/version.rb
|