|
1 | | -import { describe, it, expect, beforeEach } from "vitest"; |
| 1 | +import { describe, it, expect, beforeEach, vi } from "vitest"; |
2 | 2 | import { |
3 | 3 | Agent, |
4 | 4 | ClientSideConnection, |
@@ -461,12 +461,11 @@ describe("Connection", () => { |
461 | 461 | sessionId: "test-session", |
462 | 462 | }); |
463 | 463 |
|
464 | | - // Wait a bit for async handlers |
465 | | - await new Promise((resolve) => setTimeout(resolve, 50)); |
466 | | - |
467 | 464 | // Verify notifications were received |
468 | | - expect(notificationLog).toContain("agent message: Hello from agent"); |
469 | | - expect(notificationLog).toContain("cancelled: test-session"); |
| 465 | + await vi.waitFor(() => { |
| 466 | + expect(notificationLog).toContain("agent message: Hello from agent"); |
| 467 | + expect(notificationLog).toContain("cancelled: test-session"); |
| 468 | + }); |
470 | 469 | }); |
471 | 470 |
|
472 | 471 | it("handles initialize method", async () => { |
@@ -653,27 +652,27 @@ describe("Connection", () => { |
653 | 652 | extraNotificationField: "keep this too", |
654 | 653 | } as any); |
655 | 654 |
|
656 | | - await new Promise((resolve) => setTimeout(resolve, 50)); |
657 | | - |
658 | | - expect(receivedInitializeParams).toMatchObject({ |
659 | | - extraTopLevel: "keep me", |
660 | | - clientCapabilities: { |
661 | | - customCapability: { |
662 | | - enabled: true, |
663 | | - }, |
664 | | - fs: { |
665 | | - experimentalFs: true, |
| 655 | + await vi.waitFor(() => { |
| 656 | + expect(receivedInitializeParams).toMatchObject({ |
| 657 | + extraTopLevel: "keep me", |
| 658 | + clientCapabilities: { |
| 659 | + customCapability: { |
| 660 | + enabled: true, |
| 661 | + }, |
| 662 | + fs: { |
| 663 | + experimentalFs: true, |
| 664 | + }, |
666 | 665 | }, |
667 | | - }, |
668 | | - }); |
| 666 | + }); |
669 | 667 |
|
670 | | - expect(receivedSessionUpdate).toMatchObject({ |
671 | | - extraNotificationField: "keep this too", |
672 | | - update: { |
673 | | - extraUpdateField: { |
674 | | - keep: true, |
| 668 | + expect(receivedSessionUpdate).toMatchObject({ |
| 669 | + extraNotificationField: "keep this too", |
| 670 | + update: { |
| 671 | + extraUpdateField: { |
| 672 | + keep: true, |
| 673 | + }, |
675 | 674 | }, |
676 | | - }, |
| 675 | + }); |
677 | 676 | }); |
678 | 677 | }); |
679 | 678 |
|
@@ -796,16 +795,15 @@ describe("Connection", () => { |
796 | 795 | info: "agent notification", |
797 | 796 | }); |
798 | 797 |
|
799 | | - // Wait a bit for async handlers |
800 | | - await new Promise((resolve) => setTimeout(resolve, 50)); |
801 | | - |
802 | 798 | // Verify notifications were logged |
803 | | - expect(extensionLog).toContain( |
804 | | - "client extNotification: example.com/client/notify", |
805 | | - ); |
806 | | - expect(extensionLog).toContain( |
807 | | - "agent extNotification: example.com/agent/notify", |
808 | | - ); |
| 799 | + await vi.waitFor(() => { |
| 800 | + expect(extensionLog).toContain( |
| 801 | + "client extNotification: example.com/client/notify", |
| 802 | + ); |
| 803 | + expect(extensionLog).toContain( |
| 804 | + "agent extNotification: example.com/agent/notify", |
| 805 | + ); |
| 806 | + }); |
809 | 807 | }); |
810 | 808 |
|
811 | 809 | it("handles optional extension methods correctly", async () => { |
@@ -1248,6 +1246,8 @@ describe("Connection", () => { |
1248 | 1246 | }); |
1249 | 1247 |
|
1250 | 1248 | it("handles NES request lifecycle", async () => { |
| 1249 | + let receivedStartRequest: StartNesRequest | undefined; |
| 1250 | + |
1251 | 1251 | class TestClient implements Client { |
1252 | 1252 | async writeTextFile( |
1253 | 1253 | _: WriteTextFileRequest, |
@@ -1284,7 +1284,10 @@ describe("Connection", () => { |
1284 | 1284 | } |
1285 | 1285 | async cancel(_: CancelNotification): Promise<void> {} |
1286 | 1286 |
|
1287 | | - async unstable_startNes(_: StartNesRequest): Promise<StartNesResponse> { |
| 1287 | + async unstable_startNes( |
| 1288 | + params: StartNesRequest, |
| 1289 | + ): Promise<StartNesResponse> { |
| 1290 | + receivedStartRequest = params; |
1288 | 1291 | return { sessionId: "nes-session-1" }; |
1289 | 1292 | } |
1290 | 1293 | async unstable_suggestNes( |
@@ -1325,8 +1328,29 @@ describe("Connection", () => { |
1325 | 1328 |
|
1326 | 1329 | void clientConnection; |
1327 | 1330 |
|
1328 | | - const startResponse = await agentConnection.unstable_startNes({}); |
| 1331 | + const startResponse = await agentConnection.unstable_startNes({ |
| 1332 | + workspaceUri: "file:///workspace", |
| 1333 | + workspaceFolders: [ |
| 1334 | + { uri: "file:///workspace/frontend", name: "frontend" }, |
| 1335 | + { uri: "file:///workspace/backend", name: "backend" }, |
| 1336 | + ], |
| 1337 | + repository: { |
| 1338 | + name: "my-repo", |
| 1339 | + owner: "my-org", |
| 1340 | + remoteUrl: "https://github.com/my-org/my-repo.git", |
| 1341 | + }, |
| 1342 | + }); |
1329 | 1343 | expect(startResponse).toEqual({ sessionId: "nes-session-1" }); |
| 1344 | + expect(receivedStartRequest?.workspaceUri).toEqual("file:///workspace"); |
| 1345 | + expect(receivedStartRequest?.workspaceFolders).toEqual([ |
| 1346 | + { uri: "file:///workspace/frontend", name: "frontend" }, |
| 1347 | + { uri: "file:///workspace/backend", name: "backend" }, |
| 1348 | + ]); |
| 1349 | + expect(receivedStartRequest?.repository).toEqual({ |
| 1350 | + name: "my-repo", |
| 1351 | + owner: "my-org", |
| 1352 | + remoteUrl: "https://github.com/my-org/my-repo.git", |
| 1353 | + }); |
1330 | 1354 |
|
1331 | 1355 | const suggestResponse = await agentConnection.unstable_suggestNes({ |
1332 | 1356 | sessionId: "nes-session-1", |
@@ -1428,18 +1452,22 @@ describe("Connection", () => { |
1428 | 1452 | reason: "rejected", |
1429 | 1453 | }); |
1430 | 1454 |
|
1431 | | - await new Promise((resolve) => setTimeout(resolve, 50)); |
1432 | | - |
1433 | | - expect(notificationLog).toEqual([ |
1434 | | - { |
1435 | | - type: "acceptNes", |
1436 | | - params: { sessionId: "nes-session-1", id: "sug-1" }, |
1437 | | - }, |
1438 | | - { |
1439 | | - type: "rejectNes", |
1440 | | - params: { sessionId: "nes-session-1", id: "sug-2", reason: "rejected" }, |
1441 | | - }, |
1442 | | - ]); |
| 1455 | + await vi.waitFor(() => { |
| 1456 | + expect(notificationLog).toEqual([ |
| 1457 | + { |
| 1458 | + type: "acceptNes", |
| 1459 | + params: { sessionId: "nes-session-1", id: "sug-1" }, |
| 1460 | + }, |
| 1461 | + { |
| 1462 | + type: "rejectNes", |
| 1463 | + params: { |
| 1464 | + sessionId: "nes-session-1", |
| 1465 | + id: "sug-2", |
| 1466 | + reason: "rejected", |
| 1467 | + }, |
| 1468 | + }, |
| 1469 | + ]); |
| 1470 | + }); |
1443 | 1471 | }); |
1444 | 1472 |
|
1445 | 1473 | it("handles document notifications", async () => { |
@@ -1551,56 +1579,56 @@ describe("Connection", () => { |
1551 | 1579 | uri: "file:///test.ts", |
1552 | 1580 | }); |
1553 | 1581 |
|
1554 | | - await new Promise((resolve) => setTimeout(resolve, 50)); |
1555 | | - |
1556 | | - expect(notificationLog).toEqual([ |
1557 | | - { |
1558 | | - type: "didOpen", |
1559 | | - params: { |
1560 | | - sessionId: "s1", |
1561 | | - uri: "file:///test.ts", |
1562 | | - languageId: "typescript", |
1563 | | - version: 1, |
1564 | | - text: "const x = 1;", |
| 1582 | + await vi.waitFor(() => { |
| 1583 | + expect(notificationLog).toEqual([ |
| 1584 | + { |
| 1585 | + type: "didOpen", |
| 1586 | + params: { |
| 1587 | + sessionId: "s1", |
| 1588 | + uri: "file:///test.ts", |
| 1589 | + languageId: "typescript", |
| 1590 | + version: 1, |
| 1591 | + text: "const x = 1;", |
| 1592 | + }, |
1565 | 1593 | }, |
1566 | | - }, |
1567 | | - { |
1568 | | - type: "didChange", |
1569 | | - params: { |
1570 | | - sessionId: "s1", |
1571 | | - uri: "file:///test.ts", |
1572 | | - version: 2, |
1573 | | - contentChanges: [{ text: "const x = 2;" }], |
| 1594 | + { |
| 1595 | + type: "didChange", |
| 1596 | + params: { |
| 1597 | + sessionId: "s1", |
| 1598 | + uri: "file:///test.ts", |
| 1599 | + version: 2, |
| 1600 | + contentChanges: [{ text: "const x = 2;" }], |
| 1601 | + }, |
1574 | 1602 | }, |
1575 | | - }, |
1576 | | - { |
1577 | | - type: "didSave", |
1578 | | - params: { |
1579 | | - sessionId: "s1", |
1580 | | - uri: "file:///test.ts", |
| 1603 | + { |
| 1604 | + type: "didSave", |
| 1605 | + params: { |
| 1606 | + sessionId: "s1", |
| 1607 | + uri: "file:///test.ts", |
| 1608 | + }, |
1581 | 1609 | }, |
1582 | | - }, |
1583 | | - { |
1584 | | - type: "didFocus", |
1585 | | - params: { |
1586 | | - sessionId: "s1", |
1587 | | - uri: "file:///test.ts", |
1588 | | - version: 2, |
1589 | | - position: { line: 0, character: 5 }, |
1590 | | - visibleRange: { |
1591 | | - start: { line: 0, character: 0 }, |
1592 | | - end: { line: 10, character: 0 }, |
| 1610 | + { |
| 1611 | + type: "didFocus", |
| 1612 | + params: { |
| 1613 | + sessionId: "s1", |
| 1614 | + uri: "file:///test.ts", |
| 1615 | + version: 2, |
| 1616 | + position: { line: 0, character: 5 }, |
| 1617 | + visibleRange: { |
| 1618 | + start: { line: 0, character: 0 }, |
| 1619 | + end: { line: 10, character: 0 }, |
| 1620 | + }, |
1593 | 1621 | }, |
1594 | 1622 | }, |
1595 | | - }, |
1596 | | - { |
1597 | | - type: "didClose", |
1598 | | - params: { |
1599 | | - sessionId: "s1", |
1600 | | - uri: "file:///test.ts", |
| 1623 | + { |
| 1624 | + type: "didClose", |
| 1625 | + params: { |
| 1626 | + sessionId: "s1", |
| 1627 | + uri: "file:///test.ts", |
| 1628 | + }, |
1601 | 1629 | }, |
1602 | | - }, |
1603 | | - ]); |
| 1630 | + ]); |
| 1631 | + }); |
1604 | 1632 | }); |
1605 | 1633 |
|
1606 | 1634 | it("propagates additionalDirectories on session lifecycle methods", async () => { |
|
0 commit comments