UNPKG

@stackbit/utils

Version:
383 lines (345 loc) 14 kB
import { describe, test, expect } from '@jest/globals'; import { DocumentWithSource } from '@stackbit/types'; import { fieldPathToString, getDocumentFieldValueAtFieldPath, stringToFieldPath } from '../src'; describe('test fieldPathToString', () => { test('should convert single item fieldPath', () => { const result = fieldPathToString(['title']); expect(result).toEqual('title'); }); test('should separate multi item fieldPath with dot', () => { const result = fieldPathToString(['section', 'title']); expect(result).toEqual('section.title'); }); test('should wrap first non-alphanumeric field path item with square brackets and single quotes', () => { const result = fieldPathToString(['hero-section', 'title']); expect(result).toEqual("['hero-section'].title"); }); test('should wrap middle non-alphanumeric field path item with square brackets', () => { const result = fieldPathToString(['sections', 'hero-section', 'title']); expect(result).toEqual("sections['hero-section'].title"); }); test('should wrap successive non-alphanumeric field names with square brackets', () => { const result = fieldPathToString(['banner', 'sub-component-1', 'sub.component.2']); expect(result).toEqual("banner['sub-component-1']['sub.component.2']"); }); test('should wrap list indexes with square brackets', () => { const result = fieldPathToString(['sections', 2, 'title']); expect(result).toEqual('sections[2].title'); }); test('should not wrap string-numbers with square brackets', () => { const result = fieldPathToString(['sections', '2', 'title']); expect(result).toEqual('sections.2.title'); }); }); describe('test stringToFieldPath', () => { test('should convert single item fieldPath', () => { const result = stringToFieldPath('title'); expect(result).toEqual(['title']); }); test('should separate multi item fieldPath with dot', () => { const result = stringToFieldPath('section.title'); expect(result).toEqual(['section', 'title']); }); test('should unwrap first non-alphanumeric field path item from square brackets', () => { const result = stringToFieldPath("['hero-section'].title"); expect(result).toEqual(['hero-section', 'title']); }); test('should unwrap middle non-alphanumeric field path item from square brackets', () => { const result = stringToFieldPath("sections['hero-section'].title"); expect(result).toEqual(['sections', 'hero-section', 'title']); }); test('should wrap successive non-alphanumeric field names with square brackets', () => { const result = stringToFieldPath("banner['sub-component-1']['sub.component.2']"); expect(result).toEqual(['banner', 'sub-component-1', 'sub.component.2']); }); test('should wrap list indexes with square brackets', () => { const result = stringToFieldPath('sections[2].title'); expect(result).toEqual(['sections', 2, 'title']); }); test('should not wrap string-numbers with square brackets', () => { const result = stringToFieldPath('sections.2.title'); expect(result).toEqual(['sections', '2', 'title']); }); }); describe('test getDocumentFieldValueAtFieldPath', () => { const documents: DocumentWithSource[] = [ { type: 'document', id: 'doc-1', srcType: 'src-1', srcProjectId: 'src-project-1', manageUrl: 'https://www.example.com', modelName: 'page', status: 'published', createdAt: '2025-01-01T10:00:00.000Z', updatedAt: '2025-01-01T10:00:00.000Z', context: null, fields: { title: { type: 'string', value: 'Title Value' }, localizedString: { type: 'string', localized: true, locales: { en: { locale: 'en', value: 'Hello' }, es: { locale: 'es', value: 'Hola' } } }, modelField: { type: 'model', modelName: 'heroSection', fields: { label: { type: 'string', value: 'Label Value' } } }, localizedModelField: { type: 'model', localized: true, locales: { en: { locale: 'en', modelName: 'heroSection', fields: { label: { type: 'string', value: 'Localized Label Value' }, localizedString: { type: 'string', localized: true, locales: { es: { locale: 'es', value: 'Spanish value' } } } } } } }, listField: { type: 'list', items: [ { type: 'string', value: 'one' }, { type: 'string', value: 'two' } ] }, referenceField: { type: 'reference', refType: 'document', refId: 'doc-2' } } }, { type: 'document', id: 'doc-2', srcType: 'src-1', srcProjectId: 'src-project-1', manageUrl: 'https://www.example.com', modelName: 'page', status: 'published', createdAt: '2025-01-01T10:00:00.000Z', updatedAt: '2025-01-01T10:00:00.000Z', context: null, fields: { title: { type: 'string', value: 'Doc 2 Title Value' } } } ]; const document = documents[0]!; function getDocumentById(options: { id: string; srcType?: string; srcProjectId?: string }) { return documents.find((doc) => doc.id === options.id); } test('should throw an error if fieldPath is empty', () => { expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: '', getDocumentById }); }).toThrow("Illegal fieldPath ''. The fieldPath cannot be empty"); expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: [], getDocumentById }); }).toThrow("Illegal fieldPath ''. The fieldPath cannot be empty"); }); test('should return value of a string field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'title', getDocumentById }); expect(result).toEqual('Title Value'); }); test('should throw an error if a primitive field is followed by another field path', () => { expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: 'title.noField', getDocumentById }); }).toThrow( "Illegal fieldPath 'title.noField'. The field at path 'title' is a primitive field of type 'string' and cannot be followed by another field path." ); }); test('should return undefined for non existing field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'no_such_field', getDocumentById }); expect(result).toBeUndefined(); }); test('should return value of a localized string field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedString.es', getDocumentById }); expect(result).toEqual('Hola'); }); test('should return undefined for a non existing locale value of a localized field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedString.fr', getDocumentById }); expect(result).toBeUndefined(); }); test('should throw if locale for a localized field was not specified', () => { expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedString', getDocumentById }); }).toThrow("Illegal fieldPath 'localizedString'. The field at path 'localizedString' is a localized field and must be followed by a locale specifier."); }); test('should return a flattened object of a model field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'modelField', getDocumentById }); expect(result).toEqual({ __metadata: { modelName: 'heroSection' }, label: 'Label Value' }); }); test('should return a value of a field in a nested object', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'modelField.label', getDocumentById }); expect(result).toEqual('Label Value'); }); test('should return undefined for a non-existing field in a nested object', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'modelField.noField', getDocumentById }); expect(result).toBeUndefined(); }); test('should return undefined for a non-existing nested fields', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'noField1.noField2.noField3', getDocumentById }); expect(result).toBeUndefined(); }); test('should return a flattened object of a localized model field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedModelField.en', getDocumentById }); expect(result).toEqual({ __metadata: { modelName: 'heroSection' }, label: 'Localized Label Value' }); }); test('should return a value of a field in a localized model field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedModelField.en.label', getDocumentById }); expect(result).toEqual('Localized Label Value'); }); test('should return undefined for a non existing locale of a localized model field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedModelField.es', getDocumentById }); expect(result).toBeUndefined(); }); test('should return a value for a localized string within a localized model field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedModelField.en.localizedString.es', getDocumentById }); expect(result).toEqual('Spanish value'); }); test('should throw if locale for a localized model field was not specified', () => { expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: 'localizedModelField', getDocumentById }); }).toThrow( "Illegal fieldPath 'localizedModelField'. The field at path 'localizedModelField' is a localized field and must be followed by a locale specifier." ); }); test('should return an item list value in a list at specified index', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'listField[1]', getDocumentById }); expect(result).toEqual('two'); }); test('should throw an error if list field is not followed by index', () => { expect(() => { getDocumentFieldValueAtFieldPath({ document, fieldPath: 'listField.fieldName', getDocumentById }); }).toThrow("Illegal fieldPath 'listField.fieldName'. The field at path 'listField' is a list field and must be followed by a list item index."); }); test('should return a document id of a reference field', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'referenceField', getDocumentById }); expect(result).toEqual('doc-2'); }); test('should return a value of a field in a referenced document', () => { const result = getDocumentFieldValueAtFieldPath({ document, fieldPath: 'referenceField.title', getDocumentById }); expect(result).toEqual('Doc 2 Title Value'); }); });