You have run into a problem I've had as well.
Short answer: There is no guarantee in the documentation because it is entirely possible that the future method will run two minutes later, given platform resources, but the batch job would be invoked immediately... and then you have the batch job (in my case) selecting zero records because none have been updated by the future to have the right field value criteria for the batch.
I ended up writing synchronous code in parallel with the asynchronous (future) code, doing code reuse by returning a list of records in the method so that I can call that method in my before update trigger section, or call it and then perform DML on the returned list in my future after update trigger section.
Then for testing the batch, you set a static boolean (I call it forceSynchronous) to true, and the trigger has the logic to run synchronous code and then do the batch. For testing the future code, you leave the boolean as false and just do your asserts on what you would expect the future code to output. You don't ever end up doing end-to-end future + batch, but with enough asserts, you don't need to.