Well, I think you're just Doing It Wrong™.
I didn't spend very long on it (because debugging collection view layouts makes my head hurt), but I think you're seeing different behavior in iOS 12 because you're incorrectly relying on autolayout being done after you've created the width constraint in each cell, but it's actually being done before. (And it only worked in iOS 11 by accident.)
AFAICT you shouldn't be using autolayout for this at all. By the time you attempt to modify the constraint (TestCollectionViewCell.apply(:)) autolayout is long out of the picture. Instead, the "apply" method should actually apply your custom "cellWidth" attribute by resizing the cell. You don't really need the autolayout constraint for the width at all.
In fact, I tried modifying your code in CustomFlowLayout.layoutAttributesForElements(in:) by changing the line inside the loop from this:
attribute.cellWidth = self.widthForCollectionView(collectionVIew: collectionView!)
to this:
let cellWidth = self.widthForCollectionView(collectionVIew: collectionView!)
attribute.size = CGSize(width: cellWidth, height: attribute.size.height)
(using a standard attribute to set the width instead of your custom attribute, to avoid mucking about with the cell code). After that, the cells seemed to be drawn with the correct width (though at the wrong origin).
So you can either set a standard layout attribute (like "size") to change the width, or you can manually resize the cell (in "apply") to use a custom cellWidth. Either way, I don't think autolayout attributes come into it. More precisely, if you wanted to set the width via an autolayout constraint, you'd have to arrange to customize the constraint much earlier in the layout process.