import sinon from 'sinon'; import PortStream from 'extension-port-stream'; import { setupMultiplex } from '../../../app/scripts/lib/stream-utils'; import metaRPCClientFactory from '../../../app/scripts/lib/metaRPCClientFactory'; import { dropQueue, submitRequestToBackground, _setBackgroundConnection, } from '.'; jest.mock('../../../shared/modules/mv3.utils', () => { return { isManifestV3: () => true, }; }); const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); describe('queue integration test', () => { afterEach(() => { dropQueue(true); }); it('schedules a retry if background method failed because of a disconnect', async () => { let disconnectListener; const extensionPort = { onMessage: { addListener: sinon.stub(), }, onDisconnect: { addListener(cb) { disconnectListener = cb; }, }, postMessage: sinon.stub().callsFake(() => { disconnectListener(); }), }; const connectionStream = new PortStream(extensionPort); const mx = setupMultiplex(connectionStream); const multiplexStream1 = mx.createStream('controller'); const background = metaRPCClientFactory(multiplexStream1); _setBackgroundConnection(background); // disconnect will happen on the attempt to send the message const finished = submitRequestToBackground('backgroundFunction').catch( (error) => { // disconnect error should not get propagated, we retry. // eslint-disable-next-line jest/no-conditional-expect expect(error).not.toBeInstanceOf(background.DisconnectError); // eslint-disable-next-line jest/no-conditional-expect expect(error.message).toContain('cancelled'); }, ); // We want to make sure we disconnect in the middle of processing, so we have to wait for the control flow to reach postMessage // undetermined number of asynchronous jumps withing the stream implementation leaves no other option await wait(3); // we drop the queue because we're expecting the action to have been returned to the queue and this is the simplest way to check that dropQueue(); expect(extensionPort.postMessage.calledOnce).toStrictEqual(true); await finished; }); });