def make_html_report(path, report): def tabelize(value): try: rows = [] for key in value.keys(): rows.append( html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value) body_els = [] keys = report.keys() keys.sort() links = [] for key in keys: links.append(html.li(html.a(key, href="#" + key))) body_els.append(html.ul(links)) for key in keys: body_els.append(html.a(html.h1(key), id=key)) body_els.append(tabelize(report[key])) with open(path, 'w') as f: doc = html.html( html.head(html.style('table, td {border: 1px solid;}')), html.body(body_els)) f.write(str(doc))
def make_html_report(path, report): def tabelize(value): try: rows = [] for key in value.keys(): rows.append(html.tr(html.td(html.pre(key)), html.td(tabelize(value[key])))) return html.table(rows) except AttributeError: if type(value) == type([]): return html.table(map(tabelize, value)) else: return html.pre(value) body_els = [] keys = report.keys() keys.sort() links = [] for key in keys: links.append(html.li(html.a(key, href="#" + key))) body_els.append(html.ul(links)) for key in keys: body_els.append(html.a(html.h1(key), id=key)) body_els.append(tabelize(report[key])) with open(path, 'w') as f: doc = html.html(html.head(html.style('table, td {border: 1px solid;}')), html.body(body_els)) f.write(str(doc))
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(pages): """Generate html for given pages. :param pages: list of `Page.class` :return: path to tempdir. :rtype: string. """ tempdir = tempfile.mkdtemp() doc = html.html( html.head( # python don't allow keyword args with hypens html.meta(content="text/html; charset=utf-8", **{"http-equiv": "Content-Type"}), _get_tile(html, pages) ), html.body( html.div(_generate_body(html, pages, tempdir), id='article'), ) ) with open(os.path.join(tempdir, 'histmag.html'), 'wb') as out_file: logger.debug( 'Saving generated html to {file}'.format(file=os.path.join(tempdir, 'histmag.html')) ) out_file.write(doc.unicode(indent=2).encode('utf8')) return tempdir
def make_report(self, time, summary_results, subsuite_results): self.time = time self.summary_results = summary_results self.subsuite_results = subsuite_results return html.html( self.make_head(), self.make_body() )
def startDocument(self): h = html.html() self.head = head = html.head() self.title = title = html.title(self.title) self._push(h) h.append(head) h.append(title) self.body = body = html.body() self._push(body)
def simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage if stage.get_projectname(name) is None: # we return 200 instead of !=200 so that pip/easy_install don't # ask for the full simple page although we know it doesn't exist # XXX change that when pip-6.0 is released? abort(request, 200, "no such project %r" % name) projectname = self.context.projectname try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path_info).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.hash_spec: href += "#" + link.hash_spec links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form( html.input( type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n"] else: refresh_form = [] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def simple_html_body(title, bodytags): return html.html( html.head( html.title(title) ), html.body( html.h1(title), *bodytags ) )
def simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage projectname = stage.get_projectname(name) if projectname is None: abort(request, 200, "no such project %r" % projectname) if name != projectname: redirect("/%s/+simple/%s/" % (stage.name, projectname)) try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.md5: href += "#md5=%s" % link.md5 links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form( html.input( type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n"] else: refresh_form = [] return Response(html.html( html.head( html.title(title)), html.body( html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def generate_diff_result(self): html_report_css = """ h1 { text-align: center; } .container { width: 1170px; margin-left: auto; margin-right: auto; } table { font-family:monospace, "Courier New", Courier; border-collapse: collapse; border: 1px solid gray; width: 100%; margin-left: auto; margin-right: auto; margin-bottom: 20px; } table th { background-color: #e0e0e0; border: 1px solid gray; } table td { font-size: 10px; } /* For diff table */ .diff_header { background-color:#e0e0e0; } td.diff_header { text-align:right; } .diff_next { background-color:#c0c0c0; } .diff_add { background-color:#aaffaa; } .diff_chg { background-color:#ffff77; } .diff_sub { background-color:#ffaaaa; } """ html_report = html.html( html.head( html.meta(name='Content-Type', value='text/html; charset=utf-8'), html.title('Diff Report'), html.style(raw(html_report_css), type='text/css')), html.body(html.h1('Diff Report'), self.div_container)) self.report = html_report return self.report
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 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 simple_list_project(self): request = self.request name = self.context.name # we only serve absolute links so we don't care about the route's slash abort_if_invalid_projectname(request, name) stage = self.context.stage projectname = stage.get_projectname(name) if projectname is None: abort(request, 200, "no such project %r" % projectname) if name != projectname: redirect("/%s/+simple/%s/" % (stage.name, projectname)) try: result = stage.get_releaselinks(projectname) except stage.UpstreamError as e: threadlog.error(e.msg) abort(request, 502, e.msg) links = [] for link in result: relpath = link.entrypath href = "/" + relpath href = URL(request.path).relpath(href) if link.eggfragment: href += "#egg=%s" % link.eggfragment elif link.md5: href += "#md5=%s" % link.md5 links.extend([ "/".join(relpath.split("/", 2)[:2]) + " ", html.a(link.basename, href=href), html.br(), "\n", ]) title = "%s: links for %s" % (stage.name, projectname) if stage.has_pypi_base(projectname): refresh_title = "Refresh" if stage.ixconfig["type"] == "mirror" else \ "Refresh PyPI links" refresh_url = request.route_url( "/{user}/{index}/+simple/{name}/refresh", user=self.context.username, index=self.context.index, name=projectname) refresh_form = [ html.form(html.input(type="submit", value=refresh_title, name="refresh"), action=refresh_url, method="post"), "\n" ] else: refresh_form = [] return Response( html.html(html.head(html.title(title)), html.body(html.h1(title), "\n", refresh_form, links)).unicode(indent=2))
def simple_html_body(title, bodytags, extrahead=""): return html.html( html.head( html.title(title), extrahead, ), html.body( html.h1(title), "\n", bodytags ) )
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 __init__(self, encoding, tokenizer=None): self.encoding = encoding self.html = root = html.html() self.head = head = self.create_head() root.append(head) self.body = body = self.create_body() root.append(body) self.table, self.tbody = table, tbody = self.create_table() body.append(table) if tokenizer is None: tokenizer = Tokenizer(PythonSchema) self.tokenizer = tokenizer
def __init__(self, title=None): self.body = html.body() self.head = html.head() self.doc = html.html(self.head, self.body) if title is not None: self.head.append( html.meta(name="title", content=title)) self.head.append( html.link(rel="Stylesheet", type="text/css", href="MochiKit-1.1/examples/sortable_tables/sortable_tables.css")) self.head.append( html.script(rel="JavaScript", type="text/javascript", src="MochiKit-1.1/lib/MochiKit/MochiKit.js")) self.head.append( html.script(rel="JavaScript", type="text/javascript", src="MochiKit-1.1/examples/sortable_tables/sortable_tables.js"))
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 create_dir_html(path, href_prefix=''): h = html.html( html.head( html.title('directory listing of %s' % (path,)), style, ), ) body = html.body( html.h1('directory listing of %s' % (path,)), ) h.append(body) table = html.table() body.append(table) tbody = html.tbody() table.append(tbody) items = list(path.listdir()) items.sort(key=lambda p: p.basename) items.sort(key=lambda p: not p.check(dir=True)) for fpath in items: tr = html.tr() tbody.append(tr) td1 = html.td(fpath.check(dir=True) and 'D' or 'F', class_='type') tr.append(td1) href = fpath.basename if href_prefix: href = '%s%s' % (href_prefix, href) if fpath.check(dir=True): href += '/' td2 = html.td(html.a(fpath.basename, href=href), class_='name') tr.append(td2) td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(fpath.mtime())), class_='mtime') tr.append(td3) if fpath.check(dir=True): size = '' unit = '' else: size = fpath.size() unit = 'B' for u in ['kB', 'MB', 'GB', 'TB']: if size > 1024: size = round(size / 1024.0, 2) unit = u td4 = html.td('%s %s' % (size, unit), class_='size') tr.append(td4) return unicode(h)
def 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 _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 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 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 __init__(self, title=None): self.body = html.body() self.head = html.head() self.doc = html.html(self.head, self.body) if title is not None: self.head.append(html.meta(name="title", content=title)) self.head.append( html.link( rel="Stylesheet", type="text/css", href="MochiKit-1.1/examples/sortable_tables/sortable_tables.css" )) self.head.append( html.script(rel="JavaScript", type="text/javascript", src="MochiKit-1.1/lib/MochiKit/MochiKit.js")) self.head.append( html.script( rel="JavaScript", type="text/javascript", src="MochiKit-1.1/examples/sortable_tables/sortable_tables.js") )
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_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') 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.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.', 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(', ') results = [html.h2('Results'), html.table([html.thead( html.tr([ 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')]), 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'))), onLoad='init()') 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 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 _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 make_report(self, results): self.results = results return html.html( self.make_head(), self.make_body() )
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 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()
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 _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() environment = [] metadata = getattr(session.config, "_metadata", None) if metadata is not None: environment = metadata self.__class__.results_tree["suite_info"] = { "generated": generated, "run_time": suite_time_delta, "numtests": numtests, "environment": environment, } 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)) self.js_script = pkg_resources.resource_string( __name__, os.path.join('resources', 'main.js')) if PY3: self.js_script = self.js_script.decode('utf-8') # <DF> Add user-provided JS for path in self.config.getoption('js') or []: self.js_script += '\n/******************************' self.js_script += '\n * CUSTOM JS' self.js_script += '\n * {}'.format(path) self.js_script += '\n ******************************/\n\n' with open(path, 'r') as f: self.js_script += f.read() results_tree_dict = self.results_tree_to_dict(session) results_tree_json = json.dumps(results_tree_dict, indent=2) project_name = results_tree_dict["name"] self.js_script += "\n\nprojectName = '{}'".format(project_name) self.js_script += "\n\nresultsTree = {}".format(results_tree_json) js_ref = '{0}/{1}'.format('assets', 'script.js') html_script = html.script(src=js_ref, type='text/javascript') if self.self_contained: html_script = html.script(raw(self.js_script)) html_head = html.head( html.meta(charset='utf-8'), html.title('Test Report'), html_css, html_script, ) html_body = self._generate_body(results_tree_dict) doc = html.html() doc.extend([ html_head, html_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 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()
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: body.append(html.h2('Environment')) body.append( html.table([ html.tr(html.td(e[0]), html.td(e[1])) for e in sorted(session.config._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 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 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())
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() 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 make_report(self, results): self.results = results return html.html(self.make_head(), self.make_body())
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 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 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_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_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")
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
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')
doc = html.html( html.head(html.meta(charset='utf-8'), html.title('Test Report'), html.link(rel='stylesheet', href='html/style.css'), html.script(src='html/jquery.js'), 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'))))
def simple_html_body(title, bodytags, extrahead=""): return html.html(html.head( html.title(title), extrahead, ), html.body(html.h1(title), "\n", bodytags))
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 _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 make_report(self, time, summary_results, subsuite_results, logs): self.time = time self.logs = logs self.summary_results = summary_results self.subsuite_results = subsuite_results return html.html(self.make_head(), self.make_body())