Warning, /firebird/packages/firebird-ng/display/src/lib/services/data-model.service.spec.ts is written in an unsupported language. File is not indexed.
0001 /**
0002 * Which event is selected right after a load.
0003 *
0004 * `currentEntry` is a linkedSignal that follows `entries`, so it has already
0005 * settled on the first event by the time the loader publishes them. Adopting
0006 * events must therefore SELECT the first one, not step to the "next" - with one
0007 * event that wrapped around and looked correct, with several it showed the
0008 * second event while the painter drew the first.
0009 */
0010
0011 import { TestBed } from '@angular/core/testing';
0012 import { provideHttpClient } from '@angular/common/http';
0013 import { afterEach, describe, expect, it, beforeEach, vi } from 'vitest';
0014 import { ServerConfigService } from '@dexvis/app-features';
0015 import { DataExchange, Event } from '@dexvis/firebird-core';
0016 import { DataModelService } from './data-model.service';
0017
0018 function dexDocument(eventIds: string[]): unknown {
0019 return {
0020 type: 'firebird-dex-json',
0021 version: '1.0',
0022 events: eventIds.map(id => ({ id, pieces: [] })),
0023 };
0024 }
0025
0026 describe('DataModelService entry selection', () => {
0027 let service: DataModelService;
0028
0029 beforeEach(() => {
0030 TestBed.resetTestingModule();
0031 TestBed.configureTestingModule({ providers: [provideHttpClient()] });
0032 service = TestBed.inject(DataModelService);
0033 });
0034
0035 it('selects the first event of a multi-event document', () => {
0036 const data = service.loadDexObject(dexDocument(['0', '1', '2']));
0037 expect(data).toBeInstanceOf(DataExchange);
0038 expect(service.entries().length).toBe(3);
0039 expect(service.currentEntry()?.id).toBe('0');
0040 });
0041
0042 it('selects the only event of a single-event document', () => {
0043 service.loadDexObject(dexDocument(['7']));
0044 expect(service.currentEntry()?.id).toBe('7');
0045 });
0046
0047 it('rejects an object that is not DEX', () => {
0048 expect(service.loadDexObject({ type: 'something-else' })).toBeNull();
0049 });
0050
0051 it('still steps forward when asked to', () => {
0052 service.loadDexObject(dexDocument(['0', '1', '2']));
0053 service.setNextEntry();
0054 expect(service.currentEntry()?.id).toBe('1');
0055 service.setNextEntry();
0056 service.setNextEntry();
0057 // wraps around
0058 expect((service.currentEntry() as Event).id).toBe('0');
0059 });
0060 });
0061
0062 describe('DataModelService server conversion', () => {
0063 let service: DataModelService;
0064 const requested: string[] = [];
0065
0066 beforeEach(() => {
0067 requested.length = 0;
0068 TestBed.resetTestingModule();
0069 TestBed.configureTestingModule({ providers: [provideHttpClient()] });
0070 // Served by pyrobird: the convert endpoint lives at the API base URL
0071 TestBed.inject(ServerConfigService).setUnitTestConfig({ servedByPyrobird: true, apiBaseUrl: 'http://localhost:5454' });
0072 service = TestBed.inject(DataModelService);
0073 });
0074
0075 afterEach(() => vi.unstubAllGlobals());
0076
0077 it("asks the server to detect the data model ('auto'), so EDM4hep files convert too", async () => {
0078 vi.stubGlobal('fetch', async (input: string) => {
0079 requested.push(String(input));
0080 return new Response(JSON.stringify(dexDocument(['0', '1'])), { status: 200 });
0081 });
0082 const data = await service.fetchRootConversion('root://host//data/sim.edm4hep.root', '0-1', ['mc_trajectories']);
0083 expect(requested).toEqual([
0084 'http://localhost:5454/api/v1/convert/auto/0-1?f=' +
0085 encodeURIComponent('root://host//data/sim.edm4hep.root') + '&collections=mc_trajectories',
0086 ]);
0087 expect(data.events.map(event => event.id)).toEqual(['0', '1']);
0088 // Fetching does not replace the loaded events; the display adopts them
0089 expect(service.entries()).toEqual([]);
0090 });
0091
0092 it("rejects with the server's reason for a request with no entry in the file", async () => {
0093 vi.stubGlobal('fetch', async () => new Response(
0094 JSON.stringify({ error: "For entries='50-60': Event 50-60 is out of range: the file holds 2 events (0..1)" }),
0095 { status: 400, statusText: 'BAD REQUEST' }));
0096 await expect(service.fetchRootConversion('root://host//f.root', '50-60'))
0097 .rejects.toThrow(/HTTP 400 BAD REQUEST: For entries='50-60': Event 50-60 is out of range/);
0098 });
0099
0100 it('rejects an old DEX version with the upgrade command', () => {
0101 expect(() => service.parseDex({ ...dexDocument(['0']) as object, version: '0.04' }, 'old.firebird.json'))
0102 .toThrow(/pyrobird upgrade/);
0103 expect(() => service.parseDex({ type: 'other' }, 'x.json')).toThrow("'x.json' is not a Firebird DEX document");
0104 });
0105 });