feat(web): éditeur de périodes modifiables dans les réglages
La page Réglages permet maintenant de créer, modifier et supprimer ses propres périodes (profils) : nom, travail, pause courte, pause longue et nombre de cycles, avec bouton radio ★ pour choisir la période active. Enregistrement via profiles_json + active_profile (index). Repli automatique sur la première période si l'active est supprimée ; noms vides/doublons ignorés. La page Aide affiche le tableau des périodes réelles de la configuration. Tests : parsing, édition, repli du profil actif et intégration HTTP.
This commit is contained in:
@@ -43,8 +43,11 @@ suite "applySettings":
|
||||
test "applies a full form":
|
||||
let base = defaultConfig()
|
||||
let form = parseForm("workMin=40&shortBreakMin=8&longBreakMin=20&" &
|
||||
"cyclesBeforeLongBreak=5&dailyGoal=6&lang=en&activeProfile=Sprint&" &
|
||||
"soundEnabled=on&doNotDisturb=on&" &
|
||||
"cyclesBeforeLongBreak=5&dailyGoal=6&lang=en&" &
|
||||
"active_profile=1&" &
|
||||
"profiles_json=" & encodeUrl(
|
||||
"""[{"name":"Focus","workMin":30,"shortBreakMin":6,"longBreakMin":18,"cycles":4},{"name":"Rapide","workMin":10,"shortBreakMin":2,"longBreakMin":5,"cycles":3}]""") &
|
||||
"&soundEnabled=on&doNotDisturb=on&" &
|
||||
"reminders_json=" & encodeUrl("""[{"text":"Boire de l'eau","enabled":true}]"""))
|
||||
let cfg = applySettings(base, form)
|
||||
check cfg.workMin == 40
|
||||
@@ -53,16 +56,43 @@ suite "applySettings":
|
||||
check cfg.cyclesBeforeLongBreak == 5
|
||||
check cfg.dailyGoal == 6
|
||||
check cfg.lang == "en"
|
||||
check cfg.activeProfile == "Sprint"
|
||||
check cfg.profiles.len == 2
|
||||
check cfg.profiles[0].name == "Focus"
|
||||
check cfg.profiles[1].workMin == 10
|
||||
check cfg.activeProfile == "Rapide"
|
||||
check cfg.soundEnabled
|
||||
check cfg.doNotDisturb
|
||||
check not cfg.autoStart
|
||||
check cfg.healthReminders.len == 1
|
||||
check cfg.healthReminders[0].text == "Boire de l'eau"
|
||||
|
||||
test "profiles are edited and active profile falls back safely":
|
||||
let base = defaultConfig()
|
||||
# Deux périodes, active = index 1.
|
||||
let f1 = parseForm("profiles_json=" & encodeUrl(
|
||||
"""[{"name":"A","workMin":25,"shortBreakMin":5,"longBreakMin":15,"cycles":4},{"name":"B","workMin":50,"shortBreakMin":10,"longBreakMin":20,"cycles":5}]""") &
|
||||
"&active_profile=1")
|
||||
let c1 = applySettings(base, f1)
|
||||
check c1.profiles.len == 2
|
||||
check c1.activeProfile == "B"
|
||||
# Index hors limites (période active supprimée) : repli sur la première.
|
||||
let f2 = parseForm("profiles_json=" & encodeUrl(
|
||||
"""[{"name":"C","workMin":20,"shortBreakMin":4,"longBreakMin":10,"cycles":3}]""") &
|
||||
"&active_profile=5")
|
||||
let c2 = applySettings(base, f2)
|
||||
check c2.profiles.len == 1
|
||||
check c2.activeProfile == "C"
|
||||
# Noms vides et doublons ignorés.
|
||||
let f3 = parseForm("profiles_json=" & encodeUrl(
|
||||
"""[{"name":"","workMin":1,"shortBreakMin":1,"longBreakMin":1,"cycles":1},{"name":"D","workMin":33,"shortBreakMin":3,"longBreakMin":9,"cycles":2},{"name":"D","workMin":99,"shortBreakMin":9,"longBreakMin":27,"cycles":9}]"""))
|
||||
let c3 = applySettings(base, f3)
|
||||
check c3.profiles.len == 1
|
||||
check c3.profiles[0].name == "D"
|
||||
check c3.profiles[0].workMin == 33
|
||||
|
||||
test "invalid values fall back to current ones":
|
||||
let base = defaultConfig()
|
||||
let form = parseForm("workMin=abc&lang=zz&activeProfile=Inexistant")
|
||||
let form = parseForm("workMin=abc&lang=zz&active_profile=99")
|
||||
let cfg = applySettings(base, form)
|
||||
check cfg.workMin == base.workMin
|
||||
check cfg.lang == "auto"
|
||||
@@ -78,6 +108,8 @@ suite "rendering":
|
||||
check "Réglages" in renderSettings(cfg)
|
||||
check "name='workMin'" in renderSettings(cfg)
|
||||
check "reminders_json" in renderSettings(cfg)
|
||||
check "profiles_json" in renderSettings(cfg)
|
||||
check "active_profile" in renderSettings(cfg)
|
||||
|
||||
suite "integration (local HTTP server)":
|
||||
test "GET routes work and settings POST persists":
|
||||
@@ -109,8 +141,10 @@ suite "integration (local HTTP server)":
|
||||
|
||||
# Sauvegarde via POST (comme le ferait le navigateur).
|
||||
let body = "workMin=33&shortBreakMin=6&longBreakMin=18&cyclesBeforeLongBreak=4&" &
|
||||
"dailyGoal=5&lang=fr&activeProfile=Classique&" &
|
||||
"reminders_json=" & encodeUrl(
|
||||
"dailyGoal=5&lang=fr&active_profile=1&" &
|
||||
"profiles_json=" & encodeUrl(
|
||||
"""[{"name":"Zen","workMin":35,"shortBreakMin":7,"longBreakMin":20,"cycles":4},{"name":"Bolt","workMin":5,"shortBreakMin":1,"longBreakMin":3,"cycles":2}]""") &
|
||||
"&reminders_json=" & encodeUrl(
|
||||
"""[{"text":"Étire-toi","enabled":true},{"text":"Bois de l'eau","enabled":false}]""")
|
||||
let resp = client.postContent(base & "/settings", body)
|
||||
check "Réglages enregistrés" in resp
|
||||
@@ -120,6 +154,10 @@ suite "integration (local HTTP server)":
|
||||
check saved.workMin == 33
|
||||
check saved.dailyGoal == 5
|
||||
check saved.lang == "fr"
|
||||
check saved.profiles.len == 2
|
||||
check saved.profiles[0].name == "Zen"
|
||||
check saved.profiles[1].workMin == 5
|
||||
check saved.activeProfile == "Bolt"
|
||||
check saved.healthReminders.len == 2
|
||||
check saved.healthReminders[1].enabled == false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user