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 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.), 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 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 _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 html_summary_text(self): text = [ html.p('Test started at {} UTC and ended at {} UTC, ' 'following is the summary report: '.format( self.start_time_utc, self.end_time_utc)), ] return text
def _append_captured_output(self, log, report): # Use the output section from the "teardown" report - as it has all the previous sections (setup, call) as well test_name = self.current_test_info['name'] output = self._write_captured_output(self.current_test_reports[test_name]['teardown']) log.append(html.h3('Captured output')) stacktrace_p = html.p(class_='stacktrace') stacktrace_p.append(output) log.append(stacktrace_p) return output
def pytest_html_results_summary(prefix): """ pytest-html,自定义 Summary 部分。也可以用于注入一些报告样式。 :return: """ prefix.extend([html.p("所属部门: QA")]) prefix.extend([html.p("测试人员: xxxx")]) prefix.extend([ html.style(""" /* 自定义样式 */ body, #results-table { font-size: 15px; } /* */ """) ])
def make_body(self): body_parts = [html.div( html.h1("FirefoxOS Certification Suite Report"), html.p("Run at %s" % self.time.strftime("%Y-%m-%d %H:%M:%S")) )] 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(self.make_result_table()) return html.body(body_parts)
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 create_unknown_html(path): h = html.html( html.head( html.title('Can not display page'), style, ), html.body( html.p('The data URL (%s) does not contain Python code.' % (path,)) ), ) return h.unicode()
def _append_crash_message_section(log, report): try: message = report.longrepr.reprcrash.message log.append(html.h3('Crash Message')) crash_message_p = html.p(class_='crash_message') for line in message.splitlines(): crash_message_p.append(escape(line)) crash_message_p.append(html.br()) log.append(crash_message_p) except: return
def _append_xpass_section(log, report): log.append(html.h3('Expected failure')) xfail_p = html.p(class_='xfail') xfail_reason = report.wasxfail xfail_p.append("Reason: ") # Does xfail reason contain e.g. link to JIRA? urls = find_urls(xfail_reason) if len(urls) > 0: xfail_p.append(html.a(xfail_reason, href=urls[0], target='_blank')) else: xfail_p.append(xfail_reason) log.append(xfail_p)
def _generate_report(self): css_href = "assets/style.css" js_href = "https://cdn.dhtmlx.com/suite/edge/suite.css" html_css = html.link(href=css_href, rel="stylesheet", type="text/css") js_style = html.link(href=js_href, rel="stylesheet", type="text/css") head = html.head( html.meta(charset="utf-8"), html.title(self.TITLE), html.script(src='assets/index.js'), html.script(src='https://cdn.dhtmlx.com/suite/edge/suite.js'), html_css, js_style) body = html.body( html.h1(self.TITLE), html.p(f'Report generated at ' f'{datetime.today().strftime("%Y-%m-%d %H:%M:%S")}'), html.p(f'Tables processed: {self.tables_processed}'), html.h2("Results")) body.extend(self.data_results) doc = html.html(head, body) unicode_doc = f"<!DOCTYPE html>\n{doc.unicode(indent=2)}" unicode_doc = unicode_doc.encode("utf-8", errors="xmlcharrefreplace") return unicode_doc.decode("utf-8")
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 description_html(desc): if not desc: return '没有定义' desc_ = desc.strip() if ':param desc' in desc: desc_ = re.findall(r'(.*):param desc', desc, flags=re.RegexFlag.DOTALL)[0] desc_lines = [i.strip() for i in desc_.split('\n')] desc_html = html.html( html.head( html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body([html.p(line) for line in desc_lines])) return desc_html
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 _append_stacktrace_section(log, report): log.append(html.h3('Stacktrace')) stacktrace_p = html.p(class_='stacktrace') for line in str(report.longrepr).splitlines(): separator = line.startswith('_ ' * 10) if separator: stacktrace_p.append(line[:80]) else: exception = line.startswith("E ") if exception: stacktrace_p.append(html.span(raw(escape(line)), class_='error')) else: stacktrace_p.append(raw(escape(line))) stacktrace_p.append(html.br()) log.append(stacktrace_p)
def pytest_html_results_table_row(report, cells): """ Called after building results table row. """ try: test_steps = [ step for step in re.split('\n *', report.description) if len(step) > 0 ] html_test_steps = list(map(lambda step: html.p(step), test_steps)) test_file_path, test_class, test_name = re.search( '>(.*)<', str(cells[1])).groups()[0].split("::") cells[1] = html.td(test_name, class_='col-name') cells.insert(2, html.td(html_test_steps)) cells.insert(0, html.td(datetime.utcnow(), class_='col-time')) cells.pop() except Exception as e: pass
def _generate_body(self, results_tree): body = html.body(onload="init()") generated_time = datetime.datetime.strptime( results_tree["suite_info"]["generated"].split(".")[0], "%Y-%I-%dT%X", ) summary_div = [ html.div( html.div(results_tree["name"], class_="project-title"), html.div( html.p('Report generated on {0} at {1} by'.format( generated_time.strftime('%d-%b-%Y'), generated_time.strftime('%H:%M:%S')), html.a(' pytest-html', href=__pypi_url__), ' v{0}'.format(__version__), class_="generated-time"), class_="generated-info", ), self._generate_environment( results_tree["suite_info"]["environment"], ), self._generate_summary_count( results_tree["suite_info"]["numtests"], results_tree["summary"], results_tree["suite_info"]["run_time"], ), class_="project-test-results-summary", ) ] self.config.hook.pytest_html_results_summary(summary=summary_div) results_div = [ html.div( html.h2("Results"), html.div( html.button("expand all", id="expand-all-button"), html.button("collapse all", id="collapse-all-button"), class_="show-hide-buttons", ), html.div(class_="results-info"), class_="results-details", ) ] body.extend([ summary_div, results_div, ]) return body
def description_html(desc): """将用例中的描述转成HTML对象""" if desc is None: return "No case description" desc_ = "" for i in range(len(desc)): if i == 0: pass elif desc[i] == '\n': desc_ = desc_ + ";" else: desc_ = desc_ + desc[i] desc_lines = desc_.split(";") desc_html = html.html( html.head( html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body([html.p(line) for line in desc_lines])) return desc_html
def findlinks_view(context, request): title = "%s: all package links without root/pypi" % (context.stage.name) projectnames = set() for stage, names in context.stage.op_sro("list_projectnames_perstage"): if stage.ixconfig["type"] == "mirror": continue projectnames.update(names) all_links = [] basenames = set() for projectname in sorted(projectnames): for stage, res in context.stage.op_sro_check_pypi_whitelist( "get_releaselinks_perstage", projectname=projectname): if stage.ixconfig["type"] == "mirror": continue for link in res: if link.eggfragment: key = link.eggfragment else: key = link.basename if key not in basenames: basenames.add(key) all_links.append(link) links = [] for link in sorted(all_links, key=attrgetter('basename')): href = url_for_entrypath(request, link.entrypath) entry = link.entry if entry.eggfragment: href += "#egg=%s" % entry.eggfragment elif entry.md5: href += "#md5=%s" % entry.md5 links.extend([ "/".join(link.entrypath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n"]) if not links: links = [html.p('No releases.')] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", links)).unicode(indent=2))
def findlinks_view(context, request): title = "%s: all package links without root/pypi" % (context.stage.name) projects = set() for stage, names in context.stage.op_sro("list_projects_perstage"): if stage.ixconfig["type"] == "mirror": continue projects.update(names) all_links = [] basenames = set() for project in sorted(projects): for stage, res in context.stage.op_sro_check_mirror_whitelist( "get_releaselinks_perstage", project=project): if stage.ixconfig["type"] == "mirror": continue for link in res: if getattr(link, 'eggfragment', None): key = link.eggfragment else: key = link.basename if key not in basenames: basenames.add(key) all_links.append(link) links = [] for link in sorted(all_links, key=attrgetter('basename')): href = url_for_entrypath(request, link.entrypath) entry = link.entry if getattr(entry, 'eggfragment', None): href += "#egg=%s" % entry.eggfragment elif entry.hash_spec: href += "#%s" % entry.hash_spec links.extend([ "/".join(link.entrypath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n" ]) if not links: links = [html.p('No releases.')] return Response( html.html(html.head(html.title(title)), html.body(html.h1(title), "\n", links)).unicode(indent=2))
def pytest_html_results_summary(prefix, summary, postfix): prefix.extend([html.p("foo: bar")]) # @pytest.mark.hookwrapper # def pytest_runtest_makereport(item, call): # # timestamp = datetime.now().strftime('%H-%M-%S') # # pytest_html = item.config.pluginmanager.getplugin('html') # outcome = yield # report = outcome.get_result() # extra = getattr(report, 'extra', []) # if report.when == 'call': # # feature_request = item.funcargs['request'] # # current_date = date.today() # current_date_template = str(current_date).replace('-', '') # # driver = feature_request.getfixturevalue('browser') # path = f"./reports/{current_date_template}/scr{timestamp}.png" # driver.save_screenshot(path) # # root = os.getcwd().replace("\\", "/") # absolute_path_to_screenshot = root + path[1:] # # extra.append(pytest_html.extras.image(absolute_path_to_screenshot)) # always add url to report # extra.append(pytest_html.extras.url('http://www.example.com/')) # xfail = hasattr(report, 'wasxfail') # if (report.skipped and xfail) or (report.failed and not xfail): # # only add additional html on failure # extra.append(pytest_html.extras.image(absolute_path_to_screenshot)) # extra.append(pytest_html.extras.html('<div>Additional HTML</div>')) # report.extra = extra
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 pytest_html_results_summary(prefix, summary, postfix): prefix.extend( [html.p(html.b("Image: "), os.getenv("BFT_PYTEST_REPORT_IMAGE", ""))]) prefix.extend( [html.p(html.b("Board: "), os.getenv("BFT_PYTEST_REPORT_BOARDNAME"))]) prefix.extend([ html.p(html.b("Prov Mode: "), os.getenv("BFT_PYTEST_REPORT_PROV_MODE")) ]) seed = __get_randomly_seed() if seed: prefix.extend([html.p(html.b("Randomly Seed Value: "), str(seed))]) if os.getenv("BFT_PYTEST_BOOT_FAILED"): prefix.extend([html.p(html.b("--==** FAILED ON BOOT **==--"))]) elif os.getenv("BFT_PYTEST_REPORT_SKIP_BOOT"): prefix.extend([ html.p(html.b("BOOT Skipped: "), os.getenv("BFT_PYTEST_REPORT_SKIP_BOOT")) ])
def pytest_sessionfinish(self): if not os.path.exists(os.path.dirname(self.logfile)): os.makedirs(os.path.dirname(self.logfile)) logfile = 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 + self.xpassed + self.xfailed generated = datetime.datetime.now() style_css = pkg_resources.resource_string( __name__, os.path.join('resources', 'style.css')) if PY3: style_css = style_css.decode('utf-8') head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.style(raw(style_css))) summary = [html.h2('Summary'), html.p( '%i tests ran in %.2f seconds.' % (numtests, suite_time_delta), html.br(), html.span('%i passed' % self.passed, class_='passed'), ', ', html.span('%i skipped' % self.skipped, class_='skipped'), ', ', html.span('%i failed' % self.failed, class_='failed'), ', ', html.span('%i errors' % self.errors, class_='error'), '.', html.br(), html.span('%i expected failures' % self.xfailed, class_='skipped'), ', ', html.span('%i unexpected passes' % self.xpassed, class_='failed'), '.')] results = [html.h2('Results'), html.table([html.thead( html.tr([ html.th('Result', class_='sortable initial-sort result', 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.test_logs, id='results-table-body')], id='results-table')] main_js = pkg_resources.resource_string( __name__, os.path.join('resources', 'main.js')) if PY3: main_js = main_js.decode('utf-8') body = html.body( html.script(raw(main_js)), html.p('Report generated on %s at %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')))) environment = {} for e in self.environment: for k, v in e.items(): environment[k] = v if environment: body.append(html.h2('Environment')) body.append(html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted( environment.items()) if v], id='environment')) body.extend(summary) body.extend(results) doc = html.html(head, body) logfile.write('<!DOCTYPE html>') logfile.write(doc.unicode(indent=2)) logfile.close()
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() style_css = pkg_resources.resource_string( __name__, os.path.join('resources', 'style.css')) if PY3: style_css = style_css.decode('utf-8') head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.style(raw(style_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', **checkbox_kwargs) def generate_summary_item(self): self.summary_item = html.span('{0} {1}'. format(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'), Outcome('rerun', self.rerun)] summary = [html.h2('Summary'), html.p( '{0} tests ran in {1:.2f} seconds. '.format( numtests, suite_time_delta)), html.p('(Un)check the boxes to filter the results.')] for outcome in outcomes: summary.append(outcome.checkbox) summary.append(outcome.summary_item) summary.append(' ') results = [html.h2('Results'), html.table([html.thead( html.tr([ html.th('Result', class_='sortable initial-sort result', col='result'), html.th('Test', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), html.th('Links')]), html.tr([ html.th('No results found. Try to check the filters', colspan='5')], 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')) if PY3: main_js = main_js.decode('utf-8') body = html.body( html.script(raw(main_js)), html.p('Report generated on {0} at {1}'.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')))) if session.config._environment: environment = set(session.config._environment) body.append(html.h2('Environment')) body.append(html.table( [html.tr(html.td(e[0]), html.td(e[1])) for e in sorted( environment, key=lambda e: e[0]) if e[1]], id='environment')) body.extend(summary) body.extend(results) doc = html.html(head, body) unicode_doc = u'<!DOCTYPE html>\n{0}'.format(doc.unicode(indent=2)) if PY3: # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode('utf-8', errors='xmlcharrefreplace') unicode_doc = unicode_doc.decode('utf-8') return unicode_doc
def _generate_report(self, session): """ The method writes HTML report to a temporary logfile. """ 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() style_css = pkg_resources.resource_string( pytest_html_path, os.path.join('resources', 'style.css')) head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.style(raw(style_css))) summary = [html.h2('Summary'), html.p( '{0} tests ran in {1:.2f} seconds.'.format( numtests, suite_time_delta), html.br(), html.span('{0} passed'.format( self.passed), class_='passed'), ', ', html.span('{0} skipped'.format( self.skipped), class_='skipped'), ', ', html.span('{0} failed'.format( self.failed), class_='failed'), ', ', html.span('{0} errors'.format( self.errors), class_='error'), '.', html.br(), html.span('{0} expected failures'.format( self.xfailed), class_='skipped'), ', ', html.span('{0} unexpected passes'.format( self.xpassed), class_='failed'), '.')] results = [html.h2('Results'), html.table([html.thead( html.tr([ html.th('Result', class_='sortable initial-sort result', 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.test_logs, id='results-table-body')], id='results-table')] main_js = pkg_resources.resource_string( pytest_html_path, os.path.join('resources', 'main.js')) body = html.body( html.script(raw(main_js)), html.p('Report generated on {0} at {1}'.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')))) if session.config._environment: environment = set(session.config._environment) body.append(html.h2('Environment')) body.append(html.table( [html.tr(html.td(e[0]), html.td(e[1])) for e in sorted( environment, key=lambda e: e[0]) if e[1]], id='environment')) body.extend(summary) body.extend(results) doc = html.html(head, body) # A string which holds the complete report. report_content = ( "Test executed on commit " "[[https://www.github.com/tardis-sn/tardis/commit/{0}|{0}]]\n\n".format( tardis.__githash__ ) ) report_content += doc.unicode(indent=2) # Quick hack for preventing log to be placed in narrow left out space report_content = report_content.replace( u'class="log"', u'class="log" style="clear: both"' ) return report_content
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() css_path = Path(__file__).parent / "resources" / "style.css" self.style_css = css_path.read_text() if ansi_support(): ansi_css = [ "\n/******************************", " * ANSI2HTML STYLES", " ******************************/\n", ] ansi_css.extend( [str(r) for r in ansi_support().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" self.style_css += Path(path).read_text() 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)) session.config.hook.pytest_html_report_title(report=self) head = html.head(html.meta(charset="utf-8"), html.title(self.title), html_css) 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", col="duration"), html.th("Links", class_="sortable links", col="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_path = Path(__file__).parent / "resources" / "main.js" main_js = main_js_path.read_text() body = html.body( html.script(raw(main_js)), html.h1(self.title), html.p( "Report generated on {} at {} by ".format( generated.strftime("%d-%b-%Y"), 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_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() 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, label="通过"), Outcome("skipped", self.skipped, label="跳过"), Outcome("failed", self.failed, label="失败"), Outcome("error", self.errors, label="故障"), Outcome("xfailed", self.xfailed, label="预期的失败"), Outcome("xpassed", self.xpassed, label="未知的通过"), ] if self.rerun is not None: outcomes.append(Outcome("rerun", self.rerun, label="重跑")) summary = [ html.p( "(取消)勾选复选框, 以便筛选测试结果.", 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("测试用例", class_="sortable initial-sort", col="name"), html.th("运行时间", class_="sortable numeric", col="duration"), html.th("运行结果", class_="sortable result", col="result"), html.th("日志资源"), ] session.config.hook.pytest_html_results_table_header(cells=cells) results = [ html.table( [ html.thead( html.tr(cells), html.tr( [ html.th( "无测试结果, 请考虑更换其他测试结果筛选条件.", colspan=len(cells), ) ], id="not-found-message", hidden="true", ), id="results-table-head", ), self.test_logs, ], id="results-table", ), ] session.config.hook.pytest_html_report_title(report=self) self.style_css = pkg_resources.resource_string( __name__, os.path.join("resources", "style.css") ).decode("utf-8") main_js = pkg_resources.resource_string( __name__, os.path.join("resources", "main.js") ).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" icon_href = "assets/favicon.png" html_icon = html.link(href=icon_href, rel="shortcut icon") 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.title(self.title), html_icon, html_css ) body = html.body( html.script(raw(main_js)), onLoad="init()", ) overview = [] if hasattr(self, "tester"): overview.append(html.p(html.strong("测试人员:"), self.tester)) if hasattr(self, "department"): overview.append(html.p(html.strong("测试中心:"), self.department)) overview.append( html.p( html.strong("用例统计:"), f"合计 {numtests} 条用例, ", f"运行时间为: {suite_time_delta:.2f} 秒, ", "生成时间为: {} {}".format( generated.strftime("%Y-%m-%d"), generated.strftime("%H:%M:%S") ), ) ) if hasattr(self, "description"): overview.append(html.p(html.strong("测试描述:"), self.description)) overview_html = html.div(overview, id="overview") body.extend( [ html.h1(self.title), html.h3(html.a(self.company["name"], href=self.company["url"])), overview_html, ] ) 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_prefix + summary + summary_postfix) body.extend(results) # Mail Template MailResult.title = self.title MailResult.count = numtests MailResult.passed = self.passed MailResult.failed = self.failed MailResult.xfailed = self.xfailed MailResult.xpassed = self.xpassed MailResult.errors = self.errors MailResult.skipped = self.skipped 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 startSubParagraph(self): self._push(html.p(**{'class': 'sub'}))
def html_for_module(module): from py.xml import html out = file_for_module(module) ourlink = link_for_module('', module) head = [html.title(module.name)] body = [html.h1(module.name)] body.append(html.p('This module defines these names:')) listbody = [] defuses = {} for d in module.definitions: uses = [] for n in sorted(module.importers): N = module.system.modules[n] if N._imports[module.name].get(d) == True: uses.append(n) if not d.startswith('_'): if uses: listbody.append( html.li(html.a(d, href=link_for_name(ourlink, module, d)))) defuses[d] = uses else: listbody.append(html.li(d)) body.append(html.ul(listbody)) body.append(html.p('This module imports the following:')) listbody1 = [] for n in sorted(module._imports): if n in ('autopath', '__future__'): continue if n in module.system.modules: listbody2 = [ html.a(n, href=link_for_module(ourlink, module.system.modules[n])) ] else: listbody2 = [n] listbody3 = [] for o in sorted(module._imports[n]): if module._imports[n][o] == True: if n in module.system.modules: listbody3.append( html.li( html.a(o, href=link_for_name(ourlink, module.system.modules[n], o)))) else: listbody3.append(html.li(o)) if listbody3: listbody2.append(html.ul(listbody3)) listbody1.append(html.li(listbody2)) body.append(html.ul(listbody1)) body.append(html.p('This module is imported by the following:')) listbody1 = [] for n in module.importers: licontents = [ html.a(n, href=link_for_module(ourlink, module.system.modules[n])) ] contents = [] for o in sorted(module.system.modules[n]._imports[module.name]): contents.append( html.li(html.a(o, href=link_for_name(ourlink, module, o)))) if contents: licontents.append(html.ul(contents)) listbody1.append(html.li(licontents)) body.append(html.ul(listbody1)) out.write(html.html(head, body).unicode()) for d in defuses: out = file_for_name(module, d) ourlink = link_for_name('', module, d) head = [html.title(module.name + '.' + d)] body = [ html.h1([ html.a(module.name, href=link_for_module(ourlink, module)), '.' + d ]) ] contents = [] for n in defuses[d]: N = module.system.modules[n] contents.append( html.li(html.a(n, href=link_for_module(ourlink, N)))) body.append(html.p('This name is used in')) body.append(html.ul(contents)) out.write(html.html(head, body).unicode())
def _generate_summary_count(self, numtests, summary, run_time): summary_count = html.div( html.h2("Summary"), html.div( html.p( "{0} tests ran in {1:.2f} seconds.".format( numtests, run_time, ), ), html.p( "Toggle the buttons to filter the results.", class_="filter", ), html.div( html.button( html.div("Passes", class_="button-text"), html.div( summary["passed"], class_="summary-result-count passed", ), class_="count-toggle-button passed", title="Passes", ), html.button( html.div("Skips", class_="button-text"), html.div( summary["skipped"], class_="summary-result-count skipped", ), class_="count-toggle-button skipped", title="Skips", ), html.button( html.div("Failures", class_="button-text"), html.div( summary["failed"], class_="summary-result-count failed", ), class_="count-toggle-button failed", title="Failures", ), html.button( html.div("Errors", class_="button-text"), html.div( summary["error"], class_="summary-result-count error", ), class_="count-toggle-button error", title="Errors", ), html.button( html.div("Expected failures", class_="button-text"), html.div( summary["xfailed"], class_="summary-result-count xfailed", ), class_="count-toggle-button xfailed", title="Expected failures", ), html.button( html.div("Unexpected passes", class_="button-text"), html.div( summary["xpassed"], class_="summary-result-count xpassed", ), class_="count-toggle-button xpassed", title="Unexpected passes", ), class_="results-summary-numbers", ), class_="summary-info", ), class_="summary-details", ) return summary_count
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 stringToCellData(string, class_): return html.td([html.p(s) for s in string.split("\n")], class_=class_)
def pytest_html_results_summary(prefix, summary, postfix): # prefix.clear() # 清空summary中的内容 prefix.extend([html.p("所属部门: XX公司测试部")]) prefix.extend([html.p("测试执行人: 随风挥手")])
def pytest_sessionfinish(self, session, exitstatus, __multicall__): 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 + self.xpassed + self.xfailed server = self.config.option.sauce_labs_credentials_file and \ 'Sauce Labs' or 'http://%s:%s' % (self.config.option.host, self.config.option.port) browser = self.config.option.browser_name and \ self.config.option.browser_version and \ self.config.option.platform and \ '%s %s on %s' % (str(self.config.option.browser_name).title(), self.config.option.browser_version, str(self.config.option.platform).title()) or \ self.config.option.environment or \ self.config.option.browser generated = datetime.datetime.now() configuration = { 'Base URL': self.config.option.base_url, 'Build': self.config.option.build, 'Selenium API': self.config.option.api, 'Driver': self.config.option.driver, 'Firefox Path': self.config.option.firefox_path, 'Google Chrome Path': self.config.option.chrome_path, 'Selenium Server': server, 'Browser': browser, 'Timeout': self.config.option.webqatimeout, 'Capture Network Traffic': self.config.option.capture_network, 'Credentials': self.config.option.credentials_file, 'Sauce Labs Credentials': self.config.option.sauce_labs_credentials_file} import pytest_mozwebqa doc = html.html( html.head( html.title('Test Report'), html.style( 'body {font-family: Helvetica, Arial, sans-serif; font-size: 12px}\n', 'body * {box-sizing: -moz-border-box; box-sizing: -webkit-border-box; box-sizing: border-box}\n', 'a {color: #999}\n', 'h2 {font-size: 16px}\n', 'table {border: 1px solid #e6e6e6; color: #999; font-size: 12px; border-collapse: collapse}\n', '#configuration tr:nth-child(odd) {background-color: #f6f6f6}\n', '#results {width:100%}\n', 'th, td {padding: 5px; border: 1px solid #E6E6E6; text-align: left}\n', 'th {font-weight: bold}\n', 'tr.passed, tr.skipped, tr.xfailed, tr.error, tr.failed, tr.xpassed {color: inherit}\n' 'tr.passed + tr.additional {display: none}\n', '.passed {color: green}\n', '.skipped, .xfailed {color: orange}\n', '.error, .failed, .xpassed {color: red}\n', '.log:only-child {height: inherit}\n', raw('.log {background-color: #e6e6e6; border: 1px solid #e6e6e6; color: black; display: block; font-family: "Courier New", Courier, monospace; height: 230px; overflow-y: scroll; padding: 5px; white-space:pre-wrap}\n'), '.screenshot, .video {border: 1px solid #e6e6e6; float:right; height:240px; margin-left:5px; overflow:hidden; width:320px}\n', '.screenshot img {width: 320px}')), html.body( html.p('Report generated on %s at %s by pytest-mozwebqa %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), pytest_mozwebqa.__version__)), html.h2('Configuration'), html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted(configuration.items()) if v], id='configuration'), html.h2('Summary'), html.p( '%i tests ran in %i seconds.' % (numtests, suite_time_delta), html.br(), html.span('%i passed' % self.passed, class_='passed'), ', ', html.span('%i skipped' % self.skipped, class_='skipped'), ', ', html.span('%i failed' % self.failed, class_='failed'), ', ', html.span('%i errors' % self.errors, class_='error'), '.', html.br(), html.span('%i expected failures' % self.xfailed, class_='skipped'), ', ', html.span('%i unexpected passes' % self.xpassed, class_='failed'), '.'), html.h2('Results'), html.table( html.tr(html.th('Result'), html.th('Class'), html.th('Name'), html.th('Duration'), html.th('Links')), *self.test_logs, id='results'))) logfile.write(doc.unicode(indent=2)) logfile.close()
from py.xml import html paras = "First Para", "Second para" doc = html.html( html.head( html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) print(unicode(doc).encode('latin1'))
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')) if PY3: self.style_css = self.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') or []: self.style_css += '\n/******************************' self.style_css += '\n * CUSTOM CSS' self.style_css += '\n * {}'.format(path) self.style_css += '\n ******************************/\n\n' with open(path, 'r') as f: self.style_css += f.read() css_href = '{0}/{1}'.format('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.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('{0} {1}'. format(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( '{0} tests ran in {1:.2f} seconds. '.format( numtests, suite_time_delta)), 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')) if PY3: main_js = main_js.decode('utf-8') body = html.body( html.script(raw(main_js)), html.h1(os.path.basename(session.config.option.htmlpath)), html.p('Report generated on {0} at {1} by'.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')), html.a(' pytest-html', href=__pypi_url__), ' v{0}'.format(__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 = u'<!DOCTYPE html>\n{0}'.format(doc.unicode(indent=2)) if PY3: # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode('utf-8', errors='xmlcharrefreplace') unicode_doc = unicode_doc.decode('utf-8') return unicode_doc
def startParagraph(self): self._push(html.p())
def pytest_sessionfinish(self, session, exitstatus, __multicall__): 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 + self.xpassed + self.xfailed server = self.config.option.sauce_labs_credentials_file and \ 'Sauce Labs' or 'http://%s:%s' % (self.config.option.host, self.config.option.port) browser = self.config.option.browser_name and \ self.config.option.browser_version and \ self.config.option.platform and \ '%s %s on %s' % (str(self.config.option.browser_name).title(), self.config.option.browser_version, str(self.config.option.platform).title()) or \ self.config.option.environment or \ self.config.option.browser generated = datetime.datetime.now() configuration = { 'Base URL': self.config.option.base_url, 'Build': self.config.option.build, 'Selenium API': self.config.option.api, 'Driver': self.config.option.driver, 'Firefox Path': self.config.option.firefox_path, 'Google Chrome Path': self.config.option.chrome_path, 'Selenium Server': server, 'Browser': browser, 'Timeout': self.config.option.webqatimeout, 'Capture Network Traffic': self.config.option.capture_network, 'Credentials': self.config.option.credentials_file, 'Sauce Labs Credentials': self.config.option.sauce_labs_credentials_file} import pytest_mozwebqa 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 by pytest-mozwebqa %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), pytest_mozwebqa.__version__)), html.h2('Configuration'), html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted(configuration.items()) if v], id='configuration'), html.h2('Summary'), html.p( '%i tests ran in %i seconds.' % (numtests, suite_time_delta), html.br(), html.span('%i passed' % self.passed, class_='passed'), ', ', html.span('%i skipped' % self.skipped, class_='skipped'), ', ', html.span('%i failed' % self.failed, class_='failed'), ', ', html.span('%i errors' % self.errors, class_='error'), '.', html.br(), html.span('%i expected failures' % self.xfailed, class_='skipped'), ', ', html.span('%i unexpected passes' % self.xpassed, class_='failed'), '.'), 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('Name', class_='sortable', col='name'), html.th('Duration', class_='sortable numeric', col='duration'), 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()
def pytest_sessionfinish(self, session, exitstatus, __multicall__): 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 to BrowserStack') ]), 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()
def pytest_sessionfinish(self, session): if not os.path.exists(os.path.dirname(self.logfile)): os.makedirs(os.path.dirname(self.logfile)) logfile = 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 + self.xpassed + self.xfailed generated = datetime.datetime.now() style_css = pkg_resources.resource_string( __name__, os.path.join('resources', 'style.css')) if PY3: style_css = style_css.decode('utf-8') head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.style(raw(style_css))) summary = [html.h2('Summary'), html.p( '{0} tests ran in {1:.2f} seconds.'.format( numtests, suite_time_delta), html.br(), html.span('{0} passed'.format( self.passed), class_='passed'), ', ', html.span('{0} skipped'.format( self.skipped), class_='skipped'), ', ', html.span('{0} failed'.format( self.failed), class_='failed'), ', ', html.span('{0} errors'.format( self.errors), class_='error'), '.', html.br(), html.span('{0} expected failures'.format( self.xfailed), class_='skipped'), ', ', html.span('{0} unexpected passes'.format( self.xpassed), class_='failed'), '.')] results = [html.h2('Results'), html.table([html.thead( html.tr([ html.th('Result', class_='sortable initial-sort result', 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.test_logs, id='results-table-body')], id='results-table')] main_js = pkg_resources.resource_string( __name__, os.path.join('resources', 'main.js')) if PY3: main_js = main_js.decode('utf-8') body = html.body( html.script(raw(main_js)), html.p('Report generated on {0} at {1}'.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')))) if session.config._environment: environment = set(session.config._environment) body.append(html.h2('Environment')) body.append(html.table( [html.tr(html.td(e[0]), html.td(e[1])) for e in sorted( environment, key=lambda e: e[0]) if e[1]], id='environment')) body.extend(summary) body.extend(results) doc = html.html(head, body) logfile.write('<!DOCTYPE html>') unicode_doc = doc.unicode(indent=2) if PY3: # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode('utf-8', errors='xmlcharrefreplace') unicode_doc = unicode_doc.decode('utf-8') logfile.write(unicode_doc) logfile.close()
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): def failed_count(results): count = len(results.failures) if hasattr(results, 'unexpectedSuccesses'): count += len(results.unexpectedSuccesses) return count tests = sum([results.testsRun for results in results_list]) failures = sum([failed_count(results) for results in results_list]) skips = sum([len(results.skipped) + len(results.expectedFailures) for results in results_list]) errors = sum([len(results.errors) for results in results_list]) passes = 0 test_time = self.elapsedtime.total_seconds() test_logs = [] def _extract_html(test, text='', result='passed', debug=None): cls_name = test.__class__.__name__ tc_name = unicode(test).split()[0] tc_time = str(test.duration) additional_html = [] links_html = [] if result in ['failure', 'error', 'skipped']: if debug and debug.get('screenshot'): screenshot = 'data:image/png;base64,%s' % debug['screenshot'] additional_html.append( html.div( html.a(html.img(src=screenshot), href=screenshot), class_='screenshot')) for name, content in debug.items(): try: if 'screenshot' in name: links_html.append(html.a(name, href='data:image/png;base64,%s' % content.encode('us-ascii'))) 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. links_html.append(html.a(name, href='data:text/plain;charset=utf-8;base64,%s' % base64.b64encode(content))) links_html.append(' ') except: pass log = html.div(class_=result) 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, 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) passes = passes + 1 for result in results.failures: _extract_html(result[0], text=result[1], result='failure', debug=result[2]) for result in results.errors: _extract_html(result[0], text=result[1], result='error', debug=result[2]) jquery_src = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'jquery.js')) main_src = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'main.js')) style_src = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'style.css')) generated = datetime.datetime.now() doc = html.html( html.head( html.meta(charset='utf-8'), html.title('Test Report'), html.link(rel='stylesheet', href=style_src), html.script(src=jquery_src), html.script(src=main_src)), html.body( html.p('Report generated on %s at %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'))), html.table( 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 failed' % failures, class_='failed'), ', ', html.span('%i skipped' % skips, class_='skipped'), ', ', html.span('%i error' % errors, class_='error'), html.br()), 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_report(self, session): suite_stop_time = time.time() suite_time_delta = suite_stop_time - self.suite_start_time test_duration = '%.4f' %(suite_time_delta) numtests = self.passed + self.failed + self.xpassed + self.xfailed generated = datetime.datetime.now() jkbuildid=session.config.getoption("--jkbuildid") jkjobname=session.config.getoption("--jkjobname") if jkbuildid!=-1 and jkjobname: #print('update test collection to mysql, jobname: {}, buildid: {}'.format(jkjobname,jkbuildid)) try: from localplugins.mysql_opr import query_pymysql fpath=os.path.join(BASE_DIR,'localplugins','resources', 'mysql_conn.json') #print('fpath :',fpath) f=open(fpath, 'r', encoding='utf-8') dbinfo = json.loads(f.read()) sql=''' UPDATE uitest_collect SET fail_total={},pass_total={},skip_total={},error_total={},run_total={},duration='{}' WHERE jk_jobname='{}' AND jk_buildid='{}' '''.format(self.failed,self.passed,self.skipped,self.errors,numtests,test_duration,jkjobname,jkbuildid) #print('update uitest_collect: ',sql) query_pymysql(dbinfo['host'],dbinfo['user'],dbinfo['password'],dbinfo['port'],'qateam',sql) #print('.......update test collection to mysql <uitest_collect>......',time.strftime('%Y-%m-%d %H:%M:%S')) except Exception as e: print('[Exception<updating to uitest_collect>]',end='') #print('Exception when updating test collection to mysql: ',e) self.style_css = pkg_resources.resource_string( __name__, os.path.join('resources', 'style.css')) #print() #print('sytle_css path: ',os.path.join('resources', 'style.css')) if PY3: self.style_css = self.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') or []: self.style_css += '\n/******************************' self.style_css += '\n * CUSTOM CSS' self.style_css += '\n * {}'.format(path) self.style_css += '\n ******************************/\n\n' with open(path, 'r') as f: self.style_css += f.read() css_href = '{0}/{1}'.format('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.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('{0} {1}'. format(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')] ''' outcomes = [Outcome('passed', self.passed, label='成功'), Outcome('skipped', self.skipped, label='过滤掉'), Outcome('failed', self.failed, label='失败'), Outcome('error', self.errors, label='报错'), #Outcome('xfailed', self.xfailed,label='预期为失败'), #Outcome('xpassed', self.xpassed,label='预期为成功') ] if self.rerun is not None: outcomes.append(Outcome('rerun', self.rerun,label='再次执行')) ''' summary = [html.p( '{0} tests ran in {1:.2f} seconds. '.format( numtests, suite_time_delta)), html.p('(Un)check the boxes to filter the results.', class_='filter', hidden='true')] ''' summary_thead = [ html.th('失败'), html.th('总共'), html.th('成功'), html.th('过滤'), html.th('报错')] summary_tbody = [ html.td(self.failed,class_='red'), html.td(numtests), html.td(self.passed), html.td(self.skipped), html.td(self.errors,style='color:red;')] # summary_table = [ # html.table([ # html.thead( # html.tr(summary_thead), # id='results-table-head' # ), # html.tbody(html.tr(summary_tbody)) # ], # class_='table-50') # ] summary = [ html.p('总共 {0} 个用例,总耗时: {1:.2f} 秒. '.format( numtests, suite_time_delta)), html.table([ html.thead( html.tr(summary_thead), id='results-summary' ), html.tbody(html.tr(summary_tbody)) ], class_='table-350') ] ''' summary = [ html.p('总共 {0} 个用例,总耗时: {1:.2f} 秒. '.format( numtests, suite_time_delta)), html.table([ html.thead( html.tr(summary_thead), id='results-summary' ), html.tbody(html.tr(summary_tbody)) ], class_='table-50'), html.p('勾选/取消勾选 复选框来过滤测试结果.', 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') ] ''' cells = [ html.th('用例状态', class_='sortable result initial-sort', col='result'), html.th('用例功能描述', col='description'), html.th('测试用例', class_='sortable', col='name'), html.th('运行耗时', class_='sortable numeric', col='duration') #,html.th('链接') ] 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')] ''' results = [ html.h2('测试结果'), html.table([html.thead( html.tr(cells), html.tr([html.th('没有用例,请检查过滤条件',colspan=len(cells))], id='not-found-message', hidden='true'), id='results-table-head'), self.test_logs ], id='results-table',class_='table') ] #print('self.test_logs: ',self.test_logs) main_js = pkg_resources.resource_string( __name__, os.path.join('resources', 'main.js')) if PY3: main_js = main_js.decode('utf-8') '''***********************************gql*************************************** html.h1(os.path.basename(session.config.option.htmlpath)), html.p('Report generated on {0} at {1} by '.format( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S')), html.a('pytest-html', href=__pypi_url__), ' v{0}'.format(__version__)), # html 标题 ''' body = html.body( html.script(raw(main_js)), #html.h1(os.path.basename(session.config.option.htmlpath)), html.h1(self.htmlhead), html.p('测试报告运行于: {0} {1}'.format( generated.strftime('%Y-%m-%d'), generated.strftime('%H:%M:%S')) #,html.a('pytest-html', href='http://www.baidu.com/'),' v{0}'.format('2.11') ), onLoad='init()') '''***********************************gql*************************************** body.extend(self._generate_environment(session.config)) ''' #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) '''***********************************gql*************************************** body.extend([html.h2('Summary')] + summary_prefix + summary + summary_postfix) ''' #print('html-body-extend--summary: ',summary) body.extend(summary) body.extend(results) doc = html.html(head, body) unicode_doc = u'<!DOCTYPE html>\n{0}'.format(doc.unicode(indent=2)) if PY3: # Fix encoding issues, e.g. with surrogates unicode_doc = unicode_doc.encode('utf-8', errors='xmlcharrefreplace') unicode_doc = unicode_doc.decode('utf-8') return unicode_doc
def html_for_module(module): from py.xml import html out = file_for_module(module) ourlink = link_for_module('', module) head = [html.title(module.name)] body = [html.h1(module.name)] body.append(html.p('This module defines these names:')) listbody = [] defuses = {} for d in module.definitions: uses = [] for n in sorted(module.importers): N = module.system.modules[n] if N._imports[module.name].get(d) == True: uses.append(n) if not d.startswith('_'): if uses: listbody.append(html.li( html.a(d, href=link_for_name(ourlink, module, d)))) defuses[d] = uses else: listbody.append(html.li(d)) body.append(html.ul(listbody)) body.append(html.p('This module imports the following:')) listbody1 = [] for n in sorted(module._imports): if n in ('autopath', '__future__'): continue if n in module.system.modules: listbody2 = [html.a( n, href=link_for_module(ourlink, module.system.modules[n]))] else: listbody2 = [n] listbody3 = [] for o in sorted(module._imports[n]): if module._imports[n][o] == True: if n in module.system.modules: listbody3.append( html.li(html.a( o, href=link_for_name(ourlink, module.system.modules[n], o)))) else: listbody3.append(html.li(o)) if listbody3: listbody2.append(html.ul(listbody3)) listbody1.append(html.li(listbody2)) body.append(html.ul(listbody1)) body.append(html.p('This module is imported by the following:')) listbody1 = [] for n in module.importers: licontents = [html.a(n, href=link_for_module(ourlink, module.system.modules[n]))] contents = [] for o in sorted(module.system.modules[n]._imports[module.name]): contents.append(html.li(html.a(o, href=link_for_name(ourlink, module, o)))) if contents: licontents.append(html.ul(contents)) listbody1.append(html.li(licontents)) body.append(html.ul(listbody1)) out.write(html.html(head, body).unicode()) for d in defuses: out = file_for_name(module, d) ourlink = link_for_name('', module, d) head = [html.title(module.name + '.' + d)] body = [html.h1([html.a(module.name, href=link_for_module(ourlink, module)), '.' + d])] contents = [] for n in defuses[d]: N = module.system.modules[n] contents.append(html.li(html.a(n, href=link_for_module(ourlink, N)))) body.append(html.p('This name is used in')) body.append(html.ul(contents)) out.write(html.html(head, body).unicode())
html.p( 'Report generated on %s at %s by ASM %s' % (generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), 'v0.0.1'), html.h2('Configuration'), html.table([ html.tr(html.td(k), html.td(v)) for k, v in sorted(configuration.items()) if v ], id='configuration'), html.h2('Summary'), html.p( '%i tests ran in %i seconds.' % (numtests, suite_time_delta), #'''numtests''' '''suite_time_delta''' html.br(), html.span('%i passed' % passed, class_='passed'), ', ', #'self.passed' html.span('%i skipped' % skipped, class_='skipped'), ', ', #'self.skipped' html.span('%i failed' % failed, class_='failed'), ', ', #'self.failed' html.span('%i errors' % errors, class_='error'), '.', #'self.errors' html.br()), #html.span('%i expected failures' % 0, class_='skipped'), ', ', #'self.xfailed' #html.span('%i unexpected passes' % 0, class_='failed'), '.'), #'self.xpassed' 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('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'))))
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 = \ """ body { font-family: Helvetica, Arial, sans-serif; font-size: 12px; /* do not increase min-width as some may use split screens */ min-width: 800px; color: #999; } h1 { font-size: 24px; color: black; } h2 { font-size: 16px; color: black; } p { color: black; } a { color: #999; } table { border-collapse: collapse; } /****************************** * SUMMARY INFORMATION ******************************/ #environment td { padding: 5px; border: 1px solid #E6E6E6; } #environment tr:nth-child(odd) { background-color: #f6f6f6; } /****************************** * TEST RESULT COLORS ******************************/ span.passed, .passed .col-result { color: green; } span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result { color: orange; } span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result { color: red; } /****************************** * RESULTS TABLE * * 1. Table Layout * 2. Extra * 3. Sorting items * ******************************/ /*------------------ * 1. Table Layout *------------------*/ #results-table { border: 1px solid #e6e6e6; color: #999; font-size: 12px; width: 100% } #results-table th, #results-table td { padding: 5px; border: 1px solid #E6E6E6; text-align: left } #results-table th { font-weight: bold } /*------------------ * 2. Extra *------------------*/ .log:only-child { height: inherit } .log { background-color: #e6e6e6; border: 1px solid #e6e6e6; color: black; display: block; font-family: "Courier New", Courier, monospace; height: 230px; overflow-y: scroll; padding: 5px; white-space: pre-wrap } div.image { border: 1px solid #e6e6e6; float: right; height: 240px; margin-left: 5px; overflow: hidden; width: 320px } div.image img { width: 320px } div.video { border: 1px solid #e6e6e6; float: right; height: 240px; margin-left: 5px; overflow: hidden; width: 320px } div.video video { overflow: hidden; width: 320px; height: 240px; } .collapsed { display: none; } .expander::after { content: " (show details)"; color: #BBB; font-style: italic; cursor: pointer; } .collapser::after { content: " (hide details)"; color: #BBB; font-style: italic; cursor: pointer; } /*------------------ * 3. Sorting items *------------------*/ .sortable { cursor: pointer; } .sort-icon { font-size: 0px; float: left; margin-right: 5px; margin-top: 5px; /*triangle*/ width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; } .inactive .sort-icon { /*finish triangle*/ border-top: 8px solid #E6E6E6; } .asc.active .sort-icon { /*finish triangle*/ border-bottom: 8px solid #999; } .desc.active .sort-icon { /*finish triangle*/ border-top: 8px solid #999; } """ 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.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 = \ """ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ function toArray(iter) { if (iter === null) { return null; } return Array.prototype.slice.call(iter); } function find(selector, elem) { if (!elem) { elem = document; } return elem.querySelector(selector); } function find_all(selector, elem) { if (!elem) { elem = document; } return toArray(elem.querySelectorAll(selector)); } function sort_column(elem) { toggle_sort_states(elem); var colIndex = toArray(elem.parentNode.childNodes).indexOf(elem); var key; if (elem.classList.contains('numeric')) { key = key_num; } else if (elem.classList.contains('result')) { key = key_result; } else { key = key_alpha; } sort_table(elem, key(colIndex)); } function show_all_extras() { find_all('.col-result').forEach(show_extras); } function hide_all_extras() { find_all('.col-result').forEach(hide_extras); } function show_extras(colresult_elem) { var extras = colresult_elem.parentNode.nextElementSibling; var expandcollapse = colresult_elem.firstElementChild; extras.classList.remove("collapsed"); expandcollapse.classList.remove("expander"); expandcollapse.classList.add("collapser"); } function hide_extras(colresult_elem) { var extras = colresult_elem.parentNode.nextElementSibling; var expandcollapse = colresult_elem.firstElementChild; extras.classList.add("collapsed"); expandcollapse.classList.remove("collapser"); expandcollapse.classList.add("expander"); } function show_filters() { var filter_items = document.getElementsByClassName('filter'); for (var i = 0; i < filter_items.length; i++) filter_items[i].hidden = false; } function add_collapse() { // Add links for show/hide all var resulttable = find('table#results-table'); var showhideall = document.createElement("p"); showhideall.innerHTML = '<a href="javascript:show_all_extras()">Show all details</a> / ' + '<a href="javascript:hide_all_extras()">Hide all details</a>'; resulttable.parentElement.insertBefore(showhideall, resulttable); // Add show/hide link to each result find_all('.col-result').forEach(function(elem) { var collapsed = get_query_parameter('collapsed') || 'Passed'; var extras = elem.parentNode.nextElementSibling; var expandcollapse = document.createElement("span"); if (extras.classList.contains("collapsed")) { expandcollapse.classList.add("expander") } else if (collapsed.includes(elem.innerHTML)) { extras.classList.add("collapsed"); expandcollapse.classList.add("expander"); } else { expandcollapse.classList.add("collapser"); } elem.appendChild(expandcollapse); elem.addEventListener("click", function(event) { if (event.currentTarget.parentNode.nextElementSibling.classList.contains("collapsed")) { show_extras(event.currentTarget); } else { hide_extras(event.currentTarget); } }); }) } function get_query_parameter(name) { var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); } function init () { reset_sort_headers(); add_collapse(); show_filters(); sort_column(find('.initial-sort')); find_all('.sortable').forEach(function(elem) { elem.addEventListener("click", function(event) { sort_column(elem); }, false) }); }; function sort_table(clicked, key_func) { var rows = find_all('.results-table-row'); var reversed = !clicked.classList.contains('asc'); var sorted_rows = sort(rows, key_func, reversed); /* Whole table is removed here because browsers acts much slower * when appending existing elements. */ var thead = document.getElementById("results-table-head"); document.getElementById('results-table').remove(); var parent = document.createElement("table"); parent.id = "results-table"; parent.appendChild(thead); sorted_rows.forEach(function(elem) { parent.appendChild(elem); }); document.getElementsByTagName("BODY")[0].appendChild(parent); } function sort(items, key_func, reversed) { var sort_array = items.map(function(item, i) { return [key_func(item), i]; }); sort_array.sort(function(a, b) { var key_a = a[0]; var key_b = b[0]; if (key_a == key_b) return 0; if (reversed) { return (key_a < key_b ? 1 : -1); } else { return (key_a > key_b ? 1 : -1); } }); return sort_array.map(function(item) { var index = item[1]; return items[index]; }); } function key_alpha(col_index) { return function(elem) { return elem.childNodes[1].childNodes[col_index].firstChild.data.toLowerCase(); }; } function key_num(col_index) { return function(elem) { return parseFloat(elem.childNodes[1].childNodes[col_index].firstChild.data); }; } function key_result(col_index) { return function(elem) { var strings = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed', 'Skipped', 'Passed']; return strings.indexOf(elem.childNodes[1].childNodes[col_index].firstChild.data); }; } function reset_sort_headers() { find_all('.sort-icon').forEach(function(elem) { elem.parentNode.removeChild(elem); }); find_all('.sortable').forEach(function(elem) { var icon = document.createElement("div"); icon.className = "sort-icon"; icon.textContent = "vvv"; elem.insertBefore(icon, elem.firstChild); elem.classList.remove("desc", "active"); elem.classList.add("asc", "inactive"); }); } function toggle_sort_states(elem) { //if active, toggle between asc and desc if (elem.classList.contains('active')) { elem.classList.toggle('asc'); elem.classList.toggle('desc'); } //if inactive, reset all other functions and add ascending active if (elem.classList.contains('inactive')) { reset_sort_headers(); elem.classList.remove('inactive'); elem.classList.add('active'); } } function is_all_rows_hidden(value) { return value.hidden == false; } function filter_table(elem) { var outcome_att = "data-test-result"; var outcome = elem.getAttribute(outcome_att); class_outcome = outcome + " results-table-row"; var outcome_rows = document.getElementsByClassName(class_outcome); for(var i = 0; i < outcome_rows.length; i++){ outcome_rows[i].hidden = !elem.checked; } var rows = find_all('.results-table-row').filter(is_all_rows_hidden); var all_rows_hidden = rows.length == 0 ? true : false; var not_found_message = document.getElementById("not-found-message"); not_found_message.hidden = !all_rows_hidden; } """ session.config.hook.pytest_html_report_title(report=self) body = html.body( html.script(raw(main_js)), html.h1(self.title), html.p( "Report generated on {} at {} by ".format( generated.strftime("%d-%b-%Y"), 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")
from py.xml import html paras = "First Para", "Second para" doc = html.html( html.head( html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) print unicode(doc).encode('latin1')
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 pytest_sessionfinish(self): if not os.path.exists(os.path.dirname(self.logfile)): os.makedirs(os.path.dirname(self.logfile)) logfile = 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 + self.xpassed + self.xfailed generated = datetime.datetime.now() style_css = pkg_resources.resource_string(__name__, os.path.join("resources", "style.css")) if PY3: style_css = style_css.decode("utf-8") head = html.head(html.meta(charset="utf-8"), html.title("Test Report"), html.style(raw(style_css))) summary = [ html.h2("Summary"), html.p( "%i tests ran in %.2f seconds." % (numtests, suite_time_delta), html.br(), html.span("%i passed" % self.passed, class_="passed"), ", ", html.span("%i skipped" % self.skipped, class_="skipped"), ", ", html.span("%i failed" % self.failed, class_="failed"), ", ", html.span("%i errors" % self.errors, class_="error"), ".", html.br(), html.span("%i expected failures" % self.xfailed, class_="skipped"), ", ", html.span("%i unexpected passes" % self.xpassed, class_="failed"), ".", ), ] self._create_overview() overview = [ html.h2("Overview"), html.table( [ html.thead( html.tr( [ html.th("Test", col="name"), html.th("Setup", col="setup"), html.th("Call", col="call"), html.th("Teardown", col="teardown"), ] ), id="overview-table-head", ), html.tbody(*self.test_overview, id="overview-table-body"), ], id="overview-table", ), ] results = [ html.h2("Results"), html.table( [ html.thead( html.tr( [ html.th("Result", class_="sortable initial-sort result", 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.test_logs, id="results-table-body"), ], id="results-table", ), ] main_js = pkg_resources.resource_string(__name__, os.path.join("resources", "main.js")) if PY3: main_js = main_js.decode("utf-8") body = html.body( html.script(raw(main_js)), html.p("Report generated on %s at %s" % (generated.strftime("%d-%b-%Y"), generated.strftime("%H:%M:%S"))), ) environment = {} for e in self.environment: for k, v in e.items(): environment[k] = v if environment: body.append(html.h2("Environment")) body.append( html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted(environment.items()) if v], id="environment" ) ) body.extend(summary) body.extend(overview) body.extend(results) doc = html.html(head, body) logfile.write("<!DOCTYPE html>") logfile.write(doc.unicode(indent=2)) logfile.close()
def pytest_html_results_summary(prefix, summary, postfix): prefix.extend([html.p("测试报告")])
html.script(src='html/main.js')), html.body( html.p('Report generated on %s at %s by ASM %s' % ( generated.strftime('%d-%b-%Y'), generated.strftime('%H:%M:%S'), 'v0.0.1'), html.h2('Configuration'), html.table( [html.tr(html.td(k), html.td(v)) for k, v in sorted(configuration.items()) if v], id='configuration'), html.h2('Summary'), html.p( '%i tests ran in %i seconds.' % (numtests , suite_time_delta ), #'''numtests''' '''suite_time_delta''' html.br(), html.span('%i passed' % passed, class_='passed'), ', ', #'self.passed' html.span('%i skipped' % skipped, class_='skipped'), ', ', #'self.skipped' html.span('%i failed' % failed, class_='failed'), ', ', #'self.failed' html.span('%i errors' % errors, class_='error'), '.', #'self.errors' html.br()), #html.span('%i expected failures' % 0, class_='skipped'), ', ', #'self.xfailed' #html.span('%i unexpected passes' % 0, class_='failed'), '.'), #'self.xpassed' 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('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')))) # Write HTML report file