def assertScreenshot(self, selector, path): """ Assert that the element as defined by the passed CSS `selector` is the same as the one saved in the baseline screenshot. Note that this method will generate a baseline screenshot if the make_baseline_screenshots config option is set to true. No assertions will occur. :param unicode selector: CSS selector of element to screenshot. :param path: URL path to page where element is found. """ for display_name, browser_name, driver in self._yield_drivers(): url = self._make_url(path) driver.get(url) # selenium checks for a str instance. Unicode would fail here. element = driver.find_element_by_css_selector(str(selector)) sleep(1) screenshot = element.get_screenshot() baseline_path = self._make_screenshot_path( self._BASELINE_FOLDER_NAME, browser_name, display_name) baseline_file = '{}/{}--{}.png'.format(baseline_path, path, selector) # Create the directory if it does not exist. if not os.path.exists(baseline_path): os.makedirs(baseline_path) if self._make_baseline_screenshots: screenshot.save(baseline_file) log.warning( 'Creating baseline screenshot: {}'.format(baseline_file)) else: try: baseline_screenshot = Image.open(baseline_file).convert( 'RGB') except IOError: raise MissingBaselineScreenshotException error_path = self._make_screenshot_path( self._ERROR_FOLDER_NAME, browser_name, display_name) if not os.path.exists(error_path): os.makedirs(error_path) error_file = '{}/{}--{}.png'.format(error_path, path, selector) try: diff = ImageDiff(screenshot, baseline_screenshot) except AssertionError: screenshot.save(error_file) raise AssertScreenshotException(error_file) distance = abs(diff.get_distance()) if distance > self._THRESHOLD: screenshot.save(error_file) raise AssertScreenshotException(distance) driver.close()
def assertSameFiles(self, output_file, baseline_file, threshold): output_image = Image.open(output_file).convert('RGB') baseline_image = Image.open(baseline_file).convert('RGB') diff = ImageDiff(output_image, baseline_image) distance = abs(diff.get_distance()) if distance > threshold: raise AssertionError("The new screenshot '%s' did not match " "the baseline '%s' (by a distance of %.2f)" % (output_file, baseline_file, distance))
def test_distance_all_channels(self): diff = ImageDiff(self.get_white_image(), self.get_black_image()) self.assertAlmostEqual(diff.get_distance(), 100 * 100, delta=0.001)
def test_nrmsd_half_filled(self): diff = ImageDiff(self.get_black_image(), self.get_half_filled_image()) self.assertEqual(diff.get_nrmsd(), math.sqrt(0.5))
def test_nrmsd_one_channel(self): diff = ImageDiff(self.get_image((255, 0, 0)), self.get_black_image()) self.assertEqual(diff.get_nrmsd(), math.sqrt(1.0 / 3))
def test_nrmsd_all_channels(self): diff = ImageDiff(self.get_white_image(), self.get_black_image()) self.assertEqual(diff.get_nrmsd(), 1)
def test_distance_half_filled(self): diff = ImageDiff(self.get_black_image(), self.get_half_filled_image()) self.assertAlmostEqual(diff.get_distance(), 10000.0 / 2, delta=0.001)
def assertScreenshot(self, selector, path): """ Assert that the element as defined by the passed CSS `selector` is the same as the one saved in the baseline screenshot. Note that this method will generate a baseline screenshot if the make_baseline_screenshots config option is set to true. No assertions will occur. :param unicode selector: CSS selector of element to screenshot. :param path: URL path to page where element is found. """ for display_name, browser_name, driver in self._yield_drivers(): url = self._make_url(path) driver.get(url) # selenium checks for a str instance. Unicode would fail here. element = driver.find_element_by_css_selector(str(selector)) sleep(1) screenshot = element.get_screenshot() baseline_path = self._make_screenshot_path( self._BASELINE_FOLDER_NAME, browser_name, display_name) baseline_file = '{}/{}--{}.png'.format( baseline_path, path, selector) # Create the directory if it does not exist. if not os.path.exists(baseline_path): os.makedirs(baseline_path) if self._make_baseline_screenshots: screenshot.save(baseline_file) log.warning('Creating baseline screenshot: {}'.format( baseline_file)) else: try: baseline_screenshot = Image.open(baseline_file).convert('RGB') except IOError: raise MissingBaselineScreenshotException error_path = self._make_screenshot_path( self._ERROR_FOLDER_NAME, browser_name, display_name) if not os.path.exists(error_path): os.makedirs(error_path) error_file = '{}/{}--{}.png'.format( error_path, path, selector) try: diff = ImageDiff(screenshot, baseline_screenshot) except AssertionError: screenshot.save(error_file) raise AssertScreenshotException(error_file) distance = abs(diff.get_distance()) if distance > self._THRESHOLD: screenshot.save(error_file) raise AssertScreenshotException(distance) driver.close()
def compareScreenshot(self, element_or_selector, file, threshold=0): """ Assert that a screenshot of an element is the same as a screenshot on disk, within a given threshold. :param element_or_selector: Either a CSS selector as a string or a :py:class:`~needle.driver.NeedleWebElementMixin` object that represents the element to capture. :param file: If a string, then assumed to be the filename for the screenshot, which will be appended with ``.png``. Otherwise assumed to be a file object for the baseline image. :param threshold: The threshold for triggering a test failure. """ yield # To allow using this method as a context manager if not isinstance(element_or_selector, NeedleWebElementMixin): element = self.driver.find_element_by_css_selector( element_or_selector) else: element = element_or_selector if not isinstance(file, basestring): # Comparing in-memory files instead of on-disk files baseline_image = Image.open(file).convert('RGB') fresh_screenshot = element.get_screenshot() diff = ImageDiff(fresh_screenshot, baseline_image) distance = abs(diff.get_distance()) if distance > threshold: raise AssertionError("The new screenshot did not match " "the baseline (by a distance of %.2f)" % distance) else: baseline_file = os.path.join(self.baseline_directory, '%s.png' % file) output_file = os.path.join(self.output_directory, '%s.png' % file) # Determine whether we should save the baseline image save_baseline = False if self.save_baseline: save_baseline = True elif self.capture: warn( "The 'NeedleTestCase.capture' attribute and '--with-save-baseline' nose option " "are deprecated since version 0.2.0. Use 'save_baseline' and '--with-save-baseline' " "instead. See the changelog for more information.", PendingDeprecationWarning) if os.path.exists(baseline_file): self.skipTest( 'Not capturing %s, its baseline image already exists. If you ' 'want to capture this element again, delete %s' % (file, baseline_file)) else: save_baseline = True if save_baseline: # Save the baseline screenshot and bail out element.get_screenshot().save(baseline_file) return else: if not os.path.exists(baseline_file): raise IOError( 'The baseline screenshot %s does not exist. ' 'You might want to re-run this test in baseline-saving mode.' % baseline_file) # Save the new screenshot element.get_screenshot().save(output_file) try: self.engine.assertSameFiles(output_file, baseline_file, threshold) except: raise else: if self.cleanup_on_success: os.remove(output_file)
def assert_screenshot(self, file_path, element_or_selector=None, threshold=0, exclude=None): """Fail if new fresh image is too dissimilar from the baseline image .. note:: From needle https://github.com/python-needle/needle/blob/master/needle/cases.py#L161 :param str file_path: File name for baseline image :param element_or_selector: WebElement or tuple containing selector ex. ('id', 'mainPage') :param threshold: Distance threshold :param list exclude: Elements or element selectors for areas to exclude :return: """ element = self._find_element( element_or_selector) if element_or_selector else None # Get baseline screenshot self._create_dir(self.baseline_dir) baseline_image = os.path.join(self.baseline_dir, '%s.png' % file_path) \ if isinstance(file_path, basestring) else Image.open(file_path).convert('RGB') # Take screenshot and exit if in baseline saving mode if self.save_baseline: self.get_screenshot_as_image(element, exclude=exclude).save(baseline_image) return # Get fresh screenshot self._create_dir(self.output_dir) fresh_image = self.get_screenshot_as_image(element, exclude=exclude) fresh_image_file = os.path.join(self.output_dir, '%s.png' % file_path) fresh_image.save(fresh_image_file) # Error if there is not a baseline image to compare if not self.save_baseline and not isinstance( file_path, basestring) and not os.path.exists(baseline_image): raise IOError( 'The baseline screenshot %s does not exist. You might want to ' 're-run this test in baseline-saving mode.' % baseline_image) # Compare images if isinstance(baseline_image, basestring): try: self.engine.assertSameFiles(fresh_image_file, baseline_image, threshold) except AssertionError as err: msg = getattr(err, 'message', err.args[0] if err.args else "") args = err.args[1:] if len(err.args) > 1 else [] raise ImageMismatchException(msg, baseline_image, fresh_image_file, args) except EnvironmentError: msg = "Missing baseline '{}'. Please run again with --needle-save-baseline".format( baseline_image) raise MissingBaselineException(msg) except ValueError as err: if self.options['needle_engine'] == 'imagemagick': msg = "It appears {0} is not installed. Please verify {0} is installed or choose a different engine" raise MissingEngineException( msg.format(self.options['needle_engine'])) raise err finally: if self.cleanup_on_success: os.remove(fresh_image_file) else: diff = ImageDiff(fresh_image, baseline_image) distance = abs(diff.get_distance()) if distance > threshold: pytest.fail( 'Fail: New screenshot did not match the baseline (by a distance of %.2f)' % distance)
def test_distance_one_channel(self): diff = ImageDiff(self.get_image((255, 0, 0)), self.get_black_image()) self.assertAlmostEqual(diff.get_distance(), 10000.0 / 3, delta=0.001)
def compareScreenshot(self, element_or_selector, file, threshold=0): """ Assert that a screenshot of an element is the same as a screenshot on disk, within a given threshold. :param element_or_selector: Either a CSS selector as a string or a :py:class:`~needle.driver.NeedleWebElementMixin` object that represents the element to capture. :param file: If a string, then assumed to be the filename for the screenshot, which will be appended with ``.png``. Otherwise assumed to be a file object for the baseline image. :param threshold: The threshold for triggering a test failure. """ yield # To allow using this method as a context manager if not isinstance(element_or_selector, NeedleWebElementMixin): element = self.driver.find_element_by_css_selector(element_or_selector) else: element = element_or_selector if not isinstance(file, basestring): # Comparing in-memory files instead of on-disk files baseline_image = Image.open(file).convert('RGB') fresh_screenshot = element.get_screenshot() diff = ImageDiff(fresh_screenshot, baseline_image) distance = abs(diff.get_distance()) if distance > threshold: raise AssertionError("The new screenshot did not match " "the baseline (by a distance of %.2f)" % distance) else: baseline_file = os.path.join(self.baseline_directory, '%s.png' % file) output_file = os.path.join(self.output_directory, '%s.png' % file) # Determine whether we should save the baseline image save_baseline = False if self.save_baseline: save_baseline = True elif self.capture: warn("The 'NeedleTestCase.capture' attribute and '--with-save-baseline' nose option " "are deprecated since version 0.2.0. Use 'save_baseline' and '--with-save-baseline' " "instead. See the changelog for more information.", PendingDeprecationWarning) if os.path.exists(baseline_file): self.skipTest('Not capturing %s, its baseline image already exists. If you ' 'want to capture this element again, delete %s' % (file, baseline_file)) else: save_baseline = True if save_baseline: # Save the baseline screenshot and bail out element.get_screenshot().save(baseline_file) return else: if not os.path.exists(baseline_file): raise IOError('The baseline screenshot %s does not exist. ' 'You might want to re-run this test in baseline-saving mode.' % baseline_file) # Save the new screenshot element.get_screenshot().save(output_file) try: self.engine.assertSameFiles(output_file, baseline_file, threshold) except: raise else: if self.cleanup_on_success: os.remove(output_file)
def assert_screenshot(self, file_path, element_or_selector=None, threshold=0, exclude=None): """Fail if new fresh image is too dissimilar from the baseline image .. note:: From needle https://github.com/python-needle/needle/blob/master/needle/cases.py#L161 :param str file_path: File name for baseline image :param element_or_selector: WebElement or tuple containing selector ex. ('id', 'mainPage') :param threshold: Distance threshold :param list exclude: Elements or element selectors for areas to exclude :return: """ element = self._find_element(element_or_selector) # Get baseline image if isinstance(file_path, basestring): baseline_image = os.path.join(self.baseline_dir, '%s.png' % file_path) if self.save_baseline: # Take screenshot and exit return self.get_screenshot_as_image( element, exclude=exclude).save(baseline_image) else: if not os.path.exists(baseline_image): raise IOError( 'The baseline screenshot %s does not exist. ' 'You might want to re-run this test in baseline-saving mode.' % baseline_image) else: # Comparing in-memory files instead of on-disk files baseline_image = Image.open(file_path).convert('RGB') # Get fresh screenshot fresh_image = self.get_screenshot_as_image(element, exclude=exclude) # Compare images if isinstance(baseline_image, basestring): output_file = os.path.join(self.output_dir, '%s.png' % file_path) fresh_image.save(output_file) try: self.engine.assertSameFiles(output_file, baseline_image, threshold) except AssertionError as err: msg = err.message \ if hasattr(err, "message") \ else err.args[0] if err.args else "" args = err.args[1:] if len(err.args) > 1 else [] raise ImageMismatchException(msg, baseline_image, output_file, args) finally: if self.cleanup_on_success: os.remove(output_file) else: diff = ImageDiff(fresh_image, baseline_image) distance = abs(diff.get_distance()) if distance > threshold: pytest.fail('Fail: New screenshot did not match the ' 'baseline (by a distance of %.2f)' % distance)