File size: 13,246 Bytes
0ba5932 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | """Preparing for an exam: the exam names its units, and the student sees how ready they are and a plan of steps, with a
daily amount and each step checked off from their progress."""
import json
import socket
import threading
import time
from datetime import date, datetime, timedelta, timezone
import pytest
from app.main import create_app
from test_assignments import MemoryAssignments
from test_focus_browser import DANA, SchoolAuth, mail, session
from test_worksheets import MemoryWorksheets
from test_worksheets_browser import NoAnswers, uvicorn
playwright = pytest.importorskip("playwright.sync_api")
class ExamAuth(SchoolAuth):
exams = []
def classes(self, fresh=False):
return [{**super().classes()[0], "exams": self.exams}]
@pytest.fixture
def exam_server():
auth = ExamAuth()
app = create_app(auth=auth)
app.state.assignments, app.state.worksheets, app.state.answers = MemoryAssignments(), MemoryWorksheets(), NoAnswers()
with socket.socket() as sock:
sock.bind(("127.0.0.1", 0))
server = uvicorn().Server(uvicorn().Config(app, log_level="error"))
thread = threading.Thread(target=server.run, kwargs={"sockets": [sock]}, daemon=True)
thread.start()
try:
while not server.started:
time.sleep(.01)
yield f"http://127.0.0.1:{sock.getsockname()[1]}", auth
finally:
server.should_exit = True
thread.join(timeout=5)
def ago(days):
return (datetime.now(timezone.utc) - timedelta(days=days)).isoformat()
# unit t: t_ext finished lately, t_simplify finished long ago (fading), t_ext_eq tried, t_area and t_formulas not started
PROGRESS = {"done": {"t_ext": ago(1), "t_simplify": ago(40)}, "seen": {"t_ext": ago(1), "t_simplify": ago(40), "t_ext_eq": ago(2)},
"tries": {"t_ext_eq": 2}, "updated": 1}
def with_progress(page, progress):
k = json.dumps("mathly.progress.v1:" + mail[DANA]) # only the first time: a reload keeps what the page saved
page.add_init_script("if(!localStorage.getItem(%s)) localStorage.setItem(%s, %s)" % (k, k, json.dumps(json.dumps(progress))))
def test_the_student_sees_readiness_and_a_plan_with_a_daily_amount(exam_server):
url, auth = exam_server
auth.exams = [{"subject": "מתמטיקה", "date": (date.today() + timedelta(days=3)).isoformat(), "units": ["t"], "note": "פרק 3"}]
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, DANA)
with_progress(page, PROGRESS)
page.goto(url)
page.locator('[data-subject="מתמטיקה"]').click()
page.locator(".mx-prep-open").click()
prep = page.locator(".mx-prep-sheet")
playwright.expect(prep.locator("#mxTitle")).to_have_text("הכנה למבחן במתמטיקה")
playwright.expect(prep).to_contain_text("חומר למבחן: טכניקה אלגברית 1")
playwright.expect(prep).to_contain_text("פרק 3")
playwright.expect(prep.locator(".mx-prep-sum")).to_have_text("2 מתוך 5 מיומנויות הושלמו · 1 דועכות")
playwright.expect(prep.locator(".mx-prep-skills li")).to_have_count(5)
playwright.expect(prep.locator('.mx-prep-skills li[data-state="fading"]')).to_have_count(1)
steps = prep.locator(".mx-prep-step")
playwright.expect(steps).to_have_count(8) # 3 not finished, 1 fading, the unit's quiz, the three quizzes
playwright.expect(prep.locator(".mx-prep-plan")).to_contain_text("3 צעדים ביום")
playwright.expect(prep.locator(".mx-prep-step.today")).to_have_count(3)
playwright.expect(steps.nth(0)).to_contain_text("ללמוד ולסיים")
playwright.expect(steps.nth(5)).to_contain_text("מבחן תרגול 1")
playwright.expect(steps.nth(6)).to_contain_text("מבחן תרגול 2")
playwright.expect(steps.nth(7)).to_contain_text("מבחן תרגול כמו במבחן")
# a step done from progress made after the plan was opened
page.evaluate("""() => { const k = Object.keys(localStorage).find(k => k.startsWith('mathly.progress.v1:'));
const P = JSON.parse(localStorage.getItem(k)); P.done.t_area = new Date().toISOString(); localStorage.setItem(k, JSON.stringify(P)); }""")
page.reload()
page.locator('[data-subject="מתמטיקה"]').click()
page.locator(".mx-prep-open").click()
playwright.expect(prep.locator(".mx-prep-step.done")).to_have_count(1)
playwright.expect(prep.locator(".mx-prep-step.done")).to_contain_text("השוואת שטחים")
# the first quiz's step starts it, over the exam's units only; handed in, the step is done
prep.locator('[data-hq="s1"]').click()
sheet = page.locator(".mx-quiz-sheet")
playwright.expect(sheet.locator(".mx-uchip")).to_have_text("מבחן תרגול 1")
n = sheet.locator(".mx-quiz-dots button").count()
for i in range(n):
sheet.locator(".mx-choices button[data-right]").first.click()
sheet.locator("[data-act=quiz-submit]" if i == n - 1 else "[data-act=quiz-next]").click()
playwright.expect(sheet.locator("#mxTitle")).to_have_text(f"{n} מתוך {n} נכונות")
qs = page.evaluate("""() => { const k = Object.keys(localStorage).find(k => k.startsWith('mathly.progress.v1:'));
return JSON.parse(localStorage.getItem(k)).quizzes.at(-1).qs; }""")
assert qs and all(q.startswith("t_") for q in qs)
sheet.locator(".mx-x").click()
page.locator(".mx-prep-open").click()
playwright.expect(prep.locator(".mx-prep-step.done", has_text="מבחן תרגול 1")).to_have_count(1)
assert not errors, errors
finally:
browser.close()
def test_the_day_before_the_exam_the_plan_has_no_daily_amount(exam_server):
url, auth = exam_server
auth.exams = [{"subject": "מתמטיקה", "date": (date.today() + timedelta(days=1)).isoformat(), "units": ["t"]},
{"subject": "מתמטיקה", "date": (date.today() + timedelta(days=9)).isoformat()}] # no units: no preparation
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, DANA)
with_progress(page, PROGRESS)
page.goto(url)
page.locator('[data-subject="מתמטיקה"]').click()
playwright.expect(page.locator(".mx-prep-open")).to_have_count(1)
page.locator(".mx-prep-open").click()
prep = page.locator(".mx-prep-sheet")
playwright.expect(prep.locator(".mx-uchip")).to_have_text("מחר")
playwright.expect(prep.locator(".mx-prep-step")).to_have_count(8) # the three quizzes at the end
playwright.expect(prep.locator(".mx-prep-plan")).not_to_contain_text("צעדים ביום")
playwright.expect(prep.locator(".mx-prep-step.today")).to_have_count(0)
assert not errors, errors
finally:
browser.close()
def test_the_teacher_names_the_units_and_sees_how_ready_the_class_is(exam_server):
from test_focus_browser import TEACHER
url, auth = exam_server
auth.exams = [{"subject": "מתמטיקה", "date": (date.today() + timedelta(days=5)).isoformat()}]
saved = []
def save(class_id, exams):
saved.append(exams)
auth.exams = exams
auth.save_class_exams = save
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, TEACHER)
page.goto(url)
page.locator('[data-act="class-report"]').click()
sheet = page.locator(".mx-report-sheet")
sheet.locator("[data-report-tab=exams]").click()
form = sheet.locator("[data-exam-form]")
playwright.expect(sheet.locator(".mx-exam-t")).to_contain_text("בחרו את היחידות של המבחן")
form.locator('[name=unit][value="t"]').check()
form.locator("[name=note]").fill("פרק 3")
form.locator("button[type=submit]").click()
playwright.expect(sheet.locator(".mx-report")).to_contain_text("החומר למבחן נשמר")
assert saved[-1][0]["units"] == ["t"] and saved[-1][0]["note"] == "פרק 3"
playwright.expect(sheet.locator(".mx-exam-t .mx-report-table tbody tr")).to_have_count(5) # the 5 skills of t
playwright.expect(sheet.locator(".mx-exam-t")).to_contain_text("הכי רחוקים מהחומר")
assert not errors, errors
finally:
browser.close()
def test_a_plan_saved_with_the_old_practice_exam_step_gets_the_three_quizzes(exam_server):
url, auth = exam_server
when = (date.today() + timedelta(days=5)).isoformat()
auth.exams = [{"subject": "מתמטיקה", "date": when, "units": ["t"], "note": ""}]
old = {**PROGRESS, "prep": {f"3|מתמטיקה|{when}": {"opened": ago(1), "steps": [{"k": "skill", "id": "t_area"}, {"k": "exam"}]}}}
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, DANA)
with_progress(page, old)
page.goto(url)
page.locator('[data-subject="מתמטיקה"]').click()
page.locator(".mx-prep-open").click()
steps = page.locator(".mx-prep-sheet .mx-prep-step")
playwright.expect(steps).to_have_count(4)
playwright.expect(steps.nth(1)).to_contain_text("מבחן תרגול 1")
playwright.expect(steps.nth(3)).to_contain_text("מבחן תרגול כמו במבחן")
assert not errors, errors
finally:
browser.close()
def test_home_highlights_the_lessons_to_finish_before_the_next_exam(exam_server):
url, auth = exam_server
auth.exams = [{"subject": "מתמטיקה", "date": (date.today() + timedelta(days=4)).isoformat(), "units": ["t", "k"]}]
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, DANA)
with_progress(page, {**PROGRESS, "done": {**PROGRESS["done"], **{s: ago(1) for s in ("k_def", "k_angles", "k_diag", "k_axes")}}})
page.goto(url)
page.locator('[data-subject="מתמטיקה"]').click()
page.locator('.mx-nav [data-view="home"]').click()
lessons = page.locator(".mx-home-lessons")
playwright.expect(lessons.locator("h3")).to_have_text("להשלים לפני המבחן: שיעור אחד")
playwright.expect(lessons.locator("li.todo")).to_have_count(1) # unit t: 2 of 5 skills
playwright.expect(lessons.locator("li.todo")).to_contain_text("2 מתוך 5 מיומנויות")
playwright.expect(lessons.locator("li.done")).to_contain_text("✓ הושלם") # unit k: all done
lessons.locator("li.todo button").click() # opens the lesson on the path
playwright.expect(page.locator('.mx-nav [data-view="path"]')).to_have_attribute("aria-current", "page")
assert not errors, errors
finally:
browser.close()
def test_the_teacher_adds_and_deletes_an_exam_on_the_classs_table(exam_server):
from test_focus_browser import TEACHER
url, auth = exam_server
auth.exams = []
def save(class_id, exams):
auth.exams = exams
auth.save_class_exams = save
day = (date.today() + timedelta(days=12)).isoformat()
with playwright.sync_playwright() as p:
browser = p.chromium.launch()
try:
page, errors = session(browser, TEACHER)
page.on("dialog", lambda d: d.accept())
page.goto(url)
page.locator('[data-act="class-report"]').click()
sheet = page.locator(".mx-report-sheet")
sheet.locator("[data-report-tab=exams]").click()
playwright.expect(sheet.locator(".mx-report")).to_contain_text("אין מבחנים קרובים")
form = sheet.locator("[data-exam-add]")
form.locator("[name=date]").fill(day)
form.locator('[name=unit][value="t"]').check()
form.locator("[name=note]").fill("פרק 3")
form.locator("button[type=submit]").click()
playwright.expect(sheet.locator(".mx-flash")).to_contain_text("נוסף ללוח")
playwright.expect(sheet.locator(".mx-exam-t h4")).to_contain_text("מתמטיקה")
assert auth.exams == [{"subject": "מתמטיקה", "date": day, "units": ["t"], "note": "פרק 3"}]
sheet.locator("[data-exam-del]").click()
playwright.expect(sheet.locator(".mx-flash")).to_contain_text("נמחק")
assert auth.exams == []
assert not errors, errors
finally:
browser.close()
|