Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions src/JestExt/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@

this.events.onTestSessionStarted.fire({ ...this.extContext, session: this.processSession });

await this.updateTestFileList();
// Force update test file list during session initialization
await this.updateTestFileList(true);

// update visible editors that belong to this folder
this.updateVisibleTextEditors();
Expand Down Expand Up @@ -568,6 +569,11 @@

//** commands */
public debugTests = async (debugInfo: DebugInfo): Promise<void> => {
// Check if test file list needs updating before debug, and update if necessary
if (this.testResultProvider.isTestFileListDirty()) {
await this.updateTestFileList();
}

Check failure on line 576 in src/JestExt/core.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `····`
const getDebugConfig = (
folder?: vscode.WorkspaceFolder
): vscode.DebugConfiguration | undefined => {
Expand Down Expand Up @@ -619,6 +625,11 @@
this.enableOutputOnRun();
await this.exitDeferMode();

// Check if test file list needs updating, and update if necessary
if (this.testResultProvider.isTestFileListDirty()) {
await this.updateTestFileList();
}

if (!editor) {
if (this.processSession.scheduleProcess({ type: 'all-tests', nonBlocking: true })) {
this.dirtyFiles.clear();
Expand Down Expand Up @@ -703,6 +714,7 @@
private refreshDocumentChange(document?: vscode.TextDocument): void {
this.updateVisibleTextEditors(document);

// Update status bar with latest stats
this.updateStatusBar({
stats: this.toSBStats(this.testResultProvider.getTestSuiteStats()),
});
Expand Down Expand Up @@ -741,7 +753,12 @@
this.refreshDocumentChange(document);
}

private async updateTestFileList(): Promise<void> {
private async updateTestFileList(force: boolean = false): Promise<void> {
// Skip update if not forced and test file list isn't dirty
if (!force && !this.testResultProvider.isTestFileListDirty()) {
return;
}

Check failure on line 761 in src/JestExt/core.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `····`
return new Promise((resolve, reject) => {
this.processSession.scheduleProcess({
type: 'list-test-files',
Expand All @@ -765,13 +782,13 @@
}

onDidCreateFiles(_event: vscode.FileCreateEvent): void {
this.updateTestFileList();
this.testResultProvider.markTestFileListDirty();
}
onDidRenameFiles(_event: vscode.FileRenameEvent): void {
this.updateTestFileList();
this.testResultProvider.markTestFileListDirty();
}
onDidDeleteFiles(_event: vscode.FileDeleteEvent): void {
this.updateTestFileList();
this.testResultProvider.markTestFileListDirty();
}

toggleCoverage(): Promise<void> {
Expand Down
10 changes: 10 additions & 0 deletions src/TestResults/TestResultProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@
private testFiles?: string[];
private snapshotProvider: SnapshotProvider;
private parser: Parser;
private testFileListDirty: boolean = false;

constructor(
extEvents: JestSessionEvents,
Expand Down Expand Up @@ -258,12 +259,21 @@

updateTestFileList(testFiles?: string[]): void {
this.testFiles = testFiles;
this.testFileListDirty = false;

// clear the cache in case we have cached some non-test files prior
this.testSuites.clear();

this.events.testListUpdated.fire(testFiles);
}

Check failure on line 269 in src/TestResults/TestResultProvider.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `··`
markTestFileListDirty(): void {
this.testFileListDirty = true;
}

Check failure on line 273 in src/TestResults/TestResultProvider.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `··`
isTestFileListDirty(): boolean {
return this.testFileListDirty;
}
getTestList(): string[] {
if (this.testFiles && this.testFiles.length > 0) {
return this.testFiles;
Expand Down
72 changes: 60 additions & 12 deletions tests/JestExt/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,20 @@
const coverageCodeLensProvider: any = override?.coverageCodeLensProvider ?? {
coverageChanged: jest.fn(),
};
return new JestExt(

// Make a JestExt instance
const jestExtInstance = new JestExt(
context,
workspaceFolder,
debugConfigurationProvider,
coverageCodeLensProvider
);

// Mock the new methods on testResultProvider
jestExtInstance.testResultProvider.markTestFileListDirty = jest.fn();
jestExtInstance.testResultProvider.isTestFileListDirty = jest.fn().mockReturnValue(false);

return jestExtInstance;
};
const mockEditor = (fileName: string, languageId = 'typescript'): any => {
return {
Expand Down Expand Up @@ -178,6 +186,22 @@
let startDebugging;
const mockShowQuickPick = jest.fn();
let mockConfigurations = [];

Check failure on line 189 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `····`
it('should update test file list if marked as dirty before debugging', async () => {
const sut = newJestExt();
// Mock that test file list is dirty
(sut.testResultProvider.isTestFileListDirty as jest.Mock).mockReturnValueOnce(true);

Check failure on line 194 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `······`
// Set up updateTestFileList to resolve immediately when called
const updateTestFileListSpy = jest.spyOn(sut as any, 'updateTestFileList').mockResolvedValueOnce(undefined);

Check failure on line 196 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Replace `.spyOn(sut·as·any,·'updateTestFileList')` with `⏎········.spyOn(sut·as·any,·'updateTestFileList')⏎········`

Check failure on line 197 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `······`
await sut.debugTests({ testPath: document.fileName, testName: 'testName' });

Check failure on line 199 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `······`
// Verify updateTestFileList was called before debugging
expect(updateTestFileListSpy).toHaveBeenCalled();
expect(sut.debugConfigurationProvider.prepareTestRun).toHaveBeenCalled();
});

Check failure on line 204 in tests/JestExt/core.test.ts

View workflow job for this annotation

GitHub Actions / Pre-test checks

Delete `····`
beforeEach(() => {
startDebugging = vscode.debug.startDebugging as unknown as jest.Mock<{}>;
(startDebugging as unknown as jest.Mock<{}>).mockImplementation(
Expand Down Expand Up @@ -752,6 +776,19 @@
expect(mockTestProvider.dispose).toHaveBeenCalledTimes(1);
expect(JestTestProvider).toHaveBeenCalledTimes(2);
});

it('forces update of test file list on session start', async () => {
const sut = createJestExt();

// Set up spy to check how updateTestFileList is called
const updateTestFileListSpy = jest.spyOn(sut as any, 'updateTestFileList');

await sut.startSession();

// Verify updateTestFileList was called with force=true
expect(updateTestFileListSpy).toHaveBeenCalledWith(true);
});

describe('will update test file list', () => {
it.each`
fileNames | error | expectedTestFiles
Expand Down Expand Up @@ -861,6 +898,21 @@
});
});
describe('runAllTests', () => {
it('should update test file list if marked as dirty before running tests', async () => {
const sut = newJestExt();
// Mock that test file list is dirty
(sut.testResultProvider.isTestFileListDirty as jest.Mock).mockReturnValueOnce(true);

// Set up updateTestFileList to resolve immediately when called
const updateTestFileListSpy = jest.spyOn(sut as any, 'updateTestFileList').mockResolvedValueOnce(undefined);

await sut.runAllTests();

// Verify updateTestFileList was called before scheduling process
expect(updateTestFileListSpy).toHaveBeenCalled();
expect(mockProcessSession.scheduleProcess).toHaveBeenCalled();
});

describe.each`
scheduleProcess
${{}}
Expand Down Expand Up @@ -934,29 +986,25 @@
}
);
});
describe('refresh test file list upon file system change', () => {
const getProcessType = () => {
const { type } = mockProcessSession.scheduleProcess.mock.calls[0][0];
return type;
};
describe('mark test file list as dirty upon file system change', () => {
let jestExt: any;
beforeEach(() => {
jestExt = newJestExt();
});
it('when new file is created', () => {
jestExt.onDidCreateFiles({});
expect(mockProcessSession.scheduleProcess).toHaveBeenCalledTimes(1);
expect(getProcessType()).toEqual('list-test-files');
expect(jestExt.testResultProvider.markTestFileListDirty).toHaveBeenCalled();
expect(mockProcessSession.scheduleProcess).not.toHaveBeenCalled();
});
it('when file is renamed', () => {
jestExt.onDidRenameFiles({});
expect(mockProcessSession.scheduleProcess).toHaveBeenCalledTimes(1);
expect(getProcessType()).toEqual('list-test-files');
expect(jestExt.testResultProvider.markTestFileListDirty).toHaveBeenCalled();
expect(mockProcessSession.scheduleProcess).not.toHaveBeenCalled();
});
it('when file is deleted', () => {
jestExt.onDidDeleteFiles({});
expect(mockProcessSession.scheduleProcess).toHaveBeenCalledTimes(1);
expect(getProcessType()).toEqual('list-test-files');
expect(jestExt.testResultProvider.markTestFileListDirty).toHaveBeenCalled();
expect(mockProcessSession.scheduleProcess).not.toHaveBeenCalled();
});
});
describe('triggerUpdateSettings', () => {
Expand Down
9 changes: 9 additions & 0 deletions tests/TestResults/TestResultProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,15 @@ describe('TestResultProvider', () => {
sut.updateTestFileList(['test-file']);
itBlocks = [];
};

it('should mark test file list as not dirty after update', () => {
const sut = new TestResultProvider(eventsMock);
expect(sut.isTestFileListDirty()).toBeFalsy();
sut.markTestFileListDirty();
expect(sut.isTestFileListDirty()).toBeTruthy();
sut.updateTestFileList(['test-file']);
expect(sut.isTestFileListDirty()).toBeFalsy();
});
it.each`
desc | setup | itBlockOverride | expectedResults | statsChange
${'parse failed'} | ${forceParseError} | ${undefined} | ${[]} | ${'fail'}
Expand Down