172 lines
5.8 KiB
TypeScript
172 lines
5.8 KiB
TypeScript
import { provideHttpClient } from '@angular/common/http';
|
|
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
|
import { TestBed } from '@angular/core/testing';
|
|
import { environment } from '@environment';
|
|
import { firstValueFrom } from 'rxjs';
|
|
|
|
import { BlocksCallService } from './blocks-call';
|
|
|
|
describe('BlocksCallService', () => {
|
|
let service: BlocksCallService;
|
|
let httpMock: HttpTestingController;
|
|
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
providers: [
|
|
BlocksCallService,
|
|
provideHttpClient(),
|
|
provideHttpClientTesting()
|
|
]
|
|
});
|
|
|
|
service = TestBed.inject(BlocksCallService);
|
|
httpMock = TestBed.inject(HttpTestingController);
|
|
});
|
|
|
|
afterEach(() => {
|
|
httpMock.verify();
|
|
});
|
|
|
|
it('retrieves block descriptors from the catalog endpoint and attaches shared definitions to each schema', async () => {
|
|
const request = firstValueFrom(service.retrieveAllBlocksTypes());
|
|
|
|
const catalogRequest = httpMock.expectOne(`${environment.apiUrl}/blocks/types/catalog`);
|
|
expect(catalogRequest.request.method).toBe('GET');
|
|
catalogRequest.flush({
|
|
sharedDefinitions: {
|
|
LLMDescriptor: {
|
|
type: 'object',
|
|
properties: {
|
|
provider: { type: 'string' },
|
|
model: { type: 'string' }
|
|
}
|
|
}
|
|
},
|
|
descriptors: [
|
|
{
|
|
type: 'LLMBlock',
|
|
description: 'LLM node',
|
|
userInteractive: false,
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
llmDescriptor: {
|
|
$ref: '#/sharedDefinitions/LLMDescriptor'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
const blockTypes = await request;
|
|
|
|
expect(blockTypes).toHaveLength(1);
|
|
expect(blockTypes[0]).toEqual(expect.objectContaining({
|
|
type: 'LLMBlock',
|
|
family: 'block',
|
|
description: 'LLM node'
|
|
}));
|
|
expect(blockTypes[0].schema).toEqual(expect.objectContaining({
|
|
type: 'object',
|
|
sharedDefinitions: {
|
|
LLMDescriptor: {
|
|
type: 'object',
|
|
properties: {
|
|
provider: { type: 'string' },
|
|
model: { type: 'string' }
|
|
}
|
|
}
|
|
},
|
|
properties: {
|
|
llmDescriptor: {
|
|
$ref: '#/sharedDefinitions/LLMDescriptor'
|
|
}
|
|
}
|
|
}));
|
|
});
|
|
|
|
it('rejects the legacy block catalog array format', async () => {
|
|
const request = firstValueFrom(service.retrieveAllBlocksTypes());
|
|
|
|
httpMock.expectOne(`${environment.apiUrl}/blocks/types/catalog`).flush([
|
|
{
|
|
type: 'LLMBlock'
|
|
}
|
|
]);
|
|
|
|
await expect(request).rejects.toThrow(
|
|
'Invalid block catalog response: expected reduced catalog format with a descriptors array'
|
|
);
|
|
});
|
|
|
|
it('loads and normalizes the dynamic bias annotations descriptor', async () => {
|
|
const request = firstValueFrom(service.retrieveBiasAnnotationsDescriptor());
|
|
const httpRequest = httpMock.expectOne(`${environment.apiUrl}/blocks/bias-annotations/descriptor`);
|
|
expect(httpRequest.request.method).toBe('GET');
|
|
httpRequest.flush({
|
|
type: 'BiasAnnotation', blockProperty: 'biasAnnotations', multiple: true, maxItems: 3,
|
|
schema: { type: 'object', required: ['category'], properties: { category: { type: 'string' } } },
|
|
options: { category: [{ value: 'DYNAMIC_VALUE', label: 'Dynamic label', description: 'Dynamic description' }] },
|
|
defaults: { status: 'DYNAMIC_DEFAULT' }, serverGeneratedFields: ['id']
|
|
});
|
|
|
|
await expect(request).resolves.toEqual(expect.objectContaining({
|
|
blockProperty: 'biasAnnotations', maxItems: 3,
|
|
options: { category: [{ value: 'DYNAMIC_VALUE', label: 'Dynamic label', description: 'Dynamic description' }] }
|
|
}));
|
|
});
|
|
|
|
it('retrieves and caches type-level bias capabilities', async () => {
|
|
const first = firstValueFrom(service.retrieveBiasCapabilities('LLMBlock'));
|
|
const request = httpMock.expectOne(`${environment.apiUrl}/blocks/types/LLMBlock/bias-capabilities`);
|
|
expect(request.request.method).toBe('GET');
|
|
request.flush({
|
|
blockType: 'LLMBlock',
|
|
supported: true,
|
|
isolatedExperimentSupported: true,
|
|
fullFlowExperimentSupported: true,
|
|
externalSideEffects: false,
|
|
configurationDependent: false,
|
|
activationModes: ['PROMPT_DIRECTIVE']
|
|
});
|
|
|
|
await expect(first).resolves.toEqual(expect.objectContaining({
|
|
blockType: 'LLMBlock', activationModes: ['PROMPT_DIRECTIVE']
|
|
}));
|
|
await expect(firstValueFrom(service.retrieveBiasCapabilities('LLMBlock'))).resolves.toEqual(expect.objectContaining({
|
|
supported: true
|
|
}));
|
|
});
|
|
|
|
it('posts the configured block for instance-specific bias capabilities', async () => {
|
|
const block = {
|
|
id: 'conditional-1',
|
|
name: 'Conditional',
|
|
inputs: [],
|
|
outputs: [{ name: 'true', type: 'TEXT', multiple: false }],
|
|
specificConfiguration: { useLlm: true },
|
|
typeName: 'ConditionalBlock',
|
|
nodeFamily: 'block' as const
|
|
};
|
|
const response = firstValueFrom(service.retrieveBiasCapabilitiesForInstance('ConditionalBlock', block));
|
|
const request = httpMock.expectOne(`${environment.apiUrl}/blocks/types/ConditionalBlock/bias-capabilities`);
|
|
expect(request.request.method).toBe('POST');
|
|
expect(request.request.body).toEqual(block);
|
|
request.flush({
|
|
blockType: 'ConditionalBlock',
|
|
supported: true,
|
|
isolatedExperimentSupported: true,
|
|
fullFlowExperimentSupported: true,
|
|
externalSideEffects: false,
|
|
configurationDependent: true,
|
|
activationModes: ['PROMPT_DIRECTIVE', 'INPUT_TRANSFORMATION']
|
|
});
|
|
|
|
await expect(response).resolves.toEqual(expect.objectContaining({
|
|
configurationDependent: true,
|
|
activationModes: ['PROMPT_DIRECTIVE', 'INPUT_TRANSFORMATION']
|
|
}));
|
|
});
|
|
});
|