Insertion Sort Implementation Efficiency
You are looping over the array elements, and once you find an element greater than the element you are about to insert, you have to again find that element in the array of elements.

        insertion_index = len(sorted_array)
        for elem_sorted in sorted_array:
            if elem_sorted &gt; elem:
                insertion_index = sorted_array.index(elem_sorted)
                break


You could instead use enumerate to extract both the element and its index:

        insertion_index = len(sorted_array)
        for index, elem_sorted in sorted_array:
            if elem_sorted &gt; elem:
                insertion_index = index
                break


When you search for an element using a for loop and break when you find the element of interest, if you don't find the element, the for loop will execute an optional else: clause, so you don't need to preset the insertion_index:

        for index, elem_sorted in sorted_array:
            if elem_sorted &gt; elem:
                insertion_index = index
                break
        else:
            insertion_index = len(sorted_array)


Biggest inefficiency

sorted_array is in sorted order.  You could use a binary search to find the insertion location, \$O(\log N)\$, instead of a linear search \$O(N)\$.