| ... | ... | @@ -639,6 +639,115 @@ describe("WsTransport", () => { |
| 639 | 639 | await transport.dispose(); |
| 640 | 640 | }); |
| 641 | 641 | |
| 642 | it("re-subscribes live stream listeners after an explicit transport reconnect", async () => { |
| 643 | const transport = createTransport("ws://localhost:3020"); |
| 644 | const listener = vi.fn(); |
| 645 | const onResubscribe = vi.fn(); |
| 646 | |
| 647 | const unsubscribe = transport.subscribe( |
| 648 | (client) => client[WS_METHODS.subscribeServerLifecycle]({}), |
| 649 | listener, |
| 650 | { onResubscribe }, |
| 651 | ); |
| 652 | |
| 653 | await waitFor(() => { |
| 654 | expect(sockets).toHaveLength(1); |
| 655 | }); |
| 656 | |
| 657 | const firstSocket = getSocket(); |
| 658 | firstSocket.open(); |
| 659 | |
| 660 | await waitFor(() => { |
| 661 | expect(firstSocket.sent).toHaveLength(1); |
| 662 | }); |
| 663 | |
| 664 | const firstRequest = JSON.parse(firstSocket.sent[0] ?? "{}") as { id: string }; |
| 665 | const firstEvent = { |
| 666 | version: 1, |
| 667 | sequence: 1, |
| 668 | type: "welcome", |
| 669 | payload: { |
| 670 | environment: { |
| 671 | environmentId: "environment-local", |
| 672 | label: "Local environment", |
| 673 | platform: { os: "darwin", arch: "arm64" }, |
| 674 | serverVersion: "0.0.0-test", |
| 675 | capabilities: { repositoryIdentity: true }, |
| 676 | }, |
| 677 | cwd: "/tmp/one", |
| 678 | projectName: "one", |
| 679 | }, |
| 680 | }; |
| 681 | |
| 682 | firstSocket.serverMessage( |
| 683 | JSON.stringify({ |
| 684 | _tag: "Chunk", |
| 685 | requestId: firstRequest.id, |
| 686 | values: [firstEvent], |
| 687 | }), |
| 688 | ); |
| 689 | |
| 690 | await waitFor(() => { |
| 691 | expect(listener).toHaveBeenLastCalledWith(firstEvent); |
| 692 | }); |
| 693 | |
| 694 | await transport.reconnect(); |
| 695 | |
| 696 | await waitFor(() => { |
| 697 | expect(sockets).toHaveLength(2); |
| 698 | }); |
| 699 | |
| 700 | const secondSocket = getSocket(); |
| 701 | expect(secondSocket).not.toBe(firstSocket); |
| 702 | expect(firstSocket.readyState).toBe(MockWebSocket.CLOSED); |
| 703 | |
| 704 | secondSocket.open(); |
| 705 | |
| 706 | await waitFor(() => { |
| 707 | expect(secondSocket.sent).toHaveLength(1); |
| 708 | }); |
| 709 | |
| 710 | const secondRequest = JSON.parse(secondSocket.sent[0] ?? "{}") as { |
| 711 | id: string; |
| 712 | tag: string; |
| 713 | }; |
| 714 | expect(secondRequest.tag).toBe(WS_METHODS.subscribeServerLifecycle); |
| 715 | expect(secondRequest.id).not.toBe(firstRequest.id); |
| 716 | expect(onResubscribe).toHaveBeenCalledOnce(); |
| 717 | |
| 718 | const secondEvent = { |
| 719 | version: 1, |
| 720 | sequence: 2, |
| 721 | type: "welcome", |
| 722 | payload: { |
| 723 | environment: { |
| 724 | environmentId: "environment-local", |
| 725 | label: "Local environment", |
| 726 | platform: { os: "darwin", arch: "arm64" }, |
| 727 | serverVersion: "0.0.0-test", |
| 728 | capabilities: { repositoryIdentity: true }, |
| 729 | }, |
| 730 | cwd: "/tmp/two", |
| 731 | projectName: "two", |
| 732 | }, |
| 733 | }; |
| 734 | |
| 735 | secondSocket.serverMessage( |
| 736 | JSON.stringify({ |
| 737 | _tag: "Chunk", |
| 738 | requestId: secondRequest.id, |
| 739 | values: [secondEvent], |
| 740 | }), |
| 741 | ); |
| 742 | |
| 743 | await waitFor(() => { |
| 744 | expect(listener).toHaveBeenLastCalledWith(secondEvent); |
| 745 | }); |
| 746 | |
| 747 | unsubscribe(); |
| 748 | await transport.dispose(); |
| 749 | }); |
| 750 | |
| 642 | 751 | it("does not fire onResubscribe when the first stream attempt exits before any value", async () => { |
| 643 | 752 | const transport = createTransport("ws://localhost:3020"); |
| 644 | 753 | const listener = vi.fn(); |