import { expect, test } from './fixtures'; // The active-game limit lock on the New Game screen. When a start's kind is at the caller's per-kind // cap (Profile.game_limits), the start button shows a ๐Ÿ”’ and opens a funnel modal instead of a game; // when the cap lifts (the profile refetch a guestโ†’durable upgrade would trigger), the lock clears and // the button starts a game again. Driven by the mock's __mock.setGameLimits seam (no backend). The // native Telegram popup path is verified on the contour; here the cross-platform in-app modal shows // (the mock profile is a durable account, so it is the "finish a current game first" notice). type Limits = { vsAi: number; random: number; friends: number }; function setLimits(l: Limits) { (window as unknown as { __mock: { setGameLimits(l: Limits): void } }).__mock.setGameLimits(l); } test('new game: a start locks at its per-kind cap and the funnel modal opens', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: /guest/i }).click(); // The New Game button always opens the screen now โ€” the per-kind lock lives on the start button. await page.getByRole('button', { name: /๐ŸŽฒ/ }).click(); const start = page.getByRole('button', { name: /start game/i }); await expect(start).not.toContainText('๐Ÿ”’'); // Cap every kind: the AI start (the default opponent) locks. await page.evaluate(setLimits, { vsAi: 0, random: 0, friends: 0 }); await expect(start).toContainText('๐Ÿ”’'); // Tapping the locked start opens the modal instead of a game, and does not navigate away. await start.click(); const notice = page.getByText(/reached the limit/i); await expect(notice).toBeVisible(); await expect(page).toHaveURL(/\/new$/); await page.getByRole('button', { name: /^ok$/i }).click(); await expect(notice).toHaveCount(0); // Lift the cap (the same profile-refetch path a registration takes): the lock clears. await page.evaluate(setLimits, { vsAi: 10, random: 10, friends: 10 }); await expect(start).not.toContainText('๐Ÿ”’'); });