diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.spec.tsx b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.spec.tsx index 27070253a..f3735dd82 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.spec.tsx +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.spec.tsx @@ -6,6 +6,10 @@ import { generateExamplesFromJsonSchema } from './exampleGeneration'; const modelWithNoExamples: JSONSchema7 = require('../../__fixtures__/models/model-with-no-examples.json'); describe('generateExamplesFromJsonSchema', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it('returns error message when example generation fails ', () => { const errorMessage = 'This is a mocked Error message'; jest.spyOn(Sampler, 'sample').mockImplementation(() => { @@ -15,4 +19,196 @@ describe('generateExamplesFromJsonSchema', () => { const example = generateExamplesFromJsonSchema(modelWithNoExamples); expect(example).toEqual([{ label: '', data: `Example cannot be created for this schema\nError: ${errorMessage}` }]); }); + + it('generates example from schema with examples array', () => { + const schema: JSONSchema7 = { + type: 'object', + properties: { + name: { type: 'string' }, + }, + examples: [{ name: 'Alice' }, { name: 'Bob' }], + }; + + jest.spyOn(Sampler, 'sample').mockReturnValue({ name: 'generated' }); + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toHaveLength(2); + expect(result[0].label).toBe('default'); + expect(JSON.parse(result[0].data)).toEqual({ name: 'generated' }); + expect(result[1].label).toBe('example-1'); + expect(JSON.parse(result[1].data)).toEqual({ name: 'generated' }); + }); + + it('generates example from schema with x-examples', () => { + const schema: JSONSchema7 & { 'x-examples'?: unknown } = { + type: 'object', + properties: { + code: { type: 'string' }, + message: { type: 'string' }, + }, + 'x-examples': { + 'Example 1': { + value: { + code: 'error', + message: 'Something bad happened!', + }, + }, + }, + }; + + jest.spyOn(Sampler, 'sample').mockReturnValue({ code: 'generated', message: 'generated' }); + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toHaveLength(1); + expect(result[0].label).toBe('default'); + }); + + it('returns x-examples early when x-stoplight is present', () => { + const schema: JSONSchema7 & { 'x-examples'?: unknown; 'x-stoplight'?: unknown } = { + type: 'object', + properties: { + code: { type: 'string' }, + }, + 'x-stoplight': { id: 'test' }, + 'x-examples': { + 'My Example': { + value: { + code: 'test-code', + }, + }, + }, + }; + + const sampleSpy = jest.spyOn(Sampler, 'sample'); + + const result = generateExamplesFromJsonSchema(schema); + + expect(sampleSpy).not.toHaveBeenCalled(); + expect(result).toHaveLength(1); + expect(result[0].label).toBe('My Example'); + expect(JSON.parse(result[0].data)).toEqual({ code: 'test-code' }); + }); + + it('returns examples array early when x-stoplight is present', () => { + const schema: JSONSchema7 & { 'x-stoplight'?: unknown } = { + type: 'object', + properties: { + name: { type: 'string' }, + }, + examples: [{ name: 'Alice' }], + 'x-stoplight': { id: 'test' }, + }; + + const sampleSpy = jest.spyOn(Sampler, 'sample'); + + const result = generateExamplesFromJsonSchema(schema); + + expect(sampleSpy).not.toHaveBeenCalled(); + expect(result).toHaveLength(1); + expect(result[0].label).toBe('default'); + expect(JSON.parse(result[0].data)).toEqual({ name: 'Alice' }); + }); + + it('generates a default example when schema has no examples', () => { + jest.spyOn(Sampler, 'sample').mockReturnValue({ code: 'string' }); + + const result = generateExamplesFromJsonSchema(modelWithNoExamples); + + expect(result).toHaveLength(1); + expect(result[0].label).toBe('default'); + expect(JSON.parse(result[0].data)).toEqual({ code: 'string' }); + }); + + it('returns empty data when Sampler.sample returns null and no examples exist', () => { + jest.spyOn(Sampler, 'sample').mockReturnValue(null); + + const schema: JSONSchema7 = { + type: 'object', + }; + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toEqual([{ label: 'default', data: '' }]); + }); + + it('handles x-examples without value wrapper', () => { + const schema: JSONSchema7 & { 'x-examples'?: unknown } = { + type: 'object', + properties: { + code: { type: 'string' }, + }, + 'x-examples': { + 'Direct Example': { + code: 'direct-value', + extra: 'field', + }, + }, + }; + + jest.spyOn(Sampler, 'sample').mockReturnValue({ code: 'generated' }); + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toHaveLength(1); + expect(result[0].label).toBe('default'); + }); + + it('skips non-object entries in x-examples', () => { + const schema: JSONSchema7 & { 'x-examples'?: unknown; 'x-stoplight'?: unknown } = { + type: 'object', + properties: { + code: { type: 'string' }, + }, + 'x-stoplight': { id: 'test' }, + 'x-examples': { + 'Valid Example': { + value: { code: 'valid' }, + }, + 'Invalid Example': 'not-an-object', + 'Another Invalid': 42, + }, + }; + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toHaveLength(1); + expect(result[0].label).toBe('Valid Example'); + }); + + it('labels multiple examples in the examples array correctly', () => { + const schema: JSONSchema7 & { 'x-stoplight'?: unknown } = { + type: 'object', + properties: { + name: { type: 'string' }, + }, + examples: [{ name: 'First' }, { name: 'Second' }, { name: 'Third' }], + 'x-stoplight': { id: 'test' }, + }; + + const result = generateExamplesFromJsonSchema(schema); + + expect(result).toHaveLength(3); + expect(result[0].label).toBe('default'); + expect(result[1].label).toBe('example-1'); + expect(result[2].label).toBe('example-2'); + }); + + it('restores original examples on schema after sampling', () => { + const originalExamples = [{ name: 'Alice' }, { name: 'Bob' }]; + const schema: JSONSchema7 = { + type: 'object', + properties: { + name: { type: 'string' }, + }, + examples: [...originalExamples], + }; + + jest.spyOn(Sampler, 'sample').mockReturnValue({ name: 'generated' }); + + generateExamplesFromJsonSchema(schema); + + expect(schema.examples).toEqual(originalExamples); + }); }); diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts index 9603c3146..4d9471759 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts @@ -82,24 +82,39 @@ export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-exampl } } - if (examples.length) { + if (examples.length && 'x-stoplight' in schema) { return examples; } try { + let originalExamples = []; + if (Array.isArray(schema?.examples)) { + originalExamples = JSON.parse(JSON.stringify(schema.examples)); + delete schema.examples; + } const generated = Sampler.sample(schema, { maxSampleDepth: 4, ticks: 6000, }); - return generated !== null - ? [ - { - label: 'default', - data: safeStringify(generated, undefined, 2) ?? '', - }, - ] - : [{ label: 'default', data: '' }]; + let updatedExamples: Example[] = + generated !== null + ? [ + { + label: 'default', + data: safeStringify(generated, undefined, 2) ?? '', + }, + ] + : [{ label: 'default', data: '' }]; + if (originalExamples.length) { + schema.examples = originalExamples; + examples.forEach(item => { + item.data = updatedExamples[0].data; + }); + return examples; + } else { + return updatedExamples; + } } catch (e) { return [{ label: '', data: `Example cannot be created for this schema\n${e}` }]; }