From 59c51c4bf003ea9e7d95eb5b1d9294d05f8e0ef9 Mon Sep 17 00:00:00 2001 From: Alex Ross <38270282+alexr00@users.noreply.github.com> Date: Thu, 8 Oct 2026 11:49:41 +0200 Subject: [PATCH 1/2] Fix PR webview showing incorrect checkout state --- src/github/pullRequestOverview.ts | 3 +- src/test/github/pullRequestOverview.test.ts | 57 +++++++++++++++++++++ webviews/editorWebview/test/app.test.tsx | 28 ++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/github/pullRequestOverview.ts b/src/github/pullRequestOverview.ts index 5aaa96a066..4a02b801b0 100644 --- a/src/github/pullRequestOverview.ts +++ b/src/github/pullRequestOverview.ts @@ -558,7 +558,6 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel { + return super.processLinksInBodyHtml(bodyHTML); + } + + public override _postMessage(message: { command: string; isCurrentlyCheckedOut?: boolean; pullrequest?: Partial }): Promise { + return super._postMessage(message); + } +} + describe('PullRequestOverview', function () { let sinon: SinonSandbox; let pullRequestManager: FolderRepositoryManager; @@ -91,6 +105,49 @@ describe('PullRequestOverview', function () { } }); + describe('checkout status', function () { + for (const initiallyCheckedOut of [false, true]) { + it(`initializes with the latest checkout state when ${initiallyCheckedOut ? 'leaving' : 'entering'} review mode during loading`, async function () { + setStacksEnabled(false); + const model = new PullRequestModel(credentialStore, telemetry, repo, remote, + convertRESTPullRequestToRawPullRequest(new PullRequestBuilder().number(1000).build(), repo)); + const identity = { owner: remote.owner, repo: remote.repositoryName, number: model.number }; + pullRequestManager.activePullRequest = initiallyCheckedOut ? model : undefined; + sinon.stub(pullRequestManager, 'getCurrentUser').resolves(model.author); + sinon.stub(model, 'getTimelineEvents').resolves([]); + sinon.stub(model, 'getReviewRequests').resolves([]); + sinon.stub(model, 'validateDraftMode').resolves(false); + sinon.stub(model, 'getStatusChecks').resolves([{ state: CheckState.Success, statuses: [] }, null]); + const panel = new TestPullRequestOverviewPanel(telemetry, pullRequestManager); + context.subscriptions.push(panel); + const postMessage = sinon.spy(panel, '_postMessage'); + let releaseBody: (bodyHTML: string | undefined) => void; + const blockedBody = new Promise(resolve => releaseBody = resolve); + let bodyProcessingStarted: () => void; + const bodyStarted = new Promise(resolve => bodyProcessingStarted = resolve); + sinon.stub(panel, 'processLinksInBodyHtml').callsFake(() => { + bodyProcessingStarted(); + return blockedBody; + }); + + const opening = panel.updateWithIdentity(pullRequestManager, identity, model); + await bodyStarted; + pullRequestManager.activePullRequest = initiallyCheckedOut ? undefined : model; + releaseBody!(model.bodyHTML); + await opening; + + const calls = postMessage.getCalls(); + const checkoutUpdate = calls.find(call => call.args[0].command === 'pr.update-checkout-status'); + assert(checkoutUpdate); + assert.strictEqual(checkoutUpdate.args[0].isCurrentlyCheckedOut, !initiallyCheckedOut); + const initialize = calls.find(call => call.args[0].command === 'pr.initialize'); + assert(initialize); + assert.strictEqual(initialize.args[0].pullrequest.isCurrentlyCheckedOut, !initiallyCheckedOut); + assert(calls.indexOf(checkoutUpdate) < calls.indexOf(initialize)); + }); + } + }); + describe('createOrShow', function () { it('does not load stack membership when stacks are disabled', async function () { setStacksEnabled(false); diff --git a/webviews/editorWebview/test/app.test.tsx b/webviews/editorWebview/test/app.test.tsx index e60a9c1e6d..78b015a071 100644 --- a/webviews/editorWebview/test/app.test.tsx +++ b/webviews/editorWebview/test/app.test.tsx @@ -139,4 +139,32 @@ describe('Root', function () { assert(children.calledWith(pr)); }); + + it('updates the checkout button when the active pull request changes without clicking checkout', function () { + const pr = new PullRequestBuilder().build(); + pr.isCurrentlyCheckedOut = true; + pr.doneCheckoutBranch = 'main'; + const context = new PRContext(pr); + context.setPR(pr); + const checkout = sinon.spy(context, 'checkout'); + const out = render( + + {pullRequest => } + , + ); + + assert(out.getByText('Checkout \'main\'')); + act(() => { + context.handleMessage({ command: 'pr.update-checkout-status', isCurrentlyCheckedOut: false }); + }); + assert(out.getByText('Checkout')); + assert.strictEqual(out.queryByText('Checkout \'main\''), null); + + act(() => { + context.handleMessage({ command: 'pr.update-checkout-status', isCurrentlyCheckedOut: true }); + }); + assert(out.getByText('Checkout \'main\'')); + assert.strictEqual(out.queryByText('Checkout'), null); + sinon.assert.notCalled(checkout); + }); }); From ab1b20c80584bba7370578d04c30dfd438482414 Mon Sep 17 00:00:00 2001 From: Alex Ross <38270282+alexr00@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:14:53 +0200 Subject: [PATCH 2/2] Fix test compile error --- src/test/github/pullRequestOverview.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/github/pullRequestOverview.test.ts b/src/test/github/pullRequestOverview.test.ts index 95c147d975..61138364b3 100644 --- a/src/test/github/pullRequestOverview.test.ts +++ b/src/test/github/pullRequestOverview.test.ts @@ -142,7 +142,7 @@ describe('PullRequestOverview', function () { assert.strictEqual(checkoutUpdate.args[0].isCurrentlyCheckedOut, !initiallyCheckedOut); const initialize = calls.find(call => call.args[0].command === 'pr.initialize'); assert(initialize); - assert.strictEqual(initialize.args[0].pullrequest.isCurrentlyCheckedOut, !initiallyCheckedOut); + assert.strictEqual(initialize.args[0].pullrequest?.isCurrentlyCheckedOut, !initiallyCheckedOut); assert(calls.indexOf(checkoutUpdate) < calls.indexOf(initialize)); }); }