Revision 544:e6f81d7c26db
Added by Daniel Havlik almost 8 years ago
- ID e6f81d7c26db
- Parent 543:4190387a07c4
- Child 545:61f5f9b87a5f
src/gocept/selenium/screenshot.py | ||
---|---|---|
27 | 27 |
self.width = self.exp.size[0] |
28 | 28 |
self.height = self.exp.size[1] |
29 | 29 |
self.prepare_composition() |
30 |
self.paste_screenshots() |
|
31 |
ignored, compo_path = tempfile.mkstemp('.png') |
|
32 |
with open(compo_path, 'rw') as compo: |
|
33 |
self.path = compo.name |
|
34 |
self.compo.save(self.path) |
|
35 |
if SHOW_DIFF_IMG: |
|
36 |
self.compo.show() |
|
30 | 37 |
|
31 | 38 |
def prepare_composition(self): |
32 | 39 |
"""prepares and returns the composition image, given width |
... | ... | |
43 | 50 |
pos = (5, index*(self.height+self.label_margin)) |
44 | 51 |
self.compo.paste(img, pos) |
45 | 52 |
|
46 |
|
|
47 | 53 |
def paste_screenshots(self): |
48 | 54 |
for index, screenshot in enumerate((self.exp, self.got, self.diff)): |
49 | 55 |
pos = (0, (index*self.height)+((index+1)*self.label_margin)) |
50 | 56 |
self.compo.paste(screenshot, pos) |
51 | 57 |
|
52 | 58 |
@property |
53 |
def composition(self): |
|
54 |
self.paste_screenshots() |
|
55 |
return self.compo |
|
56 |
|
|
57 |
@property |
|
58 | 59 |
def diff(self): |
59 | 60 |
def subtract(source, sub): |
60 | 61 |
return ImageChops.invert( |
... | ... | |
87 | 88 |
def __init__(self, image_a, image_b): |
88 | 89 |
self.image_a = image_a |
89 | 90 |
self.image_b = image_b |
91 |
self.distance = self.get_nrmsd() * 100 |
|
92 |
|
|
93 |
def within_threshold(self, threshold): |
|
94 |
return self.distance < threshold |
|
90 | 95 |
|
91 | 96 |
def get_nrmsd(self): |
92 | 97 |
""" |
... | ... | |
98 | 103 |
for a, b in itertools.izip(a_values, b_values): |
99 | 104 |
rmsd += (a - b) ** 2 |
100 | 105 |
rmsd = math.sqrt(float(rmsd) / ( |
101 |
self.image_a.size[0] * self.image_a.size[1] * len(self.image_a.getbands()) |
|
106 |
self.image_a.size[0] * self.image_a.size[1] * len( |
|
107 |
self.image_a.getbands()) |
|
102 | 108 |
)) |
103 | 109 |
return rmsd / 255 |
104 | 110 |
|
... | ... | |
142 | 148 |
self.expected, self.got) |
143 | 149 |
|
144 | 150 |
|
145 |
def _get_screenshot(selenese, locator):
|
|
151 |
def make_screenshot(selenese, locator):
|
|
146 | 152 |
ignored, path = tempfile.mkstemp() |
147 | 153 |
selenese.captureScreenshot(path) |
148 | 154 |
|
... | ... | |
176 | 182 |
screenshot_directory, '') |
177 | 183 |
|
178 | 184 |
|
179 |
def assertScreenshot(selenese, name, locator, threshold=1): |
|
180 |
filename = os.path.join( |
|
181 |
_screenshot_path(selenese.screenshot_directory), '%s.png' % name) |
|
182 |
screenshot = _get_screenshot(selenese, locator) |
|
185 |
def save_screenshot_temporary(screenshot): |
|
186 |
"""Saves given screenshot to a temporary file and return |
|
187 |
the filename.""" |
|
188 |
ignored, got_path = tempfile.mkstemp('.png') |
|
189 |
with open(got_path, 'rw') as got: |
|
190 |
screenshot.save(got.name) |
|
191 |
return got.name |
|
192 |
|
|
193 |
|
|
194 |
def save_as_expected(screenshot, img_basename, exp_path): |
|
195 |
if os.path.exists(exp_path): |
|
196 |
raise ValueError( |
|
197 |
'Not capturing {}, image already exists. If you ' |
|
198 |
'want to capture this element again, delete {}'.format( |
|
199 |
img_basename, exp_path)) |
|
200 |
screenshot.save(exp_path) |
|
201 |
raise ValueError( |
|
202 |
'Captured {}. You might now want to remove capture mode and ' |
|
203 |
'check in the created screenshot {}.'.format( |
|
204 |
img_basename, exp_path)) |
|
205 |
|
|
206 |
|
|
207 |
def assertScreenshot(selenese, img_basename, locator, threshold=1): |
|
208 |
exp_path = os.path.join( |
|
209 |
_screenshot_path(selenese.screenshot_directory), '%s.png' % img_basename) |
|
210 |
screenshot = make_screenshot(selenese, locator) |
|
183 | 211 |
if selenese.capture_screenshot: |
184 |
if os.path.exists(filename): |
|
185 |
raise ValueError( |
|
186 |
'Not capturing {}, image already exists. If you ' |
|
187 |
'want to capture this element again, delete {}'.format( |
|
188 |
name, filename)) |
|
189 |
screenshot.save(filename) |
|
190 |
raise ValueError( |
|
191 |
'Captured {}. You might now want to remove capture mode and ' |
|
192 |
'check in the created screenshot {}.'.format(name, filename)) |
|
212 |
#In capture mode, we only want to save the screenshot |
|
213 |
#as the new expected image. |
|
214 |
save_as_expected(screenshot, img_basename, exp_path) |
|
193 | 215 |
return |
194 |
image = Image.open(filename) |
|
195 |
diff = ImageDiff(screenshot, image) |
|
196 |
distance = abs(diff.get_nrmsd()) * 100 |
|
197 |
if distance > threshold: |
|
198 |
ignored, got_path = tempfile.mkstemp('.png') |
|
199 |
with open(got_path, 'rw') as got: |
|
200 |
screenshot.save(got.name) |
|
201 |
if image.size != screenshot.size: |
|
216 |
exp = Image.open(exp_path) |
|
217 |
diff = ImageDiff(screenshot, exp) |
|
218 |
if not diff.within_threshold(threshold): |
|
219 |
#In failure case, we save the screenshot. |
|
220 |
got_path = save_screenshot_temporary(screenshot) |
|
221 |
if exp.size != screenshot.size: |
|
222 |
#Seperate exception if sizes differ. |
|
202 | 223 |
raise ScreenshotSizeMismatchError( |
203 |
name, image.size, screenshot.size, filename, got.name) |
|
204 |
return |
|
205 |
ignored, compo_path = tempfile.mkstemp('.png') |
|
206 |
with open(compo_path, 'rw') as compo: |
|
207 |
compo_img = DiffComposition(image, screenshot).composition |
|
208 |
compo_img.save(compo.name) |
|
209 |
if SHOW_DIFF_IMG: |
|
210 |
compo_img.show() |
|
224 |
img_basename, exp.size, screenshot.size, exp_path, got_path) |
|
225 |
#Sizes are the same, so we can render a nice diff image. |
|
226 |
compo = DiffComposition(exp, screenshot) |
|
211 | 227 |
raise ScreenshotMismatchError( |
212 |
name, distance, filename, got.name, compo.name)
|
|
228 |
img_basename, diff.distance, exp_path, got_path, compo.path)
|
|
213 | 229 |
|
230 |
|
Also available in: Unified diff
re #12065 refactor screenshot assertion