diff --git a/src/cli/commands/deploy/__tests__/deploy.test.ts b/src/cli/commands/deploy/__tests__/deploy.test.ts index 5545fee2a..ea05fe684 100644 --- a/src/cli/commands/deploy/__tests__/deploy.test.ts +++ b/src/cli/commands/deploy/__tests__/deploy.test.ts @@ -6,19 +6,14 @@ import { join } from 'node:path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; describe('deploy --help', () => { - it('shows verbose option', async () => { - const result = await runCLI(['deploy', '--help'], process.cwd()); - expect(result.exitCode).toBe(0); - expect(result.stdout.includes('--verbose'), 'Should show --verbose option').toBeTruthy(); - expect(result.stdout.includes('resource-level'), 'Should describe resource-level events').toBeTruthy(); - }); - it('shows all deploy options', async () => { const result = await runCLI(['deploy', '--help'], process.cwd()); + expect(result.exitCode).toBe(0); expect(result.stdout.includes('--yes')).toBeTruthy(); expect(result.stdout.includes('--verbose')).toBeTruthy(); expect(result.stdout.includes('--json')).toBeTruthy(); expect(result.stdout.includes('--dry-run')).toBeTruthy(); + expect(result.stdout.includes('resource-level'), 'Should describe resource-level events').toBeTruthy(); }); }); diff --git a/src/cli/commands/dev/__tests__/dev.test.ts b/src/cli/commands/dev/__tests__/dev.test.ts index 3947f6784..5b86e647b 100644 --- a/src/cli/commands/dev/__tests__/dev.test.ts +++ b/src/cli/commands/dev/__tests__/dev.test.ts @@ -74,12 +74,5 @@ describe('dev command', () => { expect(result.exitCode).toBe(1); }); - - it('stream flag is documented in help', async () => { - const result = await runCLI(['dev', '--help'], process.cwd()); - - expect(result.exitCode).toBe(0); - expect(result.stdout.includes('--stream'), 'Should show --stream option').toBeTruthy(); - }); }); }); diff --git a/src/cli/operations/identity/__tests__/credential-ops.test.ts b/src/cli/operations/identity/__tests__/credential-ops.test.ts index 3913f54ac..32568765b 100644 --- a/src/cli/operations/identity/__tests__/credential-ops.test.ts +++ b/src/cli/operations/identity/__tests__/credential-ops.test.ts @@ -147,20 +147,3 @@ describe('resolveCredentialStrategy', () => { expect(result.isAgentScoped).toBe(true); }); }); - -// TODO: OAuth credential creation needs to be added to CredentialPrimitive. -// These tests were ported from main's create-identity.ts OAuth support. -// Once CredentialPrimitive.addOAuth() is implemented, convert these to use primitive.addOAuth(). -describe('createCredential OAuth', () => { - afterEach(() => vi.clearAllMocks()); - - it.todo('creates OAuth credential and writes to project'); - - it.todo('writes CLIENT_ID and CLIENT_SECRET to env'); - - it.todo('uppercases name in env var keys'); - - it.todo('throws when OAuth credential already exists'); - - it.todo('includes scopes when provided'); -}); diff --git a/src/schema/__tests__/constants.test.ts b/src/schema/__tests__/constants.test.ts index 546770b6b..2d8bd3bc9 100644 --- a/src/schema/__tests__/constants.test.ts +++ b/src/schema/__tests__/constants.test.ts @@ -39,72 +39,45 @@ describe('matchEnumValue', () => { }); describe('SDKFrameworkSchema', () => { - it.each(['Strands', 'LangChain_LangGraph', 'GoogleADK', 'OpenAIAgents'])('accepts "%s"', framework => { - expect(SDKFrameworkSchema.safeParse(framework).success).toBe(true); - }); - - it('rejects invalid framework', () => { + it('accepts valid frameworks and rejects invalid', () => { + expect(SDKFrameworkSchema.safeParse('Strands').success).toBe(true); + expect(SDKFrameworkSchema.safeParse('OpenAIAgents').success).toBe(true); expect(SDKFrameworkSchema.safeParse('AutoGen').success).toBe(false); expect(SDKFrameworkSchema.safeParse('strands').success).toBe(false); // case-sensitive }); }); describe('ModelProviderSchema', () => { - it.each(['Bedrock', 'Gemini', 'OpenAI', 'Anthropic'])('accepts "%s"', provider => { - expect(ModelProviderSchema.safeParse(provider).success).toBe(true); - }); - - it('rejects invalid provider', () => { + it('accepts valid providers and rejects invalid', () => { + expect(ModelProviderSchema.safeParse('Bedrock').success).toBe(true); + expect(ModelProviderSchema.safeParse('Anthropic').success).toBe(true); expect(ModelProviderSchema.safeParse('Azure').success).toBe(false); }); }); -describe('PythonRuntimeSchema', () => { - it.each(['PYTHON_3_10', 'PYTHON_3_11', 'PYTHON_3_12', 'PYTHON_3_13', 'PYTHON_3_14'])('accepts "%s"', version => { - expect(PythonRuntimeSchema.safeParse(version).success).toBe(true); +describe('RuntimeVersionSchemas', () => { + it('accepts valid Python and Node versions', () => { + expect(PythonRuntimeSchema.safeParse('PYTHON_3_10').success).toBe(true); + expect(PythonRuntimeSchema.safeParse('PYTHON_3_14').success).toBe(true); + expect(NodeRuntimeSchema.safeParse('NODE_18').success).toBe(true); + expect(NodeRuntimeSchema.safeParse('NODE_22').success).toBe(true); + expect(RuntimeVersionSchema.safeParse('PYTHON_3_12').success).toBe(true); + expect(RuntimeVersionSchema.safeParse('NODE_20').success).toBe(true); }); - it('rejects unsupported versions', () => { + it('rejects invalid versions', () => { expect(PythonRuntimeSchema.safeParse('PYTHON_3_9').success).toBe(false); expect(PythonRuntimeSchema.safeParse('PYTHON_3_15').success).toBe(false); - }); -}); - -describe('NodeRuntimeSchema', () => { - it.each(['NODE_18', 'NODE_20', 'NODE_22'])('accepts "%s"', version => { - expect(NodeRuntimeSchema.safeParse(version).success).toBe(true); - }); - - it('rejects unsupported versions', () => { expect(NodeRuntimeSchema.safeParse('NODE_16').success).toBe(false); expect(NodeRuntimeSchema.safeParse('NODE_24').success).toBe(false); - }); -}); - -describe('RuntimeVersionSchema', () => { - it('accepts Python versions', () => { - expect(RuntimeVersionSchema.safeParse('PYTHON_3_12').success).toBe(true); - }); - - it('accepts Node versions', () => { - expect(RuntimeVersionSchema.safeParse('NODE_20').success).toBe(true); - }); - - it('rejects invalid versions', () => { expect(RuntimeVersionSchema.safeParse('RUBY_3_0').success).toBe(false); }); }); describe('NetworkModeSchema', () => { - it('accepts PUBLIC', () => { + it('accepts valid modes and rejects invalid', () => { expect(NetworkModeSchema.safeParse('PUBLIC').success).toBe(true); - }); - - it('accepts VPC', () => { expect(NetworkModeSchema.safeParse('VPC').success).toBe(true); - }); - - it('rejects other modes', () => { expect(NetworkModeSchema.safeParse('PRIVATE').success).toBe(false); }); }); diff --git a/src/schema/schemas/__tests__/agent-env.test.ts b/src/schema/schemas/__tests__/agent-env.test.ts index 1b8d1b668..b5b0e55a2 100644 --- a/src/schema/schemas/__tests__/agent-env.test.ts +++ b/src/schema/schemas/__tests__/agent-env.test.ts @@ -15,72 +15,41 @@ import { import { describe, expect, it } from 'vitest'; describe('AgentNameSchema', () => { - it.each(['Agent1', 'myAgent', 'A', 'agent_with_underscores', 'a' + '0'.repeat(47)])( - 'accepts valid name "%s"', - name => { - expect(AgentNameSchema.safeParse(name).success).toBe(true); - } - ); - - it('rejects empty string', () => { - expect(AgentNameSchema.safeParse('').success).toBe(false); + it('accepts valid names', () => { + expect(AgentNameSchema.safeParse('Agent1').success).toBe(true); + expect(AgentNameSchema.safeParse('A').success).toBe(true); + expect(AgentNameSchema.safeParse('agent_with_underscores').success).toBe(true); }); - it('rejects name starting with digit', () => { + it('rejects invalid names', () => { + expect(AgentNameSchema.safeParse('').success).toBe(false); expect(AgentNameSchema.safeParse('1Agent').success).toBe(false); - }); - - it('rejects name with hyphens', () => { expect(AgentNameSchema.safeParse('my-agent').success).toBe(false); }); - it('rejects name exceeding 48 chars', () => { - const name = 'A' + 'b'.repeat(48); - expect(name).toHaveLength(49); - expect(AgentNameSchema.safeParse(name).success).toBe(false); - }); - - it('accepts 48-char name (max)', () => { - const name = 'A' + 'b'.repeat(47); - expect(name).toHaveLength(48); - expect(AgentNameSchema.safeParse(name).success).toBe(true); + it('enforces 48-char boundary', () => { + expect(AgentNameSchema.safeParse('A' + 'b'.repeat(47)).success).toBe(true); + expect(AgentNameSchema.safeParse('A' + 'b'.repeat(48)).success).toBe(false); }); }); describe('EnvVarNameSchema', () => { - it.each(['MY_VAR', '_private', 'UPPER123', 'a', '_'])('accepts valid env var name "%s"', name => { - expect(EnvVarNameSchema.safeParse(name).success).toBe(true); - }); - - it('rejects name starting with digit', () => { + it('accepts valid env var names and rejects invalid', () => { + expect(EnvVarNameSchema.safeParse('MY_VAR').success).toBe(true); + expect(EnvVarNameSchema.safeParse('_private').success).toBe(true); expect(EnvVarNameSchema.safeParse('1VAR').success).toBe(false); - }); - - it('rejects name with hyphens', () => { expect(EnvVarNameSchema.safeParse('MY-VAR').success).toBe(false); - }); - - it('rejects empty string', () => { expect(EnvVarNameSchema.safeParse('').success).toBe(false); }); }); describe('GatewayNameSchema', () => { - it.each(['gateway1', 'my-gateway', 'MyGateway', 'a'])('accepts valid gateway name "%s"', name => { - expect(GatewayNameSchema.safeParse(name).success).toBe(true); - }); - - it('rejects empty string', () => { + it('accepts valid names and rejects invalid', () => { + expect(GatewayNameSchema.safeParse('gateway1').success).toBe(true); + expect(GatewayNameSchema.safeParse('my-gateway').success).toBe(true); expect(GatewayNameSchema.safeParse('').success).toBe(false); - }); - - it('rejects name with underscores', () => { expect(GatewayNameSchema.safeParse('my_gateway').success).toBe(false); - }); - - it('rejects name exceeding 100 chars', () => { - const name = 'a'.repeat(101); - expect(GatewayNameSchema.safeParse(name).success).toBe(false); + expect(GatewayNameSchema.safeParse('a'.repeat(101)).success).toBe(false); }); }); @@ -288,9 +257,10 @@ describe('AgentEnvSpecSchema', () => { }); describe('protocol', () => { - it.each(['HTTP', 'MCP', 'A2A', 'AGUI'])('accepts valid protocol "%s"', mode => { - const result = AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: mode }); - expect(result.success, `Should accept protocol ${mode}`).toBe(true); + it('accepts valid protocols', () => { + expect(AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: 'HTTP' }).success).toBe(true); + expect(AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: 'MCP' }).success).toBe(true); + expect(AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: 'A2A' }).success).toBe(true); }); it('accepts agent without protocol (backwards compat)', () => { @@ -300,7 +270,6 @@ describe('AgentEnvSpecSchema', () => { it('rejects invalid protocol', () => { expect(AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: 'GRPC' }).success).toBe(false); - expect(AgentEnvSpecSchema.safeParse({ ...validPythonAgent, protocol: 'websocket' }).success).toBe(false); }); }); }); @@ -439,12 +408,12 @@ describe('AgentEnvSpecSchema - dockerfile', () => { } }); - it.each(['Dockerfile', 'Dockerfile.dev', 'Dockerfile.gpu-v2', 'my.Dockerfile', 'dockerfile_test'])( - 'accepts valid dockerfile name "%s"', - name => { - expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: name }).success).toBe(true); - } - ); + it('accepts valid dockerfile names', () => { + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: 'Dockerfile' }).success).toBe(true); + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: 'Dockerfile.gpu-v2' }).success).toBe( + true + ); + }); it('rejects dockerfile on CodeZip builds', () => { const result = AgentEnvSpecSchema.safeParse({ ...validCodeZipAgent, dockerfile: 'Dockerfile.custom' }); @@ -454,12 +423,12 @@ describe('AgentEnvSpecSchema - dockerfile', () => { } }); - it.each(['../Dockerfile', '/etc/Dockerfile', 'path/to/Dockerfile', '.hidden'])( - 'rejects path traversal or path separator in dockerfile "%s"', - name => { - expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: name }).success).toBe(false); - } - ); + it('rejects path traversal or path separator in dockerfile', () => { + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: '../Dockerfile' }).success).toBe(false); + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: 'path/to/Dockerfile' }).success).toBe( + false + ); + }); it('rejects empty string dockerfile', () => { expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: '' }).success).toBe(false); @@ -481,12 +450,12 @@ describe('AgentEnvSpecSchema - dockerfile', () => { expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: maxName }).success).toBe(true); }); - it.each(['\\\\server\\share', 'Dockerfile\\..\\secret', '..\\Dockerfile'])( - 'rejects backslash path traversal in dockerfile "%s"', - name => { - expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: name }).success).toBe(false); - } - ); + it('rejects backslash path traversal in dockerfile', () => { + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: '\\\\server\\share' }).success).toBe( + false + ); + expect(AgentEnvSpecSchema.safeParse({ ...validContainerAgent, dockerfile: '..\\Dockerfile' }).success).toBe(false); + }); }); describe('AgentEnvSpecSchema - lifecycleConfiguration', () => { @@ -544,34 +513,21 @@ describe('AgentEnvSpecSchema - lifecycleConfiguration', () => { }); describe('RuntimeEndpointNameSchema', () => { - it.each(['prod', 'staging', 'myEndpoint', 'v1', 'A', 'a' + '0'.repeat(47)])( - 'accepts valid endpoint name "%s"', - name => { - expect(RuntimeEndpointNameSchema.safeParse(name).success).toBe(true); - } - ); - - it('rejects empty string', () => { - expect(RuntimeEndpointNameSchema.safeParse('').success).toBe(false); + it('accepts valid names', () => { + expect(RuntimeEndpointNameSchema.safeParse('prod').success).toBe(true); + expect(RuntimeEndpointNameSchema.safeParse('myEndpoint').success).toBe(true); }); - it('rejects name starting with digit', () => { + it('rejects invalid names', () => { + expect(RuntimeEndpointNameSchema.safeParse('').success).toBe(false); expect(RuntimeEndpointNameSchema.safeParse('1prod').success).toBe(false); - }); - - it('rejects name with hyphens', () => { expect(RuntimeEndpointNameSchema.safeParse('my-endpoint').success).toBe(false); - }); - - it('rejects name with special characters', () => { expect(RuntimeEndpointNameSchema.safeParse('prod!').success).toBe(false); - expect(RuntimeEndpointNameSchema.safeParse('my@endpoint').success).toBe(false); }); - it('rejects name exceeding 48 chars', () => { - const name = 'A' + 'b'.repeat(48); - expect(name).toHaveLength(49); - expect(RuntimeEndpointNameSchema.safeParse(name).success).toBe(false); + it('enforces 48-char boundary', () => { + expect(RuntimeEndpointNameSchema.safeParse('A' + 'b'.repeat(47)).success).toBe(true); + expect(RuntimeEndpointNameSchema.safeParse('A' + 'b'.repeat(48)).success).toBe(false); }); }); diff --git a/src/schema/schemas/__tests__/agentcore-project.test.ts b/src/schema/schemas/__tests__/agentcore-project.test.ts index 08aaf3b12..9fca9b6d8 100644 --- a/src/schema/schemas/__tests__/agentcore-project.test.ts +++ b/src/schema/schemas/__tests__/agentcore-project.test.ts @@ -9,69 +9,31 @@ import { import { describe, expect, it } from 'vitest'; describe('ProjectNameSchema', () => { - describe('valid names', () => { - it.each(['A', 'MyProject', 'test1', 'a1b2c3', 'ALLCAPS', 'abcdefghijklmnopqrstuvw'])('accepts "%s"', name => { - expect(ProjectNameSchema.safeParse(name).success).toBe(true); - }); + it('accepts valid names', () => { + expect(ProjectNameSchema.safeParse('A').success).toBe(true); + expect(ProjectNameSchema.safeParse('MyProject').success).toBe(true); + expect(ProjectNameSchema.safeParse('a1b2c3').success).toBe(true); }); - describe('length validation', () => { - it('rejects empty string', () => { - expect(ProjectNameSchema.safeParse('').success).toBe(false); - }); - - it('accepts 1-character name', () => { - expect(ProjectNameSchema.safeParse('A').success).toBe(true); - }); - - it('accepts 23-character name (max)', () => { - const name = 'A' + 'b'.repeat(22); - expect(name).toHaveLength(23); - expect(ProjectNameSchema.safeParse(name).success).toBe(true); - }); - - it('rejects 24-character name', () => { - const name = 'A' + 'b'.repeat(23); - expect(name).toHaveLength(24); - expect(ProjectNameSchema.safeParse(name).success).toBe(false); - }); + it('enforces 23-char boundary', () => { + expect(ProjectNameSchema.safeParse('A' + 'b'.repeat(22)).success).toBe(true); + expect(ProjectNameSchema.safeParse('A' + 'b'.repeat(23)).success).toBe(false); }); - describe('format validation', () => { - it('rejects name starting with a digit', () => { - expect(ProjectNameSchema.safeParse('1project').success).toBe(false); - }); - - it('rejects name with underscores', () => { - expect(ProjectNameSchema.safeParse('my_project').success).toBe(false); - }); - - it('rejects name with hyphens', () => { - expect(ProjectNameSchema.safeParse('my-project').success).toBe(false); - }); - - it('rejects name with spaces', () => { - expect(ProjectNameSchema.safeParse('my project').success).toBe(false); - }); - - it('rejects name with special characters', () => { - expect(ProjectNameSchema.safeParse('my.project').success).toBe(false); - expect(ProjectNameSchema.safeParse('my@project').success).toBe(false); - }); + it('rejects invalid formats', () => { + expect(ProjectNameSchema.safeParse('').success).toBe(false); + expect(ProjectNameSchema.safeParse('1project').success).toBe(false); + expect(ProjectNameSchema.safeParse('my_project').success).toBe(false); + expect(ProjectNameSchema.safeParse('my-project').success).toBe(false); + expect(ProjectNameSchema.safeParse('my project').success).toBe(false); + expect(ProjectNameSchema.safeParse('my.project').success).toBe(false); }); - describe('reserved name validation', () => { - it.each(['anthropic', 'Anthropic', 'ANTHROPIC', 'openai', 'boto3', 'strands', 'test', 'pip', 'uv'])( - 'rejects reserved name "%s"', - name => { - // Some reserved names may also fail the regex (e.g., too long). We just check it doesn't pass. - expect(ProjectNameSchema.safeParse(name).success).toBe(false); - } - ); - - it('accepts non-reserved name', () => { - expect(ProjectNameSchema.safeParse('MyAgent').success).toBe(true); - }); + it('rejects reserved names (case-insensitive)', () => { + expect(ProjectNameSchema.safeParse('anthropic').success).toBe(false); + expect(ProjectNameSchema.safeParse('Anthropic').success).toBe(false); + expect(ProjectNameSchema.safeParse('openai').success).toBe(false); + expect(ProjectNameSchema.safeParse('MyAgent').success).toBe(true); }); }); diff --git a/src/schema/schemas/__tests__/aws-targets.test.ts b/src/schema/schemas/__tests__/aws-targets.test.ts index cd84f9cb3..5da4df463 100644 --- a/src/schema/schemas/__tests__/aws-targets.test.ts +++ b/src/schema/schemas/__tests__/aws-targets.test.ts @@ -8,42 +8,32 @@ import { import { describe, expect, it } from 'vitest'; describe('AgentCoreRegionSchema', () => { - const validRegions = [ - 'ap-northeast-1', - 'ap-northeast-2', - 'ap-south-1', - 'ap-southeast-1', - 'ap-southeast-2', - 'ca-central-1', - 'eu-central-1', - 'eu-north-1', - 'eu-west-1', - 'eu-west-2', - 'eu-west-3', - 'sa-east-1', - 'us-east-1', - 'us-east-2', - 'us-west-2', - 'us-gov-west-1', - ]; - - it.each(validRegions)('accepts valid region "%s"', region => { - expect(AgentCoreRegionSchema.safeParse(region).success).toBe(true); - }); - - it('rejects unsupported regions', () => { - expect(AgentCoreRegionSchema.safeParse('us-west-1').success).toBe(false); - expect(AgentCoreRegionSchema.safeParse('af-south-1').success).toBe(false); - expect(AgentCoreRegionSchema.safeParse('me-south-1').success).toBe(false); + it('enumerates all supported regions', () => { + expect(AgentCoreRegionSchema.options).toEqual([ + 'ap-northeast-1', + 'ap-northeast-2', + 'ap-south-1', + 'ap-southeast-1', + 'ap-southeast-2', + 'ca-central-1', + 'eu-central-1', + 'eu-north-1', + 'eu-west-1', + 'eu-west-2', + 'eu-west-3', + 'sa-east-1', + 'us-east-1', + 'us-east-2', + 'us-west-2', + 'us-gov-west-1', + ]); }); - it('rejects empty string', () => { + it('rejects unsupported regions and invalid values', () => { + expect(AgentCoreRegionSchema.safeParse('us-west-1').success).toBe(false); + expect(AgentCoreRegionSchema.safeParse('af-south-1').success).toBe(false); expect(AgentCoreRegionSchema.safeParse('').success).toBe(false); - }); - - it('rejects non-string values', () => { expect(AgentCoreRegionSchema.safeParse(123).success).toBe(false); - expect(AgentCoreRegionSchema.safeParse(null).success).toBe(false); }); }); diff --git a/src/schema/schemas/__tests__/deployed-state.test.ts b/src/schema/schemas/__tests__/deployed-state.test.ts index f1791712b..4c4483392 100644 --- a/src/schema/schemas/__tests__/deployed-state.test.ts +++ b/src/schema/schemas/__tests__/deployed-state.test.ts @@ -196,43 +196,27 @@ describe('VpcConfigSchema', () => { }); describe('CredentialDeployedStateSchema', () => { - it('accepts valid credential state with all fields', () => { - const result = CredentialDeployedStateSchema.safeParse({ - credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', - clientSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:my-secret', - callbackUrl: 'https://callback.example.com', - }); - expect(result.success).toBe(true); - }); - - it('accepts credential state with only required credentialProviderArn', () => { - const result = CredentialDeployedStateSchema.safeParse({ - credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', - }); - expect(result.success).toBe(true); - }); - - it('accepts credential state with optional clientSecretArn', () => { - const result = CredentialDeployedStateSchema.safeParse({ - credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', - clientSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:my-secret', - }); - expect(result.success).toBe(true); - }); - - it('accepts credential state with optional callbackUrl', () => { - const result = CredentialDeployedStateSchema.safeParse({ - credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', - callbackUrl: 'https://callback.example.com', - }); - expect(result.success).toBe(true); + it('accepts valid credential state with all fields and required-only', () => { + expect( + CredentialDeployedStateSchema.safeParse({ + credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', + clientSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:my-secret', + callbackUrl: 'https://callback.example.com', + }).success + ).toBe(true); + expect( + CredentialDeployedStateSchema.safeParse({ + credentialProviderArn: 'arn:aws:bedrock:us-east-1:123:credential-provider/my-cred', + }).success + ).toBe(true); }); it('rejects credential state without credentialProviderArn', () => { - const result = CredentialDeployedStateSchema.safeParse({ - clientSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:my-secret', - }); - expect(result.success).toBe(false); + expect( + CredentialDeployedStateSchema.safeParse({ + clientSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:my-secret', + }).success + ).toBe(false); }); }); diff --git a/src/schema/schemas/__tests__/mcp-defs.test.ts b/src/schema/schemas/__tests__/mcp-defs.test.ts index a673bbd56..f411ca99a 100644 --- a/src/schema/schemas/__tests__/mcp-defs.test.ts +++ b/src/schema/schemas/__tests__/mcp-defs.test.ts @@ -7,34 +7,22 @@ import { import { describe, expect, it } from 'vitest'; describe('ToolNameSchema', () => { - it.each(['myTool', 'get_user', 'search-results', 'A'])('accepts valid name "%s"', name => { - expect(ToolNameSchema.safeParse(name).success).toBe(true); + it('accepts valid names', () => { + expect(ToolNameSchema.safeParse('myTool').success).toBe(true); + expect(ToolNameSchema.safeParse('get_user').success).toBe(true); + expect(ToolNameSchema.safeParse('search-results').success).toBe(true); }); - it('rejects empty string', () => { + it('rejects invalid names', () => { expect(ToolNameSchema.safeParse('').success).toBe(false); - }); - - it('rejects name starting with digit', () => { expect(ToolNameSchema.safeParse('1tool').success).toBe(false); - }); - - it('rejects name starting with hyphen', () => { expect(ToolNameSchema.safeParse('-tool').success).toBe(false); + expect(ToolNameSchema.safeParse('my.tool').success).toBe(false); }); - it('rejects name exceeding 128 chars', () => { - const name = 'a'.repeat(129); - expect(ToolNameSchema.safeParse(name).success).toBe(false); - }); - - it('accepts 128-char name (max)', () => { - const name = 'a'.repeat(128); - expect(ToolNameSchema.safeParse(name).success).toBe(true); - }); - - it('rejects name with dots', () => { - expect(ToolNameSchema.safeParse('my.tool').success).toBe(false); + it('enforces 128-char boundary', () => { + expect(ToolNameSchema.safeParse('a'.repeat(128)).success).toBe(true); + expect(ToolNameSchema.safeParse('a'.repeat(129)).success).toBe(false); }); }); diff --git a/src/schema/schemas/__tests__/mcp.test.ts b/src/schema/schemas/__tests__/mcp.test.ts index 128b43dac..0ab33c2a4 100644 --- a/src/schema/schemas/__tests__/mcp.test.ts +++ b/src/schema/schemas/__tests__/mcp.test.ts @@ -21,12 +21,16 @@ import { import { describe, expect, it } from 'vitest'; describe('GatewayTargetTypeSchema', () => { - it.each(['lambda', 'mcpServer', 'openApiSchema', 'smithyModel', 'apiGateway', 'lambdaFunctionArn'])( - 'accepts "%s"', - type => { - expect(GatewayTargetTypeSchema.safeParse(type).success).toBe(true); - } - ); + it('enumerates all target types', () => { + expect(GatewayTargetTypeSchema.options).toEqual([ + 'lambda', + 'mcpServer', + 'openApiSchema', + 'smithyModel', + 'apiGateway', + 'lambdaFunctionArn', + ]); + }); it('rejects invalid type', () => { expect(GatewayTargetTypeSchema.safeParse('http').success).toBe(false); @@ -34,29 +38,17 @@ describe('GatewayTargetTypeSchema', () => { }); describe('GatewayAuthorizerTypeSchema', () => { - it('accepts NONE', () => { + it('accepts valid types and rejects invalid', () => { expect(GatewayAuthorizerTypeSchema.safeParse('NONE').success).toBe(true); - }); - - it('accepts CUSTOM_JWT', () => { expect(GatewayAuthorizerTypeSchema.safeParse('CUSTOM_JWT').success).toBe(true); - }); - - it('rejects other types', () => { expect(GatewayAuthorizerTypeSchema.safeParse('IAM').success).toBe(false); }); }); describe('McpImplLanguageSchema', () => { - it('accepts TypeScript', () => { + it('accepts valid languages and rejects invalid', () => { expect(McpImplLanguageSchema.safeParse('TypeScript').success).toBe(true); - }); - - it('accepts Python', () => { expect(McpImplLanguageSchema.safeParse('Python').success).toBe(true); - }); - - it('rejects other languages', () => { expect(McpImplLanguageSchema.safeParse('Go').success).toBe(false); }); }); @@ -345,15 +337,9 @@ describe('AgentCoreGatewayTargetSchema', () => { }); describe('GatewayExceptionLevelSchema', () => { - it('accepts NONE', () => { + it('accepts valid levels and rejects invalid', () => { expect(GatewayExceptionLevelSchema.safeParse('NONE').success).toBe(true); - }); - - it('accepts DEBUG', () => { expect(GatewayExceptionLevelSchema.safeParse('DEBUG').success).toBe(true); - }); - - it('rejects invalid level', () => { expect(GatewayExceptionLevelSchema.safeParse('VERBOSE').success).toBe(false); }); }); diff --git a/src/schema/schemas/primitives/__tests__/evaluator.test.ts b/src/schema/schemas/primitives/__tests__/evaluator.test.ts index 9147c5cf9..f378e526b 100644 --- a/src/schema/schemas/primitives/__tests__/evaluator.test.ts +++ b/src/schema/schemas/primitives/__tests__/evaluator.test.ts @@ -9,12 +9,11 @@ import { import { describe, expect, it } from 'vitest'; describe('EvaluationLevelSchema', () => { - it.each(['SESSION', 'TRACE', 'TOOL_CALL'])('accepts %s', level => { - expect(EvaluationLevelSchema.safeParse(level).success).toBe(true); - }); - - it.each(['session', 'INVALID', '', 'SPAN'])('rejects %s', level => { - expect(EvaluationLevelSchema.safeParse(level).success).toBe(false); + it('accepts valid levels and rejects invalid', () => { + expect(EvaluationLevelSchema.safeParse('SESSION').success).toBe(true); + expect(EvaluationLevelSchema.safeParse('TOOL_CALL').success).toBe(true); + expect(EvaluationLevelSchema.safeParse('session').success).toBe(false); + expect(EvaluationLevelSchema.safeParse('INVALID').success).toBe(false); }); }); diff --git a/src/schema/schemas/primitives/__tests__/memory.test.ts b/src/schema/schemas/primitives/__tests__/memory.test.ts index 4b37eb646..082c32fa6 100644 --- a/src/schema/schemas/primitives/__tests__/memory.test.ts +++ b/src/schema/schemas/primitives/__tests__/memory.test.ts @@ -2,43 +2,16 @@ import { DEFAULT_STRATEGY_NAMESPACES, MemoryStrategySchema, MemoryStrategyTypeSc import { describe, expect, it } from 'vitest'; describe('MemoryStrategyTypeSchema', () => { - describe('valid strategy types', () => { - it('accepts SEMANTIC', () => { - expect(MemoryStrategyTypeSchema.safeParse('SEMANTIC').success).toBe(true); - }); - - it('accepts SUMMARIZATION', () => { - expect(MemoryStrategyTypeSchema.safeParse('SUMMARIZATION').success).toBe(true); - }); - - it('accepts USER_PREFERENCE', () => { - expect(MemoryStrategyTypeSchema.safeParse('USER_PREFERENCE').success).toBe(true); - }); - - it('accepts EPISODIC', () => { - expect(MemoryStrategyTypeSchema.safeParse('EPISODIC').success).toBe(true); - }); + it('accepts valid strategy types and rejects invalid', () => { + expect(MemoryStrategyTypeSchema.safeParse('SEMANTIC').success).toBe(true); + expect(MemoryStrategyTypeSchema.safeParse('EPISODIC').success).toBe(true); + expect(MemoryStrategyTypeSchema.safeParse('CUSTOM').success).toBe(false); + expect(MemoryStrategyTypeSchema.safeParse('semantic').success).toBe(false); }); - describe('invalid strategy types', () => { - // Issue #235: CUSTOM strategy has been removed - it('rejects CUSTOM strategy', () => { - const result = MemoryStrategyTypeSchema.safeParse('CUSTOM'); - expect(result.success).toBe(false); - }); - - it('rejects arbitrary invalid strategies', () => { - expect(MemoryStrategyTypeSchema.safeParse('INVALID').success).toBe(false); - expect(MemoryStrategyTypeSchema.safeParse('').success).toBe(false); - expect(MemoryStrategyTypeSchema.safeParse('semantic').success).toBe(false); // lowercase - }); - }); - - describe('schema options', () => { - it('contains four valid strategies including EPISODIC', () => { - expect(MemoryStrategyTypeSchema.options).toEqual(['SEMANTIC', 'SUMMARIZATION', 'USER_PREFERENCE', 'EPISODIC']); - expect(MemoryStrategyTypeSchema.options).not.toContain('CUSTOM'); - }); + it('contains four valid strategies including EPISODIC', () => { + expect(MemoryStrategyTypeSchema.options).toEqual(['SEMANTIC', 'SUMMARIZATION', 'USER_PREFERENCE', 'EPISODIC']); + expect(MemoryStrategyTypeSchema.options).not.toContain('CUSTOM'); }); });