One comment about this:
> But what if you can’t add a test for something because the function is untestable? You could refactor it to be testable, but that’s not safe, because you don’t have a test. It’s Catch-22.
> Can we do better? Here’s one emergency rescue procedure for untestable functions that I’ve used successfully. Ignore the existing function and write a test for the function you’d like to have. Then make that test pass by writing a new function from scratch. Finally, delete the old function.
But how do you ensure that the new function replicates the same behavior of the old one? What's suggested is essentially to do a rewrite, but that's as risky as introducing any change to the untested code.
One alternative could be to test at a higher level by adding an integration or E2E test. This way you encode how the system should behave functionally, which at least gives you some safety net to do lower-level changes. Then you could refactor the function to make it testable, or use the rewrite approach to remove it altogether.