Debugging refraction in a sphere
You need to make use of a discriminant, also when dealing with floating point comparisons it is wise to use an epsilon (small value for accommodating fp-error).
Also keep in mind that it matters whether the surface normal is pointing along the ray, or against it.
Below is a function which I use in my own raytracer, also based on the same book. It is written in C and refracts a given vector3. You would assign the return value to your ray.direction in your case.
// vector*vector means dot product here

#define EPSILON = 0.000001f

static inline vec3 refract(
    vec3 dir, // direction of incoming light ray
    vec3 n, // surface normal of refracting surface, pointing outwards (so roughly in the against the direction of light ray)
    float ni_over_nt // refractive indices fraction
){
    float dt = dir*n; // dot prod.
    float discriminant = 1.f - ni_over_nt*ni_over_nt*(1.f-dt*dt);
    if (discriminant &gt; EPSILON){
        return (dir - n*dt)*ni_over_nt - n*sqrtf(discriminant);
    } else {
        // total internal reflection
        // reflect the direction against the surface normal
        return reflect(direction, normal);
    }
}

Usage of the function is as follows:
if (direction*normal) &gt; EPSILON) // dot prod. of ray dir. and surf. normal
{
    // ray is entering the object
    nOut = -normal; 
    ni_over_nt = mat-&gt;IOR; // surface material index of refraction.
} else {
    // ray is exiting the object
    nOut = normal;
    ni_over_nt = 1.f/mat-&gt;IOR;
}

vec3 refracted = refract(direction, nOut, ni_over_nt);
// this is your refracted ray direction

Added bonus: reflection function used in the refraction:
static inline vec3 reflect3(vec3 v, vec3 n){
    // reflect a vector v off of a plane with normal n
    return  v -n*2*(v*n); //v*n = dot prod.
}