Test unitaire superficiel de (presque) toutes les vues du tableau de bord semestre

This commit is contained in:
Emmanuel Viennet 2023-02-21 21:34:38 +01:00
parent 4c7c6e1be0
commit 7ed20a8f8c
15 changed files with 246 additions and 143 deletions

View File

@ -257,6 +257,11 @@ class FormSemestre(db.Model):
d["etapes_apo_str"] = self.etapes_apo_str()
return d
def flip_lock(self):
"""Flip etat (lock)"""
self.etat = not self.etat
db.session.add(self)
def get_parcours_apc(self) -> list[ApcParcours]:
"""Liste des parcours proposés par ce semestre.
Si aucun n'est coché et qu'il y a un référentiel, tous ceux du référentiel.

View File

@ -908,7 +908,8 @@ def formsemestre_bulletinetud(
)[0]
if format not in {"html", "pdfmail"}:
filename = scu.bul_filename(formsemestre, etud, format)
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
mime, suffix = scu.get_mime_suffix(format)
return scu.send_file(bulletin, filename, mime=mime, suffix=suffix)
elif format == "pdfmail":
return ""
H = [

View File

@ -32,12 +32,12 @@
"""
from flask import request
import app.scodoc.sco_utils as scu
from app.models import FormSemestre
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_formsemestre
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_preferences
import app.scodoc.sco_utils as scu
import sco_version
@ -57,37 +57,35 @@ def formsemestre_table_estim_cost(
peut conduire à une sur-estimation du coût s'il y a des modules optionnels
(dans ce cas, retoucher le tableau excel exporté).
"""
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sco_formsemestre_status.fill_formsemestre(sem)
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
T = []
for M in Mlist:
Mod = M["module"]
T.append(
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
rows = []
for modimpl in formsemestre.modimpls:
rows.append(
{
"code": Mod["code"] or "",
"titre": Mod["titre"],
"heures_cours": Mod["heures_cours"],
"heures_td": Mod["heures_td"] * n_group_td,
"heures_tp": Mod["heures_tp"] * n_group_tp,
"code": modimpl.module.code or "",
"titre": modimpl.module.titre,
"heures_cours": modimpl.module.heures_cours,
"heures_td": modimpl.module.heures_td * n_group_td,
"heures_tp": modimpl.module.heures_tp * n_group_tp,
}
)
# calcul des heures:
for t in T:
for t in rows:
t["HeqTD"] = (
t["heures_td"] + coef_cours * t["heures_cours"] + coef_tp * t["heures_tp"]
)
sum_cours = sum([t["heures_cours"] for t in T])
sum_td = sum([t["heures_td"] for t in T])
sum_tp = sum([t["heures_tp"] for t in T])
sum_cours = sum([t["heures_cours"] for t in rows])
sum_td = sum([t["heures_td"] for t in rows])
sum_tp = sum([t["heures_tp"] for t in rows])
sum_heqtd = sum_td + coef_cours * sum_cours + coef_tp * sum_tp
assert abs(sum([t["HeqTD"] for t in T]) - sum_heqtd) < 0.01, "%s != %s" % (
sum([t["HeqTD"] for t in T]),
assert abs(sum([t["HeqTD"] for t in rows]) - sum_heqtd) < 0.01, "%s != %s" % (
sum([t["HeqTD"] for t in rows]),
sum_heqtd,
)
T.append(
rows.append(
{
"code": "TOTAL SEMESTRE",
"heures_cours": sum_cours,
@ -117,13 +115,15 @@ def formsemestre_table_estim_cost(
"heures_tp",
"HeqTD",
),
rows=T,
rows=rows,
html_sortable=True,
preferences=sco_preferences.SemPreferences(formsemestre_id),
html_class="table_leftalign table_listegroupe",
xls_before_table=[
["%(titre)s %(num_sem)s %(modalitestr)s" % sem],
["Formation %(titre)s version %(version)s" % sem["formation"]],
[formsemestre.titre_annee()],
[
f"Formation {formsemestre.formation.titre} version {formsemestre.formation.version}"
],
[],
["", "TD", "TP"],
["Nombre de groupes", n_group_td, n_group_tp],
@ -140,10 +140,8 @@ def formsemestre_table_estim_cost(
(dans ce cas, retoucher le tableau excel exporté).
</div>
""",
origin="Généré par %s le " % sco_version.SCONAME
+ scu.timedate_human_repr()
+ "",
filename="EstimCout-S%s" % sem["semestre_id"],
origin=f"""Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}""",
filename=f"EstimCout-S{formsemestre.semestre_id}",
)
return tab

View File

@ -485,7 +485,7 @@ def formation_list_table() -> GenTable:
)
+ f""", <a class="stdlink" id="add-semestre-{
formation.acronyme.lower().replace(" ", "-")}"
href={ url_for("notes.formsemestre_createwithmodules",
href="{ url_for("notes.formsemestre_createwithmodules",
scodoc_dept=g.scodoc_dept, formation_id=formation.id, semestre_id=1
)
}">ajouter</a>

View File

@ -1659,20 +1659,6 @@ def formsemestre_edit_options(formsemestre_id):
return sco_preferences.SemPreferences(formsemestre_id).edit(categories=["bul"])
def formsemestre_change_lock(formsemestre_id) -> None:
"""Change etat (verrouille si ouvert, déverrouille si fermé)
nota: etat (1 ouvert, 0 fermé)
"""
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
if not ok:
return err
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
etat = not sem["etat"]
args = {"formsemestre_id": formsemestre_id, "etat": etat}
sco_formsemestre.do_formsemestre_edit(args)
def formsemestre_change_publication_bul(
formsemestre_id, dialog_confirmed=False, redirect=True
):

View File

@ -200,7 +200,7 @@ def formsemestre_status_menubar(formsemestre: FormSemestre) -> str:
},
{
"title": change_lock_msg,
"endpoint": "notes.formsemestre_change_lock",
"endpoint": "notes.formsemestre_flip_lock",
"args": {"formsemestre_id": formsemestre_id},
"enabled": has_perm_change_sem,
"helpmsg": "",
@ -546,59 +546,6 @@ def formsemestre_page_title(formsemestre_id=None):
)
def fill_formsemestre(sem):
"""Add some useful fields to help display formsemestres"""
sem["notes_url"] = scu.NotesURL()
formsemestre_id = sem["formsemestre_id"]
if not sem["etat"]:
sem[
"locklink"
] = f"""<a href="{url_for('notes.formsemestre_change_lock',
scodoc_dept=g.scodoc_dept,formsemestre_id=formsemestre_id )
}">{scu.icontag("lock_img", border="0", title="Semestre verrouillé")}</a>"""
else:
sem["locklink"] = ""
if sco_preferences.get_preference("bul_display_publication", formsemestre_id):
if sem["bul_hide_xml"]:
eyeicon = scu.icontag("hide_img", border="0", title="Bulletins NON publiés")
else:
eyeicon = scu.icontag("eye_img", border="0", title="Bulletins publiés")
sem[
"eyelink"
] = f"""<a href="{
url_for('notes.formsemestre_change_publication_bul',
scodoc_dept=g.scodoc_dept,formsemestre_id=formsemestre_id)
}">{eyeicon}</a>"""
else:
sem["eyelink"] = ""
sem["formation"] = Formation.query.get_or_404(sem["formation_id"]).to_dict(
with_departement=False
)
parcours = codes_cursus.get_cursus_from_code(F["type_parcours"])
if sem["semestre_id"] != -1:
sem["num_sem"] = f""", {parcours.SESSION_NAME} {sem["semestre_id"]}"""
else:
sem["num_sem"] = "" # formation sans semestres
if sem["modalite"]:
sem["modalitestr"] = f""" en {sem["modalite"]}"""
else:
sem["modalitestr"] = ""
sem["etape_apo_str"] = "Code étape Apogée: " + (
sco_formsemestre.formsemestre_etape_apo_str(sem) or "Pas de code étape"
)
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
args={"formsemestre_id": formsemestre_id}
)
sem["nbinscrits"] = len(inscrits)
uresps = [
sco_users.user_info(responsable_id) for responsable_id in sem["responsables"]
]
sem["resp"] = ", ".join([u["prenomnom"] for u in uresps])
sem["nomcomplet"] = ", ".join([u["nomcomplet"] for u in uresps])
# Description du semestre sous forme de table exportable
def formsemestre_description_table(
formsemestre_id: int, with_evals=False, with_parcours=False
@ -645,7 +592,7 @@ def formsemestre_description_table(
titles["publish_incomplete_str"] = "Toujours utilisée"
title = f"{parcours.SESSION_NAME.capitalize()} {formsemestre.titre_mois()}"
R = []
rows = []
sum_coef = 0
sum_ects = 0
last_ue_id = None
@ -671,7 +618,7 @@ def formsemestre_description_table(
if use_ue_coefs:
ue_info["Coef."] = ue.coefficient
ue_info["Coef._class"] = "ue_coef"
R.append(ue_info)
rows.append(ue_info)
mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
moduleimpl_id=modimpl.id
@ -713,14 +660,15 @@ def formsemestre_description_table(
sorted([pa.code for pa in modimpl.module.parcours])
)
R.append(l)
rows.append(l)
if with_evals:
# Ajoute lignes pour evaluations
evals = nt.get_mod_evaluation_etat_list(modimpl.id)
evals.reverse() # ordre chronologique
# Ajoute etat:
for e in evals:
for eval_dict in evals:
e = eval_dict.copy()
e["_jour_order"] = e["jour"].isoformat()
e["jour"] = e["jour"].strftime("%d/%m/%Y") if e["jour"] else ""
e["UE"] = l["UE"]
@ -749,14 +697,14 @@ def formsemestre_description_table(
e[f"_ue_{ue_id}_class"] = "poids"
e[f"_ue_{ue_id}_help"] = "poids vers l'UE"
R += evals
rows += evals
sums = {"_css_row_class": "moyenne sortbottom", "ects": sum_ects, "Coef.": sum_coef}
R.append(sums)
rows.append(sums)
return GenTable(
columns_ids=columns_ids,
rows=R,
rows=rows,
titles=titles,
origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}",
caption=title,

View File

@ -294,9 +294,8 @@ def _formsemestre_recapcomplet_to_file(
include_evaluations=include_evaluations,
filename=filename,
)
return scu.send_file(
data, filename=filename, mime=scu.get_mime_suffix(tabformat)
)
mime, suffix = scu.get_mime_suffix(tabformat)
return scu.send_file(data, filename=filename, mime=mime, suffix=suffix)
elif tabformat == "xml":
data = gen_formsemestre_recapcomplet_xml(
formsemestre.id,

View File

@ -10,6 +10,7 @@
table.dataTable {
width: 100%;
margin: 0 auto;
margin-left: 0px;
clear: both;
border-collapse: separate;
border-spacing: 0;
@ -643,10 +644,12 @@ table.dataTable.order-column.stripe.hover tbody tr.even:hover td.sorting_1 {
/* Reglage largeur de la table */
table.dataTable.gt_table {
width: auto;
margin-left: 32px;
margin-top: 8px;
padding-right: 5px;
}
/* Tables non centrées */
/* Tables non centrées (inutile) */
table.dataTable.gt_table.gt_left {
margin-left: 16px;
}

View File

@ -2069,9 +2069,11 @@ table#formation_list_table tr.gt_hl {
table.formation_list_table td.buttons {
white-space: nowrap;
}
table.formation_list_table td.buttons a {
margin-left: 8px;
}
table.formation_list_table td.buttons span.but_placeholder {
display: inline-block;
width: 15px;
@ -4036,7 +4038,8 @@ div.table_recap {
}
*/
div.table_recap table.table_recap {
div.table_recap table.table_recap,
div.evaluations_recap table.evaluations_recap {
width: auto;
margin-left: 0px;
/* font-family: Consolas, monaco, monospace; */
@ -4230,6 +4233,7 @@ table.table_recap th.col_res {
border-right: 1px dashed green;
border-left: 1px dashed green;
}
table.table_recap td.abs,
table.table_recap th.abs {
color: rgb(80, 0, 0);

View File

@ -21,7 +21,7 @@
title="{{sco.sem.responsables_str(abbrev_prenom=False)}}">{{sco.sem.responsables_str()}}</a></span>
<span class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_view', scodoc_dept=g.scodoc_dept,
formsemestre_id=sco.sem.id)}}">{{sco.sem.inscriptions|length}} inscrits</a></span><span class="lock">{% if
not sco.sem.etat %}<a href="{{url_for('notes.formsemestre_change_lock', scodoc_dept=g.scodoc_dept,
not sco.sem.etat %}<a href="{{url_for('notes.formsemestre_flip_lock', scodoc_dept=g.scodoc_dept,
formsemestre_id=sco.sem.id)}}">{{sco.scu.icontag("lock_img", border="0", title="Semestre
verrouillé")|safe}}</a>{% endif %}</span><span class="eye">
{% if sco.prefs["bul_display_publication"] %}

View File

@ -21,7 +21,7 @@
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)
}}">{{formsemestre.etuds_inscriptions|length}} inscrits</a></span><span class="lock">
{%-if not formsemestre.etat -%}
<a href="{{ url_for( 'notes.formsemestre_change_lock',
<a href="{{ url_for( 'notes.formsemestre_flip_lock',
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id )}}">{{
scu.icontag("lock_img", border="0", title="Semestre verrouillé")|safe
}}</a>

View File

@ -820,20 +820,22 @@ sco_publish(
)
@bp.route("/formsemestre_change_lock", methods=["GET", "POST"])
@bp.route("/formsemestre_flip_lock", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView) # acces vérifié dans la fonction
@permission_required(Permission.ScoView) # acces vérifié dans la vue
@scodoc7func
def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False):
def formsemestre_flip_lock(formsemestre_id, dialog_confirmed=False):
"Changement de l'état de verrouillage du semestre"
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
dest_url = url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre.id,
)
if not formsemestre.est_chef_or_diretud():
raise ScoPermissionDenied("opération non autorisée", dest_url=dest_url)
if not dialog_confirmed:
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
etat = not sem["etat"]
if etat:
msg = "déverrouillage"
else:
msg = "verrouillage"
msg = "verrouillage" if formsemestre.etat else "déverrouillage"
return scu.confirm_dialog(
f"<h2>Confirmer le {msg} du semestre ?</h2>",
helpmsg="""Les notes d'un semestre verrouillé ne peuvent plus être modifiées.
@ -843,23 +845,14 @@ def formsemestre_change_lock(formsemestre_id, dialog_confirmed=False):
Le programme d'une formation qui a un semestre verrouillé ne peut plus être modifié.
""",
dest_url="",
cancel_url=url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
),
cancel_url=dest_url,
parameters={"formsemestre_id": formsemestre_id},
)
sco_formsemestre_edit.formsemestre_change_lock(formsemestre_id)
formsemestre.flip_lock()
db.session.commit()
return flask.redirect(
url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
)
return flask.redirect(dest_url)
sco_publish(

View File

@ -1 +1,17 @@
# Unit tests
# ScoDoc Unit Tests
"""Set of unit tests for ScoDoc
"""
def call_view(view_function, *args, **kwargs):
"""Undecorate a view and call it directly."""
# On a 3 décorateurs: @scodoc, @permission_required, @scodoc7func
func = (
view_function.__closure__[0]
.cell_contents.__closure__[0]
.cell_contents.__closure__[0]
.cell_contents
)
assert func
return func(*args, **kwargs)

View File

@ -42,7 +42,7 @@ def test_but_jury_GB(test_client):
app.set_sco_dept(DEPT)
# Construit la base de test GB une seule fois
# puis lance les tests de jury
doc = yaml_setup.setup_from_yaml("tests/unit/cursus_but_gb.yaml")
doc = yaml_setup.setup_from_yaml("tests/ressources/yaml/cursus_but_gb.yaml")
# Vérifie les deca de tous les semestres:
for formsemestre in FormSemestre.query:
@ -69,7 +69,7 @@ def test_but_jury_GMP_lm(test_client):
app.set_sco_dept(DEPT)
# Construit la base de test GB une seule fois
# puis lance les tests de jury
doc = yaml_setup.setup_from_yaml("tests/unit/cursus_but_gmp_iutlm.yaml")
doc = yaml_setup.setup_from_yaml("tests/ressources/yaml/cursus_but_gmp_iutlm.yaml")
formsemestres = FormSemestre.query.order_by(
FormSemestre.date_debut, FormSemestre.semestre_id
@ -95,7 +95,7 @@ def test_but_jury_GEII_lyon(test_client):
app.set_sco_dept(DEPT)
# Construit la base de test GB une seule fois
# puis lance les tests de jury
doc = yaml_setup.setup_from_yaml("tests/unit/cursus_but_geii_lyon.yaml")
doc = yaml_setup.setup_from_yaml("tests/ressources/yaml/cursus_but_geii_lyon.yaml")
formsemestres = FormSemestre.query.order_by(
FormSemestre.date_debut, FormSemestre.semestre_id
).all()

View File

@ -3,12 +3,37 @@
""" Test création/accès/clonage formsemestre
"""
from flask import Response
import pytest
from tests.unit import yaml_setup
from tests.unit import yaml_setup, call_view
import app
from app.models import Formation
from app.scodoc import sco_formsemestre_edit
from app import db
from app.models import Formation, FormSemestre
from app.scodoc import (
sco_archives,
sco_cost_formation,
sco_debouche,
sco_edit_ue,
sco_evaluations,
sco_evaluation_check_abs,
sco_evaluation_recap,
sco_formsemestre_edit,
sco_formsemestre_inscriptions,
sco_formsemestre_status,
sco_groups,
sco_inscr_passage,
sco_lycee,
sco_moduleimpl_inscriptions,
sco_poursuite_dut,
sco_preferences,
sco_recapcomplet,
sco_report,
sco_undo_notes,
)
from app.scodoc import sco_utils as scu
from app.views import notes, scolar
from config import TestConfig
DEPT = TestConfig.DEPT_TEST
@ -34,3 +59,128 @@ def test_formsemestres_associate_new_version(test_client):
assert new_formation
assert formsemestres[0].formation_id == new_formation.id
assert formsemestres[1].formation_id == new_formation.id
def test_formsemestre_misc_views(test_client):
"""Test de nombreuses vues: test juste que la page ne plante,
pas de vérif du contenu ni de soumission si c'est un formulaire.
Note: les anciennes vues renvoient souvent des str au lieu de Response.
"""
app.set_sco_dept(DEPT)
yaml_setup.setup_from_yaml("tests/ressources/yaml/simple_formsemestres.yaml")
formsemestre: FormSemestre = FormSemestre.query.first()
# ----- MENU SEMESTRE
_ = sco_formsemestre_status.formsemestre_status(formsemestre_id=formsemestre.id)
_ = sco_edit_ue.ue_table(formsemestre.formation_id)
_ = sco_formsemestre_edit.formsemestre_editwithmodules(formsemestre.id)
_ = sco_preferences.SemPreferences(formsemestre_id=formsemestre.id).edit()
_ = sco_formsemestre_edit.formsemestre_edit_options(formsemestre.id)
assert formsemestre.etat
formsemestre.flip_lock()
assert not formsemestre.etat
formsemestre.flip_lock()
assert formsemestre.etat
ans = sco_formsemestre_status.formsemestre_description(
formsemestre.id, with_evals=True
)
assert isinstance(ans, (str, Response)) # ici c'est une str
ans = sco_formsemestre_status.formsemestre_description(
formsemestre.id, with_evals=True, format="xls"
)
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.XLSX_MIMETYPE
ans = sco_formsemestre_status.formsemestre_description(
formsemestre.id, with_evals=True, format="pdf"
)
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.PDF_MIMETYPE
ans = sco_evaluation_check_abs.formsemestre_check_absences_html(formsemestre.id)
assert isinstance(ans, (str, Response))
# Appel direct de la vue: enlève les décorateurs:
ans = call_view(notes.formsemestre_enseignants_list, formsemestre.id)
assert isinstance(ans, (str, Response)) # ici str
# Juste la page dialogue avant opération::
ans = sco_formsemestre_edit.formsemestre_clone(formsemestre.id)
ans = sco_formsemestre_edit.formsemestre_associate_new_version(formsemestre.id)
ans = sco_formsemestre_edit.formsemestre_delete(formsemestre.id)
# ----- MENU INSCRIPTIONS
ans = sco_moduleimpl_inscriptions.moduleimpl_inscriptions_stats(formsemestre.id)
ans = sco_inscr_passage.formsemestre_inscr_passage(formsemestre.id)
ans = call_view(scolar.form_students_import_excel, formsemestre.id)
assert isinstance(ans, str)
ans = call_view(scolar.form_students_import_infos_admissions, formsemestre.id)
ans = sco_formsemestre_inscriptions.formsemestre_inscrits_ailleurs(formsemestre.id)
# ----- MENU GROUPES
ans = call_view(scolar.groups_view, formsemestre.id)
ans = call_view(scolar.partition_editor, formsemestre.id)
ans = sco_groups.edit_partition_form(formsemestre.id)
# ----- MENU NOTES
ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id)
ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="evals")
ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="xlsx")
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.XLSX_MIMETYPE
ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, tabformat="json")
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.JSON_MIMETYPE
ans = sco_evaluation_recap.evaluations_recap(formsemestre.id)
# Bulletins pdf:
ans = call_view(notes.formsemestre_bulletins_pdf_choice, formsemestre.id)
assert isinstance(ans, str) # sans version, on a le formulaire de choix, une str
ans = call_view(
notes.formsemestre_bulletins_pdf_choice, formsemestre.id, version="long"
)
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.PDF_MIMETYPE
# on ne teste pas les mails :)
ans = sco_evaluations.formsemestre_evaluations_cal(formsemestre.id)
assert isinstance(ans, str)
sco_undo_notes.formsemestre_list_saisies_notes(formsemestre.id)
# ----- MENU JURY
ans = sco_recapcomplet.formsemestre_recapcomplet(formsemestre.id, mode_jury=True)
ans = sco_recapcomplet.formsemestre_recapcomplet(
formsemestre.id, mode_jury=True, tabformat="xlsx"
)
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.XLSX_MIMETYPE
ans = sco_recapcomplet.formsemestre_recapcomplet(
formsemestre.id, mode_jury=True, tabformat="json"
)
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.JSON_MIMETYPE
ans = sco_archives.formsemestre_archive(formsemestre.id)
ans = sco_archives.formsemestre_list_archives(formsemestre.id)
# ----- MENU STATISTIQUES
ans = sco_report.formsemestre_report_counts(formsemestre.id)
ans = sco_report.formsemestre_report_counts(formsemestre.id, format="xls")
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.XLSX_MIMETYPE
ans = sco_report.formsemestre_suivi_cohorte(formsemestre.id)
ans = sco_report.formsemestre_suivi_cohorte(formsemestre.id, format="pdf")
assert isinstance(ans, Response)
assert ans.status == "200 OK"
assert ans.mimetype == scu.PDF_MIMETYPE
ans = sco_report.formsemestre_graph_cursus(formsemestre.id)
ans = sco_report.formsemestre_suivi_cursus(formsemestre.id)
ans = sco_lycee.formsemestre_etuds_lycees(formsemestre.id)
ans = sco_poursuite_dut.formsemestre_poursuite_report(formsemestre.id)
# pas de test des avis de poursuite
ans = sco_debouche.report_debouche_date(start_year=2000)
ans = sco_cost_formation.formsemestre_estim_cost(formsemestre.id)
# pas de test des indicateurs de suivi BUT