import { setHTMLFixture } from 'helpers/fixtures';
import waitForPromises from 'helpers/wait_for_promises';
beforeAll(async () => {
// @rails/ujs expects jQuery.ajaxPrefilter to exist if jQuery exists at
// import time. This is only a problem in tests, since we expose jQuery
// globally earlier than in production builds. Work around this by pretending
// that jQuery isn't available *before* we import @rails/ujs.
delete global.jQuery;
const { initRails } = await import('~/lib/utils/rails_ujs.js');
initRails();
});
function mockXHRResponse({ responseText, responseContentType } = {}) {
jest
.spyOn(global.XMLHttpRequest.prototype, 'getResponseHeader')
.mockReturnValue(responseContentType);
jest.spyOn(global.XMLHttpRequest.prototype, 'send').mockImplementation(function send() {
requestAnimationFrame(() => {
Object.defineProperties(this, {
readyState: { value: XMLHttpRequest.DONE },
status: { value: 200 },
response: { value: responseText },
});
this.onreadystatechange();
});
});
}
// This is a test to make sure that the patch-package patch correctly disables
// script execution for data-remote attributes.
it('does not perform script execution via data-remote', async () => {
global.scriptExecutionSpy = jest.fn();
mockXHRResponse({
responseText: 'scriptExecutionSpy();',
responseContentType: 'application/javascript',
});
setHTMLFixture(`
XSS
`);
const link = document.querySelector('[data-testid="evil-link"]');
const ajaxSuccessSpy = jest.fn();
link.addEventListener('ajax:success', ajaxSuccessSpy);
link.click();
await waitForPromises();
// Make sure Rails ajax machinery finished working as expected to avoid false
// positives
expect(ajaxSuccessSpy).toHaveBeenCalledTimes(1);
// If @rails/ujs has been patched correctly, this next assertion should pass.
//
// Because it's asserting something didn't happen, it is possible for it to
// pass for the wrong reason. So, to verify that this test correctly fails
// when @rails/ujs has not been patched, run:
//
// yarn patch-package --reverse
//
// And then re-run this test. The spy should now be called, and correctly
// fail the test.
//
// To restore the patch(es), run:
//
// yarn install
expect(global.scriptExecutionSpy).not.toHaveBeenCalled();
});