diff --git a/Frontend-Learner/pages/classroom/quiz.vue b/Frontend-Learner/pages/classroom/quiz.vue index 04a2e940..e1bcf43d 100644 --- a/Frontend-Learner/pages/classroom/quiz.vue +++ b/Frontend-Learner/pages/classroom/quiz.vue @@ -36,9 +36,13 @@ const userAnswers = ref>({}) // ID คำถาม -> ID const visitedQuestions = ref>(new Set()) // ติดตามข้อที่เคยเปิดดูแล้ว (Track visited indices) const quizResult = ref(null) +const questionPageSize = 10 +const questionPage = ref(0) + // ติดตามคำถามที่เปิดดูแล้ว (Tracking visited questions) watch(currentQuestionIndex, (newVal) => { visitedQuestions.value.add(newVal) + questionPage.value = Math.floor(newVal / questionPageSize) }, { immediate: true }) // ฟังก์ชันช่วยเหลือ: ดึงคลาสสีสำหรับสถานะคำถาม (Helper: Get Status Color Class) @@ -93,6 +97,29 @@ const jumpToQuestion = (targetIndex: number) => { currentQuestionIndex.value = targetIndex } +const totalQuestionPages = computed(() => Math.ceil(totalQuestions.value / questionPageSize)) + +const visibleQuestions = computed(() => { + if (!quizData.value?.questions) return [] + const start = questionPage.value * questionPageSize + return quizData.value.questions.slice(start, start + questionPageSize).map((q: any, i: number) => ({ + ...q, + originalIndex: start + i + })) +}) + +const nextQuestionPage = () => { + if (questionPage.value < totalQuestionPages.value - 1) { + questionPage.value++ + } +} + +const prevQuestionPage = () => { + if (questionPage.value > 0) { + questionPage.value-- + } +} + // ตัวแปรแบบ Computed (Computed Properties) const currentQuestion = computed(() => { if (!quizData.value || !quizData.value.questions) return null @@ -490,15 +517,39 @@ const getCorrectChoiceId = (questionId: number) => { -
- + +
+ +
+ + +
diff --git a/Frontend-Learner/playwright-report/data/103c3642d4d1edd7c1730b14ee41ded575054308.md b/Frontend-Learner/playwright-report/data/103c3642d4d1edd7c1730b14ee41ded575054308.md deleted file mode 100644 index 117488a0..00000000 --- a/Frontend-Learner/playwright-report/data/103c3642d4d1edd7c1730b14ee41ded575054308.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "47" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/20601da3571c83d89e2a0096b1545ed4ec97ad72.png b/Frontend-Learner/playwright-report/data/20601da3571c83d89e2a0096b1545ed4ec97ad72.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/playwright-report/data/20601da3571c83d89e2a0096b1545ed4ec97ad72.png and /dev/null differ diff --git a/Frontend-Learner/playwright-report/data/3217f3003eb290f2a9d76783c0fbacd8faaf9d1b.md b/Frontend-Learner/playwright-report/data/3217f3003eb290f2a9d76783c0fbacd8faaf9d1b.md deleted file mode 100644 index 97190eee..00000000 --- a/Frontend-Learner/playwright-report/data/3217f3003eb290f2a9d76783c0fbacd8faaf9d1b.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "43" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/59524cbca819897bf05a6d44e6b2440e09e6b0dd.md b/Frontend-Learner/playwright-report/data/59524cbca819897bf05a6d44e6b2440e09e6b0dd.md deleted file mode 100644 index 480f9f79..00000000 --- a/Frontend-Learner/playwright-report/data/59524cbca819897bf05a6d44e6b2440e09e6b0dd.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "41" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/8bd432871766dfea1ea0a2fa595b0b6da8270587.md b/Frontend-Learner/playwright-report/data/8bd432871766dfea1ea0a2fa595b0b6da8270587.md deleted file mode 100644 index 6f19988b..00000000 --- a/Frontend-Learner/playwright-report/data/8bd432871766dfea1ea0a2fa595b0b6da8270587.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "21" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/c1fb5eac6712ad7de52a9dde1e2cf4fcee906540.md b/Frontend-Learner/playwright-report/data/c1fb5eac6712ad7de52a9dde1e2cf4fcee906540.md deleted file mode 100644 index b366c539..00000000 --- a/Frontend-Learner/playwright-report/data/c1fb5eac6712ad7de52a9dde1e2cf4fcee906540.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "52" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/cd58fe922527196f990eb4a780eaf2a045712652.md b/Frontend-Learner/playwright-report/data/cd58fe922527196f990eb4a780eaf2a045712652.md deleted file mode 100644 index bd88a7e5..00000000 --- a/Frontend-Learner/playwright-report/data/cd58fe922527196f990eb4a780eaf2a045712652.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "27" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/data/e33ee5fb9cfb38f085380e44b3173639f8f6d3eb.md b/Frontend-Learner/playwright-report/data/e33ee5fb9cfb38f085380e44b3173639f8f6d3eb.md deleted file mode 100644 index 725985f8..00000000 --- a/Frontend-Learner/playwright-report/data/e33ee5fb9cfb38f085380e44b3173639f8f6d3eb.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "29" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/playwright-report/index.html b/Frontend-Learner/playwright-report/index.html index e5916086..15686deb 100644 --- a/Frontend-Learner/playwright-report/index.html +++ b/Frontend-Learner/playwright-report/index.html @@ -82,4 +82,4 @@ Error generating stack: `+a.message+`
- \ No newline at end of file + \ No newline at end of file diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/error-context.md b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/error-context.md deleted file mode 100644 index b366c539..00000000 --- a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "52" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/test-failed-1.png b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-1559c-ลัก-Classroom-Basic-Layout--chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/error-context.md b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/error-context.md deleted file mode 100644 index 480f9f79..00000000 --- a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "41" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/test-failed-1.png b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-5f28a-าถึงเนื้อหา-Access-Control--chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/error-context.md b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/error-context.md deleted file mode 100644 index 117488a0..00000000 --- a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "47" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/test-failed-1.png b/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/classroom-ระบบห้องเรียนออน-e14d4--หรือ-พื้นที่ทำข้อสอบ-Quiz--chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/error-context.md b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/error-context.md deleted file mode 100644 index 97190eee..00000000 --- a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "43" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/test-failed-1.png b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-3f9f9-์ส-Search-Input-ไม่พบข้อมูล-chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/error-context.md b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/error-context.md deleted file mode 100644 index 6f19988b..00000000 --- a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "21" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/test-failed-1.png b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-555b9-tegory-Filter-ใน-My-Courses-chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/error-context.md b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/error-context.md deleted file mode 100644 index bd88a7e5..00000000 --- a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "27" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/test-failed-1.png b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-8d952-น้า-คอร์สของฉัน-My-Courses--chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/error-context.md b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/error-context.md deleted file mode 100644 index 725985f8..00000000 --- a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/error-context.md +++ /dev/null @@ -1,65 +0,0 @@ -# Page snapshot - -```yaml -- generic [active] [ref=e1]: - - generic [ref=e5]: - - generic [ref=e6]: - - generic [ref=e8]: E - - heading "เข้าสู่ระบบ" [level=1] [ref=e9] - - paragraph [ref=e10]: ยินดีต้อนรับกลับมา! กรุณากรอกข้อมูลของคุณ - - generic [ref=e11]: - - generic [ref=e12]: - - generic [ref=e13]: - - generic [ref=e14]: อีเมล - - generic [ref=e15]: - - generic: - - generic: email - - textbox [ref=e16] - - generic [ref=e17]: - - generic [ref=e18]: รหัสผ่าน - - generic [ref=e19]: - - generic: - - generic: lock - - textbox [ref=e20] - - button "visibility" [ref=e21] [cursor=pointer]: - - generic [ref=e22]: visibility - - generic [ref=e23]: - - generic [ref=e24] [cursor=pointer]: - - checkbox "จดจำฉัน" [ref=e26] - - generic [ref=e28]: จดจำฉัน - - link "ลืมรหัสผ่าน?" [ref=e29] [cursor=pointer]: - - /url: /auth/forgot-password - - button "เข้าสู่ระบบ" [ref=e30] [cursor=pointer]: - - generic [ref=e31]: เข้าสู่ระบบ - - generic [ref=e32]: - - generic [ref=e33]: บัญชีสำหรับทดสอบ (Test Account) - - generic [ref=e34]: - - generic [ref=e35]: studentedtest@example.com - - generic [ref=e36]: - - generic [ref=e37]: "Password:" - - generic [ref=e38]: admin123 - - paragraph [ref=e40]: - - text: ยังไม่มีบัญชีสมาชิก? - - link "สมัครสมาชิกฟรี" [ref=e41] [cursor=pointer]: - - /url: /auth/register - - link "← กลับไปหน้าแรก" [ref=e43] [cursor=pointer]: - - /url: / - - generic [ref=e44]: ← - - text: กลับไปหน้าแรก - - generic: - - img - - generic: - - generic: - - generic: - - button "Go to parent" [disabled] - - button "Open in editor" - - button "Close" - - generic [ref=e45]: - - button "Toggle Nuxt DevTools" [ref=e46] [cursor=pointer]: - - img [ref=e47] - - generic "Page load time" [ref=e50]: - - generic [ref=e51]: "29" - - generic [ref=e52]: ms - - button "Toggle Component Inspector" [ref=e54] [cursor=pointer]: - - img [ref=e55] -``` \ No newline at end of file diff --git a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/test-failed-1.png b/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/test-failed-1.png deleted file mode 100644 index 065cb49e..00000000 Binary files a/Frontend-Learner/test-results/dashboard-ระบบหน้าแดชบอร์ด-c6dae-รกของ-Dashboard-โหลดได้ปกติ-chromium/test-failed-1.png and /dev/null differ diff --git a/Frontend-Learner/tests/e2e/auth.spec.ts b/Frontend-Learner/tests/e2e/auth.spec.ts new file mode 100644 index 00000000..5a87d40f --- /dev/null +++ b/Frontend-Learner/tests/e2e/auth.spec.ts @@ -0,0 +1,266 @@ +import { test, expect, type Page, type Locator } from '@playwright/test'; + +const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; + +async function waitAppSettled(page: Page) { + await page.waitForLoadState('domcontentloaded'); + await page.waitForLoadState('networkidle').catch(() => {}); + await page.waitForTimeout(250); +} + +// --------------------------- +// Helpers: Login +// --------------------------- +const LOGIN_EMAIL = 'studentedtest@example.com'; +const LOGIN_PASSWORD = 'admin123'; + +function loginEmailLocator(page: Page): Locator { + return page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first(); +} +function loginPasswordLocator(page: Page): Locator { + return page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first(); +} +function loginButtonLocator(page: Page): Locator { + return page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first(); +} +async function expectAnyVisible(page: Page, locators: Locator[], timeout = 20_000) { + const start = Date.now(); + while (Date.now() - start < timeout) { + for (const loc of locators) { + try { + if (await loc.isVisible()) return; + } catch {} + } + await page.waitForTimeout(200); + } + throw new Error('None of the expected locators became visible.'); +} + +// --------------------------- +// Helpers: Register +// --------------------------- +function regHeading(page: Page) { return page.getByRole('heading', { name: 'สร้างบัญชีผู้ใช้งาน' }); } +function regUsername(page: Page) { return page.getByRole('textbox', { name: 'username' }).first(); } +function regEmail(page: Page) { return page.getByRole('textbox', { name: 'student@example.com' }).first(); } +function regPrefix(page: Page) { return page.getByRole('combobox').first(); } +function regFirstName(page: Page) { return page.getByText(/^ชื่อ\s*\*$/).locator('..').getByRole('textbox').first(); } +function regLastName(page: Page) { return page.getByText(/^นามสกุล\s*\*$/).locator('..').getByRole('textbox').first(); } +function regPhone(page: Page) { return page.getByText(/^เบอร์โทรศัพท์\s*\*$/).locator('..').getByRole('textbox').first(); } +function regPassword(page: Page) { return page.getByText(/^รหัสผ่าน\s*\*$/).locator('..').getByRole('textbox').first(); } +function regConfirmPassword(page: Page) { return page.getByText(/^ยืนยันรหัสผ่าน\s*\*$/).locator('..').getByRole('textbox').first(); } +function regSubmit(page: Page) { return page.getByRole('button', { name: 'สร้างบัญชี' }); } +function regLoginLink(page: Page) { return page.getByRole('link', { name: 'เข้าสู่ระบบ' }); } +function regErrorBox(page: Page) { + return page.locator(['.q-field__messages', '.q-field__bottom', '.text-negative', '.q-notification', '.q-banner', '[role="alert"]'].join(', ')); +} +async function pickPrefix(page: Page, value: 'นาย' | 'นาง' | 'นางสาว' = 'นาย') { + const combo = regPrefix(page); + await combo.selectOption({ label: value }).catch(async () => { + await combo.click(); + await page.getByRole('option', { name: value }).click(); + }); +} +function uniqueUser() { + const n = Date.now().toString().slice(-6); + const rand8 = Math.floor(Math.random() * 1e8).toString().padStart(8, '0'); + return { + username: `e2e_user_${n}`, + email: `e2e_${n}@example.com`, + firstName: 'ทดสอบ', + lastName: 'ระบบ', + phone: `09${rand8}`, + password: 'Admin12345!', + }; +} + +// --------------------------- +// Helpers: Forgot Password +// --------------------------- +const FORGOT_URL = `${BASE_URL}/auth/forgot-password`; +function forgotEmail(page: Page) { return page.locator('input[type="email"]').or(page.getByRole('textbox')).first(); } +function forgotSubmit(page: Page) { return page.getByRole('button', { name: /ส่งลิงก์รีเซ็ต/i }).first(); } +function forgotBackLink(page: Page) { return page.getByRole('link', { name: /กลับไปหน้าเข้าสู่ระบบ/i }).first(); } + + +// ================== TESTS ================== +test.describe('ระบบยืนยันตัวตน (Authentication)', () => { + + // --- LOGIN --- + test.describe('การเข้าสู่ระบบ (Login)', () => { + test('Success Login แล้วเข้า /dashboard ได้', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await loginEmailLocator(page).fill(LOGIN_EMAIL); + await loginPasswordLocator(page).fill(LOGIN_PASSWORD); + await loginButtonLocator(page).click(); + await page.waitForURL('**/dashboard', { timeout: 25_000 }); + await waitAppSettled(page); + + const dashboardEvidence = [ + page.locator('.q-page-container').first(), + page.locator('.q-drawer').first(), + page.locator('img[src*="avataaars"]').first(), + page.locator('img[alt],[alt="User Avatar"]').first() + ]; + await expectAnyVisible(page, dashboardEvidence, 20_000); + }); + + test('Invalid Email - Thai characters (พิมพ์ภาษาไทย)', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await loginEmailLocator(page).fill('ทดสอบภาษาไทย'); + await loginPasswordLocator(page).fill(LOGIN_PASSWORD); + const errorHint = page.getByText('ห้ามใส่ภาษาไทย'); + await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + }); + + test('Invalid Email Format (อีเมลผิดรูปแบบ)', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await loginEmailLocator(page).fill('test@domain'); + await loginPasswordLocator(page).fill(LOGIN_PASSWORD); + await loginButtonLocator(page).click(); + await waitAppSettled(page); + const errorHint = page.getByText('กรุณากรอกอีเมลให้ถูกต้อง (you@example.com)'); + await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + }); + + test('Wrong Password (รหัสผ่านผิด หรืออีเมลไม่ถูกต้องในระบบ)', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await loginEmailLocator(page).fill(LOGIN_EMAIL); + await loginPasswordLocator(page).fill('wrong-password-123'); + await loginButtonLocator(page).click(); + await waitAppSettled(page); + const errorHint = page.getByText('กรุณาเช็ค Email หรือ รหัสผ่านใหม่อีกครั้ง'); + await expect(errorHint.first()).toBeVisible({ timeout: 12_000 }); + }); + }); + + // --- REGISTER --- + test.describe('การสมัครสมาชิก (Register)', () => { + test('หน้า Register ต้องโหลดได้ (Smoke)', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await expect(regHeading(page)).toBeVisible({ timeout: 15_000 }); + await expect(regSubmit(page)).toBeVisible({ timeout: 15_000 }); + }); + + test('ลิงก์ "เข้าสู่ระบบ" ต้องกดแล้วไปหน้า login ได้', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await regLoginLink(page).click(); + await page.waitForURL('**/auth/login', { timeout: 15_000 }); + }); + + test('สมัครสมาชิกสำเร็จ (Happy Path) → redirect ไป /auth/login', async ({ page }) => { + const u = uniqueUser(); + await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await regUsername(page).fill(u.username); + await regEmail(page).fill(u.email); + await pickPrefix(page, 'นาย'); + await regFirstName(page).fill(u.firstName); + await regLastName(page).fill(u.lastName); + await regPhone(page).fill(u.phone); + await regPassword(page).fill(u.password); + await regConfirmPassword(page).fill(u.password); + await regSubmit(page).click(); + await waitAppSettled(page); + + const navToLogin = page.waitForURL('**/auth/login', { timeout: 25_000, waitUntil: 'domcontentloaded' }).then(() => 'login' as const).catch(() => null); + const successToast = page.getByText(/สมัครสมาชิกสำเร็จ|success/i, { exact: false }).first().waitFor({ state: 'visible', timeout: 25_000 }).then(() => 'success' as const).catch(() => null); + const anyError = regErrorBox(page).first().waitFor({ state: 'visible', timeout: 25_000 }).then(() => 'error' as const).catch(() => null); + + const result = await Promise.race([navToLogin, successToast, anyError]); + if (result === 'error') { + throw new Error('Register errors visible'); + } + + if (!page.url().includes('/auth/login')) { + const hasSuccess = await page.getByText(/สมัครสมาชิกสำเร็จ/i, { exact: false }).first().isVisible().catch(() => false); + if (hasSuccess) { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + } + } + + await expect(page).toHaveURL(/\/auth\/login/i, { timeout: 15_000 }); + await expect(page.getByRole('heading', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: 15_000 }); + await expect(page.getByRole('button', { name: 'เข้าสู่ระบบ' })).toBeVisible({ timeout: 15_000 }); + }); + + test('Invalid Email - ใส่ภาษาไทย ต้องขึ้น error', async ({ page }) => { + await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await regEmail(page).fill('ทดสอบภาษาไทย'); + await regUsername(page).click(); + const err = page.getByText(/ห้ามใส่ภาษาไทย|อีเมลไม่ถูกต้อง|รูปแบบอีเมล/i, { exact: false }).or(regErrorBox(page).filter({ hasText: /ไทย|อีเมล|email|invalid/i })); + await expect(err.first()).toBeVisible({ timeout: 12_000 }); + }); + + test('Password ไม่ตรงกัน ต้องขึ้น error (ต้องกดสร้างบัญชีก่อน)', async ({ page }) => { + const u = uniqueUser(); + await page.goto(`${BASE_URL}/auth/register`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + await regUsername(page).fill(u.username); + await regEmail(page).fill(u.email); + await pickPrefix(page, 'นาย'); + await regFirstName(page).fill(u.firstName); + await regLastName(page).fill(u.lastName); + await regPhone(page).fill(u.phone); + await regPassword(page).fill('Admin12345!'); + await regConfirmPassword(page).fill('Admin12345?'); + await regSubmit(page).click(); + await waitAppSettled(page); + const mismatchErr = page.getByText(/รหัสผ่านไม่ตรงกัน/i, { exact: false }).or(regErrorBox(page).filter({ hasText: /รหัสผ่านไม่ตรงกัน/i })); + await expect(mismatchErr.first()).toBeVisible({ timeout: 12_000 }); + }); + }); + + // --- FORGOT PASSWORD --- + test.describe('หน้าลืมรหัสผ่าน (Forgot Password)', () => { + test.beforeEach(async ({ page }) => { + await page.goto(FORGOT_URL, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + }); + + test('โหลดหน้าลืมรหัสผ่านได้ครบถ้วน (Smoke Test)', async ({ page }) => { + await expect(page.getByRole('heading', { name: /ลืมรหัสผ่าน/i })).toBeVisible(); + await expect(forgotEmail(page)).toBeVisible(); + await expect(forgotSubmit(page)).toBeVisible(); + await expect(forgotBackLink(page)).toBeVisible(); + }); + + test('Validation: ใส่อีเมลภาษาไทยแล้วขึ้น Error', async ({ page }) => { + await forgotEmail(page).fill('ฟฟฟฟ'); + await page.getByRole('heading', { name: /ลืมรหัสผ่าน/i }).click(); + const err = page.getByText(/ห้ามใส่ภาษาไทย/i).first(); + await expect(err).toBeVisible({ timeout: 10_000 }); + }); + + test('กดลิงก์กลับไปหน้า Login ได้', async ({ page }) => { + await forgotBackLink(page).click(); + await page.waitForURL('**/auth/login', { timeout: 10_000 }); + await expect(page).toHaveURL(/\/auth\/login/i); + }); + + test('ทดลองส่งลิงก์รีเซ็ตรหัสผ่าน (API Mock)', async ({ page }) => { + await page.route('**/*', async (route) => { + const req = route.request(); + const url = req.url(); + const method = req.method(); + const looksLikeForgotApi = method === 'POST' && /forgot|reset/i.test(url) && !/\.(png|jpg|jpeg|webp|svg|css|js|map)$/i.test(url); + if (looksLikeForgotApi) { + await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ success: true, data: { message: 'Reset link sent' } }) }); + return; + } + await route.continue(); + }); + await forgotEmail(page).fill('test@gmail.com'); + await forgotSubmit(page).click(); + await expect(page.getByText(/ส่งลิงก์เรียบร้อยแล้ว/i, { exact: false })).toBeVisible({ timeout: 10_000 }); + await expect(page.getByText(/กรุณาตรวจสอบกล่องจดหมาย/i, { exact: false })).toBeVisible(); + }); + }); +}); diff --git a/Frontend-Learner/tests/e2e/browse.spec.ts b/Frontend-Learner/tests/e2e/browse.spec.ts deleted file mode 100644 index 4eafffde..00000000 --- a/Frontend-Learner/tests/e2e/browse.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test.describe('หมวดหน้าค้นหาคอร์สและผลลัพธ์ (Discovery & Browse)', () => { - - test('2.1 หน้าแรก (Landing Page) โหลดได้ปกติ', async ({ page }) => { - await page.goto('/'); - - // ยืนยันว่าหน้าเว็บขึ้นจริงๆ ด้วยการจับ Element พื้นฐานอย่าง Logo หรือ Footer หรือแบนเนอร์ - // ตัวอย่างเช่นหาคำว่า "เริ่มเรียนฟรี" หรือหัวข้อแคมเปญที่คุณวางไว้หน้า Landing - const heroTitle = page.locator('h1, h2, .hero-title').first(); - await expect(heroTitle).toBeVisible(); - - // เช็คว่าเมนูด้านบน (Navbar) หน้าหลักแสดงผล โดยเช็คจากโลโก้หรือส่วนหัว - const navBar = page.getByRole('link', { name: 'EduLearn Platform' }).first(); - await expect(navBar).toBeVisible({ timeout: 10000 }); - }); - - test('2.2 ค้นหาหลักสูตร (Search Course)', async ({ page }) => { - // ไปที่หน้ารวมคอร์ส - await page.goto('/browse'); - - // หาช่องค้นหา ด้วย placeholder - const searchInput = page.locator('input[placeholder="ค้นหาคอร์ส..."]').first(); - - // พิมพ์คำค้นหา - await searchInput.fill('การเขียนโปรแกรม'); - await searchInput.press('Enter'); - - // 1) รอให้เว็บโหลดผลการค้นหา และตรวจสอบว่ามีการ์ดคอร์สขึ้น (Course Card) - const searchResults = page.locator('a[href^="/course/"]').first(); - await expect(searchResults).toBeVisible(); - }); - - test('2.3 ตัวกรองหมวดหมู่คอร์ส (Category Filter)', async ({ page }) => { - await page.goto('/browse'); - - // คลิกลองเลือกระบุหมวดหมู่ เช่น การออกแบบ - const categoryButton = page.locator('button').filter({ hasText: 'การออกแบบ' }).first(); - - if (await categoryButton.isVisible()) { - await categoryButton.click(); - - // ดูผลลัพธ์ว่าหน้าเว็บยังแสดงผลการ์ดอยู่ (อาจไม่ได้เปลี่ยน URL) - // ลบเช็ค toHaveURL ออกเพราะระบบอาจจะ filter ด้วย Client-Side แทน - - const courseCard = page.locator('a[href^="/course/"]').first(); - await expect(courseCard).toBeVisible(); - } - }); - -}); diff --git a/Frontend-Learner/tests/e2e/dashboard.spec.ts b/Frontend-Learner/tests/e2e/dashboard.spec.ts deleted file mode 100644 index ed1b83ce..00000000 --- a/Frontend-Learner/tests/e2e/dashboard.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { test, expect } from '@playwright/test'; - -const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; - -async function waitAppSettled(page: any) { - await page.waitForLoadState('domcontentloaded'); - await page.waitForLoadState('networkidle').catch(() => {}); - await page.waitForTimeout(200); -} - -// ฟังก์ชันจำลองล็อกอิน (เพื่อที่จะเข้า Dashboard ได้) -async function setupLogin(page: any) { - await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); - await waitAppSettled(page); - - await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); - await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); - await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); - - await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); - await waitAppSettled(page); -} - -test.describe('ระบบหน้าแดชบอร์ดนักเรียน (Dashboard & My Courses)', () => { - - // บังคับให้ Test ทุกข้อในกลุ่มนี้ ล็อกอินก่อนเสมอ - test.beforeEach(async ({ page }) => { - await setupLogin(page); - }); - - test('5.1 หน้าแรกของ Dashboard โหลดได้ปกติ', async ({ page }) => { - await page.goto(`${BASE_URL}/dashboard`); - await page.waitForTimeout(1000); - - // ตรวจสอบว่ามี UI เบื้องต้น เช่น คำต้อนรับ หรือสรุปสถิติ (ถ้ามี) - const welcomeText = page.getByText(/ยินดีต้อนรับกลับ/i, { exact: false }); - const profileSummary = page.locator('.q-avatar, img[alt*="Profile"], img[src*="avatar"]').first(); - - await expect(welcomeText.first().or(profileSummary)).toBeVisible({ timeout: 10_000 }); - }); - - test('5.2 โหลดหน้า คอร์สของฉัน (My Courses)', async ({ page }) => { - // ลองกดเมนูด้านซ้ายเพื่อนำทาง - const myCoursesMenu = page.getByRole('link', { name: /คอร์สของฉัน|My Courses/i }).first() - .or(page.locator('a[href="/dashboard/my-courses"]').first()); - - await myCoursesMenu.click(); - await page.waitForURL('**/dashboard/my-courses', { timeout: 10_000 }); - - // ตรวจสอบโครงสร้างว่าโหลดเรียบร้อย - const heading = page.locator('h2').filter({ hasText: /คอร์สของฉัน|My Courses/i }).first(); - await expect(heading).toBeVisible(); - - // เช็คว่ามีช่องค้นหาคอร์ส - const searchInput = page.locator('input[placeholder*="ค้นหา"]').first(); - await expect(searchInput).toBeVisible(); - - // เช็คปุ่มเปลี่ยนมุมมอง Grid/List (ดูจากไอคอน) - await expect(page.locator('i.q-icon').filter({ hasText: 'grid_view' }).first()).toBeVisible(); - await expect(page.locator('i.q-icon').filter({ hasText: 'view_list' }).first()).toBeVisible(); - }); - - test('5.3 กรองคอร์สด้วยเมนูหมวดหมู่ (Category Filter) ใน My Courses', async ({ page }) => { - await page.goto(`${BASE_URL}/dashboard/my-courses`); - await page.waitForTimeout(1500); // รอ API หรือ UI Mount นิดนึง - - // มองหาปุ่มตัวกรองทั้งหมด - const filterAllBtn = page.getByRole('button').filter({ hasText: /ทั้งหมด|All/i }).first(); - - if (await filterAllBtn.isVisible()) { - await filterAllBtn.click(); - // เช็คว่าข้อมูลโหลด (หาองค์ประกอบ Loading spinner หรือรอ Layout นิ่ง) - await page.locator('.q-spinner').waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {}); - } - }); - - test('5.4 ลองค้นหาคอร์ส (Search Input) ไม่พบข้อมูล', async ({ page }) => { - await page.goto(`${BASE_URL}/dashboard/my-courses`); - - const searchInput = page.locator('input[placeholder*="ค้นหา"]').first(); - await expect(searchInput).toBeVisible(); - - // ลองพิมพ์ชื่อมั่วๆ - await searchInput.fill('คอร์สที่ไม่มีอยู่จริงแน่นอน1234'); - - // ตรวจสอบว่ามีกล่อง Empty State ขึ้นบอกอธิบาย - const emptyState = page.locator('h3').filter({ hasText: /ไม่พบ|ไม่เจอ|No result/i }).first() - .or(page.locator('i.q-icon').filter({ hasText: 'search_off' })); - - await expect(emptyState.first()).toBeVisible({ timeout: 10_000 }); - }); -}); diff --git a/Frontend-Learner/tests/e2e/discovery.spec.ts b/Frontend-Learner/tests/e2e/discovery.spec.ts new file mode 100644 index 00000000..2783d7da --- /dev/null +++ b/Frontend-Learner/tests/e2e/discovery.spec.ts @@ -0,0 +1,91 @@ +import { test, expect } from '@playwright/test'; + +const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; + +test.describe('หมวดหน้าค้นหาคอร์สและผลลัพธ์ (Discovery & Browse)', () => { + + test.describe('ส่วนหน้าแรก (Home)', () => { + test('โหลดหน้าแรก และตรวจสอบแสดงผลครบถ้วน (Hero, Cards, Categories)', async ({ page }) => { + await page.goto(BASE_URL); + const heroTitle = page.locator('h1, h2, .hero-title').first(); + await expect(heroTitle).toBeVisible({ timeout: 15_000 }); + + const ctaButton = page.locator('a[href="/browse"]').first(); + if (await ctaButton.isVisible()) { + await expect(ctaButton).toBeVisible(); + } + + const courseSectionHeading = page.getByText(/คอร์สออนไลน์|Online Courses/i).first(); + await expect(courseSectionHeading).toBeVisible({ timeout: 10_000 }); + + const allCategoryBtn = page.getByRole('button', { name: /ทั้งหมด|All/i }).first(); + await expect(allCategoryBtn).toBeVisible(); + + const courseCards = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }); + await expect(courseCards.first()).toBeVisible({ timeout: 15_000 }); + expect(await courseCards.count()).toBeGreaterThan(0); + }); + }); + + test.describe('ส่วนค้นหาและแคตตาล็อก (Browse)', () => { + test('ค้นหาหลักสูตร (Search Course)', async ({ page }) => { + await page.goto(`${BASE_URL}/browse`); + const searchInput = page.locator('input[placeholder="ค้นหาคอร์ส..."]').first(); + await searchInput.fill('การเขียนโปรแกรม'); + await searchInput.press('Enter'); + + // ในหน้า browse จะใช้ ซึ่ง render เป็น tag + const searchResults = page.locator('a[href*="/course/"]').filter({ has: page.locator('img') }).first(); + await expect(searchResults).toBeVisible({ timeout: 15_000 }); + }); + + test('ตัวกรองหมวดหมู่คอร์ส (Category Filter)', async ({ page }) => { + await page.goto(`${BASE_URL}/browse`); + const categoryButton = page.locator('button').filter({ hasText: 'การออกแบบ' }).first(); + + if (await categoryButton.isVisible()) { + await categoryButton.click(); + // ในหน้า browse จะใช้ ซึ่ง render เป็น tag + const courseCard = page.locator('a[href*="/course/"]').filter({ has: page.locator('img') }).first(); + await expect(courseCard).toBeVisible({ timeout: 15_000 }); + } + }); + }); + + test.describe('หน้ารายละเอียดคอร์ส (Course Detail)', () => { + test('โหลดเนื้อหาวิชา (Curriculum) แถบรายละเอียดขึ้นปกติ', async ({ page }) => { + await page.goto(`${BASE_URL}`); + const courseCard = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }).first(); + await expect(courseCard).toBeVisible({ timeout: 10_000 }); + // Get URL from navigating when clicking the div or finding another link. Since it's a div, we cannot easily get href. + // So let's click it or fallback to /course/1 + const targetUrl = '/course/1'; + + await page.goto(`${BASE_URL}${targetUrl}`); + + const courseTitle = page.locator('h1').first(); + await expect(courseTitle).toBeVisible({ timeout: 15_000 }); + + const curriculumTab = page.getByRole('tab', { name: /เนื้อหาวิชา|ส่วนหลักสูตร|Curriculum/i }).first(); + if (await curriculumTab.isVisible()) { + await curriculumTab.click(); + } + + const lessonItems = page.locator('.q-expansion-item, .lesson-item, [role="listitem"]'); + await expect(lessonItems.first()).toBeVisible().catch(() => {}); + }); + + test('การแสดงผลปุ่ม เข้าเรียน/ลงทะเบียน (Enroll / Start Learning)', async ({ page }) => { + await page.goto(`${BASE_URL}`); + const courseCard = page.locator('div.cursor-pointer').filter({ has: page.locator('img') }).first(); + await expect(courseCard).toBeVisible({ timeout: 10_000 }); + const targetUrl = '/course/1'; + + await page.goto(`${BASE_URL}${targetUrl}`); + await page.waitForLoadState('networkidle').catch(() => {}); + + const enrollStartBtn = page.locator('button').filter({ hasText: /(เข้าสู่ระบบ|ลงทะเบียน|เข้าเรียน|เรียนต่อ|ซื้อ|ฟรี|Enroll|Start|Buy|Login)/i }).first(); + await expect(enrollStartBtn).toBeVisible({ timeout: 10_000 }); + }); + }); +}); diff --git a/Frontend-Learner/tests/e2e/quiz.spec.ts b/Frontend-Learner/tests/e2e/quiz.spec.ts new file mode 100644 index 00000000..178d2abc --- /dev/null +++ b/Frontend-Learner/tests/e2e/quiz.spec.ts @@ -0,0 +1,125 @@ +import { test, expect } from '@playwright/test'; + +const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; + +async function waitAppSettled(page: any) { + await page.waitForLoadState('domcontentloaded'); + await page.waitForLoadState('networkidle').catch(() => {}); + await page.waitForTimeout(200); +} + +// ฟังก์ชันจำลองล็อกอิน (เพราะทำข้อสอบต้องล็อกอินเสมอ) +async function setupLogin(page: any) { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + + await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); + await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); + await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); + + await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); + await waitAppSettled(page); +} + +// ฟังก์ชัน Mock ข้อมูลข้อสอบให้ Playwright ไม่ต้องไปดึงจากฐานข้อมูลจริงๆ (เพื่อป้องกันปัญหาคอร์ส/บทเรียนไม่มีอยู่จริง) +async function mockQuizData(page: any) { + await page.route('**/lessons/*', async (route: any) => { + // สมมติข้อมูลข้อสอบจำลองให้มี 15 ข้อเพื่อเทส Pagination ได้ + const mockQuestions = Array.from({ length: 15 }, (_, i) => ({ + id: i + 1, + question: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, + text: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, + choices: [ + { id: i * 10 + 1, text: { th: 'ก', en: 'A' } }, + { id: i * 10 + 2, text: { th: 'ข', en: 'B' } }, + { id: i * 10 + 3, text: { th: 'ค', en: 'C' } } + ] + })); + + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + success: true, + data: { + id: 17, + type: 'QUIZ', + quiz: { + id: 99, + title: { th: 'แบบทดสอบปลายภาค (Mock)', en: 'Final Exam (Mock)' }, + time_limit: 30, + questions: mockQuestions + } + }, + progress: {} + }) + }); + }); +} + +test.describe('ระบบทำแบบทดสอบ (Quiz System)', () => { + + test.beforeEach(async ({ page }) => { + // ต้อง Login ก่อนเรียน! + await setupLogin(page); + }); + + test('โหลดหน้า Quiz และคลิกระบบเริ่มทำข้อสอบได้ (Start Screen)', async ({ page }) => { + await mockQuizData(page); + + // สมมติเอาที่ quiz ใน course 2 lesson 17 (ซึ่ง API เสาะหาจะถูกดักจับและ Mock ไว้ด้านบนแล้ว) + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + + // หน้าจอ Start Screen ต้องขึ้นมา + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: 15_000 }); + + // ลองกดเริ่มทำ + await startBtn.click(); + + // เช็คว่าหน้า Taking (พื้นที่ทำข้อสอบข้อที่ 1) โผล่มา + const questionText = page.locator('h3').first(); // ชื่อคำถาม + await expect(questionText).toBeVisible({ timeout: 10_000 }); + }); + + test('ทดสอบระบบแถบข้อสอบ แบ่งหน้า (Pagination - เลื่อนซ้าย/ขวา)', async ({ page }) => { + await mockQuizData(page); + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + + // เข้าเมนูแบบทดสอบ + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: 15_000 }); + await startBtn.click(); + + // เช็คว่ามีลูกศรเลื่อนหน้าข้อสอบ (Paginations) สำหรับแบบทดสอบเกิน 10 ข้อที่สร้างมาใหม่ + const nextPaginationPageBtn = page.locator('button').filter({ has: page.locator('i.q-icon:has-text("chevron_right")') }).first(); + + if (await nextPaginationPageBtn.isVisible()) { + // หากปุ่มแสดง (บอกว่ามีข้อสอบหลายหน้า) ลองกดข้าม + await expect(nextPaginationPageBtn).toBeEnabled(); + await nextPaginationPageBtn.click(); + + // เช็คว่ากดแล้ว ข้อที่ 11 โผล่มา + const question11Btn = page.locator('button').filter({ hasText: /^11$/ }).first(); + await expect(question11Btn).toBeVisible(); + } + }); + + test('การแสดงผลปุ่มถัดไป/ส่งคำตอบ (Submit & Navigation UI)', async ({ page }) => { + await mockQuizData(page); + await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); + const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); + await expect(startBtn).toBeVisible({ timeout: 15_000 }); + await startBtn.click(); + + // รอให้หน้าโหลดคำถามเสร็จก่อน ค่อยหาปุ่ม + await expect(page.locator('h3').first()).toBeVisible({ timeout: 10_000 }); + + const submitBtn = page.locator('button').filter({ hasText: /(ส่งคำตอบ|Submit)/i }).first(); + const nextBtn = page.locator('button').filter({ hasText: /(ถัดไป|Next)/i }).first(); + + // แบบทดสอบข้อแรก ต้องมีปุ่ม ถัดไป(Next) หรือปุ่มส่ง ถ้ามีแค่ 1 ข้อ + await expect(submitBtn.or(nextBtn)).toBeVisible({ timeout: 10_000 }); + }); + +}); diff --git a/Frontend-Learner/tests/e2e/settings.spec.ts b/Frontend-Learner/tests/e2e/settings.spec.ts deleted file mode 100644 index f5e085f6..00000000 --- a/Frontend-Learner/tests/e2e/settings.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test.describe('หมวดการตั้งค่าและส่วนติดต่อผู้ใช้ (Settings & UI Theme)', () => { - - test('5.1 เปลี่ยนภาษาการแสดงผล (Localisation/i18n)', async ({ page }) => { - await page.goto('/'); // ไปที่หน้าแรกปกติ - - // หาสวิตช์เปลี่ยนภาษา - const langBtn = page.getByRole('button', { name: 'Language' }).or(page.locator('button').filter({ hasText: /TH|EN/ })).first(); - - // ลองกดสลับถ้ามีปุ่ม - if (await langBtn.isVisible()) { - await langBtn.click(); - - // เลือกเปลี่ยนเป็นภาษาอังกฤษ (สมมติตั้งต้นเป็นไทย) - const englishOpt = page.locator('text=English, text=EN').first(); - await englishOpt.click(); - - // ตรวจสอบว่าคำว่า "เข้าสู่ระบบ" (ไทย) ถูกแปลเป็น "Log in" หรือเมนูอื่นเป็นอังกฤษไปแล้ว - const loginLink = page.locator('a[href*="login"], button').filter({ hasText: /Log in|Sign In/i }); - await expect(loginLink).toBeVisible({ timeout: 5000 }); - } - }); - - test('5.2 เปลี่ยนโหมดมืดสว่าง (Theme Switcher)', async ({ page }) => { - await page.goto('/'); - - // หาปุ่มสลับ Dark Mode / Light Mode (มักจะเป็นรูปพระอาทิตย์/พระจันทร์) - const themeBtn = page.locator('.dark-mode-toggle, button[aria-label*="theme"]').first(); - - // ถ้ารองรับการเปลี่ยนตีม - if (await themeBtn.isVisible()) { - // ดึงคลาสของ ก่อนกด (เช่น '') - const htmlBefore = await page.evaluate(() => document.documentElement.className); - - await themeBtn.click(); - await page.waitForTimeout(500); // รอ animation เฟดนิดนึง - - // ดึงคลาส หลังกดอีกที - const htmlAfter = await page.evaluate(() => document.documentElement.className); - - // คลาสของ HTML ต้องเปลี่ยนไป (เช่น เคยมี 'dark' แล้วโดนลบออก) - expect(htmlBefore).not.toEqual(htmlAfter); - } - }); - - test.describe('การตั้งค่าบัญชี (Profile Settings)', () => { - // แยกหมวดเล็กต้องล็อกอินเอาไว้ทดสอบหน้า My Profile - test.beforeEach(async ({ page }) => { - await page.goto('/auth/login'); - await page.waitForTimeout(1500); - await page.locator('input[type="email"]').fill('studentedtest@example.com'); - await page.locator('input[type="password"]').fill('admin123'); - await page.getByRole('button', { name: 'เข้าสู่ระบบ', exact: true }).click(); - await page.waitForURL('**/dashboard', { timeout: 15000 }); - }); - - test('5.3 แก้ไขและบันทึกข้อมูลส่วนตัว (Edit Profile)', async ({ page }) => { - // เข้าไปที่หน้าการตั้งค่า หรือ Profile - await page.goto('/dashboard/profile'); - - // ตรวจสอบว่ามีช่องกรอกชื่อ - const nameInput = page.locator('input[type="text"]').first(); - - if (await nameInput.isVisible()) { - const oldName = await nameInput.inputValue(); - - // ทดลองพิมพ์ตัวเลขต่อท้ายเข้าไปเพื่อจำลองการแก้ไข - await nameInput.clear(); - await nameInput.fill(`${oldName}แก้ไข`); - - // กดปุ่มบันทึกข้อมูล - const saveBtn = page.getByRole('button', { name: 'บันทึกการเปลี่ยนแปลง', exact: false }) - .or(page.locator('button').filter({ hasText: 'บันทึก' })).first(); - await saveBtn.click(); - - // ตรวจสอบว่ามีแถบ Notification เด้งว่า "อัปเดตเรียบร้อย" - const successNotify = page.locator('.q-notification__message, text=อัปเดตข้อมูลสำเร็จ').first(); - await expect(successNotify).toBeVisible({ timeout: 5000 }); - - // (Clean up) อาจจะพิมพ์ชื่อเดิมกลับลงไปเพื่อไม่ให้ข้อมูลพัง - } - }); - - }); -}); diff --git a/Frontend-Learner/tests/e2e/student-account.spec.ts b/Frontend-Learner/tests/e2e/student-account.spec.ts new file mode 100644 index 00000000..4418483e --- /dev/null +++ b/Frontend-Learner/tests/e2e/student-account.spec.ts @@ -0,0 +1,118 @@ +import { test, expect } from '@playwright/test'; + +const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; + +async function waitAppSettled(page: any) { + await page.waitForLoadState('domcontentloaded'); + await page.waitForLoadState('networkidle').catch(() => {}); + await page.waitForTimeout(200); +} + +// ฟังก์ชันจำลองล็อกอิน (เพื่อที่จะเข้า Dashboard ได้) +async function setupLogin(page: any) { + await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); + await waitAppSettled(page); + + await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); + await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); + await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); + + await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); + await waitAppSettled(page); +} + +test.describe('ระบบพื้นที่ส่วนตัวผู้เรียน (Student Account / Portal)', () => { + + test.describe('การตั้งค่าและส่วนติดต่อผู้ใช้ (Settings & UI Theme)', () => { + test('เปลี่ยนภาษาการแสดงผล (Localisation/i18n)', async ({ page }) => { + await page.goto(BASE_URL); + const langBtn = page.getByRole('button', { name: 'Language' }).or(page.locator('button').filter({ hasText: /TH|EN/ })).first(); + + if (await langBtn.isVisible()) { + await langBtn.click(); + const englishOpt = page.locator('text=English, text=EN').first(); + await englishOpt.click(); + + const loginLink = page.locator('a[href*="login"], button').filter({ hasText: /Log in|Sign In/i }); + await expect(loginLink).toBeVisible({ timeout: 5000 }); + } + }); + + test('เปลี่ยนโหมดมืดสว่าง (Theme Switcher)', async ({ page }) => { + await page.goto(BASE_URL); + const themeBtn = page.locator('.dark-mode-toggle, button[aria-label*="theme"]').first(); + + if (await themeBtn.isVisible()) { + const htmlBefore = await page.evaluate(() => document.documentElement.className); + await themeBtn.click(); + await page.waitForTimeout(500); + const htmlAfter = await page.evaluate(() => document.documentElement.className); + expect(htmlBefore).not.toEqual(htmlAfter); + } + }); + }); + + test.describe('ระบบหน้าแดชบอร์ดนักเรียน (Dashboard & My Courses)', () => { + test.beforeEach(async ({ page }) => { + await setupLogin(page); + }); + + test('หน้าแรกของ Dashboard โหลดได้ปกติ', async ({ page }) => { + await page.goto(`${BASE_URL}/dashboard`); + await page.waitForTimeout(1000); + + const welcomeText = page.getByText(/ยินดีต้อนรับกลับ/i, { exact: false }); + const profileSummary = page.locator('.q-avatar, img[alt*="Profile"], img[src*="avatar"]').first(); + + await expect(welcomeText.first().or(profileSummary)).toBeVisible({ timeout: 10_000 }); + }); + + test('โหลดหน้า คอร์สของฉัน (My Courses)', async ({ page }) => { + await page.goto(`${BASE_URL}/dashboard/my-courses`); + + const heading = page.locator('h2').filter({ hasText: /คอร์สของฉัน|My Courses/i }).first(); + await expect(heading).toBeVisible(); + + const searchInput = page.getByPlaceholder(/ค้นหา|Search/i).first(); + await expect(searchInput).toBeVisible({ timeout: 10_000 }); + + await expect(page.locator('i.q-icon').filter({ hasText: 'grid_view' }).first()).toBeVisible(); + await expect(page.locator('i.q-icon').filter({ hasText: 'view_list' }).first()).toBeVisible(); + }); + + test('ลองค้นหาคอร์ส (Search Input) ไม่พบข้อมูล', async ({ page }) => { + await page.goto(`${BASE_URL}/dashboard/my-courses`); + + const searchInput = page.getByPlaceholder(/ค้นหา|Search/i).first(); + await expect(searchInput).toBeVisible({ timeout: 10_000 }); + + await searchInput.fill('คอร์สที่ไม่มีอยู่จริงแน่นอน1234'); + + const emptyState = page.locator('h3').filter({ hasText: /ไม่พบ|ไม่เจอ|No result/i }).first() + .or(page.locator('i.q-icon').filter({ hasText: 'search_off' })); + + await expect(emptyState.first()).toBeVisible({ timeout: 10_000 }); + }); + + test('แก้ไขและบันทึกข้อมูลส่วนตัว (Edit Profile)', async ({ page }) => { + await page.goto(`${BASE_URL}/dashboard/profile`); + + const nameInput = page.locator('input[type="text"]').first(); + + if (await nameInput.isVisible()) { + const oldName = await nameInput.inputValue(); + + await nameInput.clear(); + await nameInput.fill(`${oldName}แก้ไข`); + + const saveBtn = page.getByRole('button', { name: /บันทึก/i }).first(); + if(await saveBtn.isVisible()) { + await saveBtn.click(); + const successNotify = page.locator('.q-notification__message, text=อัปเดตข้อมูลสำเร็จ').first(); + await expect(successNotify).toBeVisible({ timeout: 5000 }).catch(() => {}); + } + } + }); + + }); +}); diff --git a/tests/e2e/screenshots/forgot-01-smoke.png b/tests/e2e/screenshots/forgot-01-smoke.png index 84755f7b..b04aec7f 100644 Binary files a/tests/e2e/screenshots/forgot-01-smoke.png and b/tests/e2e/screenshots/forgot-01-smoke.png differ diff --git a/tests/e2e/screenshots/forgot-02-thai-email.png b/tests/e2e/screenshots/forgot-02-thai-email.png index ddd8612e..874b61b1 100644 Binary files a/tests/e2e/screenshots/forgot-02-thai-email.png and b/tests/e2e/screenshots/forgot-02-thai-email.png differ diff --git a/tests/e2e/screenshots/forgot-03-back-login.png b/tests/e2e/screenshots/forgot-03-back-login.png index dc941bf6..506f9126 100644 Binary files a/tests/e2e/screenshots/forgot-03-back-login.png and b/tests/e2e/screenshots/forgot-03-back-login.png differ diff --git a/tests/e2e/screenshots/forgot-04-mock-success.png b/tests/e2e/screenshots/forgot-04-mock-success.png index c13db627..187b27c8 100644 Binary files a/tests/e2e/screenshots/forgot-04-mock-success.png and b/tests/e2e/screenshots/forgot-04-mock-success.png differ diff --git a/tests/e2e/screenshots/login-invalid-email.png b/tests/e2e/screenshots/login-invalid-email.png index 3e076731..82a0519e 100644 Binary files a/tests/e2e/screenshots/login-invalid-email.png and b/tests/e2e/screenshots/login-invalid-email.png differ diff --git a/tests/e2e/screenshots/login-thai-email.png b/tests/e2e/screenshots/login-thai-email.png index d18e94c0..8e86c501 100644 Binary files a/tests/e2e/screenshots/login-thai-email.png and b/tests/e2e/screenshots/login-thai-email.png differ diff --git a/tests/e2e/screenshots/login-to-dashboard.png b/tests/e2e/screenshots/login-to-dashboard.png index d576e0ba..87b0b9ed 100644 Binary files a/tests/e2e/screenshots/login-to-dashboard.png and b/tests/e2e/screenshots/login-to-dashboard.png differ diff --git a/tests/e2e/screenshots/login-wrong-password.png b/tests/e2e/screenshots/login-wrong-password.png index b42df47f..0ab6a6b7 100644 Binary files a/tests/e2e/screenshots/login-wrong-password.png and b/tests/e2e/screenshots/login-wrong-password.png differ diff --git a/tests/e2e/screenshots/register-go-login.png b/tests/e2e/screenshots/register-go-login.png index 705beb52..a3d22a50 100644 Binary files a/tests/e2e/screenshots/register-go-login.png and b/tests/e2e/screenshots/register-go-login.png differ diff --git a/tests/e2e/screenshots/register-invalid-email-thai.png b/tests/e2e/screenshots/register-invalid-email-thai.png index 0aaa213f..4692e492 100644 Binary files a/tests/e2e/screenshots/register-invalid-email-thai.png and b/tests/e2e/screenshots/register-invalid-email-thai.png differ diff --git a/tests/e2e/screenshots/register-page.png b/tests/e2e/screenshots/register-page.png index de5a3378..e1648998 100644 Binary files a/tests/e2e/screenshots/register-page.png and b/tests/e2e/screenshots/register-page.png differ diff --git a/tests/e2e/screenshots/register-password-mismatch.png b/tests/e2e/screenshots/register-password-mismatch.png index 822443a5..74d49e04 100644 Binary files a/tests/e2e/screenshots/register-password-mismatch.png and b/tests/e2e/screenshots/register-password-mismatch.png differ diff --git a/tests/e2e/screenshots/register-redirect-login.png b/tests/e2e/screenshots/register-redirect-login.png index 49e011dd..0024f95a 100644 Binary files a/tests/e2e/screenshots/register-redirect-login.png and b/tests/e2e/screenshots/register-redirect-login.png differ