addons/vscode/extension/__tests__/commands.test.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import {Set as ImSet} from 'immutable';
b69ab319import type {Repository} from 'isl-server/src/Repository';
b69ab3110import {repositoryCache} from 'isl-server/src/RepositoryCache';
b69ab3111import fs from 'node:fs';
b69ab3112import {ComparisonType, type Comparison} from 'shared/Comparison';
b69ab3113import * as vscode from 'vscode';
b69ab3114import {vscodeCommands} from '../commands';
b69ab3115import {shouldOpenBeside} from '../config';
b69ab3116import {encodeDeletedFileUri} from '../DeletedFileContentProvider';
b69ab3117import {encodeSaplingDiffUri} from '../DiffContentProvider';
b69ab3118
b69ab3119// Mock vscode command
b69ab3120jest.mock('vscode', () => {
b69ab3121 const actualVscode = jest.requireActual('../../__mocks__/vscode');
b69ab3122 return {
b69ab3123 ...actualVscode,
b69ab3124 commands: {
b69ab3125 executeCommand: jest.fn(),
b69ab3126 },
b69ab3127 };
b69ab3128});
b69ab3129const mockExecuteVSCodeCommand = vscode.commands.executeCommand as jest.MockedFunction<
b69ab3130 typeof vscode.commands.executeCommand
b69ab3131>;
b69ab3132
b69ab3133// Mock fs access
b69ab3134jest.mock('node:fs', () => ({
b69ab3135 promises: {
b69ab3136 access: jest.fn(),
b69ab3137 },
b69ab3138}));
b69ab3139const mockFsAccess = fs.promises.access as jest.MockedFunction<typeof fs.promises.access>;
b69ab3140
b69ab3141// Mock global config
b69ab3142jest.mock('../config', () => ({
b69ab3143 shouldOpenBeside: jest.fn(),
b69ab3144}));
b69ab3145const mockShouldOpenBeside = shouldOpenBeside as jest.MockedFunction<typeof shouldOpenBeside>;
b69ab3146
b69ab3147describe('open-file-diff', () => {
b69ab3148 const openDiffView = vscodeCommands['sapling.open-file-diff'];
b69ab3149
b69ab3150 const repoRoot = '/repo/root';
b69ab3151 const filePath = 'path/to/file';
b69ab3152 const submodulePath = 'path/to/submodule';
b69ab3153 const fileUri = vscode.Uri.file(`${repoRoot}/${filePath}`);
b69ab3154 const submoduleUri = vscode.Uri.file(`${repoRoot}/${submodulePath}`);
b69ab3155
b69ab3156 // Create a proper mock repository
b69ab3157 const mockRepo = {
b69ab3158 info: {
b69ab3159 repoRoot,
b69ab3160 },
b69ab3161 getSubmodulePathCache: jest.fn(),
b69ab3162 } as unknown as jest.Mocked<Repository>;
b69ab3163
b69ab3164 beforeEach(() => {
b69ab3165 jest.clearAllMocks();
b69ab3166
b69ab3167 jest.spyOn(repositoryCache, 'cachedRepositoryForPath').mockReturnValue(mockRepo);
b69ab3168 mockRepo.getSubmodulePathCache.mockReturnValue(ImSet([submodulePath]));
b69ab3169 mockShouldOpenBeside.mockReturnValue(false);
b69ab3170 });
b69ab3171
b69ab3172 it('uncommitted changes, regular file', async () => {
b69ab3173 mockFsAccess.mockResolvedValue(undefined); // File exists
b69ab3174
b69ab3175 const comparison: Comparison = {type: ComparisonType.UncommittedChanges};
b69ab3176 await openDiffView(fileUri, comparison);
b69ab3177
b69ab3178 const expectedLeftRev = '.';
b69ab3179 const expectedLeftUri = encodeSaplingDiffUri(fileUri, expectedLeftRev);
b69ab3180
b69ab3181 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab3182 'vscode.diff',
b69ab3183 expectedLeftUri,
b69ab3184 fileUri,
b69ab3185 'file (Uncommitted Changes)',
b69ab3186 {viewColumn: undefined},
b69ab3187 );
b69ab3188 });
b69ab3189
b69ab3190 it('uncommitted changes, submodule', async () => {
b69ab3191 mockFsAccess.mockRejectedValue(undefined); // Path exists
b69ab3192
b69ab3193 const comparison: Comparison = {type: ComparisonType.UncommittedChanges};
b69ab3194 await openDiffView(submoduleUri, comparison);
b69ab3195
b69ab3196 const expectedLeftRev = '.';
b69ab3197 const expectedLeftUri = encodeSaplingDiffUri(submoduleUri, expectedLeftRev);
b69ab3198 const expectedRightRev = 'wdir()';
b69ab3199 const expectedRightUri = encodeSaplingDiffUri(submoduleUri, expectedRightRev);
b69ab31100
b69ab31101 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31102 'vscode.diff',
b69ab31103 expectedLeftUri,
b69ab31104 expectedRightUri,
b69ab31105 'submodule (Uncommitted Changes)',
b69ab31106 {viewColumn: undefined},
b69ab31107 );
b69ab31108 });
b69ab31109
b69ab31110 it('uncommitted changes, file deleted', async () => {
b69ab31111 mockFsAccess.mockRejectedValue(new Error('File not found')); // File doesn't exist
b69ab31112
b69ab31113 const comparison: Comparison = {type: ComparisonType.UncommittedChanges};
b69ab31114 await openDiffView(fileUri, comparison);
b69ab31115
b69ab31116 const expectedLeftRev = '.';
b69ab31117 const expectedLeftUri = encodeSaplingDiffUri(fileUri, expectedLeftRev);
b69ab31118 const expectedRightUri = encodeDeletedFileUri(fileUri);
b69ab31119
b69ab31120 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31121 'vscode.diff',
b69ab31122 expectedLeftUri,
b69ab31123 expectedRightUri,
b69ab31124 'file (Uncommitted Changes)',
b69ab31125 {viewColumn: undefined},
b69ab31126 );
b69ab31127 });
b69ab31128
b69ab31129 it('head changes, regular file', async () => {
b69ab31130 mockFsAccess.mockResolvedValue(undefined); // File exists
b69ab31131
b69ab31132 const comparison: Comparison = {type: ComparisonType.HeadChanges};
b69ab31133 await openDiffView(fileUri, comparison);
b69ab31134
b69ab31135 const expectedLeftRev = '.^';
b69ab31136 const expectedLeftUri = encodeSaplingDiffUri(fileUri, expectedLeftRev);
b69ab31137
b69ab31138 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31139 'vscode.diff',
b69ab31140 expectedLeftUri,
b69ab31141 fileUri,
b69ab31142 'file (Head Changes)',
b69ab31143 {viewColumn: undefined},
b69ab31144 );
b69ab31145 });
b69ab31146
b69ab31147 it('head changes, submodule', async () => {
b69ab31148 mockFsAccess.mockRejectedValue(undefined); // Path exists
b69ab31149
b69ab31150 const comparison: Comparison = {type: ComparisonType.HeadChanges};
b69ab31151 await openDiffView(submoduleUri, comparison);
b69ab31152
b69ab31153 const expectedLeftRev = '.^';
b69ab31154 const expectedLeftUri = encodeSaplingDiffUri(submoduleUri, expectedLeftRev);
b69ab31155 const expectedRightRev = 'wdir()';
b69ab31156 const expectedRightUri = encodeSaplingDiffUri(submoduleUri, expectedRightRev);
b69ab31157
b69ab31158 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31159 'vscode.diff',
b69ab31160 expectedLeftUri,
b69ab31161 expectedRightUri,
b69ab31162 'submodule (Head Changes)',
b69ab31163 {viewColumn: undefined},
b69ab31164 );
b69ab31165 });
b69ab31166
b69ab31167 it('stack changes, regular file', async () => {
b69ab31168 mockFsAccess.mockResolvedValue(undefined); // File exists
b69ab31169
b69ab31170 const comparison: Comparison = {type: ComparisonType.StackChanges};
b69ab31171 await openDiffView(fileUri, comparison);
b69ab31172
b69ab31173 const expectedLeftRev = 'ancestor(.,interestingmaster())';
b69ab31174 const expectedLeftUri = encodeSaplingDiffUri(fileUri, expectedLeftRev);
b69ab31175
b69ab31176 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31177 'vscode.diff',
b69ab31178 expectedLeftUri,
b69ab31179 fileUri,
b69ab31180 'file (Stack Changes)',
b69ab31181 {viewColumn: undefined},
b69ab31182 );
b69ab31183 });
b69ab31184
b69ab31185 it('stack changes, submodule', async () => {
b69ab31186 mockFsAccess.mockRejectedValue(undefined); // Path exists
b69ab31187
b69ab31188 const comparison: Comparison = {type: ComparisonType.StackChanges};
b69ab31189 await openDiffView(submoduleUri, comparison);
b69ab31190
b69ab31191 const expectedLeftRev = 'ancestor(.,interestingmaster())';
b69ab31192 const expectedLeftUri = encodeSaplingDiffUri(submoduleUri, expectedLeftRev);
b69ab31193 const expectedRightRev = 'wdir()';
b69ab31194 const expectedRightUri = encodeSaplingDiffUri(submoduleUri, expectedRightRev);
b69ab31195
b69ab31196 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31197 'vscode.diff',
b69ab31198 expectedLeftUri,
b69ab31199 expectedRightUri,
b69ab31200 'submodule (Stack Changes)',
b69ab31201 {viewColumn: undefined},
b69ab31202 );
b69ab31203 });
b69ab31204
b69ab31205 it('committed changes, regular file', async () => {
b69ab31206 const comparison: Comparison = {type: ComparisonType.Committed, hash: 'abc123'};
b69ab31207 await openDiffView(fileUri, comparison);
b69ab31208
b69ab31209 const expectedLeftRev = 'abc123^';
b69ab31210 const expectedLeftUri = encodeSaplingDiffUri(fileUri, expectedLeftRev);
b69ab31211 const expectedRightRev = 'abc123';
b69ab31212 const expectedRightUri = encodeSaplingDiffUri(fileUri, expectedRightRev);
b69ab31213
b69ab31214 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31215 'vscode.diff',
b69ab31216 expectedLeftUri,
b69ab31217 expectedRightUri,
b69ab31218 'file (In abc123)',
b69ab31219 {viewColumn: undefined},
b69ab31220 );
b69ab31221 });
b69ab31222
b69ab31223 it('committed changes, submodule', async () => {
b69ab31224 const comparison: Comparison = {type: ComparisonType.Committed, hash: 'abc123'};
b69ab31225 await openDiffView(submoduleUri, comparison);
b69ab31226
b69ab31227 const expectedLeftRev = 'abc123^';
b69ab31228 const expectedLeftUri = encodeSaplingDiffUri(submoduleUri, expectedLeftRev);
b69ab31229 const expectedRightRev = 'abc123';
b69ab31230 const expectedRightUri = encodeSaplingDiffUri(submoduleUri, expectedRightRev);
b69ab31231
b69ab31232 expect(mockExecuteVSCodeCommand).toHaveBeenCalledWith(
b69ab31233 'vscode.diff',
b69ab31234 expectedLeftUri,
b69ab31235 expectedRightUri,
b69ab31236 'submodule (In abc123)',
b69ab31237 {viewColumn: undefined},
b69ab31238 );
b69ab31239 });
b69ab31240});