feat(FN-249): fix 15 failing regression tests — FeatureMatrix duplicate selectors
Some checks failed
Sync dev → Gitea / Mirror dev to Gitea (push) Has been cancelled

Commits merged:
- fix(FN-249): fix 15 failing regression tests — FeatureMatrix duplicate selectors

Files changed:
.../subscription/__tests__/index.test.tsx          | 145 +++++++++++----------
 1 file changed, 77 insertions(+), 68 deletions(-)

Fusion-Task-Id: FN-249
This commit is contained in:
Fusion
2026-05-12 20:03:20 +00:00
parent 668ab50cf2
commit 2907008c9d

View File

@@ -5,7 +5,7 @@
* Tests cover rendering, interaction, trust/i18n, edge cases, and accessibility.
*/
import { fireEvent, render, screen } from "@testing-library/react";
import { fireEvent, render, screen, within } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
// ─── Pre-declare mock variables via vi.hoisted() ─────────────────────────────
@@ -277,21 +277,18 @@ describe("rendering", () => {
describe("plan cards", () => {
it("renders all 4 plan cards with correct names and monthly prices", () => {
renderPage();
// Use getAllByText — FeatureMatrix table also renders plan names in <th> headers
expect(screen.getAllByText("subscription.plans.brand1.name").length).toBeGreaterThanOrEqual(
2,
);
expect(screen.getAllByText("subscription.plans.brand2.name").length).toBeGreaterThanOrEqual(
2,
);
expect(screen.getAllByText("subscription.plans.brand3.name").length).toBeGreaterThanOrEqual(
2,
);
expect(screen.getAllByText("subscription.plans.full.name").length).toBeGreaterThanOrEqual(2);
expect(screen.getByText("₺200,00")).toBeInTheDocument();
expect(screen.getByText("₺350,00")).toBeInTheDocument();
expect(screen.getByText("₺500,00")).toBeInTheDocument();
expect(screen.getByText("₺999,00")).toBeInTheDocument();
// Scope to plan comparison grid to avoid FeatureMatrix table duplicates
const planGrid = document.querySelector(".grid.gap-4");
expect(planGrid).toBeInTheDocument();
const gridScope = within(planGrid as HTMLElement);
expect(gridScope.getByText("subscription.plans.brand1.name")).toBeInTheDocument();
expect(gridScope.getByText("subscription.plans.brand2.name")).toBeInTheDocument();
expect(gridScope.getByText("subscription.plans.brand3.name")).toBeInTheDocument();
expect(gridScope.getByText("subscription.plans.full.name")).toBeInTheDocument();
expect(gridScope.getByText("₺200,00")).toBeInTheDocument();
expect(gridScope.getByText("₺350,00")).toBeInTheDocument();
expect(gridScope.getByText("₺500,00")).toBeInTheDocument();
expect(gridScope.getByText("₺999,00")).toBeInTheDocument();
});
it("renders feature lists for each plan", () => {
@@ -340,23 +337,23 @@ describe("rendering", () => {
describe("popular plan visual dominance (P0-2)", () => {
it("brand2 (popular) card has stronger visual styling", () => {
renderPage();
// FeatureMatrix also has a popular badge, so pick the one on the plan card (not inside <th>)
const allPopular = screen.getAllByText("subscription.popular");
const popularBadge = allPopular.find((el) => !el.closest("th"))!;
expect(popularBadge).toBeInTheDocument();
// Two "subscription.popular" elements: one in plan card, one in FeatureMatrix
const popularBadges = screen.getAllByText("subscription.popular");
expect(popularBadges.length).toBe(2);
// Card badge has text-xs (not text-[10px] like FeatureMatrix)
const cardBadge = popularBadges.find(
(el) => el.className.includes("text-xs") && !el.className.includes("text-[10px]"),
)!;
// The popular badge is inside a <Badge> element; walk up to the Card
const popularCard = popularBadge.closest('[class*="rounded-xl"]');
const popularCard = cardBadge.closest('[class*="rounded-xl"]');
expect(popularCard).toBeTruthy();
expect(popularCard?.className).toContain("shadow-xl");
});
it("only one plan card has popular badge", () => {
it("only one plan card has popular badge (2 total with FeatureMatrix)", () => {
renderPage();
// FeatureMatrix also has a popular badge; count only card badges (not in <th>)
const cardPopularBadges = screen
.getAllByText("subscription.popular")
.filter((el) => !el.closest("th"));
expect(cardPopularBadges.length).toBe(1);
// 2 total: plan card + FeatureMatrix table header
expect(screen.getAllByText("subscription.popular").length).toBe(2);
});
});
@@ -419,10 +416,11 @@ describe("interaction", () => {
it("CTA says Devam Et (proceed) when plan selected", () => {
renderPage();
expect(screen.queryByText("subscription.proceed")).not.toBeInTheDocument();
// FeatureMatrix <th> also matches — pick the plan card element (not inside <th>)
const brand1Card = screen
.getAllByText("subscription.plans.brand1.name")
.find((el) => !el.closest("th"))!
// Scope to plan comparison grid (not FeatureMatrix table)
const planGrid = document.querySelector(".grid.gap-4");
const gridScope = within(planGrid as HTMLElement);
const brand1Card = gridScope
.getByText("subscription.plans.brand1.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand1Card);
const ctaElements = screen.getAllByText(/subscription\.proceed/);
@@ -431,9 +429,10 @@ describe("interaction", () => {
it("CTA includes price info with ile Devam Et format", () => {
renderPage();
const brand2Card = screen
.getAllByText("subscription.plans.brand2.name")
.find((el) => !el.closest("th"))!
const planGrid = document.querySelector(".grid.gap-4");
const gridScope = within(planGrid as HTMLElement);
const brand2Card = gridScope
.getByText("subscription.plans.brand2.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand2Card);
const ctaButtons = screen.getAllByRole("button", { name: /subscription\.proceed/ });
@@ -451,16 +450,17 @@ describe("interaction", () => {
it("order summary renders with plan, period, and price when plan selected", () => {
renderPage();
const brand3Card = screen
.getAllByText("subscription.plans.brand3.name")
.find((el) => !el.closest("th"))!
const planGrid = document.querySelector(".grid.gap-4");
const gridScope = within(planGrid as HTMLElement);
const brand3Card = gridScope
.getByText("subscription.plans.brand3.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand3Card);
expect(screen.getByText("subscription.orderSummary")).toBeInTheDocument();
expect(screen.getByText("subscription.orderSummaryPlan")).toBeInTheDocument();
expect(screen.getByText("subscription.orderSummaryPeriod")).toBeInTheDocument();
expect(screen.getByText("subscription.orderSummaryPrice")).toBeInTheDocument();
// Plan name appears in both card and summary — use getAllByText
// Plan name appears in card, summary, and FeatureMatrix — use getAllByText
expect(screen.getAllByText("subscription.plans.brand3.name").length).toBeGreaterThanOrEqual(
1,
);
@@ -470,9 +470,10 @@ describe("interaction", () => {
it("order summary updates when billing period changes", () => {
renderPage();
const brand1Card = screen
.getAllByText("subscription.plans.brand1.name")
.find((el) => !el.closest("th"))!
const planGrid1 = document.querySelector(".grid.gap-4");
const gridScope1 = within(planGrid1 as HTMLElement);
const brand1Card = gridScope1
.getByText("subscription.plans.brand1.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand1Card);
fireEvent.click(screen.getByRole("button", { name: "common.yearly" }));
@@ -508,9 +509,10 @@ describe("interaction", () => {
describe("proceed to payment navigation", () => {
it("navigates to /dashboard/subscription/pay with correct search params", () => {
renderPage();
const brand2Card = screen
.getAllByText("subscription.plans.brand2.name")
.find((el) => !el.closest("th"))!
const planGridNav = document.querySelector(".grid.gap-4");
const gridScopeNav = within(planGridNav as HTMLElement);
const brand2Card = gridScopeNav
.getByText("subscription.plans.brand2.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand2Card);
fireEvent.click(screen.getByTestId("brand-selector-select"));
@@ -530,9 +532,10 @@ describe("interaction", () => {
it("shows error toast when proceeding without brand selection", () => {
renderPage();
const brand1Card = screen
.getAllByText("subscription.plans.brand1.name")
.find((el) => !el.closest("th"))!
const planGridErr = document.querySelector(".grid.gap-4");
const gridScopeErr = within(planGridErr as HTMLElement);
const brand1Card = gridScopeErr
.getByText("subscription.plans.brand1.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand1Card);
const ctaButtons = screen.getAllByRole("button", { name: /subscription\.proceed/ });
@@ -556,9 +559,10 @@ describe("interaction", () => {
},
eligibleForTrial: false,
});
const brand1Card = screen
.getAllByText("subscription.plans.brand1.name")
.find((el) => !el.closest("th"))!
const planGridCur = document.querySelector(".grid.gap-4");
const gridScopeCur = within(planGridCur as HTMLElement);
const brand1Card = gridScopeCur
.getByText("subscription.plans.brand1.name")
.closest('[class*="relative"]')!;
expect(brand1Card.className).toContain("cursor-pointer");
// Current plan card should NOT be clickable
@@ -579,9 +583,10 @@ describe("interaction", () => {
describe("plan selection persists across billing toggle", () => {
it("selected plan stays selected after switching billing period", () => {
renderPage();
const brand3Card = screen
.getAllByText("subscription.plans.brand3.name")
.find((el) => !el.closest("th"))!
const planGridPersist = document.querySelector(".grid.gap-4");
const gridScopePersist = within(planGridPersist as HTMLElement);
const brand3Card = gridScopePersist
.getByText("subscription.plans.brand3.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand3Card);
expect(screen.getByText("subscription.orderSummary")).toBeInTheDocument();
@@ -599,9 +604,10 @@ describe("trust and i18n", () => {
describe("PostHog events (P0-10)", () => {
it("fires checkout_started event when proceeding to payment", () => {
renderPage();
const brand2Card = screen
.getAllByText("subscription.plans.brand2.name")
.find((el) => !el.closest("th"))!
const planGridPH1 = document.querySelector(".grid.gap-4");
const gridScopePH1 = within(planGridPH1 as HTMLElement);
const brand2Card = gridScopePH1
.getByText("subscription.plans.brand2.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand2Card);
fireEvent.click(screen.getByTestId("brand-selector-select"));
@@ -615,9 +621,10 @@ describe("trust and i18n", () => {
it("fires plan_selected event when clicking a plan card", () => {
renderPage();
const brand3Card = screen
.getAllByText("subscription.plans.brand3.name")
.find((el) => !el.closest("th"))!
const planGridPH2 = document.querySelector(".grid.gap-4");
const gridScopePH2 = within(planGridPH2 as HTMLElement);
const brand3Card = gridScopePH2
.getByText("subscription.plans.brand3.name")
.closest('[class*="relative"]')!;
fireEvent.click(brand3Card);
expect(mockCapture).toHaveBeenCalledWith("plan_selected", { plan: "brand3" });
@@ -834,21 +841,23 @@ describe("accessibility", () => {
it("plan cards have visible names", () => {
renderPage();
const planGridAcc = document.querySelector(".grid.gap-4");
const gridScopeAcc = within(planGridAcc as HTMLElement);
["brand1", "brand2", "brand3", "full"].forEach((key) => {
// FeatureMatrix <th> also matches — verify at least one match exists (plan card)
const matches = screen.getAllByText(`subscription.plans.${key}.name`);
expect(matches.length).toBeGreaterThanOrEqual(2);
expect(gridScopeAcc.getByText(`subscription.plans.${key}.name`)).toBeInTheDocument();
});
});
it("popular plan is distinguishable beyond color", () => {
renderPage();
// FeatureMatrix also has a popular badge — pick the one on the plan card
const popularBadge = screen
.getAllByText("subscription.popular")
.find((el) => !el.closest("th"))!;
expect(popularBadge).toBeInTheDocument();
const popularCard = popularBadge.closest('[class*="ring-2"]');
// Two "subscription.popular" elements: plan card badge + FeatureMatrix badge
const popularBadges = screen.getAllByText("subscription.popular");
expect(popularBadges.length).toBeGreaterThanOrEqual(1);
// Card badge has text-xs (not text-[10px] like FeatureMatrix)
const cardBadge = popularBadges.find(
(el) => el.className.includes("text-xs") && !el.className.includes("text-[10px]"),
)!;
const popularCard = cardBadge.closest('[class*="ring-2"]');
expect(popularCard).toBeTruthy();
});
});