#!/usr/bin/env python from __future__ import print_function import optparse import os import subprocess import sys import ujson TOOLS_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.dirname(TOOLS_DIR)) ROOT_DIR = os.path.dirname(TOOLS_DIR) # check for the venv from tools.lib import sanity_check sanity_check.check_venv(__file__) USAGE = ''' tools/test-js-with-node - to run all tests tools/test-js-with-node util.js activity.js - to run just a couple tests tools/test-js-with-node --coverage - to generage coverage report ''' enforce_fully_covered = { 'static/js/alert_words.js', 'static/js/bot_data.js', 'static/js/colorspace.js', 'static/js/common.js', 'static/js/compose_state.js', 'static/js/compose_ui.js', 'static/js/dict.js', 'static/js/filter.js', 'static/js/hash_util.js', 'static/js/muting.js', 'static/js/people.js', 'static/js/pm_conversations.js', 'static/js/reactions.js', 'static/js/recent_senders.js', 'static/js/rtl.js', 'static/js/search_suggestion.js', 'static/js/stream_sort.js', 'static/js/topic_generator.js', 'static/js/typing_data.js', 'static/js/typing_status.js', 'static/js/unread.js', } parser = optparse.OptionParser(USAGE) parser.add_option('--coverage', dest='coverage', action="store_true", default=False, help='Get coverage report') parser.add_option('--force', dest='force', action="store_true", default=False, help='Run tests despite possible problems.') (options, args) = parser.parse_args() from tools.lib.test_script import get_provisioning_status if not options.force: ok, msg = get_provisioning_status() if not ok: print(msg) print('If you really know what you are doing, use --force to run anyway.') sys.exit(1) os.environ['NODE_PATH'] = 'static' os.environ['TZ'] = 'UTC' INDEX_JS = 'frontend_tests/zjsunit/index.js' # The index.js test runner is the real "driver" here, and we launch # with either istanbul or node, depending on whether we want coverage # reports. Running under istanbul is slower and creates funny # tracebacks, so you generally want to get coverage reports only # after making sure tests will pass. if options.coverage: if args: print('BAD ARGS! Coverage reports run against all files.') sys.exit(1) istanbul = os.path.join(ROOT_DIR, 'node_modules/.bin/istanbul') command = [istanbul, 'cover', INDEX_JS, '--dir', 'var/node-coverage'] else: # Normal testing, no coverage analysis. # Run the index.js test runner, which runs all the other tests. command = ['node', '--stack-trace-limit=100', INDEX_JS] + args # If we got this far, we can run the tests! try: ret = subprocess.check_call(command) except OSError: print('Bad command: %s' % (command,)) raise NODE_COVERAGE_PATH = 'var/node-coverage/coverage.json' if options.coverage and ret == 0: coverage_json = None try: with open(NODE_COVERAGE_PATH, 'r') as f: coverage_json = ujson.load(f) except IOError: print(NODE_COVERAGE_PATH + " doesn't exist. Cannot enforce fully covered files.") raise print() print("=============================================================================") print("Checking enforced fully covered files...") for relative_path in enforce_fully_covered: path = ROOT_DIR + "/" + relative_path if not (path in coverage_json): print("ERROR: %s has no node test coverage" % (relative_path,)) continue line_coverage = coverage_json[path]['s'] missing_lines = [] for line in line_coverage: if line_coverage[line] == 0: missing_lines.append(line) if len(missing_lines): print("ERROR: %s no longer has complete node test coverage" % (relative_path,)) print(" Lines missing coverage: %s" % (", ".join(sorted(missing_lines, key=int)),)) print() ret = 1 if ret: print("It looks like your changes lost 100% test coverage in one or more files.") print("Usually, the right fix for this is to add some tests.") print("But also check out the include/exclude lists in `tools/test-js-with-node`.") print("To run this check locally, use `test-js-with-node --coverage`.") print() else: print("All enforced fully covered files still have 100% test coverage!") print("=============================================================================") print() if ret == 0: print("Test(s) passed. SUCCESS!") else: print("FAIL - Test(s) failed") sys.exit(ret)