Files
gold_land_user/e2e/full-path.spec.ts
T

243 lines
15 KiB
TypeScript
Raw Normal View History

import { test, expect, type Page } from '@playwright/test'
import { fetchMe, loginViaUi, logoutViaProfile, registerViaUi, uniqueUsername } from './helpers/auth'
test.describe.configure({ mode: 'serial' })
async function openLevel(page: Page, name: string, start: string) {
await page.goto('/map')
await page.getByRole('button', { name }).click()
await page.getByRole('button', { name: start }).click()
await page.getByText('در حال بارگذاری').waitFor({ state: 'detached', timeout: 30_000 }).catch(() => undefined)
}
async function clickAnswer(page: Page, label: string) {
if (label === 'درست' || label === 'نادرست') {
await page.getByRole('button', { name: label, exact: true }).click()
return
}
const button = page.getByRole('button', { name: label, exact: true })
if (await button.count()) {
await button.first().click()
return
}
await page.getByText(label, { exact: true }).click()
}
async function finishLesson(page: Page, labels: string[]) {
let cursor = 0
for (let step = 0; step < 30; step += 1) {
if (await page.getByText('امتیاز').first().isVisible().catch(() => false)) return
if (await page.getByText('خوراکی ضروری').isVisible().catch(() => false)) {
for (let move = 0; move < 4; move += 1) {
await page.locator('.sort-item').filter({ hasText: 'خوراکی ضروری' }).getByRole('button', { name: '↑' }).click()
}
}
if (cursor < labels.length) {
const label = labels[cursor]!
const visible = await page.getByText(label, { exact: true }).isVisible().catch(() => false)
if (visible) {
await clickAnswer(page, label)
cursor += 1
}
}
const finish = page.getByRole('button', { name: 'اتمام درس' })
if (await finish.isVisible().catch(() => false) && await finish.isEnabled().catch(() => false)) {
await finish.click()
await page.getByText('امتیاز').first().waitFor()
return
}
const next = page.getByRole('button', { name: 'بعدی' })
if (await next.isEnabled().catch(() => false)) await next.click()
}
throw new Error('lesson did not finish')
}
async function starsOf(page: Page, levelId: number) {
const me = await fetchMe(page)
return me.progress.mapLevels.find((level) => level.id === levelId)?.stars ?? 0
}
test('full thirteen-level journey from the interface', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'desktop', 'full journey runs once on desktop')
test.setTimeout(600_000)
const errors: string[] = []
page.on('pageerror', (error) => errors.push(error.message))
page.on('console', (message) => {
if (message.type() === 'error') errors.push(message.text())
})
const user = uniqueUsername('path')
await registerViaUi(page, user, 'pass1234', 'مسیر')
const lessons: Array<{ name: string; labels: string[] }> = [
{ name: 'مرحله 1: پول چیه؟', labels: ['مبادله آسان‌تر کالاها', 'درست', 'چون همه همیشه همان چیز را می‌خواهند', 'درست', 'پول وسیلهٔ مبادله و نگه‌داری ارزش است'] },
{ name: 'مرحله 2: پس‌انداز', labels: ['بخشی از پول را برای بعد کنار گذاشتن', 'درست', 'برای هدفش برنامه نداشت و همه را خرج کرد', 'درست', 'هدف آینده چیزی است که برایش برنامه می‌ریزیم'] },
{ name: 'مرحله 3: نیاز و خواسته', labels: ['چیزی که برای زندگی سالم لازم است', 'درست', 'اول نیازها را برطرف کنیم', 'درست'] },
{ name: 'مرحله 4: طلا چیه؟', labels: ['چون واحد استاندارد وزن طلا است', 'درست', 'زیورآلات و صنعت', 'نادرست', 'طلا دارایی با ارزش است که قیمتش می‌تواند تغییر کند'] },
{ name: 'مرحله 5: بازار طلا', labels: ['قیمت بالا و پایین می‌شود', 'نادرست', 'چون ممکن است وقت کافی برای فکر کردن نداشته باشیم', 'درست', 'فکر کردن و پراکنده نکردن تمام پول در یک دارایی'] },
{ name: 'مرحله 6: تورم', labels: ['افزایش عمومی قیمت‌ها در طول زمان', 'درست', 'قدرت خرید پول کم شده', 'نادرست', 'ممکن است ارزش واقعی‌اش کم شود'] },
]
for (let index = 0; index < lessons.length; index += 1) {
const lesson = lessons[index]!
await openLevel(page, lesson.name, 'شروع درس')
await finishLesson(page, lesson.labels)
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, index + 1)).toBeGreaterThan(0)
if (index < 5) {
await expect(page.getByRole('button', { name: lessons[index + 1]!.name })).toBeEnabled()
}
}
await page.reload()
expect(await starsOf(page, 6)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 7: بودجه‌بندی', 'شروع بازی')
await page.getByRole('button', { name: 'ساخت بودجه' }).click()
for (let index = 0; index < 4; index += 1) await page.getByRole('button', { name: 'افزایش رفت‌وآمد' }).click()
for (let index = 0; index < 5; index += 1) await page.getByRole('button', { name: 'افزایش آب و غذا' }).click()
for (let index = 0; index < 4; index += 1) await page.getByRole('button', { name: 'افزایش پس‌انداز برای هدف' }).click()
await page.getByRole('button', { name: 'بررسی برنامه' }).click()
await page.getByRole('button', { name: 'تأیید برنامه' }).click()
await page.getByRole('button', { name: 'بازتنظیم بودجه' }).click()
for (let index = 0; index < 2; index += 1) await page.getByRole('button', { name: 'افزایش رفت‌وآمد' }).click()
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 7)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 8: ریسک و بازده', 'شروع چالش')
await page.getByRole('button', { name: 'دیدن دو پیشنهاد' }).click()
await page.getByRole('button', { name: 'رفتن به فعالیت‌ها' }).click()
const risk = [
'پیشنهاد ب',
'خیر، ۳۶ فقط یکی از نتیجه‌های ممکن است',
'این پول ضروری را وارد پیشنهادهای نامطمئن نکن',
'پیشنهاد ب امکان نتیجه بالاتر و زیان بیشتری دارد؛ سود بیشتر قطعی نیست',
'وعده را تضمین معتبر فرض نکن، بررسی کن و از بزرگسال قابل اعتماد کمک بگیر',
]
for (let index = 0; index < risk.length; index += 1) {
await page.getByText(risk[index]!, { exact: true }).click()
await page.getByRole('button', { name: index === risk.length - 1 ? 'مرور پاسخ‌ها' : 'بعدی' }).click()
}
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 8)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 9: سبد سرمایه‌گذاری', 'شروع بازی')
await page.getByRole('button', { name: 'ساخت سبد' }).click()
for (let index = 0; index < 4; index += 1) await page.getByRole('button', { name: 'افزایش آفتاب' }).click()
for (let index = 0; index < 3; index += 1) await page.getByRole('button', { name: 'افزایش باران' }).click()
for (let index = 0; index < 3; index += 1) await page.getByRole('button', { name: 'افزایش باد' }).click()
await page.getByRole('button', { name: 'دیدن سه سناریو' }).click()
await page.getByRole('button', { name: 'رفتن به سؤال‌ها' }).click()
const portfolio = [
'نتیجه بیشتر به همان گزینه وابسته می‌شود',
'خیر؛ افت همگانی می‌تواند چند گزینه را هم‌زمان کم کند',
'خیر؛ رفتار و وابستگی آن‌ها مهم است',
'خیر؛ یک سناریو آینده را تضمین نمی‌کند',
'توجه به هدف، زمان نیاز به پول و ریسک؛ در مسائل واقعی کمک از بزرگسال قابل اعتماد',
]
for (let index = 0; index < portfolio.length; index += 1) {
await page.getByText(portfolio[index]!, { exact: true }).click()
await page.getByRole('button', { name: index === portfolio.length - 1 ? 'مرور پاسخ‌ها' : 'بعدی' }).click()
}
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 9)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 10: سود مرکب', 'شروع درس')
await page.getByRole('button', { name: 'بعدی' }).click()
await page.getByRole('button', { name: 'دوره بعد' }).click()
await page.getByRole('button', { name: 'دوره بعد' }).click()
await page.getByRole('button', { name: 'دوره بعد' }).click()
await page.getByRole('button', { name: 'بعدی' }).click()
const compound = [
'رشد دوره بعد بر موجودی جدید، شامل رشد قبلی، محاسبه می‌شود',
'۱۲۱ سکه',
'چون ۱۰٪ از ۱۱۰ محاسبه شده است',
'مرکب؛ ۱۳۳٫۱ در برابر ۱۳۰',
]
for (const label of compound) {
await page.getByRole('button', { name: label, exact: true }).click()
await page.getByRole('button', { name: 'بعدی' }).click()
}
await page.getByRole('button', { name: 'نادرست', exact: true }).click()
await page.getByRole('button', { name: 'بعدی' }).click()
await page.getByRole('button', { name: 'اتمام درس' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 10)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 11: خرید هوشمند', 'شروع بازی')
await page.getByRole('button', { name: 'شروع خریدها' }).click()
const shop = [
['دفتر ۶۰برگ، ۴۰ سکه، تحویل ۵ سکه', 'نیاز را برآورده می‌کند و هزینه نهایی‌اش بین گزینه‌های مناسب کمتر است'],
['مداد با قیمت نهایی ۲۸، بدون تخفیف', 'برای کالای یکسان، مبلغ نهایی پرداختی مهم است؛ درصد تخفیف به‌تنهایی کافی نیست'],
['فعلاً نخر و اندازه و هزینه نهایی را بپرس، با کمک بزرگسال قابل اعتماد', 'اطلاعات لازم برای تصمیم و مقایسه هنوز کامل نیست'],
]
for (let index = 0; index < shop.length; index += 1) {
await page.getByText(shop[index]![0]!, { exact: true }).click()
await page.getByText(shop[index]![1]!, { exact: true }).click()
await page.getByRole('button', { name: index === shop.length - 1 ? 'مرور انتخاب‌ها' : 'مأموریت بعد' }).click()
}
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 11)).toBeGreaterThan(0)
await openLevel(page, 'مرحله 12: هدف مالی', 'شروع چالش')
await page.getByRole('button', { name: 'ساخت برنامه' }).click()
await page.getByRole('button', { name: '15 سکه در هفته' }).click()
await page.getByRole('button', { name: 'تأیید برنامه اولیه' }).click()
await page.getByRole('button', { name: 'هفته دوم: 5 سکه' }).click()
await page.getByRole('button', { name: 'ادامه: 15 سکه' }).click()
await page.getByRole('button', { name: 'رفتن به سؤال‌ها' }).click()
const goal = [
'خرید بسته مشخص با قیمت ۱۲۰ و برنامه پس‌انداز',
'۹۰ سکه',
'۶ هفته',
'نیاز را تأمین کن و مبلغ پس‌انداز یا زمان هدف را اصلاح کن',
'برنامه و زمان را دوباره بررسی و به‌روز کن',
]
for (let index = 0; index < goal.length; index += 1) {
await page.getByText(goal[index]!, { exact: true }).click()
await page.getByRole('button', { name: index === goal.length - 1 ? 'مرور پاسخ‌ها' : 'بعدی' }).click()
}
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 12)).toBeGreaterThan(0)
await page.reload()
expect(await starsOf(page, 12)).toBeGreaterThan(0)
await expect(page.getByRole('button', { name: 'مرحله 14', exact: false })).toHaveCount(0)
await openLevel(page, 'مرحله 13: آزمون قلعه', 'شروع آزمون')
await page.getByRole('button', { name: 'شروع سؤال‌ها' }).click()
const castle = [
'مبادله را آسان می‌کند و مقایسه قیمت را ممکن می‌سازد',
'مبلغی متناسب با شرایط را منظم کنار بگذاریم',
'اول آب آشامیدنی را تأمین کنیم',
'طلا یک دارایی است و قیمتش می‌تواند بالا یا پایین برود',
'خیر',
'با همان پول، مقدار کمتری از آن کالاها می‌توان خرید',
'رفت‌وآمد ۳۰، غذا ۲۵، پس‌انداز ۲۰، تفریح ۱۵، ذخیره ۱۰',
'پول لازم را وارد پیشنهاد نامطمئن با احتمال زیان نکنیم',
'خیر؛ چند گزینه ممکن است هم‌زمان افت کنند',
'۱۲۱',
'ب، چون ۴۵ در برابر ۵۰ است',
'۶ هفته',
]
for (let index = 0; index < castle.length; index += 1) {
await page.getByText(castle[index]!, { exact: true }).click()
await page.getByRole('button', { name: index === castle.length - 1 ? 'مرور پاسخ‌ها' : 'بعدی' }).click()
}
await page.getByRole('button', { name: 'ثبت نتیجه' }).click()
await expect(page.getByText('آفرین! مسیر آموزشی قلعه را کامل کردی')).toBeVisible()
await expect(page.getByRole('button', { name: 'مرحله بعد' })).toHaveCount(0)
await page.getByRole('button', { name: 'بازگشت به نقشه' }).click()
expect(await starsOf(page, 13)).toBeGreaterThan(0)
await logoutViaProfile(page)
await loginViaUi(page, user, 'pass1234')
await page.goto('/map')
for (let levelId = 1; levelId <= 13; levelId += 1) {
expect(await starsOf(page, levelId)).toBeGreaterThan(0)
}
expect(errors.filter((error) => !/favicon|Download the React DevTools/i.test(error))).toEqual([])
})