I found that if I navigate using history.push() within the popup, then window.close() will not work. Using history.replace() instead will still allow javascript to close the popup.
I.e. history.length couldn't be greater than 1.
That seems to fit with this:
https://github.com/WebKit/WebKit/blob/3644f1bb237c11a5e51754fd4a56b041d247ecb6/Source/WebCore/page/DOMWindow.cpp#L1044
(Thanks: https://textslashplain.com/2021/02/04/window-close-restrictions/)