feat: coach first mobile task to completion (Closes #1146)
This commit is contained in:
1 parent
941a508d4b
commit
e2b5f6042c
7 files changed
+109
-32
No files matched your search
@@ -64,6 +64,27 @@ def test_release_artifact_guides_an_empty_mobile_account_to_first_work(
|
||||
expect(page.locator("#mobile-first-task-status")).to_contain_text("Create a task now")
|
||||
expect(page.locator("#mobile-first-task-create")).to_be_enabled()
|
||||
expect(page.locator("#mobile-first-task-create")).to_be_focused()
|
||||
|
||||
page.locator("#close-mobile-first-task").click()
|
||||
context.set_offline(False)
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
document.querySelector('[data-mobile-today-hud]').hidden = false;
|
||||
localStorage.setItem('stackchain.first-task.v1:timmy', 'coaching');
|
||||
window.firstTaskOutcomeProbe = createMobileFirstTask({
|
||||
getLogin: () => 'timmy', hasWork: () => true, isTodayActive: () => true,
|
||||
});
|
||||
return window.firstTaskOutcomeProbe.refresh();
|
||||
}"""
|
||||
)
|
||||
coach = page.locator("[data-mobile-first-task-coach]")
|
||||
expect(coach).to_be_visible()
|
||||
expect(coach).to_contain_text("Complete your first task")
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
assert page.evaluate("window.firstTaskOutcomeProbe.completeOutcome()") is True
|
||||
expect(page.locator("#mobile-first-task-receipt")).to_be_visible()
|
||||
expect(coach).to_be_hidden()
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
browser.close()
|
||||
finally:
|
||||
fake.shutdown()
|
||||
|
||||
@@ -28,31 +28,39 @@ class Element {{
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_first_task_activation_is_account_bound_and_completes_only_when_today_is_active():
|
||||
def test_first_task_activation_is_account_bound_and_completes_only_after_a_today_outcome():
|
||||
result = run_node(
|
||||
"""
|
||||
const values = new Map();
|
||||
const storage = {getItem:key => values.get(key) || null, setItem:(key,value) => values.set(key,value)};
|
||||
const sheet = new Element();
|
||||
const coach = new Element(); coach.hidden = true;
|
||||
const receipt = new Element(); receipt.hidden = true;
|
||||
let login = 'Timmy';
|
||||
let hasWork = false;
|
||||
let todayActive = false;
|
||||
let hideReceipt;
|
||||
const controller = createFirstTask({
|
||||
storage, getLogin:() => login, hasWork:() => hasWork, isTodayActive:() => todayActive,
|
||||
isOnline:() => true, mediaQuery:{matches:true}, sheet, title:new Element(),
|
||||
isOnline:() => true, mediaQuery:{matches:true}, sheet, title:new Element(), coach, receipt,
|
||||
findButton:new Element(), createButton:new Element(), setupButton:new Element(),
|
||||
closeButton:new Element(), status:new Element(), onFind() {}, onCreate() {}, onSetup() {},
|
||||
setTimer:callback => { hideReceipt = callback; return {unref() {}}; },
|
||||
});
|
||||
const before = [controller.required(), controller.open(), sheet.open];
|
||||
hasWork = true;
|
||||
const awaitingStart = controller.refresh();
|
||||
const stillRequired = controller.required();
|
||||
todayActive = true;
|
||||
const completed = controller.refresh();
|
||||
const timmyRequired = controller.required();
|
||||
const coaching = controller.refresh();
|
||||
const afterStart = {required:controller.required(), sheetOpen:sheet.open, coachHidden:coach.hidden, stored:values.get('stackchain.first-task.v1:timmy')};
|
||||
const completed = controller.completeOutcome();
|
||||
const afterOutcome = {required:controller.required(), coachHidden:coach.hidden, receiptHidden:receipt.hidden, stored:values.get('stackchain.first-task.v1:timmy')};
|
||||
hideReceipt();
|
||||
const receiptHiddenAfterTimeout = receipt.hidden;
|
||||
login = 'alexander'; hasWork = false; todayActive = false;
|
||||
const alexanderRequired = controller.required();
|
||||
process.stdout.write(JSON.stringify({before, awaitingStart, stillRequired, completed, sheetOpen:sheet.open, timmyRequired, alexanderRequired, values:[...values]}));
|
||||
process.stdout.write(JSON.stringify({before, awaitingStart, stillRequired, coaching, afterStart, completed, afterOutcome, receiptHiddenAfterTimeout, alexanderRequired}));
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -60,11 +68,22 @@ process.stdout.write(JSON.stringify({before, awaitingStart, stillRequired, compl
|
||||
"before": [True, True, True],
|
||||
"awaitingStart": "awaiting-start",
|
||||
"stillRequired": True,
|
||||
"completed": "completed",
|
||||
"sheetOpen": False,
|
||||
"timmyRequired": False,
|
||||
"coaching": "coaching",
|
||||
"afterStart": {
|
||||
"required": False,
|
||||
"sheetOpen": False,
|
||||
"coachHidden": False,
|
||||
"stored": "coaching",
|
||||
},
|
||||
"completed": True,
|
||||
"afterOutcome": {
|
||||
"required": False,
|
||||
"coachHidden": True,
|
||||
"receiptHidden": False,
|
||||
"stored": "complete",
|
||||
},
|
||||
"receiptHiddenAfterTimeout": True,
|
||||
"alexanderRequired": True,
|
||||
"values": [["stackchain.first-task.v1:timmy", "complete"]],
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +177,10 @@ async def test_dashboard_renders_and_wires_phone_safe_first_task_activation():
|
||||
assert "shouldActivate: () => mobileFirstTask.required()" in html
|
||||
assert "openActivation: () => mobileFirstTask.open()" in html
|
||||
assert "mobileFirstTask.refresh()" in html
|
||||
assert 'data-mobile-first-task-coach hidden' in html
|
||||
assert 'Complete your first task' in html
|
||||
assert 'id="mobile-first-task-receipt" role="status" aria-live="polite" hidden' in html
|
||||
assert "advance: () => (mobileFirstTask.completeOutcome(), runTodayTransition('complete'))" in html
|
||||
assert '.mobile-first-task { box-sizing:border-box; width:100%;' in html
|
||||
assert 'padding-bottom:calc(16px + env(safe-area-inset-bottom))' in html
|
||||
assert '.mobile-first-task-actions button { min-height:48px;' in html
|
||||
@@ -3829,7 +3829,7 @@ async def test_checkpointed_detail_defer_completes_today_and_advertises_next_ite
|
||||
|
||||
assert "continueSession: item => completeTodayItem(item, {" in html
|
||||
assert "successMessage: 'Deferred to Later. Next Today item opened.'" in html
|
||||
assert "advance: () => runTodayTransition('complete')" in html
|
||||
assert "advance: () => (mobileFirstTask.completeOutcome(), runTodayTransition('complete'))" in html
|
||||
assert "button.textContent = active ? 'Later today & next' : 'Later today'" in html
|
||||
assert "button.textContent = active ? 'Tomorrow & next' : 'Tomorrow'" in html
|
||||
assert "button.textContent = active ? 'Choose date & time & next' : 'Choose date & time'" in html
|
||||
|
||||
Reference in new issue
Block a user