Beginner C fgetline() implementation
Excellent comment in the header.  It's very important to be clear who owns the returned memory and how to release it.  It ought to mention that both newline and \0 are considered as end-of-line characters.
Good realloc() usage - we don't leak when allocation fails.
Some small improvements:

#define EXPAND_RATIO 2


Why do we need a preprocessor macro for this?  I would use a simple static const size_t.

size_t arr_size = sizeof(char);


sizeof (char) is 1 by definition (since sizeof yields the number of char required for its argument).  I wouldn't start with such a small buffer anyway, since almost every line will need several realloc() calls.  Start with something sensible, such as 40 (half the width of a standard terminal).

p_tmp = realloc(line, arr_size);
if (p_tmp == NULL) goto err_cleanup;
line = p_tmp;


Since we know that line is null at this point, we should just use malloc() to be clearer, and eliminate a window where *line is invalid:
char *line = malloc(arr_size);
if (!line) return line;


    if ((i * sizeof(char)) == arr_size) {


We can remove the multiplication by 1 from this:
    if (i == arr_size) {


        if (arr_size == SIZE_MAX) {


Ooh, that's very thorough.  We're unlikely to have managed to allocate that much memory in a single chunk!

            // Assuming SIZE_MAX % sizeof(char) == 0.


Again, any number modulo 1 is zero, so that's a truism, not a mere assumption.

#undef EXPAND_RATIO


Arguably overkill, given that this is the very end of the translation unit anyway.