This is a little similar to a previous answer, but I thought that I'd flesh it out and explain it fully.
As soon as you set display: inline-block, :after becomes a non-text-binding element. This is why it wraps, and why nowrap has no effect. So leave display alone.
As it's a text element by default, the content binds to previous text, as long as there's no whitespace between them. So don't add any, but make sure you have content: "", or it's the same as display: none. The only problem is height and width are controlled by the content, which in this case is collapsed. So width is 0, and height is the line height.
Resize the area with padding; left or right, it doesn't matter. Add a little margin so the icon doesn't touch the text. Keep everything as relative sizes (em, pt, etc.), and use background-size: contain, so that the icon scales with the text, like an emoji or font. Finally position the icon where you want with background-position.
ul li.completed a:after {
content: "";
background: url('icon.svg');
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
margin-left: 0.2em; /* spacing*/
padding-right: 0.75em; /* sizing */
}
I've used this for my external links (a[href*="://"]:after), and it's worked fine in Firefox, Chrome, and iOS. And since the icon remains a text element, even direct text after it binds, so any closing punctuation will wrap too.