Skip to content

Commit 690cd69

Browse files
authored
ux: Better assignment tests UX (#384)
1 parent 42d48f5 commit 690cd69

File tree

6 files changed

+158
-83
lines changed

6 files changed

+158
-83
lines changed

lms/lmstests/public/unittests/services.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@ def _handle_failed_to_execute_tests(self, raw_results: bytes) -> None:
154154
def _handle_result(
155155
self, case_name: str, result: junitparser.Element,
156156
) -> None:
157-
message = ' '.join(
158-
elem[1].replace('\n', '')
159-
for elem in result._elem.items()
157+
# Extract only the Assertion Message
158+
message = '\n'.join(
159+
msg_.partition("\n")[0].removeprefix("AssertionError: ")
160+
for _type, msg_ in result._elem.items()
160161
)
161162
self._logger.info(
162163
'Create comment on test %s solution %s.',

lms/lmsweb/translations/he/LC_MESSAGES/messages.po

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: 1.0\n"
99
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
10-
"POT-Creation-Date: 2024-03-29 05:54+0300\n"
10+
"POT-Creation-Date: 2024-03-29 21:14+0300\n"
1111
"PO-Revision-Date: 2024-03-23 18:59+0300\n"
1212
"Last-Translator: Yam Mesicka\n"
1313
"Language: he\n"
@@ -48,31 +48,31 @@ msgstr "הבודק האוטומטי נכשל ב־%(number)d דוגמאות בת
4848
msgid "Woah! Did you check your code?"
4949
msgstr "ווהו! בדקת את הקוד שלך?"
5050

51-
#: lms/lmsweb/views.py:183
51+
#: lms/lmsweb/views.py:181
5252
msgid "Can not register now"
5353
msgstr "לא ניתן להירשם כעת"
5454

55-
#: lms/lmsweb/views.py:205
55+
#: lms/lmsweb/views.py:203
5656
msgid "Registration successfully"
5757
msgstr "ההרשמה בוצעה בהצלחה"
5858

59-
#: lms/lmsweb/views.py:233
59+
#: lms/lmsweb/views.py:231
6060
msgid "The confirmation link is expired, new link has been sent to your email"
6161
msgstr "קישור האימות פג תוקף, קישור חדש נשלח אל תיבת המייל שלך"
6262

63-
#: lms/lmsweb/views.py:252
63+
#: lms/lmsweb/views.py:250
6464
msgid "Your user has been successfully confirmed, you can now login"
6565
msgstr "המשתמש שלך אומת בהצלחה, כעת אתה יכול להתחבר למערכת"
6666

67-
#: lms/lmsweb/views.py:277 lms/lmsweb/views.py:345
67+
#: lms/lmsweb/views.py:275 lms/lmsweb/views.py:343
6868
msgid "Your password has successfully changed"
6969
msgstr "הסיסמה שלך שונתה בהצלחה"
7070

71-
#: lms/lmsweb/views.py:295
71+
#: lms/lmsweb/views.py:293
7272
msgid "Password reset link has successfully sent"
7373
msgstr "קישור לאיפוס הסיסמה נשלח בהצלחה"
7474

75-
#: lms/lmsweb/views.py:321
75+
#: lms/lmsweb/views.py:319
7676
msgid "Reset password link is expired"
7777
msgstr "הקישור לאיפוס הסיסמה פג תוקף"
7878

@@ -413,7 +413,7 @@ msgid "Checker"
413413
msgstr "בודק"
414414

415415
#: lms/templates/user.html:37 lms/templates/view.html:25
416-
#: lms/templates/view.html:114
416+
#: lms/templates/view.html:118
417417
msgid "Assessment"
418418
msgstr "הערכה מילולית"
419419

@@ -485,23 +485,23 @@ msgstr "סיסמה נוכחית"
485485
msgid "Finish Checking"
486486
msgstr "סיום בדיקה"
487487

488-
#: lms/templates/view.html:86
488+
#: lms/templates/view.html:88
489489
msgid "Automatic Checking"
490490
msgstr "בדיקות אוטומטיות"
491491

492492
#: lms/templates/view.html:93
493-
msgid "Error"
494-
msgstr "כישלון"
493+
msgid "Test failed"
494+
msgstr "בדיקה נכשלה"
495495

496-
#: lms/templates/view.html:98
497-
msgid "Staff Error"
498-
msgstr "כישלון סגל"
496+
#: lms/templates/view.html:101
497+
msgid "Staff traceback"
498+
msgstr "Traceback לצוות"
499499

500-
#: lms/templates/view.html:130
500+
#: lms/templates/view.html:134
501501
msgid "Comments for this exercise"
502502
msgstr "הערות על התרגיל"
503503

504-
#: lms/templates/view.html:138
504+
#: lms/templates/view.html:142
505505
msgid "Done Checking"
506506
msgstr "סיים לבדוק"
507507

lms/lmsweb/views.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import arrow # type: ignore
55
from flask import (
6-
# Response,
76
jsonify,
87
make_response,
98
render_template,
@@ -40,7 +39,6 @@
4039
)
4140
from lms.lmsweb import (
4241
babel,
43-
# http_basic_auth,
4442
limiter,
4543
routes,
4644
webapp,

lms/static/my.css

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -467,17 +467,24 @@ button.our-button-narrow, a.our-button-narrow {
467467
border-bottom-left-radius: 0.25rem;
468468
}
469469

470-
.code-view-container {
470+
.code-review-container {
471471
position: relative;
472-
direction: ltr;
473-
text-align: left;
474472
height: min-content;
475473
display: flex;
476-
overflow-x: hidden;
477-
flex-flow: column wrap;
474+
flex-direction: column;
478475
flex-basis: 70vw;
479476
flex-grow: 4;
477+
}
478+
479+
.code-view-container {
480480
border: 1px solid #e1e4e8;
481+
direction: ltr;
482+
display: flex;
483+
flex-flow: column wrap;
484+
margin-block-end: 2rem;
485+
overflow-x: hidden;
486+
text-align: left;
487+
width: 100%;
481488
}
482489

483490
#code-view {
@@ -612,36 +619,98 @@ pre {
612619
}
613620

614621
.test-results {
615-
direction: rtl;
616-
text-align: right;
622+
font-family: Arial, sans-serif;
623+
display: flex;
624+
width: 100%;
625+
flex-direction: column;
626+
margin: auto;
627+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
617628
}
618629

619-
.test-result-title {
630+
.test-results-header {
631+
background-color: #F9FAFB;
620632
text-align: center;
621-
text-decoration: underline;
622-
margin-top: 20px;
633+
color: #333;
634+
padding: 0.5rem 0;
635+
border-radius: 6px 6px 0 0;
636+
font-size: 1.1rem;
623637
}
624638

625639
.test-results-list {
640+
list-style: none;
626641
padding: 0;
642+
margin: 0;
627643
}
628644

629645
.test-result {
630-
padding: 10px;
631-
margin: 5px 0;
646+
background-color: #FFFFFF;
647+
border-radius: 6px;
648+
border: 1px solid #E2E8F0;
632649
display: flex;
633650
flex-direction: column;
634-
border: 1px solid #c2bdbd;
651+
padding: 1.5rem;
652+
transition: box-shadow 0.2s ease;
653+
width: 100%;
635654
}
636655

637-
.test-result .test-name {
638-
border-bottom: 1px solid #c2bdbd;
639-
margin-bottom: 12px;
640-
padding-bottom: 6px;
656+
.test-header {
657+
display: flex;
658+
justify-content: space-between;
659+
align-items: center;
660+
}
661+
662+
.test-name {
663+
font-weight: 600;
664+
color: #1A202C;
665+
}
666+
667+
.test-status.failure {
668+
background-color: #F56565;
669+
border-radius: 12px;
670+
color: #FFFFFF;
671+
font-size: 0.85rem;
672+
padding: 0.25rem 0.5rem;
641673
}
642674

643-
.test-result .title {
675+
.error-description {
676+
background-color: #F7FAFC;
677+
border-radius: 4px;
678+
color: #2D3748;
679+
display: flex;
680+
line-height: 1.5;
681+
margin: 0.5rem 0;
682+
padding: 0.75rem;
683+
}
684+
685+
.staff-failure .title {
644686
font-weight: bold;
687+
display: flex;
688+
margin-bottom: 5px;
689+
}
690+
691+
.stack-trace pre {
692+
background-color: #EDF2F7;
693+
color: #2D3748;
694+
padding: 0.75rem;
695+
border-radius: 4px;
696+
overflow-x: auto;
697+
}
698+
699+
.stack-trace code {
700+
width: 100%;
701+
background-color: #F8F9FA;
702+
color: #333;
703+
padding: 10px;
704+
border-radius: 4px;
705+
display: flex;
706+
flex-direction: column;
707+
white-space: pre;
708+
}
709+
710+
@media (max-width: 768px) {
711+
.test-result {
712+
padding: 1rem; /* less padding on smaller screens */
713+
}
645714
}
646715

647716
.stack-trace {
@@ -809,7 +878,7 @@ code > code:last-of-type{
809878
*/
810879
pre[class*="language-"] {
811880
/* Override prism.js */
812-
padding: 0 !important;
881+
padding: 0.5rem !important;
813882
margin: 0 !important;
814883
}
815884

@@ -829,6 +898,10 @@ code#user-code {
829898
justify-content: start;
830899
cursor: pointer;
831900
width: 100%;
901+
/* Nice trick: with flex-grow: 1; and width: 0;
902+
* the line fits the container width
903+
* */
904+
width: 0;
832905
flex-grow: 1;
833906
}
834907

lms/templates/view.html

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,58 +50,62 @@ <h1>{{ _('Exercise view') }} {{ solution['exercise']['number'] }}: {{ solution['
5050
{%- endif %}
5151
</div>
5252
<div id="view-body">
53-
<div class="code-view-container">
54-
<div id="code-toolbar">
55-
<div id="number-of-lines">{{ current_file.code.splitlines() | length }} lines</div>
56-
<div id="code-toolbar-buttons">
57-
{% if config.SHAREABLE_SOLUTIONS and not shared_url %}
58-
<div id="share-solution" class="code-toolbar-button glowing">
59-
<div id="shared-text">
60-
<button id="share-action" title="Share solution"><i class="fa fa-share-alt"></i></button>
53+
<div class="code-review-container">
54+
<div class="code-view-container">
55+
<div id="code-toolbar">
56+
<div id="number-of-lines">{{ current_file.code.splitlines() | length }} lines</div>
57+
<div id="code-toolbar-buttons">
58+
{% if config.SHAREABLE_SOLUTIONS and not shared_url %}
59+
<div id="share-solution" class="code-toolbar-button glowing">
60+
<div id="shared-text">
61+
<button id="share-action" title="Share solution"><i class="fa fa-share-alt"></i></button>
62+
</div>
63+
<div id="shared-box" class="glowing d-none">
64+
<button id="cancel-share" class="share-button" title="Disable share solution"><i class="fa fa-trash"></i></button>
65+
<button id="copy-link" class="share-button" title="Copy shared link"><i class="fa fa-copy"></i></button>
66+
<input id="shareable-link" class="form-control" type="text" readonly>
67+
</div>
6168
</div>
62-
<div id="shared-box" class="glowing d-none">
63-
<button id="cancel-share" class="share-button" title="Disable share solution"><i class="fa fa-trash"></i></button>
64-
<button id="copy-link" class="share-button" title="Copy shared link"><i class="fa fa-copy"></i></button>
65-
<input id="shareable-link" class="form-control" type="text" readonly>
69+
{% endif -%}
70+
<div id="download-code" class="code-toolbar-button glowing">
71+
<form>
72+
<button id="download-solution" formaction="/download/{% if shared_url %}{{ shared_url }}{% else %}{{ solution['id'] }}{% endif %}">
73+
<i class="fa fa-download"></i>
74+
</button>
75+
</form>
76+
</div>
77+
<div id="copy-code" class="code-toolbar-button glowing">
78+
<button id="copy-button" class="button-copy" title="Copy code"><i class="fa fa-copy"></i></button>
6679
</div>
67-
</div>
68-
{% endif -%}
69-
<div id="download-code" class="code-toolbar-button glowing">
70-
<form>
71-
<button id="download-solution" formaction="/download/{% if shared_url %}{{ shared_url }}{% else %}{{ solution['id'] }}{% endif %}">
72-
<i class="fa fa-download"></i>
73-
</button>
74-
</form>
75-
</div>
76-
<div id="copy-code" class="code-toolbar-button glowing">
77-
<button id="copy-button" class="button-copy" title="Copy code"><i class="fa fa-copy"></i></button>
7880
</div>
7981
</div>
80-
</div>
81-
<div id="code-view" data-id="{{ solution['id'] }}" data-file="{{ current_file.id }}" data-exercise="{{ solution['exercise']['id'] }}" data-role="{{ role }}" data-solver="{{ solution['solver']['fullname'] }}" data-solver-id="{{ solution['solver']['id'] }}" data-allowed-comment="{{ config['USERS_COMMENTS'] | lower }}">
82-
<pre><code id="user-code" class="language-{{ current_file | language_name }} highlight">{% if current_file | language_name in image_extensions %}<div class="code-image-block"><img class="code-image" src="data:{{ current_file | mime_type }};base64,{{ current_file.code }}"></div>{% else %}{{- current_file.code | trim(chars=' ') | e -}}{% endif %}</code></pre>
82+
<div id="code-view" data-id="{{ solution['id'] }}" data-file="{{ current_file.id }}" data-exercise="{{ solution['exercise']['id'] }}" data-role="{{ role }}" data-solver="{{ solution['solver']['fullname'] }}" data-solver-id="{{ solution['solver']['id'] }}" data-allowed-comment="{{ config['USERS_COMMENTS'] | lower }}">
83+
<pre><code id="user-code" class="language-{{ current_file | language_name }} highlight">{% if current_file | language_name in image_extensions %}<div class="code-image-block"><img class="code-image" src="data:{{ current_file | mime_type }};base64,{{ current_file.code }}"></div>{% else %}{{- current_file.code | trim(chars=' ') | e -}}{% endif %}</code></pre>
84+
</div>
8385
</div>
8486
{% if test_results and not shared_url %}
85-
<div class="test-results">
86-
<h3 class="test-result-title">{{ _('Automatic Checking') }}</h3>
87+
<div class="test-results {{ direction }}">
88+
<div class="test-results-header">{{ _('Automatic Checking') }}</div>
8789
<ol class="test-results-list">
8890
{%- for test_result in test_results %}
8991
<li class="test-result">
90-
<h5 class="test-name">
91-
{{ test_result.pretty_test_name | e }}
92-
</h5>
93-
<span class="title">{{ _('Error') }}:</span>
94-
<span>
95-
<pre><code class="language-{{ current_file | language_name }} highlight">{{ test_result.user_message | e }}</code></pre>
96-
</span>
92+
<div class="test-header">
93+
<span class="test-status failure">{{ _('Test failed') }}: </span>
94+
<span class="test-name">{{ test_result.pretty_test_name | e }}</span>
95+
</div>
96+
<div class="test-description">
97+
<span class="error-description">{{ test_result.user_message | e }}</span>
98+
</div>
9799
{% if is_manager %}
98-
<span class="title">{{ _('Staff Error') }}:</span>
99-
<span class="stack-trace">
100-
<pre><code class="language-{{ current_file | language_name }} highlight">{{ test_result.staff_message | e }}</code></pre>
101-
</span>
100+
<div class="staff-failure">
101+
<span class="title">{{ _('Staff traceback') }}:</span>
102+
<span class="stack-trace">
103+
<pre><code class="language-{{ current_file | language_name }} highlight">{{ test_result.staff_message | e }}</code></pre>
104+
</span>
105+
</div>
102106
{% endif %}
103107
</li>
104-
{% endfor -%}
108+
{% endfor %}
105109
</ol>
106110
</div>
107111
{% endif %}

tests/test_exercise_unit_tests.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ def _verify_comments():
6464
first = auto_comments[0]
6565
assert first.exercise_test_name.test_name == 'test_check_bar_bar'
6666
assert first.exercise_test_name.pretty_test_name == 'שם כזה מגניב 2'
67-
expected = ("AssertionError: איזה ברברון"
68-
"assert 'bar' == 'barbaron' - barbaron + bar")
67+
expected = "איזה ברברון"
6968
assert expected == first.user_message
7069
assert "foo('bar') == 'barbaron'" in first.staff_message
7170

0 commit comments

Comments
 (0)