UNPKG

refine-apito

Version:

A data provider for Refine that connects to Apito - a headless CMS and backend builder.

179 lines (164 loc) 6.36 kB
import namingVectorsJson from './fixtures/naming_vectors.json'; import { apitoConnectionFilterConditionType, apitoListGraphQLTypeName, apitoMultipleResourceName, apitoSingularGraphQLTypeName, apitoModelName, apitoWhereRelationFilterConditionType, apitoWhereInputType, apitoSortInputType, apitoListKeyConditionType, apitoListCountKeyConditionType, apitoListCountSortInputType, apitoListCountWhereInputType, buildApitoCreateMutation, apitoSingularResourceName, canonicalizeModelName, formatApitoConnectionSubselections, apitoStoredSnakeModelId, apitoMutationConnectHasOneIdField, apitoMutationConnectHasManyIdsField, apitoConnectionFieldNameForRelation, } from './apitoGraphqlNames'; type VectorRow = { input: string; singularResourceName: string; multipleResourceName: string; graphqlTypeName: string; graphqlTypeNamePlural: string; }; const namingVectors = namingVectorsJson as VectorRow[]; describe('naming_vectors.json parity', () => { test.each(namingVectors.map((row) => [row.input, row] as const))( 'resource %s', (input, row) => { expect(apitoSingularResourceName(input)).toBe(row.singularResourceName); expect(apitoMultipleResourceName(input)).toBe(row.multipleResourceName); expect(apitoModelName(input)).toBe(row.singularResourceName); expect(apitoSingularGraphQLTypeName(input)).toBe(row.graphqlTypeName); expect(apitoListGraphQLTypeName(input)).toBe(row.graphqlTypeNamePlural); } ); }); describe('Go SingularResourceName parity (no English singularize)', () => { test('singular vs plural legacy camel ids', () => { expect(apitoSingularResourceName('food')).toBe('food'); expect(apitoMultipleResourceName('food')).toBe('foodList'); expect(apitoSingularResourceName('foods')).toBe('foods'); expect(apitoMultipleResourceName('foods')).toBe('foodsList'); }); }); describe('canonicalizeModelName', () => { test('normalizes compound names', () => { expect(canonicalizeModelName('foodOrder')).toBe('food_order'); expect(canonicalizeModelName('food_orders')).toBe('food_order'); }); test('rejects run-on', () => { expect(() => canonicalizeModelName('foodorder')).toThrow(); }); }); describe('mutation connect / disconnect field names (stored model id + _id / _ids)', () => { test('has_one from camel relation id', () => { expect(apitoMutationConnectHasOneIdField('foodCategory')).toBe( 'food_category_id' ); expect(apitoMutationConnectHasOneIdField('food_category')).toBe( 'food_category_id' ); }); test('has_many', () => { expect(apitoMutationConnectHasManyIdsField('foodOrder')).toBe( 'food_order_ids' ); }); test('apitoStoredSnakeModelId matches filter snake segment', () => { expect(apitoStoredSnakeModelId('bankAccount')).toBe('bank_account'); }); }); describe('filter / connection types (snake model id)', () => { test('bank_account-style resource', () => { expect(apitoConnectionFilterConditionType('bank_account')).toBe( 'BANK_ACCOUNT_CONNECTION_FILTER_CONDITION' ); expect(apitoWhereRelationFilterConditionType('bank_account')).toBe( 'BANK_ACCOUNT_WHERE_RELATION_FILTER_CONDITION' ); expect(apitoWhereInputType('bank_account')).toBe( 'BANKACCOUNTLIST_INPUT_WHERE_PAYLOAD' ); expect(apitoSortInputType('bank_account')).toBe( 'BANKACCOUNTLIST_INPUT_SORT_PAYLOAD' ); expect(apitoListKeyConditionType('bank_account')).toBe( 'BANKACCOUNTLIST_KEY_CONDITION' ); expect(apitoListCountKeyConditionType('bank_account')).toBe( 'BANK_ACCOUNT_LIST_COUNT_KEY_CONDITION' ); expect(apitoListCountWhereInputType('bank_account')).toBe( 'BANK_ACCOUNT_LIST_COUNT_INPUT_WHERE_PAYLOAD' ); expect(apitoListCountSortInputType('bank_account')).toBe( 'BANK_ACCOUNT_LIST_COUNT_INPUT_SORT_PAYLOAD' ); }); test('food_order list vs list-count where types (avoid FOODORDERLIST_COUNT_*)', () => { expect(apitoWhereInputType('food_order')).toBe( 'FOODORDERLIST_INPUT_WHERE_PAYLOAD' ); expect(apitoListCountWhereInputType('food_order')).toBe( 'FOOD_ORDER_LIST_COUNT_INPUT_WHERE_PAYLOAD' ); expect(apitoListCountSortInputType('food_order')).toBe( 'FOOD_ORDER_LIST_COUNT_INPUT_SORT_PAYLOAD' ); }); }); describe('formatApitoConnectionSubselections', () => { test('normalizes legacy snake alias target to camelCase field', () => { const s = formatApitoConnectionSubselections( { foodCategory: 'id data { name }' }, { foodCategory: 'food_category' } ); expect(s).toContain('foodCategory {'); expect(s).not.toContain('food_category'); }); test('collapses redundant alias when response key matches schema field', () => { const s = formatApitoConnectionSubselections( { foodCategory: 'id' }, { foodCategory: 'foodCategory' } ); expect(s.trim()).toBe('foodCategory { id }'); }); test('keeps distinct response key vs schema field', () => { const s = formatApitoConnectionSubselections( { cat: 'id' }, { cat: 'foodCategory' } ); expect(s.trim()).toBe('cat: foodCategory { id }'); }); test('normalizes connectionFields key without alias map', () => { const s = formatApitoConnectionSubselections({ food_category: 'id', }); expect(s.trim()).toBe('foodCategory { id }'); }); test('has_many connection field is model List not singular (food → foodList)', () => { expect(apitoConnectionFieldNameForRelation('food', 'has_many')).toBe('foodList'); expect(apitoMultipleResourceName('food')).toBe('foodList'); const wrongSingularKey = formatApitoConnectionSubselections({ food: 'id' }); expect(wrongSingularKey.trim()).toBe('food { id }'); const hasManyKey = formatApitoConnectionSubselections({ foodList: 'id' }); expect(hasManyKey.trim()).toBe('foodList { id }'); }); }); describe('buildApitoCreateMutation', () => { test('uses Food_Order_Create_Payload for food_order model', () => { const doc = buildApitoCreateMutation('food_order', ['name']); expect(doc).toContain('mutation CreateFoodOrder('); expect(doc).toContain('Food_Order_Create_Payload!'); expect(doc).toContain('Food_Order_Relation_Connect_Payload'); expect(doc).toContain('createFoodOrder('); }); });