diff --git a/e2e/mock-exam-hardening.spec.ts b/e2e/mock-exam-hardening.spec.ts index 8cd09ef..99a2fa6 100644 --- a/e2e/mock-exam-hardening.spec.ts +++ b/e2e/mock-exam-hardening.spec.ts @@ -54,6 +54,16 @@ test('retake does not re-open the "Ready to submit?" modal over question 1', asy await expect(page.getByText('Question 1 of', { exact: false })).toBeVisible() }) +test('results screen shows the star-on-GitHub CTA linking to the repo', async ({ page }) => { + await page.goto(EXAM_URL) + await startExam(page) + await submitExam(page) // guest, 0 answers -> fail results (CTA shows on pass AND fail) + + const starCta = page.getByRole('link', { name: /star the repo on GitHub/i }) + await expect(starCta).toBeVisible() + await expect(starCta).toHaveAttribute('href', 'https://github.com/nastaso/cloudcertprep') +}) + test('signed-in sub-60s submit shows an explicit "not saved" notice', async ({ page }) => { await seedSession(page) await page.goto(EXAM_URL) diff --git a/src/pages/_MockExam.tsx b/src/pages/_MockExam.tsx index a22fcb2..6447e31 100644 --- a/src/pages/_MockExam.tsx +++ b/src/pages/_MockExam.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef, Fragment } from 'react' import { useLocation, useNavigate } from 'react-router-dom' -import { Flag, AlertCircle, LayoutGrid, Heart, ArrowLeft } from 'lucide-react' +import { Flag, AlertCircle, LayoutGrid, Heart, ArrowLeft, Star } from 'lucide-react' import { Button } from '../components/Button' import { Card } from '../components/Card' import { Alert } from '../components/Alert' @@ -29,7 +29,7 @@ import type { Question, OptionKey } from '../types' import { loadAllQuestions } from '../data/questions' import { shuffleAndMapQuestions, toggleMultiAnswer, getQuestionType, encodeAnswerForDb, type OptionKeyMap } from '../lib/utils' import { trackEvent } from '../lib/analytics' -import { KOFI_URL } from '../lib/constants' +import { KOFI_URL, GITHUB_REPO_URL } from '../lib/constants' import { MAX_MULTI_ANSWER, TIMER_PULSE_THRESHOLD } from '../lib/constants' import { registerExamLeaveHandler, confirmExamLeave, isIntentionalLeave, SIGN_OUT_SENTINEL, markIntentionalLeave } from '../lib/examGuard' import { useSignOut } from '../hooks/useSignOut' @@ -997,6 +997,26 @@ export function MockExam() { Buy me a coffee + + {/* Quiet star-on-GitHub ask at the highest-intent moment (just + finished an exam) - growth lever A7, the site-to-repo funnel is + near-invisible. Recessed (no fill, hairline border only) so it + sits below both the primary result actions and the Ko-fi ask and + never competes with them. Shown on pass AND fail. Reuses the + existing `github_click` event with its own `location: 'results'`. + Real anchor to the repo with honest link text; min 44px tall. */} + trackEvent('github_click', { location: 'results' })} + className="flex min-h-[44px] items-center justify-center gap-2 rounded-2xl border border-border-hairline p-4 text-center text-sm text-text-muted transition-colors duration-200 hover:border-text-muted/40" + > +