Skip to content

Commit 061df44

Browse files
committed
test: tighten assertions, add error-path tests, and document golden-envelope schemas
1 parent 652f657 commit 061df44

5 files changed

Lines changed: 50 additions & 4 deletions

File tree

test/e2e/hello-prompt.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ describe('hello-prompt e2e', { timeout: 30_000 }, () => {
9999
);
100100
expect(sendKeysEnvelope.ok).toBe(true);
101101
expect(sendKeysEnvelope.command).toBe('send-keys');
102-
expect(sendKeysEnvelope.result).toMatchObject({
102+
expect(sendKeysEnvelope.result).toEqual({
103103
accepted: ['Enter'],
104104
bytesWritten: 1,
105+
seq: expect.any(Number) as number,
105106
});
106107
expect(sendKeysEnvelope.result.seq).toBeGreaterThanOrEqual(0);
107108

@@ -146,9 +147,10 @@ describe('hello-prompt e2e', { timeout: 30_000 }, () => {
146147
);
147148
expect(sendExitEnterEnvelope.ok).toBe(true);
148149
expect(sendExitEnterEnvelope.command).toBe('send-keys');
149-
expect(sendExitEnterEnvelope.result).toMatchObject({
150+
expect(sendExitEnterEnvelope.result).toEqual({
150151
accepted: ['Enter'],
151152
bytesWritten: 1,
153+
seq: expect.any(Number) as number,
152154
});
153155
expect(sendExitEnterEnvelope.result.seq).toBeGreaterThanOrEqual(0);
154156

@@ -227,9 +229,10 @@ describe('hello-prompt e2e', { timeout: 30_000 }, () => {
227229
);
228230
expect(sendKeysEnvelope.ok).toBe(true);
229231
expect(sendKeysEnvelope.command).toBe('send-keys');
230-
expect(sendKeysEnvelope.result).toMatchObject({
232+
expect(sendKeysEnvelope.result).toEqual({
231233
accepted: ['Enter'],
232234
bytesWritten: 1,
235+
seq: expect.any(Number) as number,
233236
});
234237
expect(sendKeysEnvelope.result.seq).toBeGreaterThanOrEqual(0);
235238

test/e2e/resize-demo.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ describe('resize-demo e2e', { timeout: 30_000 }, () => {
134134
);
135135
expect(sendKeysEnvelope.ok).toBe(true);
136136
expect(sendKeysEnvelope.command).toBe('send-keys');
137-
expect(sendKeysEnvelope.result).toMatchObject({
137+
expect(sendKeysEnvelope.result).toEqual({
138138
accepted: ['Enter'],
139139
bytesWritten: 1,
140+
seq: expect.any(Number) as number,
140141
});
141142
expect(sendKeysEnvelope.result.seq).toBeGreaterThanOrEqual(0);
142143

test/integration/lifecycle.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,28 @@ describe('lifecycle integration', { timeout: 30000 }, () => {
689689
expect(envelope.error.code).toBe('SESSION_NOT_FOUND');
690690
});
691691

692+
it('send-keys to non-existent session returns SESSION_NOT_FOUND', () => {
693+
const result = runCli(['send-keys', 'NONEXISTENT', 'Enter', '--json'], {
694+
AGENT_TERMINAL_HOME: testHome,
695+
});
696+
expect(result.status).not.toBe(0);
697+
expect(result.stderr).toBe('');
698+
const envelope = JSON.parse(result.stdout) as ErrorEnvelope;
699+
expect(envelope.ok).toBe(false);
700+
expect(envelope.error.code).toBe('SESSION_NOT_FOUND');
701+
});
702+
703+
it('destroy non-existent session returns SESSION_NOT_FOUND', () => {
704+
const result = runCli(['destroy', 'NONEXISTENT', '--json'], {
705+
AGENT_TERMINAL_HOME: testHome,
706+
});
707+
expect(result.status).not.toBe(0);
708+
expect(result.stderr).toBe('');
709+
const envelope = JSON.parse(result.stdout) as ErrorEnvelope;
710+
expect(envelope.ok).toBe(false);
711+
expect(envelope.error.code).toBe('SESSION_NOT_FOUND');
712+
});
713+
692714
it('event log contains output and exit records', async () => {
693715
const createResult = runCli(
694716
[

test/unit/commands/golden-envelopes.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ const VersionResultSchema = z
3737
})
3838
.strict();
3939

40+
// CreateResultSchema is defined locally because create does not go through
41+
// the RPC layer — it constructs the result from the session manifest.
42+
// This schema acts as the golden contract lock for the create result shape.
43+
// If a protocol-level CreateResultSchema is added later, replace this.
4044
const CreateResultSchema = z
4145
.object({
4246
sessionId: NonEmptyStringSchema,
@@ -49,6 +53,10 @@ const CreateResultSchema = z
4953
})
5054
.strict();
5155

56+
// SessionSummarySchema is defined locally because list returns session summaries
57+
// assembled from manifests rather than a shared protocol export. This schema
58+
// locks the expected per-session list payload used by the local ListResultSchema.
59+
// If a protocol-level SessionSummarySchema is added later, replace this.
5260
const SessionSummarySchema = z
5361
.object({
5462
sessionId: NonEmptyStringSchema,
@@ -60,6 +68,10 @@ const SessionSummarySchema = z
6068
})
6169
.strict();
6270

71+
// ListResultSchema is defined locally because list does not go through the
72+
// RPC layer — it constructs the result from session manifests and summaries.
73+
// This schema acts as the golden contract lock for the list result shape.
74+
// If a protocol-level ListResultSchema is added later, replace this.
6375
const ListResultSchema = z
6476
.object({
6577
sessions: z.array(SessionSummarySchema),

test/unit/protocol/messages.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,14 @@ describe('RPC message schemas', () => {
541541
expect(result.success).toBe(false);
542542
});
543543

544+
it('accepts sendKeys params with multiple keys', () => {
545+
const result = SendKeysParamsSchema.safeParse({
546+
keys: ['Ctrl+L', 'g', 'g'],
547+
});
548+
549+
expect(result.success).toBe(true);
550+
});
551+
544552
it('rejects empty paste text', () => {
545553
const result = PasteParamsSchema.safeParse({
546554
text: '',

0 commit comments

Comments
 (0)