96 lines
4.7 KiB
Python
96 lines
4.7 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
FRONTEND = Path(__file__).resolve().parents[2] / "apps/web/vue3/index.html"
|
|
|
|
|
|
def _frontend_text() -> str:
|
|
return FRONTEND.read_text(encoding="utf-8")
|
|
|
|
|
|
def test_gwas_dialog_uses_species_prefix_copy_and_batch_binding() -> None:
|
|
frontend = _frontend_text()
|
|
|
|
assert "物种简称(用于结果前缀)" in frontend
|
|
assert 'placeholder="At / Os / Zm"' in frontend
|
|
assert 'v-model="batchExecuteParams.prefix"' in frontend
|
|
assert 'v-if="!isBatchExecuting && batchIncludesGwasStages()"' in frontend
|
|
|
|
|
|
def test_gwas_template_helpers_are_exposed_from_vue_setup() -> None:
|
|
frontend = _frontend_text()
|
|
setup_return_start = frontend.rindex(" return {")
|
|
setup_return_end = frontend.index(" };\n }\n });", setup_return_start)
|
|
setup_return = frontend[setup_return_start:setup_return_end]
|
|
|
|
assert " isGwasStage," in setup_return
|
|
assert " batchIncludesGwasStages," in setup_return
|
|
|
|
|
|
def test_gwas_prefix_helpers_require_and_lock_one_batch_value(tmp_path: Path) -> None:
|
|
frontend = _frontend_text()
|
|
start = frontend.index("const gwasStageIds =")
|
|
end = frontend.index("const uniqueSpeciesList =", start)
|
|
helper_source = frontend[start:end]
|
|
node_script = tmp_path / "gwas-prefix-contract.cjs"
|
|
node_script.write_text(
|
|
"const batchExecuteParams={value:{prefix:'Os',params:{prefix:'Os'},plan:{params:{prefix:'Os'}}}};"
|
|
"const batchExecuteStages={value:["
|
|
"{id:'gwas_fmt',params:{prefix:'Os'}},"
|
|
"{id:'gwas_trait',params:{}},"
|
|
"{id:'rnaseq_qc',params:{prefix:'RNA'}}]};"
|
|
"const confirmParams={prefix:'Os'};"
|
|
"const getStageId=(stage)=>typeof stage==='object'?stage.id:stage;"
|
|
"const prefixlessStages=new Set(); const isGeneFamilyScopeStage=()=>false;"
|
|
"const geneFamilyAutoPrefix=()=>''; const params={prefix:''};"
|
|
"const normalizedPrefix=(value)=>String(value||'').trim()||'At';"
|
|
+ helper_source
|
|
+ "const blankMissing=gwasPrefixMissingFor({stage:'gwas_fmt',prefix:' '});"
|
|
+ "const locked=lockGwasBatchPrefix(' cohort ');"
|
|
+ "const lockedBatch=JSON.parse(JSON.stringify(batchExecuteParams.value));"
|
|
+ "const lockedStages=JSON.parse(JSON.stringify(batchExecuteStages.value));"
|
|
+ "const lockedConfirm=confirmParams.prefix;"
|
|
+ "batchExecuteParams.value={}; confirmParams.prefix='';"
|
|
+ "const blankExecutionPrefix=executionPrefix('gwas_fmt',{});"
|
|
+ "process.stdout.write(JSON.stringify({blankMissing,locked,blankExecutionPrefix,batch:lockedBatch,stages:lockedStages,confirm:lockedConfirm}));",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
completed = subprocess.run(["node", str(node_script)], text=True, capture_output=True, check=False)
|
|
|
|
assert completed.returncode == 0, completed.stderr
|
|
payload = json.loads(completed.stdout)
|
|
assert payload["blankMissing"] is True
|
|
assert payload["locked"] == "cohort"
|
|
assert payload["blankExecutionPrefix"] == ""
|
|
assert payload["batch"]["prefix"] == "cohort"
|
|
assert payload["batch"]["params"]["prefix"] == "cohort"
|
|
assert payload["batch"]["plan"]["params"]["prefix"] == "cohort"
|
|
assert payload["stages"][0]["params"]["prefix"] == "cohort"
|
|
assert payload["stages"][1]["params"]["prefix"] == "cohort"
|
|
assert payload["stages"][2]["params"]["prefix"] == "RNA"
|
|
assert payload["confirm"] == "cohort"
|
|
|
|
|
|
def test_gwas_submission_validates_before_closing_dialog_and_disables_auto_start() -> None:
|
|
frontend = _frontend_text()
|
|
batch_start = frontend.index("const startBatchExecute = async () =>")
|
|
batch_end = frontend.index("const executeStagesWithDependencies =", batch_start)
|
|
batch_source = frontend[batch_start:batch_end]
|
|
direct_start = frontend.index("const doExecute = async () =>")
|
|
direct_end = frontend.index("const queueAutofillFromPayload = async", direct_start)
|
|
direct_source = frontend[direct_start:direct_end]
|
|
batch_timer_start = frontend.index("const startBatchExecuteTimer = () =>")
|
|
batch_timer_end = frontend.index("const clearBatchExecuteTimer =", batch_timer_start)
|
|
batch_timer_source = frontend[batch_timer_start:batch_timer_end]
|
|
|
|
assert batch_source.index("gwasPrefixMissingFor") < batch_source.index("batchExecuteDialogVisible.value = false")
|
|
assert batch_source.index("lockGwasBatchPrefix") < batch_source.index("batchExecuteDialogVisible.value = false")
|
|
assert direct_source.index("gwasPrefixMissingFor") < direct_source.index("confirmDialogVisible.value = false")
|
|
assert "batchIncludesGwasStages()" in batch_timer_source
|
|
assert "batchExecuteCountdown.value = 0" in batch_timer_source
|