def _appendrow(self, result_name, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] for extra in getattr(report, 'extra', []): self.append_extra_html(extra, additional_html, links_html) self.append_log_html(report, additional_html) test_id = report.nodeid if report.when != 'call': test_id = '::'.join([report.nodeid, report.when]) rows_table = html.tr([ html.td(result_name, class_='col-result'), html.td(test_id, class_='col-name'), html.td('{0:.2f}'.format(time), class_='col-duration'), html.td(links_html, class_='col-links')]) rows_extra = html.tr(html.td(additional_html, class_='extra', colspan='5')) self.test_logs.append(html.tbody(rows_table, rows_extra, class_=result_name.lower() + ' results-table-row'))
def __init__(self, outcome, report, self_contained, logfile): self.test_id = report.nodeid if report.when != 'call': self.test_id = '::'.join([report.nodeid, report.when]) self.time = getattr(report, 'duration', 0.0) self.outcome = outcome self.additional_html = [] self.links_html = [] self.self_contained = self_contained self.logfile = logfile test_index = hasattr(report, 'rerun') and report.rerun + 1 or 0 for extra_index, extra in enumerate(getattr(report, 'extra', [])): self.append_extra_html(extra, extra_index, test_index) xfail = hasattr(report, 'wasxfail') if (report.skipped and xfail) or (report.failed and not xfail): self.append_log_html(report, self.additional_html) self.row_table = html.tr([ html.td(self.outcome, class_='col-result'), html.td(self.test_id, class_='col-name'), html.td('{0:.2f}'.format(self.time), class_='col-duration'), html.td(self.links_html, class_='col-links') ]) self.row_extra = html.tr( html.td(self.additional_html, class_='extra', colspan='5'))
def insert_data(self, tables_data: dict): if not isinstance(tables_data, dict): raise TypeError( f'{self.__module__} supports only dict as InputParam') self.tables_processed = len(tables_data.keys()) for raw_table_name, raw_table_data in tables_data.items(): csv_file_path = raw_table_data['Athena']['FilePath'] database_name, table_name = raw_table_name.split('.') self.data_results.append( html.div( html.h3(f"Input data: {raw_table_name}"), html.table( html.tr([ html.th('Database:', class_='database-name'), html.th(database_name) ]), html.tr([ html.th('Table name:', class_='table-name'), html.th(table_name) ]), self._generate_glue_report(raw_table_data['Glue']), self._generate_s3_report(raw_table_data['S3']), self._generate_athena_report(raw_table_data['Athena']), class_="processed-table"), html.div(f"{self._get_csv_data(csv_file_path)}", table_name=table_name, class_="data-tables")))
def __init__(self, outcome, report, logfile, config): self.test_id = report.nodeid.encode("utf-8").decode( "unicode_escape") if getattr(report, "when", "call") != "call": self.test_id = "::".join([report.nodeid, report.when]) self.time = getattr(report, "duration", 0.0) self.formatted_time = self._format_time(report) self.outcome = outcome self.additional_html = [] self.links_html = [] self.self_contained = config.getoption("self_contained_html") self.max_asset_filename_length = int( config.getini("max_asset_filename_length")) self.logfile = logfile self.config = config self.row_table = self.row_extra = None test_index = hasattr(report, "rerun") and report.rerun + 1 or 0 for extra_index, extra in enumerate(getattr(report, "extra", [])): self.append_extra_html(extra, extra_index, test_index) self.append_log_html( report, self.additional_html, config.option.capture, config.option.showcapture, ) cells = [ html.td(self.outcome, class_="col-result"), html.td(self.test_id, class_="col-name"), html.td(self.formatted_time, class_="col-duration"), html.td(self.links_html, class_="col-links"), ] self.config.hook.pytest_html_results_table_row(report=report, cells=cells) self.config.hook.pytest_html_results_table_html( report=report, data=self.additional_html) if len(cells) > 0: tr_class = None if self.config.getini("render_collapsed"): tr_class = "collapsed" self.row_table = html.tr(cells) self.row_extra = html.tr( html.td(self.additional_html, class_="extra", colspan=len(cells)), class_=tr_class, )
def generate_html(self): generated = datetime.utcnow() with open(os.path.join(base_path, "main.js")) as main_f: doc = html.html( self.head, html.body( html.script(raw(main_f.read())), html.p('Report generated on %s at %s' % (generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'))), html.h2('Environment'), html.table([ html.tr(html.td(k), html.td(v)) for k, v in sorted(self.env.items()) if v ], id='environment'), html.h2('Summary'), html.p( '%i tests ran in %.1f seconds.' % (sum(self.test_count.itervalues()), (self.suite_times["end"] - self.suite_times["start"]) / 1000.), html.br(), html.span('%i passed' % self.test_count["PASS"], class_='pass'), ', ', html.span('%i skipped' % self.test_count["SKIP"], class_='skip'), ', ', html.span('%i failed' % self.test_count["UNEXPECTED_FAIL"], class_='fail'), ', ', html.span('%i errors' % self.test_count["UNEXPECTED_ERROR"], class_='error'), '.', html.br(), html.span('%i expected failures' % self.test_count["EXPECTED_FAIL"], class_='expected_fail'), ', ', html.span('%i unexpected passes' % self.test_count["UNEXPECTED_PASS"], class_='unexpected_pass'), '.'), html.h2('Results'), html.table([ html.thead(html.tr([ html.th('Result', class_='sortable', col='result'), html.th('Test', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), html.th('Links') ]), id='results-table-head'), html.tbody(self.result_rows, id='results-table-body') ], id='results-table'))) return u"<!DOCTYPE html>\n" + doc.unicode(indent=2)
def gen_html_table(mtx): from py.xml import html # print("DBG genhtmltable", mtx) result = html.table( html.thead(html.tr([html.th(x) for x in mtx[0]])), # header html.tbody(*[ html.tr([html.td(x) for x in row]) # rows for row in mtx[1:] ]), class_="fixed_headers") # make it fixed height scrollable # https://codepen.io/tjvantoll/pen/JEKIu # result = str(result) + """ # """ return str(result)
def gen_html_table( mtx ): from py.xml import html # print("DBG genhtmltable", mtx) result = html.table( html.thead( html.tr( [html.th( x ) for x in mtx[0] ] ) ), # header html.tbody( *[ html.tr( [html.td( x ) for x in row] ) # rows for row in mtx[1:] ] ), class_="fixed_headers" ) # make it fixed height scrollable # https://codepen.io/tjvantoll/pen/JEKIu # result = str(result) + """ # """ return str(result)
def __init__(self, outcome, report, logfile, config): #self.test_id = report.nodeid self.test_id = (' ::').join(report.nodeid.split('::')) if getattr(report, 'when', 'call') != 'call': self.test_id = ' ::'.join([report.nodeid, report.when]) self.time = getattr(report, 'duration', 0.00) self.outcome = outcome self.additional_html = [] self.links_html = [] self.self_contained = config.getoption('self_contained_html') self.logfile = logfile self.config = config self.row_table = self.row_extra = None test_index = hasattr(report, 'rerun') and report.rerun + 1 or 0 for extra_index, extra in enumerate(getattr(report, 'extra', [])): self.append_extra_html(extra, extra_index, test_index) self.append_log_html(report, self.additional_html) #add description if hasattr(report, "description"): des = report.description else: des = "无" cells = [ html.td(self.outcome, class_='col-result'), html.td(des, class_='col-description'), #des html.td(self.test_id, class_='col-name'), html.td('{0:.2f}'.format(self.time), class_='col-duration') #,html.td(self.links_html, class_='col-links') ] self.config.hook.pytest_html_results_table_row(report=report, cells=cells) self.config.hook.pytest_html_results_table_html( report=report, data=self.additional_html) if len(cells) > 0: self.row_table = html.tr(cells) self.row_extra = html.tr( html.td(self.additional_html, class_='extra', colspan=len(cells)))
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata environment = [html.h2("测试环境")] rows = [] keys = [k for k in metadata.keys()] # if not isinstance(metadata, OrderedDict): # keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in sorted(map(str, value))) elif isinstance(value, dict): sorted_dict = {k: value[k] for k in sorted(value)} value = json.dumps(sorted_dict) raw_value_string = raw(str(value)) rows.append(html.tr(html.td(TEST_ENV.get(key)), html.td(raw_value_string))) environment.append(html.table(rows, id="environment")) return environment
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata if 'Capabilities' in metadata: metadata.pop('Capabilities') if 'Base URL' in config._metadata: metadata.pop('Base URL') environment = [html.h2("Environment")] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in value) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id="environment")) return environment
def _generate_environment(self, environment_details): rows = [] keys = [ k for k in environment_details.keys() if environment_details[k] ] if not isinstance(environment_details, OrderedDict): keys.sort() for key in keys: value = environment_details[key] if isinstance(value, basestring) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment = html.div( html.h2("Environment"), html.div( html.table(rows, id="environment"), class_="environment-info", ), class_="environment-details", ) return environment
def make_table_rows(self): regressions = self.results.regressions rv = [] tests = sorted(regressions.keys()) for i, test in enumerate(tests): test_data = regressions[test] cells, needs_subtest = self.make_test_name(test, test_data, i) for subtest in sorted(test_data.keys()): if needs_subtest: cells.append(html.td(subtest)) subtest_data = test_data[subtest] cells.extend([ html.td(subtest_data["expected"].title(), class_="condition %s" % subtest_data["expected"]), html.td(subtest_data["status"].title(), class_="condition %s" % subtest_data["status"]), html.td(subtest_data.get("message", ""), class_="message") ]) tr = html.tr(cells) rv.append(tr) cells = [] needs_subtest = True return rv
def _generate_environment(self, config): if not hasattr(config, "_metadata") or config._metadata is None: return [] metadata = config._metadata environment = [html.h2("Environment")] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, str) and value.startswith("http"): value = html.a(value, href=value, target="_blank") elif isinstance(value, (list, tuple, set)): value = ", ".join(str(i) for i in sorted(map(str, value))) elif isinstance(value, dict): key_value_list = [f"'{k}': {value[k]}" for k in sorted(value)] value = ", ".join(key_value_list) value = "{" + value + "}" raw_value_string = raw(str(value)) rows.append(html.tr(html.td(key), html.td(raw_value_string))) environment.append(html.table(rows, id="environment")) return environment
def version_get(self, user, index, name, version): stage = self.getstage(user, index) name = ensure_unicode(name) version = ensure_unicode(version) metadata = stage.get_projectconfig(name) if not metadata: abort(404, "project %r does not exist" % name) verdata = metadata.get(version, None) if not verdata: abort(404, "version %r does not exist" % version) if json_preferred(): apireturn(200, type="versiondata", result=verdata) # if html show description and metadata rows = [] for key, value in sorted(verdata.items()): if key == "description": continue if isinstance(value, list): value = html.ul([html.li(x) for x in value]) rows.append(html.tr(html.td(key), html.td(value))) title = "%s/: %s-%s metadata and description" % (stage.name, name, version) content = stage.get_description(name, version) #css = "https://pypi.python.org/styles/styles.css" return simple_html_body( title, [html.table(*rows), py.xml.raw(content)], extrahead=[ html.link(media="screen", type="text/css", rel="stylesheet", title="text", href="https://pypi.python.org/styles/styles.css") ]).unicode(indent=2)
def version_get(self, user, index, name, version): stage = self.getstage(user, index) name = ensure_unicode(name) version = ensure_unicode(version) metadata = stage.get_projectconfig(name) if not metadata: abort(404, "project %r does not exist" % name) verdata = metadata.get(version, None) if not verdata: abort(404, "version %r does not exist" % version) if json_preferred(): apireturn(200, type="versiondata", result=verdata) # if html show description and metadata rows = [] for key, value in sorted(verdata.items()): if key == "description": continue if isinstance(value, list): value = html.ul([html.li(x) for x in value]) rows.append(html.tr(html.td(key), html.td(value))) title = "%s/: %s-%s metadata and description" % ( stage.name, name, version) content = stage.get_description(name, version) #css = "https://pypi.python.org/styles/styles.css" return simple_html_body(title, [html.table(*rows), py.xml.raw(content)], extrahead= [html.link(media="screen", type="text/css", rel="stylesheet", title="text", href="https://pypi.python.org/styles/styles.css")] ).unicode(indent=2)
def make_table_rows(self, results): rv = [] for result in results: details_link = "%s/report.html" % result.name cells = [html.td(result.name)] if result.has_errors: cells.append(html.td( len(result.errors), class_="condition FAIL", )) else: cells.append(html.td("0", class_="condition PASS")) if result.has_regressions: num_regressions = sum(len(item) for item in result.regressions.itervalues()) cells.append(html.td(num_regressions, class_="condition FAIL")) else: cells.append(html.td("0", class_="condition PASS")) if result.is_pass: cells.append(html.td()) else: cells.append(html.td( html.a("details", href=details_link), class_="details" )) rv.append(html.tr(cells)) return rv
def add_row(self, lineno, text): if text == ['']: text = [raw(' ')] else: text = prepare_line(text, self.tokenizer, self.encoding) self.tbody.append(html.tr(html.td(str(lineno), class_='lineno'), html.td(class_='code', *text)))
def generate_html(self): generated = datetime.datetime.now() with open(os.path.join(base_path, "main.js")) as main_f: doc = html.html( self.head, html.body( html.script(raw(main_f.read())), html.p( "Report generated on %s at %s" % (generated.strftime("%d-%b-%Y"), generated.strftime("%H:%M:%S")), html.h2("Summary"), html.p( "%i tests ran in %.1f seconds." % ( sum(self.test_count.itervalues()), (self.suite_times["end"] - self.suite_times["start"]) / 1000.0, ), html.br(), html.span("%i passed" % self.test_count["PASS"], class_="pass"), ", ", html.span("%i skipped" % self.test_count["SKIP"], class_="skip"), ", ", html.span("%i failed" % self.test_count["UNEXPECTED_FAIL"], class_="fail"), ", ", html.span("%i errors" % self.test_count["UNEXPECTED_ERROR"], class_="error"), ".", html.br(), html.span( "%i expected failures" % self.test_count["EXPECTED_FAIL"], class_="expected_fail" ), ", ", html.span( "%i unexpected passes" % self.test_count["UNEXPECTED_PASS"], class_="unexpected_pass" ), ".", ), html.h2("Results"), html.table( [ html.thead( html.tr( [ html.th("Result", class_="sortable", col="result"), html.th("Class", class_="sortable", col="class"), html.th("Test Name", class_="sortable", col="name"), html.th("Duration", class_="sortable numeric", col="duration"), html.th("Links"), ] ), id="results-table-head", ), html.tbody(self.result_rows, id="results-table-body"), ], id="results-table", ), ), ), ) return u"<!DOCTYPE html>\n" + doc.unicode(indent=2)
def _appendrow(self, result, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] for extra in getattr(report, 'extra', []): href = None if extra.get('format') == extras.FORMAT_IMAGE: href = '#' image = 'data:image/png;base64,%s' % extra.get('content') additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif extra.get('format') == extras.FORMAT_HTML: additional_html.append(extra.get('content')) elif extra.get('format') == extras.FORMAT_JSON: href = data_uri(json.dumps(extra.get('content')), mime_type='application/json') elif extra.get('format') == extras.FORMAT_TEXT: href = data_uri(extra.get('content')) elif extra.get('format') == extras.FORMAT_URL: href = extra.get('content') if href is not None: links_html.append(html.a( extra.get('name'), class_=extra.get('format'), href=href, target='_blank')) links_html.append(' ') if 'Passed' not in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): if not PY3: line = line.decode('utf-8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(escape(line)), class_='error')) else: log.append(raw(escape(line))) log.append(html.br()) additional_html.append(log) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(report.nodeid, class_='col-name'), html.td('%.2f' % time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='extra')], class_=result.lower() + ' results-table-row'))
def make_result_html(self, data): tc_time = (data["time"] - self.start_times.pop(data["test"])) / 1000. additional_html = [] debug = data.get("extra", {}) links_html = [] status = status_name = data["status"] expected = data.get("expected", status) if status != expected: status_name = "UNEXPECTED_" + status elif status != "PASS": status_name = "EXPECTED_" + status self.test_count[status_name] += 1 if status in ['SKIP', 'FAIL', 'ERROR']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append(html.div( html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content.encode('utf-8')) links_html.append(html.a( name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') log = html.div(class_='log') output = data.get('stack', '').splitlines() output.extend(data.get('message', '').splitlines()) for line in output: separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) self.result_rows.append( html.tr([html.td(status_name, class_='col-result'), html.td(data['test'], class_='col-name'), html.td('%.2f' % tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=status_name.lower() + ' results-table-row'))
def html_table_row(self): cells = html.tr([ html.td(v, class_=class_) for v, class_ in zip(self.formatted_statistics, COLUMN_CLASSES) ]) self.config.hook.pytest_aggreport_html_table_row(result=self, cells=cells) return cells
def make_errors_table(self, errors): rows = [] for error in errors: rows.append(html.tr( html.td(error["level"], class_="log_%s" % error["level"]), html.td(error.get("message", "")) )) return html.table(rows, id_="errors")
def make_result_table(self): return html.table(html.thead( html.tr(html.th("Subsuite", class_='sortable', col='subsuite'), html.th("Subsuite Errors"), html.th("Test Executions"), html.th("Details"))), html.tbody(self.make_table_rows( self.subsuite_results), id='results-table-body'), id='results-table')
def _appendrow(self, result, report): time = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] if 'Passed' not in result: for extra in getattr(report, 'extra', []): href = None if type(extra) is Image: href = '#' image = 'data:image/png;base64,%s' % extra.content additional_html.append(html.div( html.a(html.img(src=image), href="#"), class_='image')) elif type(extra) is HTML: additional_html.append(extra.content) elif type(extra) is Text: href = 'data:text/plain;charset=utf-8;base64,%s' % \ b64encode(extra.content) elif type(extra) is URL: href = extra.content if href is not None: links_html.append(html.a( extra.name, class_=extra.__class__.__name__.lower(), href=href, target='_blank')) links_html.append(' ') if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf-8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(report.nodeid, class_='col-name'), html.td('%.2f' % time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='extra')], class_=result.lower() + ' results-table-row'))
def _create_overview(self): for node, results in self.tempDict.iteritems(): table = [html.td(node, class_="col-name")] res = [ html.td(result.capitalize(), class_="%s col-%s" % (result.lower(), when)) for when, result in results.iteritems() ] table.extend(res) self.test_overview.append(html.tr(table))
def make_body(self): body_parts = [ html.div( html.script(raw( pkg_resources.resource_string( rcname, os.path.sep.join( ['resources', 'htmlreport', 'jquery.js']))), type='text/javascript'), html.script(raw( pkg_resources.resource_string( rcname, os.path.sep.join( ['resources', 'htmlreport', 'main.js']))), type='text/javascript'), html.h1("FirefoxOS Certification Suite Report"), html.p("Run at %s" % self.time.strftime("%Y-%m-%d %H:%M:%S"))) ] if self.logs: device_profile_object = None with open(self.logs[-1]) as f: device_profile_object = json.load(f)['result']['contact'] device_profile = [html.h2('Device Information')] device_table = html.table() for key in device_profile_object: device_table.append( html.tr(html.td(key), html.td(device_profile_object[key]))) #device_profile.append(html.p("%s, %s"% (key, device_profile_object[key]))) device_profile.append(device_table) body_parts.extend(device_profile) if self.summary_results.has_errors: body_parts.append(html.h2("Errors During Run")) body_parts.append( self.make_errors_table(self.summary_results.errors)) body_parts.append(html.h2("Test Results")) body_parts.append(self.make_result_table()) if self.logs: ulbody = [] for log_path in self.logs: details_log = '' with open(log_path, 'r') as f: details_log = f.read() href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode( details_log) ulbody.append( html.li( html.a(os.path.basename(log_path), href=href, target='_blank'))) device_profile_object = None body_parts.append(html.h2("Details log information")) body_parts.append(html.ul(ulbody)) return html.body(body_parts)
def make_regression_table(self): return html.table(html.thead(html.tr( html.th("Parent Test", col='parent'), html.th("Subtest", col='subtest'), html.th("Expected", col='expected'), html.th("Result", col='result'), ), id='results-table-head'), html.tbody(*self.make_table_rows(), id='results-table-body'), id='results-table')
def pytest_html_results_summary(prefix, summary, postfix): postfix.extend([HTMLStyle.table( html.thead( html.tr([ HTMLStyle.th("Tests"), HTMLStyle.th("Success"), HTMLStyle.th("Failed"), HTMLStyle.th("XFail"), HTMLStyle.th("Error")] ), ), [html.tbody( html.tr([ HTMLStyle.td(k), HTMLStyle.td(v['passed']), HTMLStyle.td(v['failed']), HTMLStyle.td(v['xfailed']), HTMLStyle.td(v['error']), ]) ) for k, v in results.items()])])
def tabelize(value): try: rows = [] for key in value.keys(): rows.append(html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value)
def _extract_html(test, class_name, duration=0, text='', result='passed', debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ['skipped', 'failure', 'expected failure', 'error']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append(html.div( html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): try: if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content) links_html.append(html.a( name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') except: pass log = html.div(class_='log') for line in text.splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append(html.tr([ html.td(result.title(), class_='col-result'), html.td(cls_name, class_='col-class'), html.td(tc_name, class_='col-name'), html.td(tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=result.lower() + ' results-table-row'))
def __init__(self, outcome, report, logfile, config): # self.test_id = report.nodeid.encode("utf-8").decode("unicode_escape") self.test_id = report.nodeid if getattr(report, "when", "call") != "call": self.test_id = "::".join([report.nodeid, report.when]) self.time = getattr(report, "duration", 0.0) self.outcome = outcome self.additional_html = [] self.links_html = [] self.self_contained = config.getoption("self_contained_html") self.logfile = logfile self.config = config self.row_table = self.row_extra = None test_index = hasattr(report, "rerun") and report.rerun + 1 or 0 for extra_index, extra in enumerate(getattr(report, "extra", [])): self.append_extra_html(extra, extra_index, test_index) self.append_log_html(report, self.additional_html) cells = [ html.td(self.outcome, class_="col-result"), html.td(self.test_id, class_="col-name"), html.td(f"{self.time:.2f}", class_="col-duration"), html.td(self.links_html, class_="col-links"), ] self.config.hook.pytest_html_results_table_row(report=report, cells=cells) self.config.hook.pytest_html_results_table_html( report=report, data=self.additional_html) if len(cells) > 0: self.row_table = html.tr(cells) self.row_extra = html.tr( html.td(self.additional_html, class_="extra", colspan=len(cells)))
def _extract_html(test, class_name, duration=0, text="", result="passed", debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ["skipped", "failure", "expected failure", "error"]: if debug.get("screenshot"): screenshot = "data:image/png;base64,%s" % debug["screenshot"] additional_html.append(html.div(html.a(html.img(src=screenshot), href="#"), class_="screenshot")) for name, content in debug.items(): try: if "screenshot" in name: href = "#" else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = "data:text/plain;charset=utf-8;base64,%s" % base64.b64encode(content) links_html.append(html.a(name.title(), class_=name, href=href, target="_blank")) links_html.append(" ") except: pass log = html.div(class_="log") for line in text.splitlines(): separator = line.startswith(" " * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_="error")) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append( html.tr( [ html.td(result.title(), class_="col-result"), html.td(cls_name, class_="col-class"), html.td(tc_name, class_="col-name"), html.td(tc_time, class_="col-duration"), html.td(links_html, class_="col-links"), html.td(additional_html, class_="debug"), ], class_=result.lower() + " results-table-row", ) )
def tabelize(value): try: rows = [] for key in value.keys(): rows.append( html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value)
def generate_html(self): generated = datetime.utcnow() with open(os.path.join(base_path, "main.js")) as main_f: doc = html.html( self.head, html.body( html.script(raw(main_f.read())), html.p('Report generated on %s at %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'))), html.h2('Environment'), html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted(self.env.items()) if v], id='environment'), html.h2('Summary'), html.p('%i tests ran in %.1f seconds.' % (sum(self.test_count.itervalues()), (self.suite_times["end"] - self.suite_times["start"]) / 1000.), html.br(), html.span('%i passed' % self.test_count["PASS"], class_='pass'), ', ', html.span('%i skipped' % self.test_count["SKIP"], class_='skip'), ', ', html.span('%i failed' % self.test_count["UNEXPECTED_FAIL"], class_='fail'), ', ', html.span('%i errors' % self.test_count["UNEXPECTED_ERROR"], class_='error'), '.', html.br(), html.span('%i expected failures' % self.test_count["EXPECTED_FAIL"], class_='expected_fail'), ', ', html.span('%i unexpected passes' % self.test_count["UNEXPECTED_PASS"], class_='unexpected_pass'), '.'), html.h2('Results'), html.table([html.thead( html.tr([ html.th('Result', class_='sortable', col='result'), html.th('Test', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), html.th('Links')]), id='results-table-head'), html.tbody(self.result_rows, id='results-table-body')], id='results-table'))) return u"<!DOCTYPE html>\n" + doc.unicode(indent=2)
def make_regression_table(self): return html.table( html.thead( html.tr( html.th("Parent Test", col='parent'), html.th("Subtest", col='subtest'), html.th("Expected", col='expected'), html.th("Result", col='result'), ), id='results-table-head' ), html.tbody(*self.make_table_rows(), id='results-table-body'), id='results-table' )
def _appendrow(self, result, report): names = mangle_testnames(report.nodeid.split("::")) testclass = (names[:-1]) if self.prefix: testclass.insert(0, self.prefix) testclass = ".".join(testclass) testmethod = names[-1] time = getattr(report, 'duration', 0.0) additional_html = [] if not 'Passed' in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append( html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) if not os.path.exists(self.screenshot_path): os.makedirs(self.screenshot_path) self.append_screenshot(testmethod, log) additional_html.append(log) output = self._write_captured_output(report) info = output.split(" ") links_html = [] for i in range(0, len(info)): if ("http" in info[i] and "browserstack.com" in info[i]): links_html.append(html.a("link", href=info[i], target='_blank')) links_html.append(' ') self.test_logs.append( html.tr([ html.td(result, class_='col-result'), html.td(testclass, class_='col-class'), html.td(testmethod, class_='col-name'), html.td(round(time), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug') ], class_=result.lower() + ' results-table-row'))
def make_result_table(self): return html.table( html.thead( html.tr( html.th("Subsuite"), html.th("Subsuite Errors"), html.th("Test Regressions"), html.th("Details") ) ), html.tbody( self.make_table_rows(self.subsuite_results) ) )
def pytest_sessionfinish(self, session, exitstatus): self._make_report_dir() logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8') suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time numtests = self.passed + self.failed generated = datetime.datetime.now() doc = html.html( html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.link(rel='stylesheet', href='style.css'), html.script(src='jquery.js'), html.script(src='main.js')), html.body( html.p('Report generated on %s at %s ' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), )), html.div([html.p( html.span('%i tests' % numtests, class_='all clickable'), ' ran in %i seconds.' % suite_time_delta, html.br(), html.span('%i passed' % self.passed, class_='passed clickable'), ', ', html.span('%i skipped' % self.skipped, class_='skipped clickable'), ', ', html.span('%i failed' % self.failed, class_='failed clickable'), ', ', html.span('%i errors' % self.errors, class_='error clickable'), '.', html.br(), ), html.span('Hide all errors', class_='clickable hide_all_errors'), ', ', html.span('Show all errors', class_='clickable show_all_errors'), ], id='summary-wrapper'), html.div(id='summary-space'), html.table([ html.thead(html.tr([ html.th('Result', class_='sortable', col='result'), html.th('Class', class_='sortable', col='class'), html.th('Name', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), # html.th('Output')]), id='results-table-head'), html.th('Links')]), id='results-table-head'), html.tbody(*self.test_logs, id='results-table-body')], id='results-table'))) logfile.write( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' + doc.unicode( indent=2)) logfile.close() self.process_screenshot_files() self.process_debug_event_files() self.process_performance_files()
def __init__(self, outcome, report, logfile, config): self.test_id = report.nodeid if getattr(report, 'when', 'call') != 'call': self.test_id = '::'.join([report.nodeid, report.when]) self.time = getattr(report, 'duration', 0.0) self.outcome = outcome self.additional_html = [] self.links_html = [] self.self_contained = config.getoption('self_contained_html') self.logfile = logfile self.config = config self.row_table = self.row_extra = None test_index = hasattr(report, 'rerun') and report.rerun + 1 or 0 for extra_index, extra in enumerate(getattr(report, 'extra', [])): self.append_extra_html(extra, extra_index, test_index) self.append_log_html(report, self.additional_html) cells = [ html.td(self.outcome, class_='col-result'), html.td(self.test_id, class_='col-name'), html.td('{0:.2f}'.format(self.time), class_='col-duration'), html.td(self.links_html, class_='col-links')] self.config.hook.pytest_html_results_table_row( report=report, cells=cells) self.config.hook.pytest_html_results_table_html( report=report, data=self.additional_html) if len(cells) > 0: self.row_table = html.tr(cells) self.row_extra = html.tr(html.td(self.additional_html, class_='extra', colspan=len(cells)))
def _generate_s3_report(s3_data: dict): s3_link = s3_data['S3Link'] s3_data.pop('S3Link') file_results = [ html.p(item) for item in s3_data['FileResults'] if not item.endswith('/') ] s3_report = html.tr([ html.th(f'S3 results:', class_='s3-results'), html.th( *file_results, html.p(html.a(s3_link, href=s3_link)), ) ]) return s3_report
def make_result_table(self): return html.table( html.thead( html.tr( html.th("Subsuite", class_='sortable', col='subsuite'), html.th("Subsuite Errors"), html.th("Test Executions"), html.th("Details") ) ), html.tbody( self.make_table_rows(self.subsuite_results),id='results-table-body' ), id='results-table' )
def make_regression_table(self): return html.table( html.thead( html.tr( html.th("Parent Test"), html.th("Subtest"), html.th("Expected"), html.th("Result"), html.th("Message") ) ), html.tbody( *self.make_table_rows() ) )
def html_summary_table(self): cells = [ html.th(header, class_=header_class) for header, header_class in zip( COLUMN_HEADERS, COLUMN_HEADER_CLASSES) ] self.config.hook.pytest_aggreport_html_table_header(cells=cells) tbody = [ html.tr(cells, id='aggregate-report-header'), ] for case_report in self.case_reports.values(): tbody.append(case_report.html_table_row) html_report = html.table(html.tbody(tbody), id='aggregate-report-table') return html_report
def handle_dcmp(self, dcmp): self.div_container.append( html.h2('Diff between %s and %s' % (dcmp.left, dcmp.right))) if len(dcmp.left_only) == 0 and len(dcmp.right_only) == 0 and len( dcmp.diff_files) == 0: self.div_container.append(html.p('No Differences Found')) # handle left dir1 if len(dcmp.left_only) > 0: self.div_container.append(html.h3('Only in %s' % (dcmp.left, ))) ul_left = html.ul() for name in dcmp.left_only: ul_left.append(html.li(name)) self.div_container.append(ul_left) # handle right dir2 if len(dcmp.right_only) > 0: self.div_container.append(html.h3('Only in %s' % (dcmp.right, ))) ul_right = html.ul() for name in dcmp.right_only: ul_right.append(html.li(name)) self.div_container.append(ul_right) # handle diff between dir1 and dir2 for name in dcmp.diff_files: if self.is_binary_file(os.path.join(dcmp.left, name), 1024): self.div_container.append( html.table(html.thead( html.tr(html.th(os.path.join(dcmp.left, name)), html.th(os.path.join(dcmp.right, name)))), html.tbody( html.tr(html.td('Binary files differ'))), class_='table')) else: self.diff_file(os.path.join(dcmp.left, name), os.path.join(dcmp.right, name)) # handle sub-dirs for sub_dcmp in dcmp.subdirs.values(): self.handle_dcmp(sub_dcmp)
def _create_test_steps_tr(self, test_step_main_div, user_id, status_code, request_headers_main_div): test_steps_tr = html.tr(class_="steps_table_tr") test_steps_tr.append( html.td(test_step_main_div, class_="tr_step_name")) test_steps_tr.append( html.td(raw(user_id), class_="tr_step_user_id")) test_steps_tr.append( html.td(raw(status_code), class_="tr_step_status_code")) test_steps_tr.append( html.td(request_headers_main_div, class_="tr_step_request_headers")) return test_steps_tr
def make_table_rows(self, results): rv = [] for key in results.keys(): result = results[key]['results'] cells = [html.td(key, class_="col-subsuite")] if result.has_errors: cells.append( html.td( len(result.errors), class_="condition FAIL col-subsuite", )) else: cells.append(html.td("0", class_="condition PASS")) style = '' if result.has_fails or result.has_errors: style = 'background-color: darkblue;' if result.has_regressions: num_regressions = sum( len(item) for item in result.regressions.itervalues()) cells.append( html.td(num_regressions, class_="condition PASS", style=style)) else: cells.append(html.td("0", class_="condition PASS")) details_link = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode( results[key]['html_str']) ulbody = [ html.li( html.a("subsuite report", href=details_link, target='_blank')) ] files = results[key]['files'] for fname in files.keys(): href = '%s/%s' % (key, fname) #if key[-4:] == 'html' or key[-3:] == 'htm': # href = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(files[key]) #else: # href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(files[key]) ulbody.append( html.li(html.a(fname, href=href, target='_blank'))) cells.append(html.td(html.ul(ulbody), class_="details")) rv.append(html.tr(cells, class_='results-table-row')) return rv
def make_body(self): body_parts = [html.div( html.script(raw(pkg_resources.resource_string( rcname, os.path.sep.join(['resources', 'htmlreport', 'jquery.js']))), type='text/javascript'), html.script(raw(pkg_resources.resource_string( rcname, os.path.sep.join(['resources', 'htmlreport', 'main.js']))), type='text/javascript'), html.h1("FirefoxOS Certification Suite Report"), html.p("Run at %s" % self.time.strftime("%Y-%m-%d %H:%M:%S")) )] if self.logs: device_profile_object = None with open(self.logs[-1]) as f: device_profile_object = json.load(f)['result']['contact'] device_profile = [html.h2('Device Information')] device_table = html.table() for key in device_profile_object: device_table.append( html.tr( html.td(key), html.td(device_profile_object[key]) ) ) #device_profile.append(html.p("%s, %s"% (key, device_profile_object[key]))) device_profile.append(device_table) body_parts.extend(device_profile); if self.summary_results.has_errors: body_parts.append(html.h2("Errors During Run")) body_parts.append(self.make_errors_table(self.summary_results.errors)) body_parts.append(html.h2("Test Results")) body_parts.append(self.make_result_table()) if self.logs: ulbody = []; for log_path in self.logs: details_log = '' with open(log_path, 'r') as f: details_log = f.read() href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(details_log) ulbody.append(html.li(html.a(os.path.basename(log_path), href=href, target='_blank'))) device_profile_object = None body_parts.append(html.h2("Details log information")) body_parts.append(html.ul(ulbody)) return html.body(body_parts)
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] for key in [k for k in sorted(metadata.keys()) if metadata[k]]: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def _appendrow(self, result, report): names = mangle_testnames(report.nodeid.split("::")) testclass = (names[:-1]) if self.prefix: testclass.insert(0, self.prefix) testclass = ".".join(testclass) testmethod = names[-1] time = getattr(report, 'duration', 0.0) additional_html = [] if not 'Passed' in result: if report.longrepr: log = html.div(class_='log') for line in str(report.longrepr).splitlines(): line = line.decode('utf8') separator = line.startswith('_ ' * 10) if separator: log.append(line[:80]) else: exception = line.startswith("E ") if exception: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) if not os.path.exists(self.screenshot_path): os.makedirs(self.screenshot_path) self.append_screenshot(testmethod, log) additional_html.append(log) output = self._write_captured_output(report) info = output.split(" ") links_html = [] for i in range(0, len(info)): if ("http" in info[i] and "browserstack.com" in info[i]): links_html.append(html.a("link", href=info[i], target='_blank')) links_html.append(' ') self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(testclass, class_='col-class'), html.td(testmethod, class_='col-name'), html.td(round(time), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=result.lower() + ' results-table-row'))
def create_dir_html(path, href_prefix=''): h = html.html( html.head( html.title('directory listing of %s' % (path,)), style, ), ) body = html.body( html.h1('directory listing of %s' % (path,)), ) h.append(body) table = html.table() body.append(table) tbody = html.tbody() table.append(tbody) items = list(path.listdir()) items.sort(key=lambda p: p.basename) items.sort(key=lambda p: not p.check(dir=True)) for fpath in items: tr = html.tr() tbody.append(tr) td1 = html.td(fpath.check(dir=True) and 'D' or 'F', class_='type') tr.append(td1) href = fpath.basename if href_prefix: href = '%s%s' % (href_prefix, href) if fpath.check(dir=True): href += '/' td2 = html.td(html.a(fpath.basename, href=href), class_='name') tr.append(td2) td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(fpath.mtime())), class_='mtime') tr.append(td3) if fpath.check(dir=True): size = '' unit = '' else: size = fpath.size() unit = 'B' for u in ['kB', 'MB', 'GB', 'TB']: if size > 1024: size = round(size / 1024.0, 2) unit = u td4 = html.td('%s %s' % (size, unit), class_='size') tr.append(td4) return unicode(h)
def _appendrow(self, result, report): testclass = self.prefix + " " + self.current_test_info['package'] + self.current_test_info['class'] testmethod = self.current_test_info['name'] duration = getattr(report, 'duration', 0.0) additional_html = [] links_html = [] log = html.div(class_='log') if report.passed: log.append('Your tests are passing, but you are still curious. I like it :)') else: if hasattr(report, 'wasxfail'): self._append_xpass_section(log, report) if not report.skipped: self._append_crash_message_section(log, report) self._append_screenshot(testmethod, log) self._append_stacktrace_section(log, report) links_html.append(self._link_to_debug_event(testmethod, log)) output = self._append_captured_output(log, report) additional_html.append(log) links_html.append(self._link_to_browserstack_log(output)) self.test_logs.append(html.tr([ html.td(result, class_='col-result'), html.td(testclass, class_='col-class'), html.td(testmethod, class_='col-name'), html.td(round(duration), class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug')], class_=result.lower() + ' results-table-row'))
def make_errors_table(self, errors): rows = [] for error in errors: error_message = error.get("message", "") log = html.div(class_='log') for line in error_message.splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) rows.append(html.tr( html.td(error["level"], class_="log_%s" % error["level"]), html.td(log, class_='log') )) return html.table(rows, id_="errors")
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] keys = [k for k in metadata.keys()] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') elif isinstance(value, (list, tuple, set)): value = ', '.join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def _generate_environment(self, config): if not hasattr(config, '_metadata') or config._metadata is None: return [] metadata = config._metadata environment = [html.h2('Environment')] rows = [] keys = [k for k in metadata.keys() if metadata[k]] if not isinstance(metadata, OrderedDict): keys.sort() for key in keys: value = metadata[key] if isinstance(value, basestring) and value.startswith('http'): value = html.a(value, href=value, target='_blank') elif isinstance(value, (list, tuple, set)): value = ', '.join((str(i) for i in value)) rows.append(html.tr(html.td(key), html.td(value))) environment.append(html.table(rows, id='environment')) return environment
def make_errors_table(self, errors): rows = [] for error in errors: error_message = error.get("message", "") log = html.div(class_='log') for line in error_message.splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find( "exception") != -1: log.append( html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) rows.append( html.tr( html.td(error["level"], class_="log_%s" % error["level"]), html.td(log, class_='log'))) return html.table(rows, id_="errors")
def make_table_rows(self, results): rv = [] for key in results.keys(): result = results[key]['results'] cells = [html.td(key, class_="col-subsuite")] if result.has_errors: cells.append(html.td( len(result.errors), class_="condition FAIL col-subsuite", )) else: cells.append(html.td("0", class_="condition PASS")) style = '' if result.has_fails or result.has_errors: style = 'background-color: darkblue;' if result.has_regressions: num_regressions = sum(len(item) for item in result.regressions.itervalues()) cells.append(html.td(num_regressions, class_="condition PASS", style=style)) else: cells.append(html.td("0", class_="condition PASS")) details_link = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(results[key]['html_str']) ulbody = [html.li(html.a("subsuite report", href=details_link, target='_blank'))] files = results[key]['files'] for fname in files.keys(): href = '%s/%s' % (key, fname) #if key[-4:] == 'html' or key[-3:] == 'htm': # href = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(files[key]) #else: # href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(files[key]) ulbody.append(html.li(html.a(fname, href=href, target='_blank'))) cells.append(html.td(html.ul(ulbody), class_="details")) rv.append(html.tr(cells, class_='results-table-row')) return rv
def _generate_report(self, session): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time numtests = self.passed + self.failed + self.xpassed + self.xfailed generated = datetime.datetime.now() self.style_css = pkg_resources.resource_string( __name__, os.path.join("resources", "style.css")).decode("utf-8") if ANSI: ansi_css = [ "\n/******************************", " * ANSI2HTML STYLES", " ******************************/\n", ] ansi_css.extend([str(r) for r in style.get_styles()]) self.style_css += "\n".join(ansi_css) # <DF> Add user-provided CSS for path in self.config.getoption("css"): self.style_css += "\n/******************************" self.style_css += "\n * CUSTOM CSS" self.style_css += f"\n * {path}" self.style_css += "\n ******************************/\n\n" with open(path, "r") as f: self.style_css += f.read() css_href = "assets/style.css" html_css = html.link(href=css_href, rel="stylesheet", type="text/css") if self.self_contained: html_css = html.style(raw(self.style_css)) head = html.head( html.meta(charset="utf-8"), html.meta( content= "width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=no" ), html.title("Test Report"), html_css) class Outcome: def __init__(self, outcome, total=0, label=None, test_result=None, class_html=None): self.outcome = outcome self.label = label or outcome self.class_html = class_html or outcome self.total = total self.test_result = test_result or outcome self.generate_checkbox() self.generate_summary_item() def generate_checkbox(self): checkbox_kwargs = { "data-test-result": self.test_result.lower() } if self.total == 0: checkbox_kwargs["disabled"] = "true" self.checkbox = html.input( type="checkbox", checked="true", onChange="filter_table(this)", name="filter_checkbox", class_="filter", hidden="true", **checkbox_kwargs, ) def generate_summary_item(self): self.summary_item = html.span(f"{self.total} {self.label}", class_=self.class_html) outcomes = [ Outcome("passed", self.passed), Outcome("skipped", self.skipped), Outcome("failed", self.failed), Outcome("error", self.errors, label="errors"), Outcome("xfailed", self.xfailed, label="expected failures"), Outcome("xpassed", self.xpassed, label="unexpected passes"), ] if self.rerun is not None: outcomes.append(Outcome("rerun", self.rerun)) summary = [ html.p( f"{numtests} tests ran in {suite_time_delta:.2f} seconds. "), html.p( "(Un)check the boxes to filter the results.", class_="filter", hidden="true", ), ] for i, outcome in enumerate(outcomes, start=1): summary.append(outcome.checkbox) summary.append(outcome.summary_item) if i < len(outcomes): summary.append(", ") cells = [ html.th("Result", class_="sortable result initial-sort", col="result"), html.th("Test", class_="sortable", col="name"), html.th("Duration", class_="sortable numeric", col="duration"), html.th("Links"), ] session.config.hook.pytest_html_results_table_header(cells=cells) results = [ html.h2("Results"), html.table( [ html.thead( html.tr(cells), html.tr( [ html.th( "No results found. Try to check the filters", colspan=len(cells), ) ], id="not-found-message", hidden="true", ), id="results-table-head", ), self.test_logs, ], id="results-table", ), ] main_js = pkg_resources.resource_string( __name__, os.path.join("resources", "main.js")).decode("utf-8") report_title = self.logfile.split('/')[-4] + '测试报告如下:' body = html.body( html.script(raw(main_js)), # html.h1(os.path.basename(self.logfile)), html.h1(report_title), # 测试报告title html. p("Report generated on {} at {}.".format( generated.strftime("%Y-%m-%d"), generated.strftime("%H:%M:%S")), # html.a("pytest-html", href=__pypi_url__), # f" v{__version__}", ), onLoad="init()", ) body.extend(self._generate_environment(session.config)) summary_prefix, summary_postfix = [], [] session.config.hook.pytest_html_results_summary( prefix=summary_prefix, summary=summary, postfix=summary_postfix) body.extend([html.h2("Summary")] + summary_prefix + summary + summary_postfix) body.extend(results) doc = html.html(head, body) unicode_doc = "<!DOCTYPE html>\n{}".format(doc.unicode(indent=2)) # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode("utf-8", errors="xmlcharrefreplace") return unicode_doc.decode("utf-8")
def generate_html(self, results_list): tests = sum([results.testsRun for results in results_list]) failures = sum([len(results.failures) for results in results_list]) expected_failures = sum([len(results.expectedFailures) for results in results_list]) skips = sum([len(results.skipped) for results in results_list]) errors = sum([len(results.errors) for results in results_list]) passes = sum([results.passed for results in results_list]) unexpected_passes = sum([len(results.unexpectedSuccesses) for results in results_list]) test_time = self.elapsedtime.total_seconds() test_logs = [] def _extract_html(test, class_name, duration=0, text="", result="passed", debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ["skipped", "failure", "expected failure", "error"]: if debug.get("screenshot"): screenshot = "data:image/png;base64,%s" % debug["screenshot"] additional_html.append(html.div(html.a(html.img(src=screenshot), href="#"), class_="screenshot")) for name, content in debug.items(): try: if "screenshot" in name: href = "#" else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = "data:text/plain;charset=utf-8;base64,%s" % base64.b64encode(content) links_html.append(html.a(name.title(), class_=name, href=href, target="_blank")) links_html.append(" ") except: pass log = html.div(class_="log") for line in text.splitlines(): separator = line.startswith(" " * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower().find("exception") != -1: log.append(html.span(raw(cgi.escape(line)), class_="error")) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append( html.tr( [ html.td(result.title(), class_="col-result"), html.td(cls_name, class_="col-class"), html.td(tc_name, class_="col-name"), html.td(tc_time, class_="col-duration"), html.td(links_html, class_="col-links"), html.td(additional_html, class_="debug"), ], class_=result.lower() + " results-table-row", ) ) for results in results_list: for test in results.tests_passed: _extract_html(test.name, test.test_class) for result in results.skipped: _extract_html(result.name, result.test_class, text="\n".join(result.output), result="skipped") for result in results.failures: _extract_html( result.name, result.test_class, text="\n".join(result.output), result="failure", debug=result.debug ) for result in results.expectedFailures: _extract_html( result.name, result.test_class, text="\n".join(result.output), result="expected failure", debug=result.debug, ) for test in results.unexpectedSuccesses: _extract_html(test.name, test.test_class, result="unexpected pass") for result in results.errors: _extract_html( result.name, result.test_class, text="\n".join(result.output), result="error", debug=result.debug ) generated = datetime.datetime.now() doc = html.html( html.head( html.meta(charset="utf-8"), html.title("Test Report"), html.style( raw( pkg_resources.resource_string(__name__, os.path.sep.join(["resources", "report", "style.css"])) ), type="text/css", ), ), html.body( html.script( raw( pkg_resources.resource_string(__name__, os.path.sep.join(["resources", "report", "jquery.js"])) ), type="text/javascript", ), html.script( raw(pkg_resources.resource_string(__name__, os.path.sep.join(["resources", "report", "main.js"]))), type="text/javascript", ), html.p( "Report generated on %s at %s by %s %s" % (generated.strftime("%d-%b-%Y"), generated.strftime("%H:%M:%S"), __name__, __version__) ), html.h2("Summary"), html.p( "%i tests ran in %i seconds." % (tests, test_time), html.br(), html.span("%i passed" % passes, class_="passed"), ", ", html.span("%i skipped" % skips, class_="skipped"), ", ", html.span("%i failed" % failures, class_="failed"), ", ", html.span("%i errors" % errors, class_="error"), ".", html.br(), html.span("%i expected failures" % expected_failures, class_="expected failure"), ", ", html.span("%i unexpected passes" % unexpected_passes, class_="unexpected pass"), ".", ), html.h2("Results"), html.table( [ html.thead( html.tr( [ html.th("Result", class_="sortable", col="result"), html.th("Class", class_="sortable", col="class"), html.th("Test Name", class_="sortable", col="name"), html.th("Duration", class_="sortable numeric", col="duration"), html.th("Links"), ] ), id="results-table-head", ), html.tbody(test_logs, id="results-table-body"), ], id="results-table", ), ), ) return doc.unicode(indent=2)
def generate_html(self, results_list): tests = sum([results.testsRun for results in results_list]) failures = sum([len(results.failures) for results in results_list]) expected_failures = sum( [len(results.expectedFailures) for results in results_list]) skips = sum([len(results.skipped) for results in results_list]) errors = sum([len(results.errors) for results in results_list]) passes = sum([results.passed for results in results_list]) unexpected_passes = sum( [len(results.unexpectedSuccesses) for results in results_list]) test_time = self.elapsedtime.total_seconds() test_logs = [] def _extract_html(test, class_name, duration=0, text='', result='passed', debug=None): cls_name = class_name tc_name = unicode(test) tc_time = duration additional_html = [] debug = debug or {} links_html = [] if result in ['skipped', 'failure', 'expected failure', 'error']: if debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug[ 'screenshot'] additional_html.append( html.div(html.a(html.img(src=screenshot), href="#"), class_='screenshot')) for name, content in debug.items(): try: if 'screenshot' in name: href = '#' else: # use base64 to avoid that some browser (such as Firefox, Opera) # treats '#' as the start of another link if the data URL contains. # use 'charset=utf-8' to show special characters like Chinese. href = 'data:text/plain;charset=utf-8;base64,%s' % base64.b64encode( content) links_html.append( html.a(name.title(), class_=name, href=href, target='_blank')) links_html.append(' ') except: pass log = html.div(class_='log') for line in text.splitlines(): separator = line.startswith(' ' * 10) if separator: log.append(line[:80]) else: if line.lower().find("error") != -1 or line.lower( ).find("exception") != -1: log.append( html.span(raw(cgi.escape(line)), class_='error')) else: log.append(raw(cgi.escape(line))) log.append(html.br()) additional_html.append(log) test_logs.append( html.tr([ html.td(result.title(), class_='col-result'), html.td(cls_name, class_='col-class'), html.td(tc_name, class_='col-name'), html.td(tc_time, class_='col-duration'), html.td(links_html, class_='col-links'), html.td(additional_html, class_='debug') ], class_=result.lower() + ' results-table-row')) for results in results_list: for test in results.tests_passed: _extract_html(test.name, test.test_class) for result in results.skipped: _extract_html(result.name, result.test_class, text='\n'.join(result.output), result='skipped') for result in results.failures: _extract_html(result.name, result.test_class, text='\n'.join(result.output), result='failure', debug=result.debug) for result in results.expectedFailures: _extract_html(result.name, result.test_class, text='\n'.join(result.output), result='expected failure', debug=result.debug) for test in results.unexpectedSuccesses: _extract_html(test.name, test.test_class, result='unexpected pass') for result in results.errors: _extract_html(result.name, result.test_class, text='\n'.join(result.output), result='error', debug=result.debug) generated = datetime.datetime.now() doc = html.html( html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.style(raw( pkg_resources.resource_string( __name__, os.path.sep.join(['resources', 'report', 'style.css']))), type='text/css')), html.body( html.script(raw( pkg_resources.resource_string( __name__, os.path.sep.join(['resources', 'report', 'jquery.js']))), type='text/javascript'), html.script(raw( pkg_resources.resource_string( __name__, os.path.sep.join(['resources', 'report', 'main.js']))), type='text/javascript'), html.p( 'Report generated on %s at %s by %s %s' % (generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), __name__, __version__)), html.h2('Summary'), html.p( '%i tests ran in %i seconds.' % (tests, test_time), html.br(), html.span('%i passed' % passes, class_='passed'), ', ', html.span('%i skipped' % skips, class_='skipped'), ', ', html.span('%i failed' % failures, class_='failed'), ', ', html.span('%i errors' % errors, class_='error'), '.', html.br(), html.span('%i expected failures' % expected_failures, class_='expected failure'), ', ', html.span('%i unexpected passes' % unexpected_passes, class_='unexpected pass'), '.'), html.h2('Results'), html.table([ html.thead(html.tr([ html.th('Result', class_='sortable', col='result'), html.th('Class', class_='sortable', col='class'), html.th('Test Name', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), html.th('Links') ]), id='results-table-head'), html.tbody(test_logs, id='results-table-body') ], id='results-table'))) return doc.unicode(indent=2)