Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 22e8a49

Browse files
authored
Merge pull request #1105 from bjones1/logBook_async
Fix: Return data from the server, instead of the HTTP response, from …
2 parents b7a62b0 + 2c52879 commit 22e8a49

6 files changed

Lines changed: 44 additions & 38 deletions

File tree

runestone/activecode/js/activecode_js.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default class JSActiveCode extends ActiveCode {
5555
this.addErrorMessage(e);
5656
einfo = e;
5757
}
58+
// Note that, since this isn't awaited, the request may not be complete when this function returns.
5859
this.logRunEvent({
5960
div_id: this.divid,
6061
code: this.editor.getValue(),
@@ -64,6 +65,6 @@ export default class JSActiveCode extends ActiveCode {
6465
prefix: this.pretext,
6566
suffix: this.suffix,
6667
partner: this.partner,
67-
}); // Log the run event
68+
});
6869
}
6970
}

runestone/common/js/runestonebase.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,16 @@ export default class RunestoneBase {
6161
});
6262
}
6363

64+
// .. _logBookEvent:
65+
//
66+
// logBookEvent
67+
// ------------
68+
// This function sends the provided ``eventInfo`` to the `hsblog endpoint` of the server. Awaiting this function returns either ``undefined`` (if Runestone services are not available) or the data returned by the server as a JavaScript object (already JSON-decoded).
6469
async logBookEvent(eventInfo) {
6570
if (this.graderactive) {
6671
return;
6772
}
68-
let post_return = Promise.resolve();
73+
let post_return;
6974
eventInfo.course = eBookConfig.course;
7075
eventInfo.clientLoginStatus = eBookConfig.isLoggedIn;
7176
eventInfo.timezoneoffset = new Date().getTimezoneOffset() / 60;
@@ -78,10 +83,11 @@ export default class RunestoneBase {
7883
headers: this.jsonHeaders,
7984
body: JSON.stringify(eventInfo),
8085
});
81-
post_return = await fetch(request);
82-
if (!post_return.ok) {
86+
let response = await fetch(request);
87+
if (!response.ok) {
8388
throw new Error("Failed to save the log entry");
8489
}
90+
post_return = response.json();
8591
}
8692
console.log("logging event " + JSON.stringify(eventInfo));
8793
if (
@@ -93,8 +99,14 @@ export default class RunestoneBase {
9399
}
94100
return post_return;
95101
}
102+
103+
// .. _logRunEvent:
104+
//
105+
// logRunEvent
106+
// -----------
107+
// This function sends the provided ``eventInfo`` to the `runlog endpoint`. When awaited, this function returns the data (decoded from JSON) the server sent back.
96108
async logRunEvent(eventInfo) {
97-
let post_promise = Promise.resolve("done");
109+
let post_promise = "done";
98110
if (this.graderactive) {
99111
return;
100112
}
@@ -114,6 +126,7 @@ export default class RunestoneBase {
114126
if (!post_promise.ok) {
115127
throw new Error("Failed to log the run");
116128
}
129+
post_promise = await response.json();
117130
}
118131
console.log("running " + JSON.stringify(eventInfo));
119132
if (

runestone/fitb/js/fitb.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,9 @@ export default class FITB extends RunestoneBase {
241241
}
242242
if (logFlag) {
243243
// Sometimes we don't want to log the answer--for example, when timed exam questions are re-loaded
244-
let ret = await this.logCurrentAnswer();
244+
let data = await this.logCurrentAnswer();
245245
if (!this.feedbackArray) {
246246
// On success, update the feedback from the server's grade.
247-
let data = await ret.json();
248247
this.setLocalStorage({
249248
answer: JSON.stringify(this.given_arr),
250249
timestamp: data.timestamp,

runestone/mchoice/test/test_assess.py

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

77
from unittest import TestCase
88
from selenium.webdriver.support import expected_conditions as EC
9-
from selenium.webdriver.support.ui import WebDriverWait
109
from selenium.webdriver.common.by import By
1110
from runestone.unittest_base import module_fixture_maker, RunestoneTestCase
1211

@@ -63,12 +62,6 @@ class MultipleChoiceQuestion_Tests(RunestoneTestCase):
6362
def test_ma1(self):
6463
"""Multiple Answer: Nothing selected, Check button clicked"""
6564
self.driver.get(self.host + "/index.html")
66-
wait = WebDriverWait(self.driver, 10)
67-
try:
68-
wait.until(EC.presence_of_element_located((By.ID, "question1")))
69-
except:
70-
text = self.driver.page_source
71-
print(text[:300])
7265
t1 = self.driver.find_element_by_id("question1")
7366

7467
btn_check = t1.find_element_by_tag_name("button")

runestone/overview.rst

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@ Consistent Component API
33

44
A standardized API will make the Runestone Components easier to work on and more maintainable. For example in trying to find out how to JUST score a component in a timed exam (not render any feedback) I found the following methods:
55

6-
* processXXXSubmissions - mchoice
7-
* startEvaluation - fitb
8-
* dragEval - dragndrop
9-
* checkMe - parsons
10-
* clickableEval - clickaablearea
11-
* activecode - runProg
12-
* submitJournal - short answer
6+
* processXXXSubmissions - mchoice
7+
* startEvaluation - fitb
8+
* dragEval - dragndrop
9+
* checkMe - parsons
10+
* clickableEval - clickaablearea
11+
* activecode - runProg
12+
* submitJournal - short answer
1313

1414
All of the above mix the scoring of the component with rendering the feedback. I would like to separate those two things and standardize on some names for doing so.
1515

1616
Base Class Provides
1717
-------------------
18-
* shouldUseServer
19-
* checkServer
20-
* logRunEvent
21-
* logBookEvent
22-
* loadData
23-
* repopulateFromStorage
24-
* localStorageKey
25-
* addCaption
26-
* constructor that takes opts
18+
* shouldUseServer
19+
* checkServer
20+
* `logRunEvent` - send the results of executing an ActiveCode exercise to the `runlog endpoint`.
21+
* `logBookEvent` - send the results of answering a question to the `hsblog endpoint`.
22+
* loadData
23+
* repopulateFromStorage
24+
* localStorageKey
25+
* addCaption
26+
* constructor that takes opts
2727

2828
All Components
2929
--------------
@@ -33,14 +33,12 @@ All Components
3333
* setLocalStorage
3434
* checkLocalStorage
3535
* hasUserActivity
36-
*
37-
Gradable
38-
--------
3936

37+
Gradable
38+
--------
4039
Each Gradable should provide these three functions as an external API. We want to separate checking, from logging and providing feedback
41-
* checkCurrentAnswer - async? so that for server side grading we can await
42-
* logCurrentAnswer
43-
* renderFeedback
44-
* disableInteraction
45-
4640

41+
* checkCurrentAnswer - async? so that for server side grading we can await
42+
* logCurrentAnswer
43+
* renderFeedback
44+
* disableInteraction

runestone/unittest_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ def setUp(self):
228228
# Use the shared module-wide driver.
229229
self.driver = mf.driver
230230
self.host = HOST_URL
231+
# Add an `implicit wait <https://selenium-python.readthedocs.io/waits.html#implicit-waits>`_.
232+
self.driver.implicitly_wait(5)
231233

232234
def tearDown(self):
233235
# Clear as much as possible, to present an almost-fresh instance of a browser for the next test. (Shutting down then starting up a browswer is very slow.)

0 commit comments

Comments
 (0)