jakub holý

building the right thing, building it right, fast

iTerm coprocess reporting result of (Mocha) tests run via nodemon

2015-04-30 06:33:57Tools

See this gist:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Inspired by https://gist.github.com/ddbeck/1421861
# About: This coprocess produces an OSX notification with results of Mocha tests run via nodemon
# # Installation:
# 1. Make this script executable
# 2. Register it: iTerm - Profiles - Open Profiles... - [Edit Profiles...] - <select your profile> -
# - Advanced - Triggers - [Edit] - add a new trigger:
# Regular Expression: [nodemon] starting `npm .*(run )?test.*`
# Action: Run Coprocess
# Parameters: /path/to/iterm-notify-test-failure.sh
# 3. Troubleshooting tips:
# * Verify the script can be run from the command line
# * Instead waiting for Mocha to run, use e.g. `echo "npm test"` to trigger it
# * Print into a file to produce debugging log or/and use e.g. the `say` osx command to track what is being processed
import subprocess
import sys
import re
## Example input from a Mocha run:
# 28 Apr 10:12:26 - [nodemon] starting `npm --silent run test:server`
# ...
# CacheItem fetching from a source
# ✓ should return the in-progress-call promise if expired and requireNonExpired set
# 1) should refresh its value even though valid when forceRefresh=true and return it
# lookup
# ✓ should return a promise
#
#
# 2 passing (12ms)
# 1 failing
#
# 1) CacheItem fetching from a source should refresh its value even though valid when forceRefresh=true and return it:
#
# AssertionError: expected 2 to deeply equal 23
# + expected - actual
# ...
# 28 Apr 10:12:36 - [nodemon] clean exit - waiting for changes before restart
def incoming():
while True:
yield raw_input()
def notify(title_end = 'FAILED', msg = ''):
subprocess.call([
'osascript',
"-e",
('display notification "%s" with title "Tests %s"' %
(msg, title_end))
])
def main():
title_end = 'FAILED: '
msg = ''
failingCountPattern = re.compile('.*(\d+) failing')
# Failed test name example: ' [2K[0G [31m 1) Stack should do something [0m'
# (the [2k etc. are Bash color escape/sequences, the ' ' is actually the control char \033)
failedTestPattern = re.compile('(\033\\[\w+| \\W)+(\\d+\\) .*)\033\\[\w+') # TODO The end color seq. is not ignored
for line in incoming():
failingCountMatch = failingCountPattern.match(line)
failedTestMatch = failedTestPattern.match(line)
if failingCountMatch: # ex: " 1 failing"
title_end += failingCountMatch.group(1)
if failedTestPattern.match(line):
msg += failedTestMatch.group(2) + ': ' # Notifications display only one line so just the 1st error is displayed
if 'AssertionError' in line:
msg += line + '\n'
if '[nodemon] app crashed' in line:
notify(title_end = title_end, msg = msg)
sys.exit(0)
if '[nodemon] clean exit' in line:
notify("OK");
sys.exit(0)
if __name__ == '__main__':
main()