fix(update): align no-update dependency injection

This commit is contained in:
Tam Nhu Tran
2026-04-10 23:06:37 -04:00
parent a4496ff1d9
commit 94bcad2d1a
3 changed files with 25 additions and 44 deletions
+6 -36
View File
@@ -15,7 +15,7 @@ import {
type CurrentInstall,
type InstalledPackageState,
} from '../utils/package-manager-detector';
import { compareVersionsWithPrerelease } from '../utils/update-checker';
import { compareVersionsWithPrerelease, type UpdateResult } from '../utils/update-checker';
import { getVersion } from '../utils/version';
/**
@@ -28,29 +28,6 @@ export interface UpdateOptions {
type TargetTag = 'latest' | 'dev';
type UpdateCheckResult =
| {
status: 'update_available';
current?: string;
latest?: string;
message?: string;
reason?: string;
}
| {
status: 'check_failed';
message?: string;
latest?: string;
current?: string;
reason?: string;
}
| {
status: 'no_update';
reason?: string;
latest?: string;
current?: string;
message?: string;
};
export interface UpdateCommandDeps {
initUI: typeof initUI;
getVersion: typeof getVersion;
@@ -64,7 +41,7 @@ export interface UpdateCommandDeps {
interactive: boolean,
channel: 'npm' | 'direct',
targetTag: TargetTag
) => Promise<UpdateCheckResult>;
) => Promise<UpdateResult>;
spawn: typeof spawn;
}
@@ -73,14 +50,9 @@ async function loadCheckForUpdates(
interactive: boolean,
channel: 'npm' | 'direct',
targetTag: TargetTag
): Promise<UpdateCheckResult> {
): Promise<UpdateResult> {
const { checkForUpdates } = await import('../utils/update-checker');
return checkForUpdates(
currentVersion,
interactive,
channel,
targetTag
) as Promise<UpdateCheckResult>;
return checkForUpdates(currentVersion, interactive, channel, targetTag);
}
const defaultDeps: UpdateCommandDeps = {
@@ -150,7 +122,7 @@ export async function handleUpdateCommand(
}
if (updateResult.status === 'no_update') {
handleNoUpdate(updateResult.reason);
handleNoUpdate(updateResult.reason, currentVersion);
return;
}
@@ -215,9 +187,7 @@ function handleCheckFailed(
/**
* Handle no update available
*/
function handleNoUpdate(reason: string | undefined): void {
const version = getVersion();
function handleNoUpdate(reason: string | undefined, version: string): void {
let message = `You are already on the latest version (${version})`;
switch (reason) {
+1 -1
View File
@@ -21,7 +21,7 @@ interface UpdateCache {
dismissed_version: string | null;
}
interface UpdateResult {
export interface UpdateResult {
status: 'update_available' | 'no_update' | 'check_failed';
reason?: string;
latest?: string;
@@ -1,5 +1,6 @@
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import { handleUpdateCommand, type UpdateCommandDeps } from '../../../src/commands/update-command';
import type { UpdateResult } from '../../../src/utils/update-checker';
let logLines: string[] = [];
let spawnCalls: Array<{ command: string; args: string[]; env?: NodeJS.ProcessEnv }> = [];
@@ -18,13 +19,8 @@ type Scenario = {
afterState: InstalledState;
};
type UpdateCheckResult =
| { status: 'update_available'; current: string; latest: string }
| { status: 'no_update' }
| { status: 'check_failed'; message: string };
let scenario: Scenario;
let updateCheckResult: UpdateCheckResult;
let updateCheckResult: UpdateResult;
let currentInstallOverride: ReturnType<typeof installDescriptor>;
let stateReads = 0;
@@ -39,7 +35,7 @@ function installDescriptor() {
};
}
function createDeps(): UpdateCommandDeps {
function createDeps(overrides: Partial<UpdateCommandDeps> = {}): UpdateCommandDeps {
return {
initUI: async () => {},
getVersion: () => '7.67.0-dev.5',
@@ -95,6 +91,7 @@ function createDeps(): UpdateCommandDeps {
},
};
}) as typeof UpdateCommandDeps.prototype.spawn,
...overrides,
};
}
@@ -196,6 +193,20 @@ describe('update-command current install handling', () => {
expect(exitCodes).toContain(0);
});
it('uses the injected version in the no-update message', async () => {
updateCheckResult = { status: 'no_update' };
await handleUpdateCommand(
{},
createDeps({
getVersion: () => '9.9.9-test.1',
})
);
expect(logLines.join('\n')).toContain('latest version (9.9.9-test.1)');
expect(exitCodes).toContain(0);
});
it('accepts a newer installed version when the dist-tag moves during update', async () => {
scenario = {
beforeState: { version: '7.67.0-dev.5', packageJsonMtimeMs: 100, scriptMtimeMs: 100 },