Source code for timApp.tests.browser.test_csplugin

import re
from time import sleep

from selenium.webdriver.common.by import By

from timApp.tests.browser.browsertest import BrowserTest, PREV_ANSWER
from timApp.tests.db.timdbtest import running_in_gitlab


[docs]class CsPluginTest(BrowserTest):
[docs] def test_csplugin_translation(self): self.login_browser_quick_test1() self.login_test1() d = self.create_doc( initial_par=""" #- {plugin=csPlugin #py} type: python pointsRule: code: 1 expectCode: .*Hei maailma.* """ ) dt = self.create_translation(d) dt.document.set_settings( { "global_plugin_attrs": {"all": {"lang": "en"}}, # Hide the out-of-date decoration so we don't have to update the screenshot because of it. "css": ".troutofdate::before { display: none; }", } ) tr_par = dt.document.get_paragraphs()[1] tr_par.set_markdown( """ type: python pointsRule: code: 1 expectCode: .*Hello world.* """ ) tr_par.save() self.goto_document(d) self.wait_until_present_and_vis("#py textarea") textarea = self.find_element_and_move_to("#py textarea") textarea.send_keys('print("Hei maailma!")') par = self.find_element_avoid_staleness("#py > tim-plugin-loader > div") runbutton = par.find_element(by=By.CSS_SELECTOR, value="button") runbutton.click() self.wait_until_present_and_vis(".console") self.wait_until_present_and_vis("answerbrowser") ptxt = self.find_element_by_text("Points:", "span") self.assertEqual("Points: 1", ptxt.text) self.goto_document(dt) self.wait_until_present_and_vis("#py textarea") textarea = self.find_element_and_move_to("#py textarea") textarea.clear() textarea.send_keys('print("Hello world!")') self.get_uninteractable_element().click() par = self.find_element_avoid_staleness("#py > tim-plugin-loader > div") self.assert_same_screenshot(par, ["csplugin/python_before_answer"]) runbutton = par.find_element(by=By.CSS_SELECTOR, value="button") runbutton.click() self.wait_until_present_and_vis(".console") self.wait_until_present_and_vis("answerbrowser") ptxt = self.find_element_by_text("Points:", "span") self.assertEqual("Points: 1", ptxt.text) self.get_uninteractable_element().click() self.assert_same_screenshot(par, "csplugin/python_after_answer", attempts=2) # post a second answer because otherwise clicking previous answer does not do anything textarea.send_keys(" ") runbutton.click() self.wait_until_hidden("#py tim-loading") self.wait_and_click(PREV_ANSWER) self.wait_until_hidden(".console") # Wait until answer is replaced in HTML # self.wait.until(ec.staleness_of(par.find_element(by=By.CSS_SELECTOR, value='*'))) par = self.find_element("#py > tim-plugin-loader > div") # Wait until the height workaround completes (see answerbrowser3.ts) # self.wait.until(expected_conditions.presence_of_element_located((By.XPATH, "//*[@id='py'][@style='opacity: 1;']"))) # TODO: Why is this slightly different from python_before_answer ? self.assert_same_screenshot(par, "csplugin/python_after_answer_switch") self.verify_answer_content( f"{d.id}.py", "usercode", 'print("Hello world!") ', self.test_user_1, expected_count=3, ) # The answers should always be saved under the original document, so the translated document should # not have answers. self.verify_answer_content( f"{dt.id}.py", "usercode", "", self.test_user_1, expected_count=0, )
[docs] def make_text_and_answer(self, d): self.goto_document(d) self.wait_until_present_and_vis("#text textarea") textarea = self.find_element_and_move_to("#text textarea") textarea.send_keys('print("Hello world!")') self.get_uninteractable_element().click() par = self.find_element_avoid_staleness("#text > tim-plugin-loader > div") runbutton = par.find_element(by=By.CSS_SELECTOR, value="button") runbutton.click() self.wait_until_present_and_vis("answerbrowser") self.wait_until_hidden("tim-loading") return textarea, runbutton
[docs] def test_csplugin_saveindicators(self): """ Check that savebutton is enabled/disabled by whatever is the current desired logic. For now: disableUnchanged false or missing: savebutton always enabled disableUnchanged true: savebutton disabled if saved and input doesn't change Also check yellow margin is (un)hidden and savedText (dis)appears """ self.login_browser_quick_test1() self.login_test1() d = self.create_doc( initial_par=""" #- {plugin=csPlugin #text} type: text """ ) textarea, runbutton = self.make_text_and_answer(d) self.assertTrue(runbutton.is_enabled()) savedtext = self.find_element(".savedText") self.assertTrue(savedtext.is_displayed()) self.should_not_exist(".csRunNotSaved") d = self.create_doc( initial_par=""" #- {plugin=csPlugin #text} type: text disableUnchanged: true """ ) textarea, runbutton = self.make_text_and_answer(d) self.assertFalse(runbutton.is_enabled()) savedtext = self.find_element(".savedText") self.assertTrue(savedtext.is_displayed()) self.should_not_exist(".csRunNotSaved") textarea.send_keys("more input, let me save") self.assertTrue(runbutton.is_enabled()) self.should_not_exist(".savedText") margin = self.find_element(".csRunNotSaved") self.assertTrue(margin.is_displayed())
[docs] def test_csplugin_require_type(self): self.login_test1() d = self.create_doc( initial_par=""" #- {plugin=csPlugin} stem: "" """ ) self.assert_content( self.get(d.url, as_tree=True), ['Attribute "type" is required.'] )
[docs] def test_csplugin_answernr1(self): def input_and_send(s): input = self.find_element(".csEditArea") input.clear() input.send_keys(s) button = self.find_element(".csRunDiv .timButton") button.click() self.wait_until_hidden("tim-loading") self.login_browser_quick_test1() self.login_test1() # Do not change id below because the sequence of question will be with that id: # 0: -6 + -3 # 1: 1 + -5 # 2: -2 + -1 # 3: 10 + -3 d = self.create_doc( initial_par=""" ``` {id="suSn2NPH8MC3" #summa2 plugin="csPlugin" rnd="[[-10,10],[-10,-1]]" seed="answernr"} type: text buttonNewTask: Uusi stem: "Laske: %%rnd[0]%% + %%rnd[1]%%" postoutput: web.console postprogram: |!! let a = %%rnd[0]%%; let b = %%rnd[1]%%; let c = a + b; let u = parseInt(data.save_object.usercode); let t = "väärin!"; data.points = 0; if (c === u) { t = "OK"; data.points = 1; } print(a + " + " + b + " = " + c + "; " + u + " on " + t); return data; !! ``` """ ) # Pick document self.goto_document(d) stem = self.find_element(".stem") self.assertEqual("Laske: -6 + -3", stem.text) # how to test that there is no new button # answer to first (new) question input_and_send("-9") button_new = self.find_element_by_text("Uusi") count = self.find_element(".answer-index-count") self.assertEqual("1/1", count.text) self.assertEqual("-6 + -3 = -9; -9 on OK", self.find_element(".console").text) # make a new anwser, that is not saved (see later) input_and_send("3") self.assertEqual("1/1", count.text) self.assertEqual( "-6 + -3 = -9; 3 on väärin!", self.find_element(".console").text ) # Answer to new task 2 button_new.click() sleep(0.3) self.assertEqual("2/1", count.text) stem = self.find_element(".stem") self.assertEqual("Laske: 1 + -5", stem.text) input_and_send("-4") self.assertEqual("2/2", count.text) self.assertEqual("Laske: 1 + -5", stem.text) self.assertEqual("1 + -5 = -4; -4 on OK", self.find_element(".console").text) # Make new answer to same task => no changes input_and_send("-4") self.assertEqual("2/2", count.text) self.assertEqual("1 + -5 = -4; -4 on OK", self.find_element(".console").text) # got to task 1/2 there should be the first correct answer -9 self.find_element(".nextAnswer").click() sleep(0.3) input = self.find_element(".csEditArea") self.assertEqual("-9", input.get_attribute("value")) # answer again to task 1/2 self.assertEqual("1/2", count.text) self.assertEqual("Laske: -6 + -3", self.find_element(".stem").text) input_and_send("4") self.assertEqual("1/2", count.text) self.assertEqual("Laske: -6 + -3", self.find_element(".stem").text) self.assertEqual( "-6 + -3 = -9; 4 on väärin!", self.find_element(".console").text ) sleep(0.3) # Answer to new task 3 button_new = self.find_element_by_text("Uusi") button_new.click() sleep(0.3) # how to test that there is no new button self.assertEqual("3/2", count.text) self.assertEqual("Laske: -2 + -1", self.find_element(".stem").text) input_and_send("-3") self.assertEqual("3/3", count.text) self.assertEqual("Laske: -2 + -1", self.find_element(".stem").text) self.assertEqual("-2 + -1 = -3; -3 on OK", self.find_element(".console").text) # Let's refresh, should be 4/3 and Uusi button visible and new task self.goto_document(d) self.wait_until_present(".csEditArea") input = self.find_element(".csEditArea") input.click() self.wait_until_present_and_vis(".answer-index-count") # self.assertEqual("Uusi", button_new.text) # how to test that there is no new button self.assertEqual("Laske: 10 + -3", self.find_element(".stem").text) self.assertEqual("4/3", self.find_element(".answer-index-count").text)
[docs]class StackRandomTest(BrowserTest):
[docs] def test_csplugin_answernr_stack1(self): if running_in_gitlab(): self.skipTest("Not running in GitLab") self.login_browser_quick_test1() self.login_test1() # Do not change id below because the sequence of question will be with that id: # 0: 4553:15+2 # 1: 11370:1+5 # 2: # 3: d = self.create_doc( initial_par=""" ``` {id="suSn2NPH8MC3" #summa3 plugin="csPlugin" rnd="1,20000" seed="answernr"} type: stack buttonNewTask: Uusi undo: button: Yay -pointsRule: {} open: true -stackData: seed: %%rnd[0]%% readOnly: false feedback: true score: true lang: 'fi' question: |!! --- name: Ynnää question_html: | <p>%%rnd[0]%%: {@a@} + {@b@} [[input:ans1]] &nbsp;&nbsp;[[validation:ans1]]</p> variables: |- a : rand(20); b : rand(20); specific_feedback_html: '[[feedback:prt1]]' note: <p>Tämä on note</p> inputs: ans1: type: algebraic model_answer: a+b box_size: 15 syntax_hint: "" syntax_attribute: value response_trees: prt1: first_node: node_0 nodes: node_0: answer: ans1 model_answer: a+b T: score_mode: equals answer_note: prt1-1-T feedback_html: <p>OK!</p> F: answer_note: prt1-1-F feedback_html: <p>Wrong! %%rnd[0]%%</p> stackversion: 0 ... !! ```""" ) def removeTex(s): s = ( s.replace("\n", "") .replace("\\({", "") .replace("}\\)", "") .strip() .replace(" ", "") ) s = re.sub("\\{[^}]*}", "", s) return s def stem_text(): return removeTex(self.find_element(".stackOutput p").text) def feedback_text(): return self.find_element(".stackprtfeedback-ans1").text def input_and_send(s): input = self.find_element("#stackapi_ans1") input.clear() input.send_keys(s) button = self.find_element(".csRunDiv .timButton") button.click() sleep(0.8) self.wait_until_hidden("tim-loading") # Pick document self.goto_document(d) self.wait_until_present(".stackOutput") self.assertEqual("4553:15+2", stem_text()) # answer to first (new) question input_and_send("17") button_new = self.find_element_by_text("Uusi") count = self.find_element(".answer-index-count") self.assertEqual("1/1", count.text) self.assertEqual("OK!", feedback_text()) # make a new anwser, that is not saved (see later) input_and_send("16") self.assertEqual("1/1", count.text) self.assertEqual("4553:15+2", stem_text()) self.assertEqual("Wrong! 4553", feedback_text()) # Answer to new task 2 button_new.click() sleep(0.3) self.assertEqual("2/1", count.text) self.assertEqual("11370:1+5", stem_text()) input_and_send("6") self.assertEqual("2/2", count.text) self.assertEqual("11370:1+5", stem_text()) self.assertEqual("OK!", feedback_text()) # Make new answer to same task => no changes input_and_send("5") self.assertEqual("2/2", count.text) self.assertEqual("11370:1+5", stem_text()) self.assertEqual("Wrong! 11370", feedback_text())