UNPKG

maplibre-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

276 lines (216 loc) 14.5 kB
import {beforeEach, describe, expect, test, vi} from 'vitest'; import fs from 'fs'; import path from 'path'; import {RequestManager} from '../util/request_manager'; import {loadSprite, normalizeSpriteURL} from './load_sprite'; import {type FakeServer, fakeServer} from 'nise'; import {bufferToArrayBuffer, sleep} from '../util/test/util'; import {ABORT_ERROR} from '../util/abort_error'; import * as util from '../util/util'; import {ensureError} from '../util/util'; describe('normalizeSpriteURL', () => { test('concantenates path, ratio, and extension for non-mapbox:// scheme', () => { expect( normalizeSpriteURL('http://www.foo.com/bar', '@2x', '.png') ).toBe('http://www.foo.com/bar@2x.png'); }); test('concantenates path, ratio, and extension for file:/// scheme', () => { expect( normalizeSpriteURL('file:///path/to/bar', '@2x', '.png') ).toBe('file:///path/to/bar@2x.png'); }); test('normalizes non-mapbox:// scheme when query string exists', () => { expect( normalizeSpriteURL('http://www.foo.com/bar?fresh=true', '@2x', '.png') ).toBe('http://www.foo.com/bar@2x.png?fresh=true'); }); test('test relative URL', () => { expect( () => normalizeSpriteURL('/bar?fresh=true', '@2x', '.png') ).toThrow(/Invalid/i); }); test('No Path', () => { expect( normalizeSpriteURL('http://www.foo.com?fresh=true', '@2x', '.json') ).toBe('http://www.foo.com/@2x.json?fresh=true'); }); }); describe('loadSprite', () => { let server: FakeServer; beforeEach(() => { vi.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation(async (_data: ArrayBuffer) => { try { return await createImageBitmap(new ImageData(1024, 824)); } catch (e) { throw new Error(`Could not load image because of ${ensureError(e).message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`); } }); global.fetch = null; server = fakeServer.create(); }); test('backwards compatibility: single string is treated as a URL for the default sprite', async () => { const transform = vi.fn().mockImplementation((url, type) => { return {url, type}; }); const manager = new RequestManager(transform); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); const promise = loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, new AbortController()); await sleep(0); server.respond(); const result = await promise; expect(transform).toHaveBeenCalledTimes(2); expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); expect(Object.keys(result)).toHaveLength(1); expect(Object.keys(result)[0]).toBe('default'); for (const styleImage of Object.values(result['default'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); }); test('backwards compatibility: single string is treated as a URL for the default sprite (async transformRequest)', async () => { const manager = new RequestManager((url) => ({ url, headers: {Authorization: 'Bearer token'} })); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); const promise = loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, new AbortController()); await sleep(0); server.respond(); const result = await promise; expect(Object.keys(result)).toHaveLength(1); expect(Object.keys(result)[0]).toBe('default'); for (const styleImage of Object.values(result['default'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[0].requestHeaders.Authorization).toBe('Bearer token'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); expect(server.requests[1].requestHeaders.Authorization).toBe('Bearer token'); }); test('array of objects support', async () => { const transform = vi.fn().mockImplementation((url, type) => { return {url, type}; }); const manager = new RequestManager(transform); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png')))); const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, new AbortController()); await sleep(0); server.respond(); const result = await promise; expect(transform).toHaveBeenCalledTimes(4); expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1.json', 'SpriteJSON'); expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1.png', 'SpriteImage'); expect(transform).toHaveBeenNthCalledWith(3, 'http://localhost:9966/test/unit/assets/sprite2.json', 'SpriteJSON'); expect(transform).toHaveBeenNthCalledWith(4, 'http://localhost:9966/test/unit/assets/sprite2.png', 'SpriteImage'); expect(Object.keys(result)).toHaveLength(2); expect(Object.keys(result)[0]).toBe('sprite1'); expect(Object.keys(result)[1]).toBe('sprite2'); for (const styleImage of Object.values(result['sprite1'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } for (const styleImage of Object.values(result['sprite2'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); expect(server.requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json'); expect(server.requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png'); }); test('array of objects support (async tranformRequest)', async () => { const manager = new RequestManager(async (url) => ({ url, headers: {Authorization: 'Bearer token'} })); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png')))); const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, new AbortController()); await sleep(0); server.respond(); const result = await promise; expect(Object.keys(result)).toHaveLength(2); expect(Object.keys(result)[0]).toBe('sprite1'); expect(Object.keys(result)[1]).toBe('sprite2'); for (const styleImage of Object.values(result['sprite1'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } for (const styleImage of Object.values(result['sprite2'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[0].requestHeaders.Authorization).toBe('Bearer token'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); expect(server.requests[1].requestHeaders.Authorization).toBe('Bearer token'); expect(server.requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json'); expect(server.requests[2].requestHeaders.Authorization).toBe('Bearer token'); expect(server.requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png'); expect(server.requests[3].requestHeaders.Authorization).toBe('Bearer token'); }); test('server returns error', async () => { const transform = vi.fn().mockImplementation((url, type) => { return {url, type}; }); const manager = new RequestManager(transform); server.respondWith((xhr) => xhr.respond(500)); const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, new AbortController()); await sleep(0); server.respond(); await expect(promise).rejects.toThrow(/AJAXError.*500.*/); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); }); test('request canceling', async () => { const transform = vi.fn().mockImplementation((url, type) => { return {url, type}; }); const manager = new RequestManager(transform); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); const abortController = new AbortController(); const promise = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, abortController); await sleep(0); abortController.abort(); expect((server.requests[0] as any).aborted).toBeTruthy(); expect((server.requests[1] as any).aborted).toBeTruthy(); await expect(promise).rejects.toThrow(expect.objectContaining({name: ABORT_ERROR})); server.respond(); expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png'); }); test('pixelRatio is respected', async () => { const transform = vi.fn().mockImplementation((url, type) => { return {url, type}; }); const manager = new RequestManager(transform); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString()); server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')))); const promise = loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 2, new AbortController()); await sleep(0); server.respond(); const result = await promise; expect(transform).toHaveBeenCalledTimes(2); expect(transform).toHaveBeenNthCalledWith(1, 'http://localhost:9966/test/unit/assets/sprite1@2x.json', 'SpriteJSON'); expect(transform).toHaveBeenNthCalledWith(2, 'http://localhost:9966/test/unit/assets/sprite1@2x.png', 'SpriteImage'); expect(Object.keys(result)).toHaveLength(1); expect(Object.keys(result)[0]).toBe('default'); for (const styleImage of Object.values(result['default'])) { expect(styleImage.spriteData).toBeTruthy(); expect(styleImage.spriteData.context).toBeInstanceOf(CanvasRenderingContext2D); } expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.json'); expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png'); }); });