In a unit test, when using TestBrowserThreadBundle, all "threads" use the same backing MessageLoop hence RunLoop.RunUntilIdle() truly runs all "browser threads" until idle.
Otherwise if what you're doing is tickling something in an integration (browser) test and wanting to observe the full repercussions that had (and didn't have) on the system after everything it triggered unwound, the best way is Primiano's approach (have your API take a Closure which it invokes when done and in tests pass in the RunLoop's QuitClosure()).
You can't really spin all loops until idle (anything I can think of is racy -- even using TaskObservers, e.g. Thread A signals that it's idle, Thread B posts to A and then signals it's also idle: you can get the signal that both are idle before A starts running the task posted from B).
Perhaps MessageLoop::SetTaskRunner() could allow you to mock some of the browser threads in a browser test but I doubt you need to go that far.