diff --git a/src/source/rtl_text_plugin_main_thread.test.ts b/src/source/rtl_text_plugin_main_thread.test.ts index 5fda93ec3c..e38d78c418 100644 --- a/src/source/rtl_text_plugin_main_thread.test.ts +++ b/src/source/rtl_text_plugin_main_thread.test.ts @@ -11,6 +11,7 @@ describe('RTLMainThreadPlugin', () => { let server: FakeServer; let broadcastSpy: jest.SpyInstance; const url = 'http://example.com/plugin'; + const failedToLoadMessage = `RTL Text Plugin failed to import scripts from ${url}`; const SyncRTLPluginStateMessageName = 'syncRTLPluginState'; beforeEach(() => { @@ -22,6 +23,7 @@ describe('RTLMainThreadPlugin', () => { }); function broadcastMockSuccess(message: MessageType, payload: PluginState): Promise { + console.log('broadcastMockSuccessDefer', payload.pluginStatus); if (message === SyncRTLPluginStateMessageName) { if (payload.pluginStatus === 'loading') { const resultState: PluginState = { @@ -33,11 +35,11 @@ describe('RTLMainThreadPlugin', () => { } } - function broadcastMockFailure(message: MessageType, payload: PluginState): Promise { + function broadcastMockSuccessDefer(message: MessageType, payload: PluginState): Promise { if (message === SyncRTLPluginStateMessageName) { - if (payload.pluginStatus === 'loading') { + if (payload.pluginStatus === 'deferred') { const resultState: PluginState = { - pluginStatus: 'error', + pluginStatus: 'deferred', pluginURL: payload.pluginURL }; return Promise.resolve([resultState]); @@ -45,20 +47,13 @@ describe('RTLMainThreadPlugin', () => { } } - /** return two results, one success one failure */ - function broadcastMockMix(message: MessageType, payload: PluginState): Promise { + function broadcastMockFailure(message: MessageType, payload: PluginState): Promise { if (message === SyncRTLPluginStateMessageName) { if (payload.pluginStatus === 'loading') { - const resultState0: PluginState = { - pluginStatus: 'loaded', - pluginURL: payload.pluginURL - }; - const resultState1: PluginState = { - pluginStatus: 'error', - pluginURL: payload.pluginURL - }; - return Promise.resolve([resultState0, resultState1]); + return Promise.reject(failedToLoadMessage); } + } else { + return Promise.resolve([]); } } @@ -98,37 +93,42 @@ describe('RTLMainThreadPlugin', () => { it('should be in error state if download fails', async () => { broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockFailure as any); - await rtlMainThreadPlugin.setRTLTextPlugin(url); + const resultPromise = rtlMainThreadPlugin.setRTLTextPlugin(url); + await expect(resultPromise).rejects.toBe(failedToLoadMessage); expect(rtlMainThreadPlugin.url).toEqual(url); expect(rtlMainThreadPlugin.status).toBe('error'); }); it('should lazy load the plugin if deferred', async () => { // use success spy to make sure test case does not throw exception - broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockSuccess as any); + const deferredSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockSuccessDefer as any); await rtlMainThreadPlugin.setRTLTextPlugin(url, true); - expect(broadcastSpy).toHaveBeenCalledWith(SyncRTLPluginStateMessageName, {pluginStatus: 'deferred', pluginURL: url}); + expect(deferredSpy).toHaveBeenCalledTimes(1); + expect(deferredSpy).toHaveBeenCalledWith(SyncRTLPluginStateMessageName, {pluginStatus: 'deferred', pluginURL: url}); expect(rtlMainThreadPlugin.status).toBe('deferred'); + deferredSpy.mockRestore(); // this is really a fire and forget // two calls to lazyLoad + broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockSuccess as any); rtlMainThreadPlugin.lazyLoad(); await sleep(1); expect(broadcastSpy).toHaveBeenCalledWith(SyncRTLPluginStateMessageName, {pluginStatus: 'loading', pluginURL: url}); - // two times, first for "deferred", second for 'loading' - expect(broadcastSpy).toHaveBeenCalledTimes(2); + // 'loading' + expect(broadcastSpy).toHaveBeenCalledWith(SyncRTLPluginStateMessageName, {pluginStatus: 'loading', pluginURL: url}); + expect(broadcastSpy).toHaveBeenCalledTimes(1); - // second call to lazyLoad should not change anything + // // second call to lazyLoad should not change anything rtlMainThreadPlugin.lazyLoad(); - expect(broadcastSpy).toHaveBeenCalledTimes(2); + expect(broadcastSpy).toHaveBeenCalledTimes(1); expect(rtlMainThreadPlugin.status).toBe('loaded'); // 3rd call to lazyLoad should not change anything rtlMainThreadPlugin.lazyLoad(); expect(rtlMainThreadPlugin.status).toBe('loaded'); - expect(broadcastSpy).toHaveBeenCalledTimes(2); + expect(broadcastSpy).toHaveBeenCalledTimes(1); }); it('should set status to requested if RTL plugin was not set', async () => { @@ -155,13 +155,18 @@ describe('RTLMainThreadPlugin', () => { expect(rtlMainThreadPlugin.status).toBe('requested'); }); - it('should report error for multiple results and one failure', async () => { - broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockMix as any); + it('should be in error state if lazyLoad fails', async () => { + broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockSuccessDefer); + const resultPromise = rtlMainThreadPlugin.setRTLTextPlugin(url, true); + await expect(resultPromise).resolves.toBeUndefined(); - await rtlMainThreadPlugin.setRTLTextPlugin(url); + expect(rtlMainThreadPlugin.status).toBe('deferred'); + + // the next one should fail + broadcastSpy = jest.spyOn(Dispatcher.prototype, 'broadcast').mockImplementation(broadcastMockFailure as any); + await expect(rtlMainThreadPlugin._requestImport()).rejects.toBe(failedToLoadMessage); expect(rtlMainThreadPlugin.url).toEqual(url); expect(rtlMainThreadPlugin.status).toBe('error'); - }); }); diff --git a/test/integration/browser/browser.test.ts b/test/integration/browser/browser.test.ts index f7d02b6c3d..bd9a2c7ea9 100644 --- a/test/integration/browser/browser.test.ts +++ b/test/integration/browser/browser.test.ts @@ -1,4 +1,4 @@ -import puppeteer, {Page, Browser} from 'puppeteer'; +import puppeteer, {Page, Browser, ConsoleMessage} from 'puppeteer'; import st from 'st'; import http, {type Server} from 'http'; import type {AddressInfo} from 'net'; @@ -385,4 +385,21 @@ describe('Browser tests', () => { expect(markerOpacity).toBe('1'); }, 20000); + + test('Load map with RTL plugin should throw exception for invalid URL', async () => { + + const rtlPromise = page.evaluate(() => { + // console.log('Testing start'); + return maplibregl.setRTLTextPlugin('badURL', false); + }); + + await rtlPromise.catch(e => { + const message: string = e.message; + + // exact message looks like + // Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:52015/test/integration/browser/fixtures/badURL' failed to load. + const regex = new RegExp('Failed to execute \'importScripts\' on \'WorkerGlobalScope\': The script at \'.*\' failed to load.'); + expect(regex.test(message)).toBe(true); + }); + }, 2000); });