feat(runner): Add support for async onCleanUp functions

If the `onCleanUp` function returns a promise, the process will allow it to resolve before exiting. Any other return value, including the absence of a return value, will return the `exitCode` like normal. This is useful for performing async operations like writing to a file or calling an API at the end of a test run.

For on specific use case, BrowserStack does not use exit codes to mark test runs as success or failure, so this would allow a user to easily call the BrowserStack API from `onCleanUp` to set the test status accordingly.