feat: synchronize CH1 vehicle control and feedback
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
|
||||
SOURCE_PATH = REPOSITORY_ROOT / "apps" / "web-console" / "self-extension.js"
|
||||
|
||||
|
||||
class SelfExtensionFrontendDelayContractTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.source = SOURCE_PATH.read_text(encoding="utf-8")
|
||||
hydrate_start = cls.source.index(" function hydratePlan(steps) {")
|
||||
hydrate_end = cls.source.index("\n function setExecutionState", hydrate_start)
|
||||
cls.hydrate_source = cls.source[hydrate_start:hydrate_end]
|
||||
execute_start = cls.source.index(" async function executePlan(plan) {")
|
||||
execute_end = cls.source.index("\n function addHistory", execute_start)
|
||||
cls.execute_source = cls.source[execute_start:execute_end]
|
||||
|
||||
def test_hydration_recognizes_and_strictly_validates_delay_steps(self) -> None:
|
||||
self.assertIn('if (step.kind === "delay")', self.hydrate_source)
|
||||
self.assertIn("Number.isInteger(step.delay_ms)", self.hydrate_source)
|
||||
self.assertIn("step.delay_ms < MIN_PLAN_DELAY_MS", self.hydrate_source)
|
||||
self.assertIn("step.delay_ms > MAX_PLAN_DELAY_MS", self.hydrate_source)
|
||||
self.assertIn("totalDelayMs > MAX_TOTAL_PLAN_DELAY_MS", self.hydrate_source)
|
||||
self.assertIn("index === 0 || index === plan.length - 1", self.hydrate_source)
|
||||
self.assertIn('plan[index - 1].kind === "delay"', self.hydrate_source)
|
||||
self.assertIn("step.delay_ms !== undefined && step.delay_ms !== 0", self.hydrate_source)
|
||||
self.assertNotIn(".filter(Boolean)", self.hydrate_source)
|
||||
|
||||
def test_hydration_displays_a_canonical_five_second_label(self) -> None:
|
||||
self.assertIn("`等待 ${step.delay_ms / 1000} 秒`", self.hydrate_source)
|
||||
self.assertIn("delayMs: step.delay_ms", self.hydrate_source)
|
||||
|
||||
def test_execution_routes_delay_only_to_the_timer(self) -> None:
|
||||
delay_branch = self.execute_source.index('if (step.kind === "delay")')
|
||||
vehicle_branch = self.execute_source.index('else if (step.kind === "vehicle")')
|
||||
peripheral_branch = self.execute_source.index('await sendGatewayCommand("emit"')
|
||||
self.assertLess(delay_branch, vehicle_branch)
|
||||
self.assertLess(vehicle_branch, peripheral_branch)
|
||||
between_delay_and_vehicle = self.execute_source[delay_branch:vehicle_branch]
|
||||
self.assertIn("await delay(step.delayMs);", between_delay_and_vehicle)
|
||||
self.assertNotIn("executeVehicle", between_delay_and_vehicle)
|
||||
self.assertNotIn("sendGatewayCommand", between_delay_and_vehicle)
|
||||
|
||||
def test_explicit_delay_does_not_stack_with_default_action_spacing(self) -> None:
|
||||
self.assertIn("const nextStep = plan[index + 1];", self.execute_source)
|
||||
self.assertIn(
|
||||
'nextStep && step.kind !== "delay" && nextStep.kind !== "delay"',
|
||||
self.execute_source,
|
||||
)
|
||||
self.assertIn("await delay(state.settings.actionDelayMs);", self.execute_source)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user