This other blog helped me understand what was going on with my unit tests and why forkJoin wasn't being triggered when I used EMPTY.
The TL;DR of it is that EMPTY immediately emits a complete without ever emitting a value, but forkJoin fires when all observables emit their value. Since EMPTY never emits a value, forkJoin never fires. Simple as that.