1. The library makes an assumption on a type (in the case of Python, that's typically "there's only one type of strings", "there's only one type of streams", sometimes "there's only one type of numbers", etc.). Since the language is loosely-typed, there's no API barrier that checks this, it's all duck-typing.
2. Tons of code is written based on this assumption.
3. Assumption changes. In this example, this happened with the Python 2 => Python 3 migration, but it also happens once in a while with smaller version increments of either Python itself or Python libraries.
4. Where is the assumption used in your code? Well, if you're lucky, you're going to find out once a piece of your code throws an error because it's attempting to use a method that doesn't exist anymore. If you're not lucky, the behavior of your code has changed subtly.
In the loosely-typed world, the only way to avoid this is to have very strict boundary checks. Which means basically manually implementing subpar type checking at the borders and unit tests and/or fuzzing just to ensure that your mock-type-checking actually does its jobs.
Of course, you can often get away without doing this as long as your code is for internal use only. But if you're writing a library and if you want your users to be able to troubleshoot problems without too many difficulties, you're doing manually what the compiler is doing for you in a statically-typed language.
Metric or imperial integers? Your unit tests failed to prevent this $300 million blunder:
https://www.wired.com/2010/11/1110mars-climate-observer-repo...
But more commonly what is going to happen is that someone (two years from now) is going to change a 'person' parameter from legacy SSN to database id and some users are going to get "you don't exist" when they show up at the hospital to get medical service.
You're right though, most folks in the JS/Ruby/Python ecosystems don't do this kind of testing. It's a recurring joke:
https://www.google.com/search?q=2+unit+tests+0+integration+t...
As for frameworks in the languages you listed...
Ruby and Python: https://github.com/HypothesisWorks/hypothesis
Elixir and Erlang: https://github.com/proper-testing/proper
Node and JS: https://jsverify.github.io/
As for real world use-cases, imagine you’re writing a program that accepts timestamps as input and has to implement branching, requirements-defined business logic based off of them. When you’re writing your unit tests you can use the requirements to select timestamps that are “known good” and “known bad”, but it’s hard to explore this state space on your own.
Same thing goes for handling unexpected inputs to certain functions. You probably don’t want to check _every_ type of input for _every_ dynamic function, but it might make sense to make sure that certain “entry points” to your program fail in the expected manner when they get poorly typed input.