Class: Lineup::Screenshot

Inherits:
Object
  • Object
show all
Defined in:
lib/lineup.rb

Instance Method Summary collapse

Constructor Details

#initialize(baseurl) ⇒ Screenshot

Returns a new instance of Screenshot.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/lineup.rb', line 11

def initialize(baseurl)

  # the base URL is the root url (in normal projects the frontpage or for us storefront)
  # while the base url is passed in, defaults for other values are set, too
  #
  # for us the base url is https://www.otto.
  #
  # the base url needs to be a string and cannot be an empty sting

  raise "base URL needs to be a string" unless baseurl.is_a? String
  raise "base URL is needed, cannot be empty" if baseurl == ''

  @baseurl = baseurl

  # the urls are combined with the root url and give the absolute url of the pages to be tested
  # see more in the according method below
  # the default value is the baseurl itself, represented by a forward slash
  # the images will be saved as "frontpage" images

  urls('/')

  # the resolutions can be as many as desired, we use a mobile, a tablet and a desktop resolution
  # by default this is 640px, 800px and 1180px width
  # see more in the according method below

  resolutions('640, 800, 1180')

  # this sets the path where to store the screenshots, by default this is the current directory
  # see more in the according method below

  filepath_for_images("#{Dir.pwd}/screenshots")

  # using selenium in a headless environment vs firefox.
  # by default in headless
  # see more in according method below

  use_phantomjs(true)

  # this is the path where to save the difference images of two not alike screenshots
  # by default the current directory, like for the other images
  # see more in according method below

  difference_path("#{Dir.pwd}/screenshots")

  @comparer = []
end

Instance Method Details

#compare(base, new) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/lineup.rb', line 297

def compare(base, new)

  # this compares two previously taken screenshots
  # the "base" and "new" variable need to be the same as previously assigned
  # as "variable" in the method "record_screenshot"!
  # all other information are constants and are passed along

  #threads = []
  #i=0
  @urls.each { |url|
    @resolutions.each { |resolution|
      #threads[i] = Thread.new {
      @comparer.push(Comparer.new(base, new, @difference_path, @baseurl, [url], [resolution], @screenshots_path))
      #}
      #i+=1;
    }
  }
  #threads.each { |t| t.join } //TODO Fix multithreading issue with 3rd party lib

  # this gives back an array, which as one element for each difference image.
  # [ {diff_1}, {diff_2}, ...]
  # while each diff is a hash with keys:
  # {url: <url>, width: <width in px>, difference: <%of changed pixel>, base_file: <file path>, new_file: <file path>, diff_file: <file path>}
  merged_differences = []
  @comparer.each { |c| merged_differences += c.difference }
  return merged_differences;
end

#cookies(cookies) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/lineup.rb', line 173

def cookies(cookies)

  # a hash for cookies can be set here. this is optional.
  #
  # e.g {name: 'name', value: 'value', domain: 'domain.com', path: '/', expires: <Time>, secure: false}
  #
  # if it is not nil it has to be an array:

  @cookies = []
  if cookies
    cookies.each do |cookie|
      # generate :symbol => "value" hash map from "symbol" => "value"
      cookie = cookie.inject({}) { |element, (symbol, value)| element[symbol.to_sym] = value; element }

      #Validation
      (raise "Cookie must be a hash of format
            {name: 'name', value: 'value', domain: 'domain.com', path: '/', expires: <Time>, secure: false}
            " unless cookie.is_a? Hash)

      raise "cookie must have value for :name" unless (cookie[:name]).is_a? String
      raise "cookie must have value for :value" unless (cookie[:value]).is_a? String
      raise "cookie must have value for :domain" unless (cookie[:domain]).is_a? String
      raise "cookie must have value for :path" unless (cookie[:path]).is_a? String
      raise "cookie must have value for :secure" if (cookie[:secure]) == nil

      @cookies.push(cookie)
    end
  end
end

#difference_path(path) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/lineup.rb', line 156

def difference_path(path)

  # if required an absolute path to store all difference images can be passed here.
  # in most usecases you may want to save them along with the base and new images
  #
  # e.g '/home/finn/pictures/otto'
  #
  # if its not a string or the string is empty an exception is raised

  raise "path for difference images needs to be a string" unless path.is_a? String
  raise "the path for the difference images cannot be <empty string>" if path == ''

  # assign the variable

  @difference_path = path
end

#filepath_for_images(path) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/lineup.rb', line 113

def filepath_for_images(path)

  # if required an absolute path to store all images can be passed here.
  # at the path a file "screenshots" will be generated
  #
  # e.g '/home/finn/pictures/otto'
  #
  # if its not a string or the string is empty an exception is raised

  raise "path for screenshots needs to be a string" unless path.is_a? String
  raise "the path for the screenshots cannot be <empty string>" if path == ''

  # after the base screenshots are taken, the path cannot be changed, an exception would be raised

  raise_base_screenshots_taken('The path')

  # the path is one string. we just assign the variable

  @screenshots_path = path
end

#load_json_config(path) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/lineup.rb', line 246

def load_json_config(path)

  # loads all possible configs from a json file.
  # in this file all parameters need to be set
  # an example configuration is
  # '{"urls":"/multimedia, /sport","resolutions":"600,800,1200","filepath_for_images":"~/images/","use_headless":true,"difference_path":"#/images/diff"}'

  #open the file and parse JSON format
  configuration = JSON.parse(File.read(path))

  # write to method above
  urls(configuration["urls"])
  resolutions(configuration["resolutions"])
  filepath_for_images(configuration["filepath_for_images"])
  use_phantomjs(configuration["use_phantomjs"])
  difference_path(configuration["difference_path"])
  wait_for_asynchron_pages(configuration["wait_for_asynchron_pages"])
  cookies(configuration["cookies"])
  localStorage(configuration["localStorage"])

  # the method calls set the variables for the parameters, we return an array with all of them.
  # for the example above it is:
  # [["/multimedia", "/sport"], [600, 800, 1200], "~/images/", true, "#/images/diff"]
  [@urls, @resolutions, @screenshots_path, @headless, @difference_path, @wait_for_asynchron_pages, @cookies, @localStorage]
end

#localStorage(localStorage) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/lineup.rb', line 204

def localStorage(localStorage)

  # a hash for localStorage Key Value pair can be set here. this is optional.
  #
  # e.g {'key': 'value'}
  #
  # if it is not nil it has to be an array:

  @localStorage = {}
  if localStorage
    #Validation
    (raise "LocalStorage must be a hash of format
            {'key'=>'value'}
            " unless localStorage.is_a? Hash)

    localStorage.each do |key, value|
      raise "LocalStorage must have a string as key" if (key).empty?
      raise "LocalStorage key must be a string" unless (key).is_a? String
      raise "LocalStorage value must be a string" unless (value).is_a? String

      @localStorage[key] = value
    end
  end

end

#record_screenshot(version) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/lineup.rb', line 273

def record_screenshot(version)

  # to take a screenshot we have all parameters given from the methods above (or set to default values)
  # selenium is started in
  #   @headless or firefox
  # and takes a screenshot of the urls
  #   @baseurl/@url[0], @baseurl/@url[1], etc...
  # and takes a screenshot for each url for all given resolutions
  #   @resolutions[0], @resolutions[1], etc...
  # and saves the screenshot in the file
  #   @screenshot_path

  browser = Browser.new(@baseurl, @urls, @resolutions, @screenshots_path, @headless, @wait_for_asynchron_pages, @cookies, @localStorage)
  # the only argument missing is if this is the "base" or "new" screenshot, this can be
  # passed as an argument. The value does not need to be "base" or "new", but can be anything
  browser.record(version)
  # this will close the browser and terminate the headless environment
  browser.end

  # this flag is set, so that parameters like resolution or urls cannot be changed any more
  @got_base_screenshots = true
end

#resolutions(resolutions) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/lineup.rb', line 87

def resolutions(resolutions)

  # all resolutions to be tested are defined here
  # they need to be passed as a comma separated string (with or without whitespaces)
  #
  # e.g "400, 800, 1200"
  #
  # if its not a string or the string is empty an exception is raised

  raise "resolutions for screenshots needs to be a string" unless resolutions.is_a? String
  raise "the resolutions for screenshot cannot be <empty string>" if resolutions == ''

  # after the base screenshots are taken, the resolutions cannot be changed, an exception would be raised

  raise_base_screenshots_taken('The resolutions')

  #we remove whitespaces from the urls, replace ; by , and generate an array of integers

  begin
    @resolutions = clean(resolutions).split(",").map { |s| s.to_i }
  rescue NoMethodError
    raise "resolutions must be in a comma separated string"
  end
end

#save_json(path) ⇒ Object



325
326
327
328
329
330
331
332
333
# File 'lib/lineup.rb', line 325

def save_json(path)

  # json output can be saved if needed. A path is required to save the file
  raise "screenshots need to be compared before json output can be generated" unless @comparer.count > 0

  # the array from @comparer.difference is saved as json
  save_comparer_log(path)

end

#urls(urls) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/lineup.rb', line 59

def urls(urls)

  # all urls to be tested are defined here
  # they need to be passed as a comma separated string (with or without whitespaces)
  #
  # e.g "/, /multimedia, /sport"
  #
  # the pages are used to name the image files, too
  #
  # if it is not a string or the string is empty an exception is raised

  raise "url for screenshots needs to be a string" unless urls.is_a? String
  raise "url for screenshots cannot be <empty string>" if urls == ''

  # after the base screenshots are taken, the urls cannot be changed, an exception would be raised

  raise_base_screenshots_taken('The urls')

  #we remove whitespaces from the urls, replace ; by , and generate an array, splitted by comma

  begin
    @urls= clean(urls).split(",")
  rescue NoMethodError
    raise "urls must be in a comma separated string"
  end
end

#use_phantomjs(boolean) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/lineup.rb', line 135

def use_phantomjs(boolean)

  # if required the headless environment can we skipped and firefox used for the screenshots
  #
  # e.g use_headless = false
  #
  # if its not a boolean an exception is raised

  raise "use_headless can only be true or false" unless boolean == !!boolean

  # after the base screenshots are taken, the browser cannot be changed, an exception would be raised

  raise_base_screenshots_taken('The browser type (headless)')

  # sometimes packages are missing on ubuntu to run the headless environment, installing these should resolve it:
  # sudo apt-get install -y xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic xvfb x11-apps  imagemagick

  @headless = boolean
end

#wait_for_asynchron_pages(wait) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/lineup.rb', line 230

def wait_for_asynchron_pages(wait)

  # if required a wait time in seconds can be set. This may be needed, if after pageload some
  # elements are still loaded (Third-Party-Tools, AJAX, JS, Fonts)
  #
  # this value is a number (integer) how many seconds lineup will wait before taking a screenshot
  #
  # if its not an integer an exception is raised

  raise "wait time needs to be an integer (wait time in seconds)" unless wait.is_a? Integer

  # assign the variable

  @wait_for_asynchron_pages = wait
end