diff --git a/.changeset/all-pandas-hide.md b/.changeset/all-pandas-hide.md
new file mode 100644
index 0000000000..657654830b
--- /dev/null
+++ b/.changeset/all-pandas-hide.md
@@ -0,0 +1,5 @@
+---
+"landscape-ui": patch
+---
+
+Sort the local repositories packages list so it stays consistent
diff --git a/src/features/local-repositories/components/ImportRepositoryPackagesSidePanel/ValidationResult/ValidationResult.test.tsx b/src/features/local-repositories/components/ImportRepositoryPackagesSidePanel/ValidationResult/ValidationResult.test.tsx
index ad819ded92..cd4ae1705a 100644
--- a/src/features/local-repositories/components/ImportRepositoryPackagesSidePanel/ValidationResult/ValidationResult.test.tsx
+++ b/src/features/local-repositories/components/ImportRepositoryPackagesSidePanel/ValidationResult/ValidationResult.test.tsx
@@ -85,9 +85,7 @@ describe("ValidationResult", () => {
).toBeInTheDocument();
expect(screen.getByText(/packages to import/i)).toBeInTheDocument();
- expect(
- screen.getByText("python3-snap-http_1.4.0-0ubuntu0_all"),
- ).toBeInTheDocument();
+ expect(screen.getByText("package1-0.2.1")).toBeInTheDocument();
expect(screen.getByText(/page 1 of 10/i)).toBeInTheDocument();
});
@@ -97,9 +95,7 @@ describe("ValidationResult", () => {
);
expect(screen.getByText(/packages to import/i)).toBeInTheDocument();
- expect(
- screen.getByText("python3-snap-http_1.4.0-0ubuntu0_all"),
- ).toBeInTheDocument();
+ expect(screen.getByText("package1-0.2.1")).toBeInTheDocument();
expect(screen.getByText("package2-1.0.0")).toBeInTheDocument();
});
});
diff --git a/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.test.tsx b/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.test.tsx
index 98506e10c0..bbd2b022fb 100644
--- a/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.test.tsx
+++ b/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.test.tsx
@@ -1,27 +1,34 @@
import { renderWithProviders } from "@/tests/render";
import { describe, it, expect } from "vitest";
import LocalRepositoryPackagesList from "./LocalRepositoryPackagesList";
-import { paginatedPackages } from "@/tests/mocks/localRepositories";
+import {
+ paginatedPackages,
+ sortedPackages,
+} from "@/tests/mocks/localRepositories";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-const singlePagePackages = paginatedPackages.slice(0, 10);
-
describe("LocalRepositoryPackagesList", () => {
- it("renders table with default column header", async () => {
+ it("renders table with default column header and paginated data", async () => {
renderWithProviders(
- ,
+ ,
);
expect(
await screen.findByRole("columnheader", { name: "Package name" }),
).toBeInTheDocument();
+
+ for (const pkg of sortedPackages.slice(0, 10)) {
+ expect(await screen.findByText(pkg)).toBeInTheDocument();
+ }
+
+ expect(await screen.findByText(/page 1 of 3/i)).toBeInTheDocument();
});
it("renders custom header when provided", async () => {
renderWithProviders(
,
);
@@ -31,15 +38,6 @@ describe("LocalRepositoryPackagesList", () => {
).toBeInTheDocument();
});
- it("renders package names in table rows", async () => {
- renderWithProviders(
- ,
- );
-
- expect(await screen.findByText("package-1")).toBeInTheDocument();
- expect(screen.getByText("package-2")).toBeInTheDocument();
- });
-
it("renders empty message when no packages", async () => {
renderWithProviders();
@@ -48,28 +46,22 @@ describe("LocalRepositoryPackagesList", () => {
).toBeInTheDocument();
});
- it("renders pagination info if more than 1 page", async () => {
- renderWithProviders(
- ,
- );
-
- expect(await screen.findByText(/page 1 of 3/i)).toBeInTheDocument();
- });
-
it("navigates to next page on click", async () => {
const user = userEvent.setup();
renderWithProviders(
,
);
- await screen.findByText("package-1");
- expect(screen.queryByText("package-11")).not.toBeInTheDocument();
+ assert(sortedPackages[0]);
+ assert(sortedPackages[10]);
+ await screen.findByText(sortedPackages[0]);
+ expect(screen.queryByText(sortedPackages[10])).not.toBeInTheDocument();
const nextButton = screen.getByRole("button", { name: /next/i });
await user.click(nextButton);
- expect(screen.getByText("package-11")).toBeInTheDocument();
- expect(screen.queryByText("package-1")).not.toBeInTheDocument();
+ expect(screen.getByText(sortedPackages[10])).toBeInTheDocument();
+ expect(screen.queryByText(sortedPackages[0])).not.toBeInTheDocument();
});
it("navigates to previous page on click", async () => {
@@ -78,16 +70,18 @@ describe("LocalRepositoryPackagesList", () => {
,
);
- await screen.findByText("package-1");
+ assert(sortedPackages[0]);
+ assert(sortedPackages[10]);
+ await screen.findByText(sortedPackages[0]);
const nextButton = screen.getByRole("button", { name: /next/i });
await user.click(nextButton);
- expect(screen.getByText("package-11")).toBeInTheDocument();
+ expect(screen.getByText(sortedPackages[10])).toBeInTheDocument();
const prevButton = screen.getByRole("button", { name: /previous/i });
await user.click(prevButton);
- expect(screen.getByText("package-1")).toBeInTheDocument();
+ expect(screen.getByText(sortedPackages[0])).toBeInTheDocument();
});
});
diff --git a/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.tsx b/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.tsx
index 08328ee24f..a497dafa25 100644
--- a/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.tsx
+++ b/src/features/local-repositories/components/LocalRepositoryPackagesList/LocalRepositoryPackagesList.tsx
@@ -16,7 +16,13 @@ const LocalRepositoryPackagesList: FC = ({
const [currentPage, setCurrentPage] = useState(1);
const pageSize = 10;
- const formattedPackages: LocalPackage[] = packages.map((name) => ({ name }));
+ const formattedPackages = useMemo(
+ () =>
+ packages
+ .map((name) => ({ name }))
+ .toSorted((a, b) => a.name.localeCompare(b.name)),
+ [packages],
+ );
const pagedPackages = useMemo(
() =>
formattedPackages.slice(
diff --git a/src/features/local-repositories/components/ViewLocalRepositorySidePanel/components/ViewRepositoryPackagesTab/ViewRepositoryPackagesTab.test.tsx b/src/features/local-repositories/components/ViewLocalRepositorySidePanel/components/ViewRepositoryPackagesTab/ViewRepositoryPackagesTab.test.tsx
index 607a536cd8..20b0993b05 100644
--- a/src/features/local-repositories/components/ViewLocalRepositorySidePanel/components/ViewRepositoryPackagesTab/ViewRepositoryPackagesTab.test.tsx
+++ b/src/features/local-repositories/components/ViewLocalRepositorySidePanel/components/ViewRepositoryPackagesTab/ViewRepositoryPackagesTab.test.tsx
@@ -2,7 +2,7 @@ import { renderWithProviders } from "@/tests/render";
import { describe, it, expect } from "vitest";
import { screen } from "@testing-library/react";
import ViewRepositoryPackagesTab from "./ViewRepositoryPackagesTab";
-import { repositories } from "@/tests/mocks/localRepositories";
+import { repositories, sortedPackages } from "@/tests/mocks/localRepositories";
describe("ViewRepositoryPackagesTab", () => {
it("renders table with correct header after loading", async () => {
@@ -16,8 +16,7 @@ describe("ViewRepositoryPackagesTab", () => {
await screen.findByRole("columnheader", { name: "Package name" }),
).toBeInTheDocument();
- expect(await screen.findByText("package-1")).toBeInTheDocument();
- expect(screen.getByText("package-2")).toBeInTheDocument();
- expect(screen.getByText("package-3")).toBeInTheDocument();
+ assert(sortedPackages[0]);
+ expect(await screen.findByText(sortedPackages[0])).toBeInTheDocument();
});
});
diff --git a/src/features/overview/components/DonutChart/DonutChart.test.tsx b/src/features/overview/components/DonutChart/DonutChart.test.tsx
index 6028c50c13..bf361e9e3d 100644
--- a/src/features/overview/components/DonutChart/DonutChart.test.tsx
+++ b/src/features/overview/components/DonutChart/DonutChart.test.tsx
@@ -136,14 +136,8 @@ describe("DonutChart", () => {
it("uses light-mode default colors by default", () => {
const { container } = renderChart();
const arcs = getArcs(container);
- expect(arcs[0]).toHaveAttribute(
- "stroke",
- colorMap.green.light.default,
- );
- expect(arcs[1]).toHaveAttribute(
- "stroke",
- colorMap.orange.light.default,
- );
+ expect(arcs[0]).toHaveAttribute("stroke", colorMap.green.light.default);
+ expect(arcs[1]).toHaveAttribute("stroke", colorMap.orange.light.default);
expect(arcs[2]).toHaveAttribute("stroke", colorMap.red.light.default);
});
@@ -151,14 +145,8 @@ describe("DonutChart", () => {
localStorage.setItem("_landscape_dark_theme", "true");
const { container } = renderChart();
const arcs = getArcs(container);
- expect(arcs[0]).toHaveAttribute(
- "stroke",
- colorMap.green.dark.default,
- );
- expect(arcs[2]).toHaveAttribute(
- "stroke",
- colorMap.red.dark.default,
- );
+ expect(arcs[0]).toHaveAttribute("stroke", colorMap.green.dark.default);
+ expect(arcs[2]).toHaveAttribute("stroke", colorMap.red.dark.default);
});
it("keeps default colors on every ring when one is hovered (dim via CSS opacity, not palette swap)", async () => {
@@ -168,14 +156,8 @@ describe("DonutChart", () => {
await user.hover(getRingGroup(0));
const arcs = getArcs(container);
- expect(arcs[0]).toHaveAttribute(
- "stroke",
- colorMap.green.light.default,
- );
- expect(arcs[1]).toHaveAttribute(
- "stroke",
- colorMap.orange.light.default,
- );
+ expect(arcs[0]).toHaveAttribute("stroke", colorMap.green.light.default);
+ expect(arcs[1]).toHaveAttribute("stroke", colorMap.orange.light.default);
expect(arcs[2]).toHaveAttribute("stroke", colorMap.red.light.default);
});
@@ -185,9 +167,7 @@ describe("DonutChart", () => {
await user.hover(getRingGroup(0));
- expect(getRingGroup(0).getAttribute("class") ?? "").toMatch(
- /ring--active/,
- );
+ expect(getRingGroup(0).getAttribute("class") ?? "").toMatch(/ring--active/);
expect(getRingGroup(0).getAttribute("class") ?? "").not.toMatch(
/ring--inactive/,
);
@@ -211,9 +191,7 @@ describe("DonutChart", () => {
expect(getRingGroup(1).getAttribute("class") ?? "").toMatch(
/ring--inactive/,
);
- expect(getRingGroup(2).getAttribute("class") ?? "").toMatch(
- /ring--active/,
- );
+ expect(getRingGroup(2).getAttribute("class") ?? "").toMatch(/ring--active/);
});
it("resets state when the inner container loses pointer", async () => {
@@ -228,7 +206,9 @@ describe("DonutChart", () => {
) as HTMLElement;
fireEvent.mouseLeave(inner);
- expect(getRingGroup(0).getAttribute("class") ?? "").not.toMatch(/ring--active/);
+ expect(getRingGroup(0).getAttribute("class") ?? "").not.toMatch(
+ /ring--active/,
+ );
});
it("activates a ring on keyboard focus and clears on blur", () => {
@@ -291,9 +271,7 @@ describe("DonutChart", () => {
],
});
- expect(screen.getByTestId("donut-center-number").textContent).toBe(
- "12.3K",
- );
+ expect(screen.getByTestId("donut-center-number").textContent).toBe("12.3K");
});
it("formats compactly when a large ring is hovered", async () => {
@@ -309,9 +287,7 @@ describe("DonutChart", () => {
await user.hover(getRingGroup(0));
- expect(screen.getByTestId("donut-center-number").textContent).toBe(
- "87.4K",
- );
+ expect(screen.getByTestId("donut-center-number").textContent).toBe("87.4K");
expect(screen.getByTestId("donut-center-sublabel").textContent).toBe(
"of 100K",
);
@@ -319,9 +295,7 @@ describe("DonutChart", () => {
it("renders a track circle behind each ring with the track class", () => {
const { container } = renderChart();
- const tracks = container.querySelectorAll(
- `circle[class*='track']`,
- );
+ const tracks = container.querySelectorAll(`circle[class*='track']`);
expect(tracks).toHaveLength(3);
});
});
diff --git a/src/features/saved-searches/components/SavedSearchList/SavedSearchList.tsx b/src/features/saved-searches/components/SavedSearchList/SavedSearchList.tsx
index ffd496fb0d..6ccc3f91f4 100644
--- a/src/features/saved-searches/components/SavedSearchList/SavedSearchList.tsx
+++ b/src/features/saved-searches/components/SavedSearchList/SavedSearchList.tsx
@@ -88,9 +88,7 @@ const SavedSearchList: FC = ({