UNPKG

@speckle/shared

Version:

Shared code between various Speckle JS packages

354 lines (308 loc) 12.5 kB
import { describe, expect, it } from 'vitest' import { createGetParamFromResources, parseResourceFromString, parseUrlParameters, resourceBuilder } from './route.js' describe('Viewer Route Helpers', () => { describe('parseResourceFromString', () => { it('parses "all" as ViewerAllModelsResource', () => { const resource = parseResourceFromString('all') expect(resource.type).toBe('all-models') expect(resource.toString()).toBe('all') }) it('parses modelId as ViewerModelResource', () => { const resource = parseResourceFromString('abc123') expect(resource.type).toBe('Model') expect(resource.toString()).toBe('abc123') }) it('parses modelId@versionId as ViewerModelResource', () => { const resource = parseResourceFromString('abc123@ver456') expect(resource.type).toBe('Model') expect(resource.toString()).toBe('abc123@ver456') }) it('parses $folderName as ViewerModelFolderResource', () => { const resource = parseResourceFromString('$myFolder') expect(resource.type).toBe('ModelFolder') expect(resource.toString()).toBe('$myFolder') // keep casing }) it('parses 32-char string as ViewerObjectResource', () => { const objectId = '1234567890abcdef1234567890abcdef' const resource = parseResourceFromString(objectId) expect(resource.type).toBe('Object') expect(resource.toString()).toBe(objectId) }) it('parses modelId with uppercase as ViewerModelResource and lowercases it', () => { const resource = parseResourceFromString('ABC123') expect(resource.type).toBe('Model') expect(resource.toString()).toBe('abc123') }) it('parses $FOLDERNAME with uppercase as ViewerModelFolderResource and lowercases it', () => { const resource = parseResourceFromString('$FOLDERNAME') expect(resource.type).toBe('ModelFolder') expect(resource.toString()).toBe('$FOLDERNAME') }) it('parses modelId@versionId with uppercase as ViewerModelResource and lowercases it', () => { const resource = parseResourceFromString('ABC123@VER456') expect(resource.type).toBe('Model') expect(resource.toString()).toBe('abc123@ver456') }) }) describe('parseUrlParameters', () => { it('returns empty array for empty string', () => { expect(parseUrlParameters('')).toEqual([]) }) it('parses single modelId', () => { const resources = parseUrlParameters('abc123') expect(resources).toHaveLength(1) expect(resources[0].type).toBe('Model') expect(resources[0].toString()).toBe('abc123') }) it('parses multiple modelIds and sorts them', () => { const resources = parseUrlParameters('zxy,abc') expect(resources).toHaveLength(2) expect(resources[0].toString()).toBe('abc') expect(resources[1].toString()).toBe('zxy') }) it('parses modelId@versionId and $folder', () => { const resources = parseUrlParameters('abc@ver,$folder') expect(resources).toHaveLength(2) expect(resources.some((r) => r.type === 'Model')).toBe(true) expect(resources.some((r) => r.type === 'ModelFolder')).toBe(true) }) it('removes duplicate resources', () => { const resources = parseUrlParameters('abc,abc,ABC') expect(resources).toHaveLength(1) expect(resources[0].toString()).toBe('abc') }) it('handles all resource types together', () => { const objectId = '1234567890abcdef1234567890abcdef' const resources = parseUrlParameters(`all,abc@ver,$folder,${objectId}`) expect(resources).toHaveLength(4) expect(resources.some((r) => r.type === 'all-models')).toBe(true) expect(resources.some((r) => r.type === 'Model')).toBe(true) expect(resources.some((r) => r.type === 'ModelFolder')).toBe(true) expect(resources.some((r) => r.type === 'Object')).toBe(true) }) it('handles whitespace and ignores empty parts', () => { const resources = parseUrlParameters('abc, , ,def') expect(resources).toHaveLength(2) expect(resources[0].toString()).toBe('abc') expect(resources[1].toString()).toBe('def') }) it('lowercases all resource strings', () => { const resources = parseUrlParameters('ABC,$FOLDER,DEF@VER') expect(resources.map((r) => r.toString()).sort()).toEqual( ['$FOLDER', 'abc', 'def@ver'].sort() ) }) it('sorts resources alphabetically by toString', () => { const resources = parseUrlParameters('z,abc,def') expect(resources.map((r) => r.toString())).toEqual(['abc', 'def', 'z']) }) }) describe('createGetParamFromResources', () => { it('returns empty string for empty resource array', () => { expect(createGetParamFromResources([])).toBe('') }) it('returns single resource string for one resource', () => { const resources = [parseResourceFromString('abc123')] expect(createGetParamFromResources(resources)).toBe('abc123') }) it('returns comma-separated, sorted, lowercased resource strings', () => { const resources = [ parseResourceFromString('ZXY'), parseResourceFromString('abc'), parseResourceFromString('DEF@VER') ] expect(createGetParamFromResources(resources)).toBe('abc,def@ver,zxy') }) it('removes duplicate resources (case-insensitive)', () => { const resources = [ parseResourceFromString('abc'), parseResourceFromString('ABC'), parseResourceFromString('Abc') ] expect(createGetParamFromResources(resources)).toBe('abc') }) it('handles all resource types and sorts them', () => { const objectId = '1234567890abcdef1234567890abcdef' const resources = [ parseResourceFromString('all'), parseResourceFromString('abc@ver'), parseResourceFromString('$folder'), parseResourceFromString(objectId) ] expect(createGetParamFromResources(resources)).toBe( `$folder,1234567890abcdef1234567890abcdef,abc@ver,all` .split(',') .sort() .join(',') ) }) it('handles resources with mixed case and sorts them', () => { const resources = [ parseResourceFromString('DEF@VER'), parseResourceFromString('abc'), parseResourceFromString('ZXY') ] expect(createGetParamFromResources(resources)).toBe('abc,def@ver,zxy') }) it('handles resources with $ in folder names', () => { const resources = [ parseResourceFromString('$FolderA'), parseResourceFromString('$folderb') ] expect(createGetParamFromResources(resources)).toBe('$FolderA,$folderb') }) }) describe('resourceBuilder', () => { it('can add a single model', () => { const builder = resourceBuilder().addModel('abc123') expect(builder.length).toBe(1) expect(builder.toResources()[0].type).toBe('Model') expect(builder.toString()).toBe('abc123') }) it('can add a model with version', () => { const builder = resourceBuilder().addModel('abc123', 'ver456') expect(builder.length).toBe(1) expect(builder.toResources()[0].toString()).toBe('abc123@ver456') }) it('can add all models', () => { const builder = resourceBuilder().addAllModels() expect(builder.length).toBe(1) expect(builder.toResources()[0].type).toBe('all-models') expect(builder.toString()).toBe('all') }) it('can add a model folder', () => { const builder = resourceBuilder().addModelFolder('MyFolder') expect(builder.length).toBe(1) expect(builder.toResources()[0].type).toBe('ModelFolder') expect(builder.toString()).toBe('$MyFolder') }) it('can add an object', () => { const objectId = '1234567890abcdef1234567890abcdef' const builder = resourceBuilder().addObject(objectId) expect(builder.length).toBe(1) expect(builder.toResources()[0].type).toBe('Object') expect(builder.toString()).toBe(objectId) }) it('can add from string with multiple resources', () => { const builder = resourceBuilder().addFromString('abc,def@ver,$folder') expect(builder.length).toBe(3) expect(builder.toString().split(',').sort()).toEqual( ['abc', 'def@ver', '$folder'].sort() ) }) it('can clear versionIds', () => { const builder = resourceBuilder().addResources('abc,def@ver') expect(builder.length).toBe(2) expect(builder.toString()).toBe('abc,def@ver') builder.clearVersions() expect(builder.length).toBe(2) expect(builder.toString()).toBe('abc,def') }) it('can add resources array', () => { const resources = [ parseResourceFromString('abc'), parseResourceFromString('def@ver') ] const builder = resourceBuilder().addResources(resources) expect(builder.length).toBe(2) expect(builder.toString().split(',').sort()).toEqual(['abc', 'def@ver'].sort()) }) it('can clear resources', () => { const builder = resourceBuilder().addModel('abc').addModel('def') expect(builder.length).toBe(2) builder.clear() expect(builder.length).toBe(0) expect(builder.toString()).toBe('') }) it('can clone builder', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const clone = builder.clone() expect(clone).not.toBe(builder) expect(clone.toString()).toBe(builder.toString()) clone.addModel('xyz') expect(clone.length).toBe(3) expect(builder.length).toBe(2) }) it('can iterate over resources', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const ids = [] for (const r of builder) { ids.push(r.toString()) } expect(ids.sort()).toEqual(['abc', 'def'].sort()) }) it('can use forEach', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const ids: string[] = [] builder.forEach((r) => ids.push(r.toString())) expect(ids.sort()).toEqual(['abc', 'def'].sort()) }) it('can use filter', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const res = builder.filter((r) => r.toString() === 'abc') expect(res.length).toBe(1) expect(res[0].toString()).toBe('abc') }) it('can use map', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const types = builder.map((r) => r.type) expect(types.sort()).toEqual(['Model', 'Model'].sort()) }) it('toResources returns a copy', () => { const builder = resourceBuilder().addModel('abc') const arr = builder.toResources() expect(arr).toHaveLength(1) arr.push(parseResourceFromString('def')) expect(builder.length).toBe(1) }) it('can find an item', () => { const builder = resourceBuilder().addModel('abc').addModel('def') const found = builder.find((r) => r.toString() === 'def') expect(found).toBeDefined() expect(found?.toString()).toBe('def') }) it('addNew only adds new resources', () => { const builder = resourceBuilder().addModel('abc').addModel('def') builder.addNew('abc') // should not add expect(builder.length).toBe(2) builder.addNew('abc@yaya') // should not add expect(builder.length).toBe(2) builder.addNew('xyz') // should add expect(builder.length).toBe(3) builder.addNew('$newFolder') // should add expect(builder.length).toBe(4) expect(builder.toString()).toBe('$newFolder,abc,def,xyz') // $newFolder should keep casing }) it('addResources can add any kind of ViewerResources', () => { const resources = [ 'abc', ['def@ver', '$folder'], parseResourceFromString('abc2'), parseResourceFromString('def2@ver'), parseResourceFromString('$2folder'), resourceBuilder().addModel('nestedModel') ] const builder = resourceBuilder() for (const res of resources) { builder.addResources(res) } expect(builder.length).toBe(7) expect(builder.toString().split(',').sort()).toEqual( [ 'abc', 'abc2', 'def@ver', 'def2@ver', 'nestedmodel', '$2folder', '$folder' ].sort() ) }) }) })