Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ describe('createComponent', () => {
});
});

it('omits viewports when creating a viewport-free component', async () => {
const { viewports: _, ...viewportFreeArgs } = args;
mockComponentCreate.mockResolvedValue(mockComponent);

await createComponentTool(mockConfig)(viewportFreeArgs);

expect(mockComponentCreate.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects writes to a protected environment', async () => {
const protectedConfig = createMockConfig({
protectedEnvironments: ['test-environment'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const CreateComponentToolParams = BaseToolSchema.extend({
description: z.string().describe('Description of the component'),
viewports: z
.array(ViewportSchema)
.optional()
Comment thread
Chaoste marked this conversation as resolved.
.describe('Viewport definitions for the component (may be empty)'),
contentProperties: z
.array(ContentPropertySchema)
Expand Down Expand Up @@ -63,7 +64,7 @@ export function createComponentTool(config: ContentfulConfig) {
const componentData = {
name: args.name,
description: args.description,
viewports: args.viewports,
...(args.viewports !== undefined && { viewports: args.viewports }),
contentProperties: args.contentProperties,
designProperties: args.designProperties,
...(args.componentTree && { componentTree: args.componentTree }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ describe('upsertComponent', () => {
expect(body.dataAssemblies).toEqual(dataAssemblies);
});

it('does not reintroduce viewports from a viewport-free component', async () => {
mockComponentGet.mockResolvedValue({
...mockComponent,
viewports: undefined,
});
mockComponentUpsert.mockResolvedValue(mockComponent);

await upsertComponentTool(mockConfig)({ ...mockArgs, version: 1 });

expect(mockComponentUpsert.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects a stale version', async () => {
mockComponentGet.mockResolvedValue(mockComponent); // sys.version === 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export function upsertComponentTool(config: ContentfulConfig) {
},
name: args.name ?? current.name,
description: args.description ?? current.description,
viewports: args.viewports ?? current.viewports,
...((args.viewports ?? current.viewports) !== undefined && {
viewports: args.viewports ?? current.viewports,
}),
Comment thread
Chaoste marked this conversation as resolved.
Outdated
contentProperties: args.contentProperties ?? current.contentProperties,
designProperties: args.designProperties ?? current.designProperties,
...((args.componentTree ?? current.componentTree)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ describe('createExperienceFragment', () => {
);
});

it('creates a viewport-free experience fragment with flattened design properties', async () => {
const { viewports: _, ...viewportFreeArgs } = baseArgs;
mockExperienceFragmentCreate.mockResolvedValue(mockExperienceFragment);

await createExperienceFragmentTool(mockConfig)({
...viewportFreeArgs,
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});

expect(mockExperienceFragmentCreate.mock.calls[0][1]).toMatchObject({
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});
expect(mockExperienceFragmentCreate.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects creates in a protected environment', async () => {
const tool = createExperienceFragmentTool(
createMockConfig({ protectedEnvironments: ['test-environment'] }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import {
ViewportSchema,
ExperienceMetadataSchema,
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
ExperienceContentBindingsSchema,
ExperienceSlotNodeSchema,
Expand All @@ -26,9 +27,16 @@ export const CreateExperienceFragmentToolParams = BaseToolSchema.extend({
),
viewports: z
.array(ViewportSchema)
.optional()
Comment thread
Chaoste marked this conversation as resolved.
.describe('Viewport definitions (may be empty)'),
designProperties: z
.record(z.string(), DimensionedDesignPropertyValueSchema)
.record(
z.string(),
z.union([
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
]),
)
.describe(
'Design property values keyed by property ID (may be empty object)',
),
Expand Down Expand Up @@ -61,7 +69,7 @@ export function createExperienceFragmentTool(config: ContentfulConfig) {
name: args.name,
description: args.description,
component: args.component,
viewports: args.viewports,
...(args.viewports !== undefined && { viewports: args.viewports }),
designProperties: args.designProperties,
...(args.contentBindings && { contentBindings: args.contentBindings }),
...(args.slots && { slots: args.slots }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ describe('updateExperienceFragment', () => {
);
});

it('preserves flattened design properties without reintroducing viewports', async () => {
mockExperienceFragmentGet.mockResolvedValue({
...mockExperienceFragment,
viewports: undefined,
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});
mockExperienceFragmentUpsert.mockResolvedValue(mockExperienceFragment);

await updateExperienceFragmentTool(mockConfig)({ ...mockArgs, version: 1 });

const [, body] = mockExperienceFragmentUpsert.mock.calls[0];
Comment thread
Chaoste marked this conversation as resolved.
expect(body).not.toHaveProperty('viewports');
expect(body.designProperties).toEqual({
color: { type: 'ManualDesignValue', value: 'red' },
});
});

it('rejects a stale version', async () => {
mockExperienceFragmentGet.mockResolvedValue(mockExperienceFragment); // sys.version === 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import {
ViewportSchema,
ExperienceMetadataSchema,
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
ExperienceContentBindingsSchema,
ExperienceSlotNodeSchema,
Expand Down Expand Up @@ -39,7 +40,13 @@ export const UpdateExperienceFragmentToolParams = BaseToolSchema.extend({
.optional()
.describe('Viewport definitions; replaces existing viewports if provided'),
designProperties: z
.record(z.string(), DimensionedDesignPropertyValueSchema)
.record(
z.string(),
z.union([
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
]),
)
.optional()
.describe('Design property values; replaces existing if provided'),
contentBindings: ExperienceContentBindingsSchema.optional().describe(
Expand Down Expand Up @@ -97,7 +104,9 @@ export function updateExperienceFragmentTool(config: ContentfulConfig) {
},
name: args.name ?? current.name,
description: args.description ?? current.description,
viewports: args.viewports ?? current.viewports,
...((args.viewports ?? current.viewports) !== undefined && {
viewports: args.viewports ?? current.viewports,
}),
Comment thread
Chaoste marked this conversation as resolved.
Outdated
designProperties: args.designProperties ?? current.designProperties,
...((args.contentBindings ?? current.contentBindings)
? { contentBindings: args.contentBindings ?? current.contentBindings }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ describe('createExperienceTemplate', () => {
);
});

it('omits viewports when creating a viewport-free experience template', async () => {
const { viewports: _, ...viewportFreeArgs } = createArgs;
mockExperienceTemplateCreate.mockResolvedValue(mockExperienceTemplate);

await createExperienceTemplateTool(mockConfig)(viewportFreeArgs);

expect(mockExperienceTemplateCreate.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects writes to a protected environment', async () => {
const tool = createExperienceTemplateTool(
createMockConfig({ protectedEnvironments: ['test-environment'] }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const CreateExperienceTemplateToolParams = BaseToolSchema.extend({
description: z.string().describe('Description of the experience template'),
viewports: z
.array(ViewportSchema)
.optional()
Comment thread
Chaoste marked this conversation as resolved.
.describe(
'Viewport definitions for the experience template (may be empty)',
),
Expand Down Expand Up @@ -61,7 +62,7 @@ export function createExperienceTemplateTool(config: ContentfulConfig) {
{
name: args.name,
description: args.description,
viewports: args.viewports,
...(args.viewports !== undefined && { viewports: args.viewports }),
contentProperties: args.contentProperties,
designProperties: args.designProperties,
...(args.componentTree && { componentTree: args.componentTree }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ describe('upsertExperienceTemplate', () => {
expect(body.dataAssemblies).toEqual(dataAssemblies);
});

it('does not reintroduce viewports from a viewport-free experience template', async () => {
mockExperienceTemplateGet.mockResolvedValue({
...mockExperienceTemplate,
viewports: undefined,
});
mockExperienceTemplateUpsert.mockResolvedValue(mockExperienceTemplate);

await upsertExperienceTemplateTool(mockConfig)({ ...mockArgs, version: 1 });

expect(mockExperienceTemplateUpsert.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects a stale version', async () => {
mockExperienceTemplateGet.mockResolvedValue(mockExperienceTemplate); // sys.version === 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ export function upsertExperienceTemplateTool(config: ContentfulConfig) {
},
name: args.name ?? current.name,
description: args.description ?? current.description,
viewports: args.viewports ?? current.viewports,
...((args.viewports ?? current.viewports) !== undefined && {
viewports: args.viewports ?? current.viewports,
}),
Comment thread
Chaoste marked this conversation as resolved.
Outdated
contentProperties: args.contentProperties ?? current.contentProperties,
designProperties: args.designProperties ?? current.designProperties,
...((args.componentTree ?? current.componentTree)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ describe('createExperience', () => {
expect(result.content[0].text).toContain('Experience created successfully');
});

it('creates a viewport-free experience with flattened design properties', async () => {
const { viewports: _, ...viewportFreeArgs } = createArgs;
mockExperienceCreate.mockResolvedValue(mockExperience);

await createExperienceTool(mockConfig)({
...viewportFreeArgs,
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});

expect(mockExperienceCreate.mock.calls[0][1]).toMatchObject({
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});
expect(mockExperienceCreate.mock.calls[0][1]).not.toHaveProperty(
'viewports',
);
});

it('rejects writes to a protected environment', async () => {
const tool = createExperienceTool(
createMockConfig({ protectedEnvironments: ['test-environment'] }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import {
ViewportSchema,
ExperienceMetadataSchema,
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
ExperienceContentBindingsSchema,
ExperienceSlotNodeSchema,
Expand All @@ -26,9 +27,16 @@ export const CreateExperienceToolParams = BaseToolSchema.extend({
),
viewports: z
.array(ViewportSchema)
.optional()
.describe('Viewport definitions for the experience (may be empty)'),
designProperties: z
.record(z.string(), DimensionedDesignPropertyValueSchema)
.record(
z.string(),
z.union([
DesignPropertyValueSchema,
DimensionedDesignPropertyValueSchema,
]),
)
Comment thread
Chaoste marked this conversation as resolved.
.describe(
'Design property values keyed by property ID. Each value is a dimensioned map ' +
'(viewport ID → design value). May be an empty object.',
Expand Down Expand Up @@ -64,7 +72,7 @@ export function createExperienceTool(config: ContentfulConfig) {
name: args.name,
description: args.description,
experienceTemplate: args.experienceTemplate,
viewports: args.viewports,
...(args.viewports !== undefined && { viewports: args.viewports }),
designProperties: args.designProperties,
...(args.contentBindings && { contentBindings: args.contentBindings }),
...(args.slots && { slots: args.slots }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ describe('upsertExperience', () => {

it('reads the current experience before updating (read-before-write)', async () => {
mockExperienceGet.mockResolvedValue(mockExperience);
mockExperienceUpsert.mockResolvedValue({ ...mockExperience, name: 'Renamed' });
mockExperienceUpsert.mockResolvedValue({
...mockExperience,
name: 'Renamed',
});

const tool = upsertExperienceTool(mockConfig);
const result = await tool({ ...mockArgs, version: 1, name: 'Renamed' });
Expand Down Expand Up @@ -43,7 +46,9 @@ describe('upsertExperience', () => {
it('preserves unspecified fields from the existing experience', async () => {
mockExperienceGet.mockResolvedValue({
...mockExperience,
designProperties: { color: { _: { type: 'ManualDesignValue', value: 'red' } } },
designProperties: {
color: { _: { type: 'ManualDesignValue', value: 'red' } },
},
});
mockExperienceUpsert.mockResolvedValue(mockExperience);

Expand All @@ -56,6 +61,25 @@ describe('upsertExperience', () => {
});
});

it('preserves flattened design properties without reintroducing viewports', async () => {
mockExperienceGet.mockResolvedValue({
...mockExperience,
viewports: undefined,
designProperties: {
color: { type: 'ManualDesignValue', value: 'red' },
},
});
mockExperienceUpsert.mockResolvedValue(mockExperience);

await upsertExperienceTool(mockConfig)({ ...mockArgs, version: 1 });

const [, body] = mockExperienceUpsert.mock.calls[0];
expect(body).not.toHaveProperty('viewports');
expect(body.designProperties).toEqual({
color: { type: 'ManualDesignValue', value: 'red' },
});
});

it('rejects a stale version', async () => {
mockExperienceGet.mockResolvedValue(mockExperience); // sys.version === 1

Expand Down
Loading
Loading