106 lines
3.5 KiB
TypeScript
106 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { GameLibrary, GameLibraryGame, GameLibraryVersion } from '../../src/lib/game-files.js';
|
|
import { latestGameFiles, selectLatestGameFiles } from '../../src/lib/ui/native-game-files.js';
|
|
|
|
function upload(
|
|
id: string,
|
|
game: GameLibraryGame = 't5',
|
|
state: GameLibraryVersion['state'] = 'ready'
|
|
): GameLibraryVersion {
|
|
return {
|
|
id,
|
|
libraryId: game,
|
|
game,
|
|
version: id,
|
|
description: '',
|
|
state,
|
|
sizeBytes: 10,
|
|
fileCount: 1,
|
|
manifestSha256: 'manifest',
|
|
files: [],
|
|
createdAt: '2026-10-04T12:00:00Z',
|
|
publishedAt: state === 'ready' ? '2026-10-04T12:05:00Z' : null,
|
|
storageLocation: '',
|
|
sourceHostId: null,
|
|
sourceVolume: null,
|
|
error: null,
|
|
operationId: null,
|
|
caches: []
|
|
};
|
|
}
|
|
|
|
function slot(
|
|
game: GameLibraryGame,
|
|
latestVersionId: string | null,
|
|
versions: GameLibraryVersion[]
|
|
): GameLibrary {
|
|
return {
|
|
id: game,
|
|
name: game.toUpperCase(),
|
|
game,
|
|
description: '',
|
|
createdAt: '',
|
|
latestVersionId,
|
|
versions
|
|
};
|
|
}
|
|
|
|
describe('automatic game file selection for new launches', () => {
|
|
it('follows the controller latest upload even when older files are already cached', () => {
|
|
const old = upload('old');
|
|
old.caches = [
|
|
{
|
|
hostId: 'host',
|
|
libraryVersionId: old.id,
|
|
status: 'ready',
|
|
bytesDownloaded: 10,
|
|
bytesTotal: 10,
|
|
manifestSha256: 'manifest',
|
|
error: null,
|
|
updatedAt: '',
|
|
operationId: null
|
|
}
|
|
];
|
|
const current = upload('latest');
|
|
// The API can retain older uploads and unfinished uploads in its history.
|
|
const libraries = [
|
|
slot('t5', current.id, [upload('unfinished', 't5', 'importing'), old, current])
|
|
];
|
|
const selected = { t5: old.id };
|
|
const latest = latestGameFiles(libraries);
|
|
|
|
expect(latest.t5).toBe(current);
|
|
expect(selectLatestGameFiles(selected, latest, ['t5'])).toBe(true);
|
|
expect(selected.t5).toBe(current.id);
|
|
expect(selectLatestGameFiles(selected, latest, ['t5'])).toBe(false);
|
|
});
|
|
|
|
it('updates both games and removes a stale selection when a game has no available upload', () => {
|
|
const latest = latestGameFiles([
|
|
slot('t5', null, [upload('unavailable')]),
|
|
slot('t6', 'new-t6', [upload('new-t6', 't6')])
|
|
]);
|
|
const selected: Partial<Record<GameLibraryGame, string>> = { t5: 'old-t5', t6: 'old-t6' };
|
|
|
|
expect(selectLatestGameFiles(selected, latest, ['t5', 't6'])).toBe(true);
|
|
expect(selected).toEqual({ t6: 'new-t6' });
|
|
});
|
|
|
|
it('never selects an unfinished or missing latest upload from history', () => {
|
|
expect(
|
|
latestGameFiles([
|
|
slot('t5', 'pending', [upload('old'), upload('pending', 't5', 'importing')])
|
|
])
|
|
).toEqual({});
|
|
expect(latestGameFiles([slot('t6', 'missing', [upload('old', 't6')])])).toEqual({});
|
|
});
|
|
|
|
it('only changes games needed by the current launch', () => {
|
|
const selected = { t5: 'old-t5', t6: 'keep-t6' };
|
|
const latest = latestGameFiles([slot('t5', 'new-t5', [upload('new-t5')])]);
|
|
|
|
expect(selectLatestGameFiles(selected, latest, ['t5'])).toBe(true);
|
|
expect(selected).toEqual({ t5: 'new-t5', t6: 'keep-t6' });
|
|
});
|
|
});
|