diff --git a/packages/api-client/src/controllers/integration.ts b/packages/api-client/src/controllers/integration.ts index aad60816..621d427c 100644 --- a/packages/api-client/src/controllers/integration.ts +++ b/packages/api-client/src/controllers/integration.ts @@ -9,7 +9,7 @@ import { GetIntegrationResponse, UpdateIntegrationRequest, UpdateIntegrationResponse -} from '@api-client/types/integration.types' +} from '@keyshade/schema' import { APIClient } from '@api-client/core/client' import { ClientResponse } from '@keyshade/schema' import { parseResponse } from '@api-client/core/response-parser' diff --git a/packages/api-client/src/controllers/user.ts b/packages/api-client/src/controllers/user.ts index 3b8e5d32..c20ff87e 100644 --- a/packages/api-client/src/controllers/user.ts +++ b/packages/api-client/src/controllers/user.ts @@ -45,7 +45,7 @@ export default class UserController { headers?: Record ): Promise> { const response = await this.apiClient.post( - `./api/user/validate-email-change-otp?otp=${request.otp}`, + `/api/user/validate-email-change-otp?otp=${request.otp}`, request, headers ) diff --git a/packages/api-client/src/types/integration.types.d.ts b/packages/api-client/src/types/integration.types.d.ts deleted file mode 100644 index 3628c47a..00000000 --- a/packages/api-client/src/types/integration.types.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { PageRequest, PageResponse } from '@keyshade/schema' - -export enum IntegrationType { - DISCORD, - SLACK, - GITHUB, - GITLAB -} - -export enum EventType { - INVITED_TO_WORKSPACE, - REMOVED_FROM_WORKSPACE, - ACCEPTED_INVITATION, - DECLINED_INVITATION, - CANCELLED_INVITATION, - LEFT_WORKSPACE, - WORKSPACE_MEMBERSHIP_UPDATED, - WORKSPACE_UPDATED, - WORKSPACE_CREATED, - WORKSPACE_ROLE_CREATED, - WORKSPACE_ROLE_UPDATED, - WORKSPACE_ROLE_DELETED, - PROJECT_CREATED, - PROJECT_UPDATED, - PROJECT_DELETED, - SECRET_UPDATED, - SECRET_DELETED, - SECRET_ADDED, - VARIABLE_UPDATED, - VARIABLE_DELETED, - VARIABLE_ADDED, - ENVIRONMENT_UPDATED, - ENVIRONMENT_DELETED, - ENVIRONMENT_ADDED, - INTEGRATION_ADDED, - INTEGRATION_UPDATED, - INTEGRATION_DELETED -} - -export interface Integration { - id: string - name: string - slug: string - metadata: Record - createdAt: string - updatedAt: string - type: IntegrationType - notifyOn: EventType[] - workspaceId: string - projectId: string - environmentId: string -} - -export interface CreateIntegrationRequest { - workspaceSlug?: string - projectSlug?: string - name: string - type: string - notifyOn: [string] - metadata: Record - environmentSlug: string -} - -export interface CreateIntegrationResponse extends Integration {} - -export interface UpdateIntegrationRequest - extends Partial> { - integrationSlug: string -} - -export interface UpdateIntegrationResponse extends Integration {} - -export interface DeleteIntegrationResponse {} - -export interface DeleteIntegrationRequest { - integrationSlug: string -} - -export interface GetIntegrationRequest { - integrationSlug: string -} - -export interface GetIntegrationResponse extends Integration {} - -export interface GetAllIntegrationRequest extends PageRequest { - workspaceSlug: string -} - -export interface GetAllIntegrationResponse extends PageResponse {} diff --git a/packages/schema/src/index.types.ts b/packages/schema/src/index.types.ts index 73ffeeae..48023d85 100644 --- a/packages/schema/src/index.types.ts +++ b/packages/schema/src/index.types.ts @@ -1,6 +1,5 @@ import { z } from 'zod' import { CreateApiKeySchema, UpdateApiKeySchema } from './api-key' -import { CreateIntegrationSchema, UpdateIntegrationSchema } from './integration' import { CreateWorkspaceRoleSchema, UpdateWorkspaceRoleSchema @@ -15,12 +14,10 @@ export * from './user/index.types' export * from './workspace/index.types' export * from './variable/index.types' export * from './event/index.types' +export * from './integration/index.types' export type TCreateApiKey = z.infer export type TUpdateApiKey = z.infer -export type TCreateIntegration = z.infer -export type TUpdateIntegration = z.infer - export type TCreateWorkspaceRole = z.infer export type TUpdateWorkspaceRole = z.infer diff --git a/packages/schema/src/integration.ts b/packages/schema/src/integration.ts deleted file mode 100644 index b3af0c0e..00000000 --- a/packages/schema/src/integration.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { eventTypeEnum, integrationTypeEnum } from '@/enums' - -export const CreateIntegrationSchema = z.object({ - name: z.string(), - type: integrationTypeEnum, - metadata: z.record(z.string(), z.any()), - notifyOn: z.array(eventTypeEnum).optional(), - environmentId: z.string().optional(), - projectId: z.string().optional() -}) - -export const UpdateIntegrationSchema = CreateIntegrationSchema.partial() diff --git a/packages/schema/src/integration/index.ts b/packages/schema/src/integration/index.ts new file mode 100644 index 00000000..33c388a4 --- /dev/null +++ b/packages/schema/src/integration/index.ts @@ -0,0 +1,64 @@ +import { z } from 'zod' +import { PageRequestSchema, PageResponseSchema } from '@/pagination' +import { eventTypeEnum, integrationTypeEnum } from '@/enums' +import { WorkspaceSchema } from '@/workspace' +import { BaseProjectSchema } from '@/project' +import { EnvironmentSchema } from '@/environment' + +export const IntegrationSchema = z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + metadata: z.record(z.string()), + createdAt: z.string(), + updatedAt: z.string(), + type: integrationTypeEnum, + notifyOn: z.array(eventTypeEnum), + workspaceId: WorkspaceSchema.shape.id, + projectId: BaseProjectSchema.shape.id, + environmentId: EnvironmentSchema.shape.id +}) + +export const CreateIntegrationRequestSchema = z.object({ + workspaceSlug: WorkspaceSchema.shape.slug, + projectSlug: BaseProjectSchema.shape.slug.optional(), + name: z.string(), + type: IntegrationSchema.shape.type, + notifyOn: IntegrationSchema.shape.notifyOn.min(1).optional(), + metadata: z.record(z.string()), + environmentSlug: EnvironmentSchema.shape.slug.optional() +}) + +export const CreateIntegrationResponseSchema = IntegrationSchema + +export const UpdateIntegrationRequestSchema = + CreateIntegrationRequestSchema.partial() + .omit({ + workspaceSlug: true + }) + .extend({ + integrationSlug: IntegrationSchema.shape.slug + }) + +export const UpdateIntegrationResponseSchema = IntegrationSchema + +export const DeleteIntegrationRequestSchema = z.object({ + integrationSlug: IntegrationSchema.shape.slug +}) + +export const DeleteIntegrationResponseSchema = z.void() + +export const GetIntegrationRequestSchema = z.object({ + integrationSlug: IntegrationSchema.shape.slug +}) + +export const GetIntegrationResponseSchema = IntegrationSchema.extend({ + workspace: WorkspaceSchema +}) + +export const GetAllIntegrationRequestSchema = PageRequestSchema.extend({ + workspaceSlug: WorkspaceSchema.shape.slug +}) + +export const GetAllIntegrationResponseSchema = + PageResponseSchema(IntegrationSchema) diff --git a/packages/schema/src/integration/index.types.ts b/packages/schema/src/integration/index.types.ts new file mode 100644 index 00000000..9998a0aa --- /dev/null +++ b/packages/schema/src/integration/index.types.ts @@ -0,0 +1,54 @@ +import { + IntegrationSchema, + CreateIntegrationRequestSchema, + CreateIntegrationResponseSchema, + UpdateIntegrationRequestSchema, + UpdateIntegrationResponseSchema, + DeleteIntegrationRequestSchema, + DeleteIntegrationResponseSchema, + GetIntegrationRequestSchema, + GetIntegrationResponseSchema, + GetAllIntegrationRequestSchema, + GetAllIntegrationResponseSchema +} from '.' +import { z } from 'zod' + +export type Integration = z.infer + +export type CreateIntegrationRequest = z.infer< + typeof CreateIntegrationRequestSchema +> + +export type CreateIntegrationResponse = z.infer< + typeof CreateIntegrationResponseSchema +> + +export type UpdateIntegrationRequest = z.infer< + typeof UpdateIntegrationRequestSchema +> + +export type UpdateIntegrationResponse = z.infer< + typeof UpdateIntegrationResponseSchema +> + +export type DeleteIntegrationRequest = z.infer< + typeof DeleteIntegrationRequestSchema +> + +export type DeleteIntegrationResponse = z.infer< + typeof DeleteIntegrationResponseSchema +> + +export type GetIntegrationRequest = z.infer + +export type GetIntegrationResponse = z.infer< + typeof GetIntegrationResponseSchema +> + +export type GetAllIntegrationRequest = z.infer< + typeof GetAllIntegrationRequestSchema +> + +export type GetAllIntegrationResponse = z.infer< + typeof GetAllIntegrationResponseSchema +> diff --git a/packages/schema/src/project/index.ts b/packages/schema/src/project/index.ts index 89969da0..6b71f8ef 100644 --- a/packages/schema/src/project/index.ts +++ b/packages/schema/src/project/index.ts @@ -3,28 +3,28 @@ import { PageRequestSchema, PageResponseSchema } from '@/pagination' import { CreateEnvironmentRequestSchema } from '@/environment' import { projectAccessLevelEnum } from '@/enums' -export const ProjectSchema = z - .object({ - id: z.string(), - name: z.string(), - slug: z.string(), - description: z.string(), - createdAt: z.string(), - updatedAt: z.string(), - publicKey: z.string(), - privateKey: z.string(), - storePrivateKey: z.boolean(), - isDisabled: z.boolean(), - accessLevel: projectAccessLevelEnum, - pendingCreation: z.boolean(), - isForked: z.boolean(), - lastUpdatedById: z.string(), - workspaceId: z.string(), - forkedFromId: z.string().nullable() - }) - .refine((obj) => - obj.isForked ? obj.forkedFromId !== null : obj.forkedFromId === null - ) +export const BaseProjectSchema = z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + description: z.string(), + createdAt: z.string(), + updatedAt: z.string(), + publicKey: z.string(), + privateKey: z.string(), + storePrivateKey: z.boolean(), + isDisabled: z.boolean(), + accessLevel: z.string(), + pendingCreation: z.boolean(), + isForked: z.boolean(), + lastUpdatedById: z.string(), + workspaceId: z.string(), + forkedFromId: z.string().nullable() +}) + +export const ProjectSchema = BaseProjectSchema.refine((obj) => + obj.isForked ? obj.forkedFromId !== null : obj.forkedFromId === null +) export const CreateProjectRequestSchema = z.object({ name: z.string(), diff --git a/packages/schema/tests/integration.spec.ts b/packages/schema/tests/integration.spec.ts index 9d47730b..2f2a2906 100644 --- a/packages/schema/tests/integration.spec.ts +++ b/packages/schema/tests/integration.spec.ts @@ -1,20 +1,90 @@ -import { CreateIntegrationSchema } from '@/integration' +import { + IntegrationSchema, + CreateIntegrationRequestSchema, + CreateIntegrationResponseSchema, + UpdateIntegrationRequestSchema, + UpdateIntegrationResponseSchema, + DeleteIntegrationRequestSchema, + DeleteIntegrationResponseSchema, + GetIntegrationRequestSchema, + GetIntegrationResponseSchema, + GetAllIntegrationRequestSchema, + GetAllIntegrationResponseSchema +} from '@/integration' import { eventTypeEnum, integrationTypeEnum } from '@/enums' describe('Integration Schema Tests', () => { + // Tests for IntegrationSchema + it('should validate a valid IntegrationSchema', () => { + const result = IntegrationSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.DISCORD, + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(true) + }) + + it('should validate if empty notifyOn array is provided for IntegrationSchema', () => { + const result = IntegrationSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.DISCORD, + notifyOn: [], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid IntegrationSchema', () => { + const result = IntegrationSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: 'INVALID_TYPE', // Invalid type + notifyOn: ['INVALID_EVENT'], // Invalid event + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(2) + }) + + // Tests for CreateIntegrationRequestSchema it('should validate if proper input is specified', () => { - const result = CreateIntegrationSchema.safeParse({ + const result = CreateIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', name: 'Integration Test', type: integrationTypeEnum.Enum.DISCORD, metadata: { key: 'value' }, - notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION] + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + projectSlug: 'project123', + environmentSlug: 'environment123' }) expect(result.success).toBe(true) }) it('should validate if only required fields are specified', () => { - const result = CreateIntegrationSchema.safeParse({ + const result = CreateIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', name: 'Integration Test', type: integrationTypeEnum.Enum.DISCORD, metadata: { key: 'value' } @@ -24,7 +94,8 @@ describe('Integration Schema Tests', () => { }) it('should not validate if invalid values are specified', () => { - const result = CreateIntegrationSchema.safeParse({ + const result = CreateIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', name: 123, type: integrationTypeEnum.Enum.DISCORD, metadata: 'invalid metadata' @@ -35,16 +106,17 @@ describe('Integration Schema Tests', () => { }) it('should not validate if required values are not specified', () => { - const result = CreateIntegrationSchema.safeParse({ + const result = CreateIntegrationRequestSchema.safeParse({ metadata: { key: 'value' } }) expect(result.success).toBe(false) - expect(result.error?.issues).toHaveLength(2) + expect(result.error?.issues).toHaveLength(3) }) it('should validate with optional fields omitted', () => { - const result = CreateIntegrationSchema.safeParse({ + const result = CreateIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', name: 'Integration Test', type: integrationTypeEnum.Enum.DISCORD, metadata: { key: 'value' } @@ -53,14 +125,279 @@ describe('Integration Schema Tests', () => { expect(result.success).toBe(true) }) - it('should validate if empty notifyOn array is provided', () => { - const result = CreateIntegrationSchema.safeParse({ + it('should not validate if empty notifyOn array is provided', () => { + const result = CreateIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', name: 'Integration Test', type: integrationTypeEnum.Enum.DISCORD, metadata: { key: 'value' }, notifyOn: [] }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(1) + }) + + // Tests for CreateIntegrationResponseSchema + it('should validate a valid CreateIntegrationResponseSchema', () => { + const result = CreateIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.DISCORD, + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) expect(result.success).toBe(true) }) + + it('should not validate an invalid CreateIntegrationResponseSchema', () => { + const result = CreateIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: 'INVALID_TYPE', // Invalid type + notifyOn: ['INVALID_EVENT'], // Invalid event + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(2) + }) + + // Tests for UpdateIntegrationRequestSchema + it('should validate a valid UpdateIntegrationRequestSchema', () => { + const result = UpdateIntegrationRequestSchema.safeParse({ + integrationSlug: 'integration-slug', + name: 'Updated Integration Name', + notifyOn: [eventTypeEnum.Enum.PROJECT_DELETED], + metadata: { key: 'new-value' } + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid UpdateIntegrationRequestSchema', () => { + const result = UpdateIntegrationRequestSchema.safeParse({ + integrationSlug: 123, // Should be a string + name: 'Updated Integration Name', + notifyOn: ['EVENT_A'], // Invalid event + metadata: { key: 'new-value' } + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(2) + }) + + // Tests for UpdateIntegrationResponseSchema + it('should validate a valid UpdateIntegrationResponseSchema', () => { + const result = UpdateIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.DISCORD, + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid UpdateIntegrationResponseSchema', () => { + const result = UpdateIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: 'INVALID_TYPE', // Invalid type + notifyOn: ['INVALID_EVENT'], // Invalid event + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(2) + }) + + // Tests for DeleteIntegrationRequestSchema + it('should validate a valid DeleteIntegrationRequestSchema', () => { + const result = DeleteIntegrationRequestSchema.safeParse({ + integrationSlug: 'integration-slug' + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid DeleteIntegrationRequestSchema', () => { + const result = DeleteIntegrationRequestSchema.safeParse({ + integrationSlug: 123 // Should be a string + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(1) + }) + + // Tests for DeleteIntegrationResponseSchema + it('should validate a valid DeleteIntegrationResponseSchema', () => { + const result = DeleteIntegrationResponseSchema.safeParse(undefined) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid DeleteIntegrationResponseSchema', () => { + const result = DeleteIntegrationResponseSchema.safeParse({ + unexpectedField: 'value' + }) + expect(result.success).toBe(false) + }) + + // Tests for GetIntegrationRequestSchema + it('should validate a valid GetIntegrationRequestSchema', () => { + const result = GetIntegrationRequestSchema.safeParse({ + integrationSlug: 'integration-slug' + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetIntegrationRequestSchema', () => { + const result = GetIntegrationRequestSchema.safeParse({ + integrationSlug: 123 // Should be a string + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(1) + }) + + // Tests for GetIntegrationResponseSchema + it('should validate a valid GetIntegrationResponseSchema', () => { + const result = GetIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.GITHUB, + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123', + workspace: { + id: 'workspace123', + name: 'Workspace Name', + slug: 'workspace-slug', + icon: 'workspace-icon', + isFreeTier: true, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + ownerId: 'owner123', + isDefault: false, + lastUpdatedBy: 'user123' + } + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetIntegrationResponseSchema', () => { + const result = GetIntegrationResponseSchema.safeParse({ + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: 'INVALID_TYPE', // Invalid type + notifyOn: ['INVALID_EVENT'], // Invalid event + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + // Missing workspace field + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(3) + }) + + // Tests for GetAllIntegrationRequestSchema + it('should validate a valid GetAllIntegrationRequestSchema', () => { + const result = GetAllIntegrationRequestSchema.safeParse({ + workspaceSlug: 'workspace123', + page: 1, + limit: 10 + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetAllIntegrationRequestSchema', () => { + const result = GetAllIntegrationRequestSchema.safeParse({ + workspaceSlug: 123, // Should be a string + page: 1 + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(1) + }) + + // Tests for GetAllIntegrationResponseSchema + it('should validate a valid GetAllIntegrationResponseSchema', () => { + const result = GetAllIntegrationResponseSchema.safeParse({ + items: [ + { + id: 'integration123', + name: 'Integration Name', + slug: 'integration-slug', + metadata: { key: 'value' }, + createdAt: '2024-10-01T00:00:00Z', + updatedAt: '2024-10-01T00:00:00Z', + type: integrationTypeEnum.Enum.DISCORD, + notifyOn: [eventTypeEnum.Enum.ACCEPTED_INVITATION], + workspaceId: 'workspace123', + projectId: 'project123', + environmentId: 'environment123' + } + ], + metadata: { + page: 1, + perPage: 10, + pageCount: 1, + totalCount: 1, + links: { + self: 'http://example.com/page/1', + first: 'http://example.com/page/1', + previous: null, + next: null, + last: 'http://example.com/page/1' + } + } + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetAllIntegrationResponseSchema', () => { + const result = GetAllIntegrationResponseSchema.safeParse({ + items: 'not-an-array', // Should be an array + metadata: { + page: 1, + perPage: 10, + pageCount: 1, + totalCount: 1, + links: { + self: 'http://example.com/page/1', + first: 'http://example.com/page/1', + previous: null, + next: null, + last: 'http://example.com/page/1' + } + } + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(1) + }) })