feat: the library's albums go on the wanted list as held, once; after that the list is the truth (M502 #5567)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m44s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m31s
release / Build signed APK (releases and dev) (push) Successful in 5m35s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m44s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m31s
release / Build signed APK (releases and dev) (push) Successful in 5m35s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
A one-time job in the wanted worker lists every album in the library as a held want, one per release group, with a record that it happened (acquisition_settings.library_listed_at). Albums whose tags name only a release are named on MusicBrainz first, 120 a pass; what nothing names is counted and shown on the Held tab. Re-acquisition now wants back only albums on the list. Taking a held album off the list leaves its files, and it is never fetched back; albums put in the library folder by hand afterwards are not added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,61 +1,94 @@
|
||||
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
import { createRawSnippet } from 'svelte';
|
||||
import { mockInfiniteQuery } from '../../test-utils/query';
|
||||
import { pageUrlModule } from '#test-utils/mocks/appState.js';
|
||||
import type { WantCounts, WantsPage } from '#lib/api/types.js';
|
||||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/svelte";
|
||||
import { createRawSnippet } from "svelte";
|
||||
import { mockInfiniteQuery } from "../../test-utils/query";
|
||||
import { pageUrlModule } from "#test-utils/mocks/appState.js";
|
||||
import type { WantCounts, WantsPage } from "#lib/api/types.js";
|
||||
|
||||
const state = vi.hoisted(() => ({ pageUrl: new URL('http://localhost/wanted') }));
|
||||
vi.mock('$app/state', () => pageUrlModule(state));
|
||||
vi.mock('#lib/api/wanted.js', () => ({ createWantsQuery: vi.fn() }));
|
||||
const state = vi.hoisted(() => ({
|
||||
pageUrl: new URL("http://localhost/wanted"),
|
||||
}));
|
||||
vi.mock("$app/state", () => pageUrlModule(state));
|
||||
vi.mock("#lib/api/wanted.js", () => ({ createWantsQuery: vi.fn() }));
|
||||
|
||||
import WantedLayout from './+layout.svelte';
|
||||
import { createWantsQuery } from '#lib/api/wanted.js';
|
||||
import WantedLayout from "./+layout.svelte";
|
||||
import { createWantsQuery } from "#lib/api/wanted.js";
|
||||
|
||||
const counts: WantCounts = { wanted: 5, missing: 1, held: 9, following: 2, activity: 3, attention: 0, blocked: 4 };
|
||||
const children = createRawSnippet(() => ({ render: () => `<p data-testid="tab-body">body</p>` }));
|
||||
const counts: WantCounts = {
|
||||
wanted: 5,
|
||||
missing: 1,
|
||||
held: 9,
|
||||
following: 2,
|
||||
activity: 3,
|
||||
attention: 0,
|
||||
blocked: 4,
|
||||
};
|
||||
const children = createRawSnippet(() => ({
|
||||
render: () => `<p data-testid="tab-body">body</p>`,
|
||||
}));
|
||||
|
||||
afterEach(() => vi.clearAllMocks());
|
||||
|
||||
function setup(c: WantCounts = counts, path = '/wanted') {
|
||||
function setup(c: WantCounts = counts, path = "/wanted") {
|
||||
state.pageUrl = new URL(`http://localhost${path}`);
|
||||
const page: WantsPage = { items: [], total: 0, limit: 50, offset: 0, counts: c };
|
||||
const page: WantsPage = {
|
||||
items: [],
|
||||
total: 0,
|
||||
limit: 50,
|
||||
offset: 0,
|
||||
counts: c,
|
||||
library: { listed_at: null, unlisted: 0 },
|
||||
};
|
||||
vi.mocked(createWantsQuery).mockReturnValue(
|
||||
mockInfiniteQuery({ pages: [page] }) as unknown as ReturnType<typeof createWantsQuery>
|
||||
mockInfiniteQuery({ pages: [page] }) as unknown as ReturnType<
|
||||
typeof createWantsQuery
|
||||
>,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return render(WantedLayout, { children } as any);
|
||||
}
|
||||
|
||||
describe('/wanted layout', () => {
|
||||
test('tabs are links carrying their counts, the current one marked', () => {
|
||||
setup(counts, '/wanted/activity');
|
||||
const nav = screen.getByRole('navigation', { name: /wanted sections/i });
|
||||
const links = Array.from(nav.querySelectorAll('a')).map((a) => [a.getAttribute('href'), a.textContent?.replace(/\s+/g, ' ').trim()]);
|
||||
expect(links).toEqual([
|
||||
['/wanted', 'Wanted 5'],
|
||||
['/wanted/activity', 'Activity 3'],
|
||||
['/wanted/missing', 'Missing files 1'],
|
||||
['/wanted/held', 'Held 9'],
|
||||
['/wanted/following', 'Following 2'],
|
||||
['/wanted/blocked', 'Blocked 4']
|
||||
describe("/wanted layout", () => {
|
||||
test("tabs are links carrying their counts, the current one marked", () => {
|
||||
setup(counts, "/wanted/activity");
|
||||
const nav = screen.getByRole("navigation", { name: /wanted sections/i });
|
||||
const links = Array.from(nav.querySelectorAll("a")).map((a) => [
|
||||
a.getAttribute("href"),
|
||||
a.textContent?.replace(/\s+/g, " ").trim(),
|
||||
]);
|
||||
expect(screen.getByRole('link', { name: /activity/i })).toHaveAttribute('aria-current', 'page');
|
||||
expect(screen.getByRole('link', { name: /^wanted/i })).not.toHaveAttribute('aria-current');
|
||||
expect(screen.getByTestId('tab-body')).toBeTruthy();
|
||||
expect(links).toEqual([
|
||||
["/wanted", "Wanted 5"],
|
||||
["/wanted/activity", "Activity 3"],
|
||||
["/wanted/missing", "Missing files 1"],
|
||||
["/wanted/held", "Held 9"],
|
||||
["/wanted/following", "Following 2"],
|
||||
["/wanted/blocked", "Blocked 4"],
|
||||
]);
|
||||
expect(screen.getByRole("link", { name: /activity/i })).toHaveAttribute(
|
||||
"aria-current",
|
||||
"page",
|
||||
);
|
||||
expect(screen.getByRole("link", { name: /^wanted/i })).not.toHaveAttribute(
|
||||
"aria-current",
|
||||
);
|
||||
expect(screen.getByTestId("tab-body")).toBeTruthy();
|
||||
});
|
||||
|
||||
test('when nothing needs a person the verdict says so', () => {
|
||||
test("when nothing needs a person the verdict says so", () => {
|
||||
setup();
|
||||
expect(screen.getByTestId('wanted-verdict').textContent).toMatch(/5 albums wanted, 3 downloading\. Nothing needs you\./);
|
||||
expect(screen.queryByTestId('tab-attention')).toBeNull();
|
||||
expect(screen.getByTestId("wanted-verdict").textContent).toMatch(
|
||||
/5 albums wanted, 3 downloading\. Nothing needs you\./,
|
||||
);
|
||||
expect(screen.queryByTestId("tab-attention")).toBeNull();
|
||||
});
|
||||
|
||||
test('downloads waiting on a person lead the page and mark Activity', () => {
|
||||
test("downloads waiting on a person lead the page and mark Activity", () => {
|
||||
setup({ ...counts, attention: 2 });
|
||||
const verdict = screen.getByTestId('wanted-verdict');
|
||||
const verdict = screen.getByTestId("wanted-verdict");
|
||||
expect(verdict.textContent).toMatch(/2 downloads need you/);
|
||||
expect(screen.getByRole('link', { name: /see activity/i }).getAttribute('href')).toBe('/wanted/activity');
|
||||
expect(screen.getByTestId('tab-attention').textContent).toBe('2');
|
||||
expect(
|
||||
screen.getByRole("link", { name: /see activity/i }).getAttribute("href"),
|
||||
).toBe("/wanted/activity");
|
||||
expect(screen.getByTestId("tab-attention").textContent).toBe("2");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user