Skip to content

Commit

Permalink
fix: Handling of native dialogs inconsistent with handling in Firefox…
Browse files Browse the repository at this point in the history
… (closes #6815) (#2980)

* fix: Handling of native dialogs inconsistent with handling in Firefox

* fix test

* update client/sandbox/event/unload

* return test

* refactor test

* requests changes

* requests changes

* align and change titles
  • Loading branch information
PavelMor25 authored Nov 24, 2023
1 parent bade0f6 commit 7f42798
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
7 changes: 3 additions & 4 deletions src/client/sandbox/event/unload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SandboxBase from '../base';
import nativeMethods from '../native-methods';
import createPropertyDesc from '../../utils/create-property-desc.js';
import { isFirefox, isIOS } from '../../utils/browser';
import { isIOS } from '../../utils/browser';
import { overrideDescriptor } from '../../utils/overriding';
import Listeners from './listeners';
import { isFunction } from '../../utils/types';
Expand Down Expand Up @@ -83,11 +83,10 @@ export default class UnloadSandbox extends SandboxBase {
nativeMethods.objectDefineProperty(e, 'returnValue', createPropertyDesc({
get: () => eventProperties.storedReturnValue,
set: value => {
// NOTE: In all browsers, if the property is set to any value, unload is prevented. In FireFox,
// only if a value is set to an empty string, the unload operation is prevented.
// NOTE: In all browsers, if the property is set to any value except empty string, unload is prevented.
eventProperties.storedReturnValue = UnloadSandbox._prepareStoredReturnValue(value);

eventProperties.prevented = isFirefox ? value !== '' : true;
eventProperties.prevented = eventProperties.prevented || value !== '';
},
}));

Expand Down
33 changes: 33 additions & 0 deletions test/client/data/unload/iframe-beforeunload.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script src="/hammerhead.js" class="script-hammerhead-shadow-ui"></script>
</head>
<body>
<script type="text/javascript">
var hammerhead = window['%hammerhead%'];
var hhPostMessage = hammerhead.sandbox.event.message.postMessage;

hammerhead.utils.destLocation.forceLocation('http://localhost/sessionId/https://example.com');
hammerhead.start({ crossDomainProxyPort: 2000 });

hammerhead.on(hammerhead.EVENTS.beforeUnload, e => {
hhPostMessage(window.parent, [e.prevented, '*']);
});

window.addEventListener('message', function (m) {
const { returnValue, needPrevent } = m.data;

window.addEventListener('beforeunload', function (e) {
if (needPrevent)
e.preventDefault();

e.returnValue = returnValue;
});

location.reload();
});
</script>
</body>
</html>
46 changes: 46 additions & 0 deletions test/client/fixtures/sandbox/event/unload-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,50 @@ if (!browserUtils.isSafari) {
strictEqual(returnValue, '[object BeforeUnloadEvent]');
});
});

const testCasesOnbeforeunloadNativeDialog = [
{
returnValue: '',
needPrevent: true,
expectPrevent: true,
title: 'to prevent opening native dialog with empty return Value and e.preventDefault',
},
{
returnValue: '',
needPrevent: false,
expectPrevent: false,
title: 'without preventing the opening native dialog',
},
{
returnValue: 'message',
needPrevent: true,
expectPrevent: true,
title: 'to prevent opening native dialog with return Value and e.preventDefault',
},
{
returnValue: 'message',
needPrevent: false,
expectPrevent: true,
title: 'to prevent opening native dialog with returnValue',
},
];

testCasesOnbeforeunloadNativeDialog.forEach(testCase => {
const { returnValue, needPrevent, expectPrevent, title } = testCase;

test(`onbeforeunload handler must be called ${title} (GH-6815)`, function () {
return createTestIframe({ src: getCrossDomainPageUrl('../../../data/unload/iframe-beforeunload.html') })
.then(function (iframe) {
postMessage(iframe.contentWindow, [{
returnValue,
needPrevent,
}, '*']);

return waitForMessage(window);
})
.then(function (isPrevented) {
strictEqual(isPrevented, expectPrevent);
});
});
});
}

0 comments on commit 7f42798

Please sign in to comment.