diff --git a/src/components/GenerateCourse/AICourseLesson.tsx b/src/components/GenerateCourse/AICourseLesson.tsx
index c213aac01..244b066ff 100644
--- a/src/components/GenerateCourse/AICourseLesson.tsx
+++ b/src/components/GenerateCourse/AICourseLesson.tsx
@@ -27,6 +27,7 @@ import { queryClient } from '../../stores/query-client';
 import { AICourseFollowUp } from './AICourseFollowUp';
 import './AICourseFollowUp.css';
 import { RegenerateLesson } from './RegenerateLesson';
+import { TestMyKnowledgeAction } from './TestMyKnowledgeAction';
 
 type AICourseLessonProps = {
   courseSlug: string;
@@ -203,7 +204,9 @@ export function AICourseLesson(props: AICourseLessonProps) {
     isLoading;
 
   const cantGoBack =
-    (activeModuleIndex === 0 && activeLessonIndex === 0) || isGenerating || isLoading;
+    (activeModuleIndex === 0 && activeLessonIndex === 0) ||
+    isGenerating ||
+    isLoading;
 
   return (
     <div className="mx-auto max-w-4xl">
@@ -319,6 +322,14 @@ export function AICourseLesson(props: AICourseLessonProps) {
           </div>
         )}
 
+        {!isLoading && !isGenerating && (
+          <TestMyKnowledgeAction
+            courseSlug={courseSlug}
+            activeModuleIndex={activeModuleIndex}
+            activeLessonIndex={activeLessonIndex}
+          />
+        )}
+
         <div className="mt-8 flex items-center justify-between">
           <button
             onClick={onGoToPrevLesson}
diff --git a/src/components/GenerateCourse/TestMyKnowledgeAction.tsx b/src/components/GenerateCourse/TestMyKnowledgeAction.tsx
new file mode 100644
index 000000000..8695748bb
--- /dev/null
+++ b/src/components/GenerateCourse/TestMyKnowledgeAction.tsx
@@ -0,0 +1,409 @@
+import {
+  ChevronLeftIcon,
+  ChevronRightIcon,
+  CircleCheckIcon,
+  CircleIcon,
+  CircleXIcon,
+  FlaskConicalIcon,
+  Loader2Icon,
+  RotateCcwIcon,
+} from 'lucide-react';
+import { cn } from '../../lib/classname';
+import {
+  generateAiCourseLessonQuestions,
+  readStream,
+  type Question,
+} from '../../lib/ai';
+import { useCallback, useMemo, useState } from 'react';
+import { isLoggedIn, removeAuthToken } from '../../lib/jwt';
+
+type TestMyKnowledgeActionProps = {
+  courseSlug: string;
+  activeModuleIndex: number;
+  activeLessonIndex: number;
+};
+
+export function TestMyKnowledgeAction(props: TestMyKnowledgeActionProps) {
+  const { courseSlug, activeModuleIndex, activeLessonIndex } = props;
+
+  const [questions, setQuestions] = useState<Question[]>([]);
+  const [isKnowledgeTestOpen, setIsKnowledgeTestOpen] = useState(false);
+
+  const [isLoading, setIsLoading] = useState(false);
+  const [isGenerating, setIsGenerating] = useState(false);
+  const [error, setError] = useState('');
+
+  const abortController = useMemo(
+    () => new AbortController(),
+    [activeModuleIndex, activeLessonIndex],
+  );
+
+  const generateAiLessonQuestions = async () => {
+    setIsLoading(true);
+    setError('');
+
+    if (!isLoggedIn()) {
+      setIsLoading(false);
+      setError('Please login to generate course content');
+      return;
+    }
+
+    const response = await fetch(
+      `${import.meta.env.PUBLIC_API_URL}/v1-generate-ai-course-lesson-question/${courseSlug}`,
+      {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        signal: abortController.signal,
+        credentials: 'include',
+        body: JSON.stringify({
+          moduleIndex: activeModuleIndex,
+          lessonIndex: activeLessonIndex,
+        }),
+      },
+    );
+
+    if (!response.ok) {
+      const data = await response.json();
+
+      setError(data?.message || 'Something went wrong');
+      setIsLoading(false);
+
+      // Logout user if token is invalid
+      if (data.status === 401) {
+        removeAuthToken();
+        window.location.reload();
+      }
+      return;
+    }
+
+    if (!response.body) {
+      setIsLoading(false);
+      setError('No response body received');
+      return;
+    }
+
+    try {
+      const reader = response.body.getReader();
+      setIsLoading(false);
+      setIsGenerating(true);
+      await readStream(reader, {
+        onStream: async (result) => {
+          if (abortController.signal.aborted) {
+            return;
+          }
+
+          const questions = generateAiCourseLessonQuestions(result);
+          setQuestions(questions);
+        },
+        onStreamEnd: async (result) => {
+          if (abortController.signal.aborted) {
+            return;
+          }
+
+          const questions = generateAiCourseLessonQuestions(result);
+          setQuestions(questions);
+          setIsGenerating(false);
+        },
+      });
+    } catch (e) {
+      setError(e instanceof Error ? e.message : 'Something went wrong');
+      setIsLoading(false);
+      setIsGenerating(false);
+    }
+  };
+
+  return (
+    <div className="mt-12 flex flex-col gap-4">
+      <div className="flex items-center gap-2">
+        <button
+          className="flex flex-shrink-0 items-center gap-2 rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 hover:text-gray-900"
+          onClick={() => {
+            if (isGenerating || isLoading || isKnowledgeTestOpen) {
+              return;
+            }
+
+            setIsKnowledgeTestOpen(true);
+            generateAiLessonQuestions();
+          }}
+        >
+          <FlaskConicalIcon className="size-5 shrink-0" />
+          <span>Test My Knowledge</span>
+        </button>
+      </div>
+
+      {isKnowledgeTestOpen && (
+        <ListQuestions
+          isLoading={isLoading}
+          isGenerating={isGenerating}
+          questions={questions}
+        />
+      )}
+    </div>
+  );
+}
+
+type ListQuestionsProps = {
+  isLoading: boolean;
+  isGenerating: boolean;
+  questions: Question[];
+};
+
+export function ListQuestions(props: ListQuestionsProps) {
+  const { isLoading, isGenerating, questions } = props;
+
+  const [selectedAnswers, setSelectedAnswers] = useState<
+    Record<string, string[]>
+  >({});
+  const [submitted, setSubmitted] = useState(false);
+  const [activeQuestionIndex, setActiveQuestionIndex] = useState(0);
+
+  const activeQuestion = questions[activeQuestionIndex];
+  const handleOptionSelectChange = useCallback(
+    (questionId: string, optionId: string) => {
+      setSelectedAnswers((prev) => {
+        const newSelectedAnswers = { ...prev };
+        const selectedOptionIds = newSelectedAnswers[questionId] ?? [];
+        newSelectedAnswers[questionId] = selectedOptionIds.includes(optionId)
+          ? selectedOptionIds.filter((id) => id !== optionId)
+          : [...selectedOptionIds, optionId];
+        return newSelectedAnswers;
+      });
+    },
+    [],
+  );
+
+  const handleNext = useCallback(() => {
+    const isLastQuestion = activeQuestionIndex === questions.length - 1;
+    if (isLastQuestion) {
+      setSubmitted(true);
+      setActiveQuestionIndex(0);
+      return;
+    }
+
+    setActiveQuestionIndex(activeQuestionIndex + 1);
+  }, [activeQuestionIndex, questions, submitted]);
+
+  const handlePrevious = useCallback(() => {
+    setActiveQuestionIndex((prev) => Math.max(prev - 1, 0));
+  }, [questions]);
+
+  const handleTryAgain = useCallback(() => {
+    setSelectedAnswers({});
+    setSubmitted(false);
+    setActiveQuestionIndex(0);
+  }, []);
+
+  const correctAnswerCount = useMemo(() => {
+    if (!submitted) {
+      return 0;
+    }
+
+    return questions.filter((question) => {
+      const selectedOptionIds = selectedAnswers[question.id];
+      const correctAnswerIds = question.options
+        .filter((option) => option.isCorrect)
+        .map((option) => option.id);
+
+      return (
+        correctAnswerIds.length === selectedOptionIds?.length &&
+        correctAnswerIds.every((correctAnswerId) =>
+          selectedOptionIds?.includes(correctAnswerId),
+        )
+      );
+    }).length;
+  }, [questions, selectedAnswers, submitted]);
+
+  if (isLoading || !questions.length) {
+    return (
+      <div className="flex h-[306px] w-full items-center justify-center rounded-lg border p-5 text-black">
+        <Loader2Icon className="size-8 animate-spin stroke-[2.5]" />
+      </div>
+    );
+  }
+
+  return (
+    <QuizItem
+      totalQuestions={questions.length}
+      correctAnswerCount={correctAnswerCount}
+      isLoading={isGenerating}
+      question={activeQuestion}
+      onOptionSelectChange={handleOptionSelectChange}
+      selectedOptionIds={selectedAnswers[activeQuestion.id]}
+      submitted={submitted}
+      onNext={handleNext}
+      onPrevious={handlePrevious}
+      onTryAgain={handleTryAgain}
+    />
+  );
+}
+
+type QuizItemProps = {
+  totalQuestions: number;
+  correctAnswerCount: number;
+
+  question: Question;
+  onOptionSelectChange?: (id: string, optionId: string) => void;
+  selectedOptionIds?: string[];
+  submitted?: boolean;
+
+  isLoading: boolean;
+
+  onNext?: () => void;
+  onPrevious?: () => void;
+  onTryAgain?: () => void;
+};
+
+export function QuizItem(props: QuizItemProps) {
+  const {
+    totalQuestions,
+    correctAnswerCount,
+
+    isLoading,
+
+    question,
+    onOptionSelectChange,
+    selectedOptionIds,
+    submitted = false,
+    onNext,
+    onPrevious,
+    onTryAgain,
+  } = props;
+  const { id: questionId, title, options } = question;
+
+  const correctAnswerIds = options
+    .filter((option) => option.isCorrect)
+    .map((option) => option.id);
+
+  const isAllCorrectAnswer =
+    correctAnswerIds.length === selectedOptionIds?.length &&
+    correctAnswerIds.every((correctAnswerId) =>
+      selectedOptionIds?.includes(correctAnswerId),
+    );
+  const hasWrongAnswer = submitted && !isAllCorrectAnswer;
+  const hasCorrectAnswer = submitted && isAllCorrectAnswer;
+
+  return (
+    <div
+      className={cn('relative w-full rounded-lg border p-5 text-black', {
+        'border-red-400': hasWrongAnswer,
+        'border-green-500': hasCorrectAnswer,
+      })}
+    >
+      <h3 className="mx-2 text-balance text-lg font-medium">{title}</h3>
+
+      <div className="mt-4 flex flex-col gap-1">
+        {options.map((option, index) => {
+          let status: QuizOptionStatus = 'default';
+          if (submitted) {
+            if (option.isCorrect) {
+              status = 'correct';
+            } else if (selectedOptionIds?.includes(option.id)) {
+              status = 'wrong';
+            }
+          } else {
+            if (selectedOptionIds?.includes(option.id)) {
+              status = 'selected';
+            }
+          }
+
+          return (
+            <QuizOption
+              key={index}
+              title={option.title}
+              status={status}
+              onSelect={() => onOptionSelectChange?.(questionId, option.id)}
+              submitted={submitted}
+            />
+          );
+        })}
+      </div>
+
+      <div className="mt-4 flex w-full items-center justify-between px-2">
+        <div className="text-gray-500">
+          {submitted ? (
+            <span>
+              You got {correctAnswerCount} out of {totalQuestions} correct
+            </span>
+          ) : (
+            <span>Answer all questions to submit</span>
+          )}
+        </div>
+
+        <div className="flex gap-2">
+          <button
+            className="flex h-8 items-center justify-center gap-1 rounded-lg border border-gray-200 p-2 pr-4 text-sm text-black hover:bg-black hover:text-white focus:outline-none max-sm:pr-2"
+            onClick={onPrevious}
+          >
+            <ChevronLeftIcon className="size-5 shrink-0" />
+            <span className="max-sm:hidden">Previous</span>
+          </button>
+          <button
+            className="flex h-8 items-center justify-center gap-1 rounded-lg border border-gray-200 p-2 pl-4 text-sm text-black hover:bg-black hover:text-white focus:outline-none max-sm:pl-2"
+            onClick={onNext}
+          >
+            <span className="max-sm:hidden">Next</span>
+            <ChevronRightIcon className="size-5 shrink-0" />
+          </button>
+        </div>
+      </div>
+
+      {submitted && (
+        <button
+          className="absolute right-2 top-2 flex h-8 items-center justify-center gap-1 rounded-lg border border-gray-200 p-2 text-sm text-black hover:bg-black hover:text-white focus:outline-none"
+          onClick={onTryAgain}
+        >
+          <RotateCcwIcon className="size-5 shrink-0" />
+          <span className="max-sm:hidden">Try Again</span>
+        </button>
+      )}
+
+      {isLoading && (
+        <div className="absolute right-2 top-2 flex h-8 items-center justify-center gap-1 rounded-lg border border-gray-200 p-2 text-sm text-black hover:bg-black hover:text-white focus:outline-none">
+          <Loader2Icon className="size-5 animate-spin" />
+        </div>
+      )}
+    </div>
+  );
+}
+
+type QuizOptionStatus = 'default' | 'selected' | 'wrong' | 'correct';
+
+type QuizOptionProps = {
+  title: string;
+  status?: QuizOptionStatus;
+  onSelect: () => void;
+  submitted?: boolean;
+};
+
+export function QuizOption(props: QuizOptionProps) {
+  const { title, status = 'default', onSelect, submitted = false } = props;
+
+  return (
+    <button
+      onClick={onSelect}
+      className={cn(
+        'flex items-start gap-2 rounded-xl p-2 text-base disabled:cursor-not-allowed',
+        status === 'selected' && 'bg-gray-600 text-white',
+        status === 'wrong' && submitted && 'bg-red-200 text-black',
+        status === 'correct' && submitted && 'bg-green-200 text-black',
+        status === 'default' && 'bg-white hover:bg-gray-100',
+        submitted && status !== 'correct' && 'opacity-40',
+      )}
+      disabled={submitted}
+    >
+      <span className="mt-[1px]">
+        {status === 'wrong' && submitted && <CircleXIcon className="size-5" />}
+        {status === 'correct' && submitted && (
+          <CircleCheckIcon className="size-5" />
+        )}
+
+        {(status === 'selected' || status === 'default') && (
+          <CircleIcon className="size-5" />
+        )}
+      </span>
+      <p className="text-left">{title}</p>
+    </button>
+  );
+}
diff --git a/src/lib/ai.ts b/src/lib/ai.ts
index ac9bf1d9e..6a70d5e9f 100644
--- a/src/lib/ai.ts
+++ b/src/lib/ai.ts
@@ -1,3 +1,5 @@
+import { nanoid } from 'nanoid';
+
 export const IS_KEY_ONLY_ROADMAP_GENERATION = false;
 
 type Lesson = string;
@@ -52,6 +54,7 @@ export function generateAiCourseStructure(
   return {
     title,
     modules,
+    done: [],
   };
 }
 
@@ -207,3 +210,59 @@ export async function readStream(
   onStreamEnd?.(result);
   reader.releaseLock();
 }
+
+export type Question = {
+  id: string;
+  title: string;
+  options: {
+    id: string;
+    title: string;
+    isCorrect: boolean;
+  }[];
+};
+
+export function generateAiCourseLessonQuestions(
+  questionData: string,
+): Question[] {
+  const questions: Question[] = [];
+
+  const lines = questionData.split('\n');
+  let currentQuestion: Question | null = null;
+
+  for (let i = 0; i < lines.length; i++) {
+    const line = lines[i].trim();
+    if (line.startsWith('#')) {
+      if (currentQuestion) {
+        questions.push(currentQuestion);
+        currentQuestion = null;
+      }
+
+      const title = line.replace('#', '').trim();
+      currentQuestion = {
+        id: nanoid(),
+        title,
+        options: [],
+      };
+    } else if (line.startsWith('-')) {
+      if (!currentQuestion) {
+        continue;
+      }
+
+      let title = line.replace('-', '').trim();
+      const isCorrect = title.startsWith('*');
+      title = title.replace('*', '').trim();
+
+      currentQuestion.options.push({
+        id: nanoid(),
+        title,
+        isCorrect,
+      });
+    }
+  }
+
+  if (currentQuestion) {
+    questions.push(currentQuestion);
+  }
+
+  return questions;
+}