This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
import { afterEach, beforeEach, expect, it, vi } from 'vitest';
|
||||
import { flushSync, mount, unmount } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import BetaSetupPage from '../../src/routes/betas/new/+page.svelte';
|
||||
|
||||
const currentPage = writable({
|
||||
url: new URL('http://localhost/betas/new'),
|
||||
data: { user: { role: 'operator' } }
|
||||
});
|
||||
vi.mock('$app/stores', () => ({
|
||||
page: {
|
||||
subscribe: (run: Parameters<typeof currentPage.subscribe>[0]) => currentPage.subscribe(run)
|
||||
}
|
||||
}));
|
||||
vi.mock('$app/navigation', () => ({ goto: vi.fn(), beforeNavigate: vi.fn() }));
|
||||
vi.mock('../../src/lib/ui/stores/fleet.js', () => ({
|
||||
fleetServers: writable([]),
|
||||
fleetError: writable(''),
|
||||
refreshFleet: vi.fn().mockResolvedValue(undefined)
|
||||
}));
|
||||
|
||||
let component: ReturnType<typeof mount> | undefined;
|
||||
beforeEach(() => {
|
||||
const storage = new Map<string, string>();
|
||||
vi.stubGlobal('localStorage', {
|
||||
getItem: (key: string) => storage.get(key) ?? null,
|
||||
setItem: (key: string, value: string) => storage.set(key, value),
|
||||
removeItem: (key: string) => storage.delete(key)
|
||||
});
|
||||
window.history.replaceState({}, '', '/betas/new');
|
||||
});
|
||||
afterEach(async () => {
|
||||
if (component) await unmount(component);
|
||||
component = undefined;
|
||||
document.body.replaceChildren();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
function file(
|
||||
id: number,
|
||||
options: {
|
||||
currentVersionId?: number;
|
||||
latestVersionId?: number | null;
|
||||
runningBetaId?: number;
|
||||
} = {}
|
||||
) {
|
||||
const latestVersionId =
|
||||
options.latestVersionId === undefined ? id * 10 + 2 : options.latestVersionId;
|
||||
return {
|
||||
id,
|
||||
name: `File ${id}`,
|
||||
kind: 'script',
|
||||
target_rel_path: `file-${id}.gsc`,
|
||||
scope_type: null,
|
||||
scope_value: null,
|
||||
current_version_id: options.currentVersionId ?? id * 10,
|
||||
latestVersion: latestVersionId === null ? null : { id: latestVersionId },
|
||||
runningBetaId: options.runningBetaId ?? null
|
||||
};
|
||||
}
|
||||
const files = [
|
||||
file(1),
|
||||
file(2),
|
||||
file(3, { currentVersionId: 32 }),
|
||||
file(4, { runningBetaId: 7 }),
|
||||
file(5, { latestVersionId: null })
|
||||
];
|
||||
const button = (label: string) =>
|
||||
[...document.querySelectorAll('button')].find((node) => node.textContent?.trim() === label)!;
|
||||
const selections = () =>
|
||||
[...document.querySelectorAll('.pick-row')].map((row) =>
|
||||
[...row.querySelectorAll('select')].map((select) => select.value)
|
||||
);
|
||||
|
||||
async function show({ query = '', failingFile = 0 } = {}) {
|
||||
window.history.replaceState({}, '', `/betas/new${query}`);
|
||||
currentPage.set({
|
||||
url: new URL(window.location.href),
|
||||
data: { user: { role: 'operator' } }
|
||||
});
|
||||
const fetch = vi.fn(async (url: string) => {
|
||||
if (url === '/api/scripts') return Response.json({ scripts: files });
|
||||
const script = files.find((entry) => url === `/api/scripts/${entry.id}`);
|
||||
if (!script) throw new Error(`Unexpected request: ${url}`);
|
||||
if (script.id === failingFile) return new Response('', { status: 503 });
|
||||
return Response.json({
|
||||
script,
|
||||
versions: [2, 1, 0].map((version) => ({
|
||||
id: script.id * 10 + version,
|
||||
version: version + 1,
|
||||
release_version: `1.0.${version}`,
|
||||
sha256: `hash-${script.id}-${version}`,
|
||||
state: 'untested'
|
||||
})),
|
||||
matchedServers: []
|
||||
});
|
||||
});
|
||||
vi.stubGlobal('fetch', fetch);
|
||||
component = mount(BetaSetupPage, { target: document.body });
|
||||
flushSync();
|
||||
await vi.waitFor(() => {
|
||||
flushSync();
|
||||
expect(button('Add all eligible files')).toBeDefined();
|
||||
});
|
||||
return fetch;
|
||||
}
|
||||
|
||||
it('adds every eligible file with its latest unpromoted version and replaces empty rows', async () => {
|
||||
const fetch = await show();
|
||||
button('Add file').click();
|
||||
flushSync();
|
||||
expect(document.querySelectorAll('.pick-row')).toHaveLength(2);
|
||||
button('Add all eligible files').click();
|
||||
await vi.waitFor(() => {
|
||||
flushSync();
|
||||
expect(selections()).toEqual([
|
||||
['1', '12'],
|
||||
['2', '22']
|
||||
]);
|
||||
});
|
||||
expect(button('Continue').disabled).toBe(false);
|
||||
expect(button('Add all eligible files').disabled).toBe(true);
|
||||
button('Add all eligible files').click();
|
||||
flushSync();
|
||||
expect(document.querySelectorAll('.pick-row')).toHaveLength(2);
|
||||
expect(fetch.mock.calls.map(([url]) => url)).toEqual([
|
||||
'/api/scripts',
|
||||
'/api/scripts/1',
|
||||
'/api/scripts/2'
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves exact linked versions, including an older upload of a promoted file', async () => {
|
||||
await show({ query: '?artifact=1:11&artifact=3:31' });
|
||||
button('Add file').click();
|
||||
flushSync();
|
||||
button('Add all eligible files').click();
|
||||
await vi.waitFor(() => {
|
||||
flushSync();
|
||||
expect(selections()).toEqual([
|
||||
['1', '11'],
|
||||
['3', '31'],
|
||||
['2', '22']
|
||||
]);
|
||||
});
|
||||
expect(button('Continue').disabled).toBe(false);
|
||||
});
|
||||
|
||||
it('retains successful selections and blocks continuing when one file cannot load versions', async () => {
|
||||
await show({ failingFile: 2 });
|
||||
button('Add all eligible files').click();
|
||||
await vi.waitFor(() => {
|
||||
flushSync();
|
||||
expect(document.querySelector('[role="alert"]')?.textContent).toContain(
|
||||
'Could not load versions'
|
||||
);
|
||||
});
|
||||
expect(selections()[0]).toEqual(['1', '12']);
|
||||
expect(selections()[1][0]).toBe('2');
|
||||
const failedVersion = document.querySelectorAll('.pick-row')[1].querySelectorAll('select')[1];
|
||||
expect(failedVersion.selectedOptions[0].textContent).toBe('Choose a version');
|
||||
expect(button('Continue').disabled).toBe(true);
|
||||
});
|
||||
Reference in New Issue
Block a user