import datetime
from dateutil.parser import parse
import json
import pytest


def test_poll(test_client, test_user_1, test_user, runestone_db_tools):

The parameters to test_poll are really pytest fixtures, you don’t have to pass them explicitly as the framework takes care of it. If you have your own parameters they shold come last.

test_client – A client that can communicate with web2py server test_user_1 – A pre-registered user test_user – a function to make more users runestone_db_tools – a way to get manual access to the database

All tests can assume that the database is present, but empty except for the essential data for the automtaically created users and courses.

 

Make sure the user is logged in

    test_user_1.login()

Using hsblog have the user respond to a poll this is what you would do to simulate a user activity an any kind of runeston component.

    test_user_1.hsblog(
        event="poll",
        act="1",
        div_id="LearningZone_poll",
        course=test_user_1.course.course_name,
    )
 

Now lets get a handle on the database

    db = runestone_db_tools.db
 

Manually check that the response made it to the database

    res = db(db.useinfo.div_id == "LearningZone_poll").select().first()
    assert res
    assert res["act"] == "1"
 

Next we’ll invoke the API call that returns the poll results. this is a list [<num responses> [option list] [response list] divid myvote]

    test_client.post(
        "ajax/getpollresults",
        data=dict(course=test_user_1.course.course_name, div_id="LearningZone_poll"),
    )

print statements are useful for debugging and only shown in the Captured stdout call section of the output from pytest if the test fails. Otherwise print output is hidden

    print(test_client.text)
    res = json.loads(test_client.text)

expecting [1 [0, 1] [0, 1] ‘LearningZone_poll’ ‘1’]

    assert res[0] == 1
    assert res[-1] == "1"
 

Now lets have a second user respond to the poll.

    user2 = test_user("test_user_2", "password", test_user_1.course)
    test_user_1.logout()
    user2.login()
    user2.hsblog(
        event="poll",
        act="2",
        div_id="LearningZone_poll",
        course=user2.course.course_name,
    )
    test_client.post(
        "ajax/getpollresults",
        data=dict(course=user2.course.course_name, div_id="LearningZone_poll"),
    )
    res = json.loads(test_client.text)
    assert res[0] == 2
    assert res[1] == [0, 1, 2]
    assert res[2] == [0, 1, 1]
    assert res[-1] == "2"


def test_hsblog(test_client, test_user_1, test_user, runestone_db_tools):
    test_user_1.login()

    kwargs = dict(
        act="run",
        event="acivecode",
        course=test_user_1.course.course_name,
        div_id="unit_test_1",
    )
    res = test_user_1.hsblog(**kwargs)
    print(res)
    assert len(res.keys()) == 2
    assert res["log"] == True
    time_delta = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc
    ) - parse(res["timestamp"]).replace(tzinfo=datetime.timezone.utc)
    assert time_delta < datetime.timedelta(seconds=2)

    db = runestone_db_tools.db
    dbres = db(db.useinfo.div_id == "unit_test_1").select(db.useinfo.ALL)
    assert len(dbres) == 1
    assert dbres[0].course_id == test_user_1.course.course_name


def ajaxCall(client, funcName, **kwargs):

Call the funcName using the client Returns json.loads(funcName())

    client.post("ajax/" + funcName, data=kwargs)
    print(client.text)
    if client.text != "None":
        return json.loads(client.text)


def genericGetAssessResults(test_client, test_user, **kwargs):

A generic function that calls the ajax/getAssessResults API for a variety of runestone events. It returns the result of the API call

**kwargs – the remaining arguments are the list of parameters for the hsblog() call

System Message: WARNING/2 (/home/docs/checkouts/readthedocs.org/user_builds/runestoneserverascholer/checkouts/stable/tests/test_ajax2.py, line 118); backlink

Inline strong start-string without end-string.

 

Make sure the user is logged in

    test_user.login()
 

Using hsblog have the user respond to a event in the specified course this is what you would do to simulate a user activity an any kind of runeston component.

    test_user.hsblog(**kwargs)
 

Next we’ll invoke the API call that returns the event results.

    test_client.post(
        "ajax/getAssessResults",
        data=dict(
            course=kwargs["course"], div_id=kwargs["div_id"], event=kwargs["event"]
        ),
    )
 

print statements are useful for debugging and only shown in the Captured stdout call section of the output from pytest if the test fails. Otherwise print output is hidden

    print(test_client.text)
    res = json.loads(test_client.text)
    return res
 
 

The following tests are a port from the test_ajax.py

def test_GetMChoiceResults(test_client, test_user_1):
 

Generate a incorrect mChoice answer

    val = "1"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="mChoice",
        div_id="test_mchoice_1",
        answer=val,
        act=val,
        correct="F",
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert not res["correct"]
 

Generate a correct mChoice answer

    val = "3"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="mChoice",
        div_id="test_mchoice_1",
        answer=val,
        act=val,
        correct="T",
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert res["correct"]


def test_GetParsonsResults(test_client, test_user_1):
    val = "0_0-1_2_0-3_4_0-5_1-6_1-7_0"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="parsons",
        div_id="test_parsons_1",
        answer=val,
        act=val,
        correct="F",
        course=test_user_1.course.course_name,
        source="test_source_1",
    )
    assert res["answer"] == val


def test_GetClickableResults(test_client, test_user_1):
    val = "0;1"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="clickableArea",
        div_id="test_clickable_1",
        answer=val,
        act=val,
        correct="F",
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert not res["correct"]


def test_GetShortAnswerResults(test_client, test_user_1):
    val = "hello_test"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="shortanswer",
        div_id="test_short_answer_1",
        answer=val,
        act=val,
        correct="F",
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val


def test_GetFITBAnswerResults(test_client, test_user_1, runestone_db_tools):
 

Test old format, server-side grading

    ## -----------------------------------

A correct answer.

    val = "red,away"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_1",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert res["correct"]
 

An incorrect answer.

    val = "blue,away"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_1",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert not res["correct"]
 

Test new format, server-side grading

    ## -----------------------------------

A correct answer. Add spaces to verify these are ignored.

    val = '[" red ","away"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_1",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert res["correct"]
 

An incorrect answer.

    val = '["blue","away"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_1",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert not res["correct"]
 

Test server-side grading of a regex

    val = '["mARy"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_regex",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["correct"]

    val = '["mairI"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_regex",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["correct"]

    val = '["mairy"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_regex",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert not res["correct"]
 

Test server-side grading of a range of numbers, using various bases.

    val = '["10"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["correct"]

Sphinx 1.8.5 and Sphinx 2.0 render text a bit differently.

    assert res["displayFeed"] in (["Correct."], ["<p>Correct.</p>\n"])

    val = '["0b1010"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["correct"]

    val = '["0xA"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert res["correct"]

    val = '["9"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert not res["correct"]

Sphinx 1.8.5 and Sphinx 2.0 render text a bit differently.

    assert res["displayFeed"] in (["Close."], ["<p>Close.</p>\n"])

    val = '["11"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert not res["correct"]
    assert res["displayFeed"] in (["Close."], ["<p>Close.</p>\n"])

    val = '["8"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        course=test_user_1.course.course_name,
    )
    assert not res["correct"]
    assert res["displayFeed"] in (["Nope."], ["<p>Nope.</p>\n"])
 

Test client-side grading.

    db = runestone_db_tools.db
    db(db.courses.course_name == test_user_1.course.course_name).update(
        login_required=False
    )
    val = '["blue","away"]'
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="fillb",
        div_id="test_fitb_numeric",
        answer=val,
        act=val,
        correct="F",
        course=test_user_1.course.course_name,
    )
    assert res["answer"] == val
    assert not res["correct"]


def test_GetDragNDropResults(test_client, test_user_1):

    val = "0;1;2"
    res = genericGetAssessResults(
        test_client,
        test_user_1,
        event="dragNdrop",
        div_id="test_dnd_1",
        answer=val,
        act=val,
        correct="T",
        minHeight="512",
        course=test_user_1.course.course_name,
    )
    assert res["correct"]


def test_GetHist(test_client, test_user_1):

    test_user_1.login()

    kwargs = dict(
        course=test_user_1.course.course_name,
        sid="test_user_1",
        div_id="test_activecode_1",
        error_info="success",
        event="acivecode",
        to_save="true",
    )
    for x in range(0, 10):
        kwargs["code"] = "test_code_{}".format(x)
        test_client.post("ajax/runlog", data=kwargs)

    kwargs = dict(acid="test_activecode_1", sid="test_user_1")
    test_client.post("ajax/gethist", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)

    assert len(res["timestamps"]) == 0
    assert len(res["history"]) == 0

    kwargs = dict(
        acid="test_activecode_1",

sid = ‘test_user_1’

    )
    test_client.post("ajax/gethist", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)

    assert len(res["timestamps"]) == 10
    assert len(res["history"]) == 10

    time_delta = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc
    ) - parse(res["timestamps"][-1]).replace(tzinfo=datetime.timezone.utc)

    assert time_delta < datetime.timedelta(seconds=2)


def test_RunLog(test_client, test_user_1):
 

runlog should add an entry into the useinfo table as well as the code table

    test_user_1.login()

    kwargs = dict(
        course=test_user_1.course.course_name,
        sid="test_user_1",
        div_id="test_activecode_1",
        code="this is a unittest",
        error_info="success",
        event="acivecode",
        to_save="True",
    )
    test_client.post("ajax/runlog", data=kwargs)

    kwargs = dict(acid="test_activecode_1")
    test_client.post("ajax/gethist", data=kwargs)
    print(test_client.text)
    prog = json.loads(test_client.text)

    assert prog["history"][-1] == "this is a unittest"


def test_GetLastPage(test_client, test_user_1):

    test_user_1.login()
    kwargs = dict(
        course=test_user_1.course.course_name,
        lastPageUrl="test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=100,
        completionFlag="1",
    )

Call getlastpage first to insert a new record.

    test_client.post("ajax/getlastpage", data=kwargs)

Then, we can update it with the required info.

    test_client.post("ajax/updatelastpage", data=kwargs)
 

Now, test a query.

    res = ajaxCall(test_client, "getlastpage", **kwargs)
    assert res[0]["lastPageUrl"] == "test_chapter_1/subchapter_a.html"
    assert "Test chapter 1" in res[0]["lastPageChapter"]


def test_LastPageCrossCourse(test_client, test_user_1, runestone_db_tools):

    course_2 = runestone_db_tools.create_course("test_course_2")
    test_user_1.login()
    orig_course = test_user_1.course.course_name

    test_user_1.update_profile("Support Runestone", course_name=course_2.course_name)
    kwargs = dict(
        course="test_course_2",
        lastPageUrl="test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=100,
        completionFlag="1",
    )

Call getlastpage first to insert a new record.

    test_client.post("ajax/getlastpage", data=kwargs)
 

Then, we can update it with the required info.

    test_client.post("ajax/updatelastpage", data=kwargs)
    test_user_1.update_profile(course_name=orig_course)

    kwargs = dict(
        course=test_user_1.course.course_name,
        lastPageUrl="test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=100,
        completionFlag="1",
    )

Now, test a query.

    res = ajaxCall(test_client, "getlastpage", **kwargs)
    assert res is None


def test_GetTop10Answers(test_client, test_user_1, test_user):
    user_ids = []
    for index in range(0, 6):
        user = test_user(
            "test_user_{}".format(index + 2), "password", test_user_1.course
        )
        user_ids.append(user)
        user.login()

        kwargs = dict(
            event="fillb", course=user.course.course_name, div_id="test_fitb_1"
        )
        if index % 2 == 1:
            kwargs["answer"] = "42"
            kwargs["correct"] = "T"
        else:
            kwargs["answer"] = "41"
            kwargs["correct"] = "F"
        kwargs["act"] = kwargs["answer"]

        test_client.post("ajax/hsblog", data=kwargs)
        user.logout()

    user_ids[0].login()
    test_client.post("ajax/gettop10Answers", data=kwargs)
    print(test_client.text)
    res, misc = json.loads(test_client.text)

    assert res[0]["answer"] == "41"
    assert res[0]["count"] == 3
    assert res[1]["answer"] == "42"
    assert res[1]["count"] == 3
    assert misc["yourpct"] == 0
 
 

@unittest.skipIf(not is_linux, ‘preview_question only runs under Linux.’) FIXME

def testPreviewQuestion(test_client, test_user_1):
    src = """
.. activecode:: preview_test1

   Hello World
   ~~~~
   print("Hello World")

"""
    test_user_1.login()

    kwargs = dict(code=json.dumps(src))
    test_client.post("ajax/preview_question", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)

    assert 'id="preview_test1"' in res
    assert 'print("Hello World")' in res
    assert "textarea>" in res
    assert 'div data-component="activecode"' in res


def test_GetUserLoggedIn(test_client, test_user_1):
    test_user_1.login()
    test_client.post("ajax/getuser")
    print(test_client.text)
    res = json.loads(test_client.text)

    assert res[0]["nick"] == test_user_1.username


def test_GetUserNotLoggedIn(test_client, test_user_1):
    test_user_1.logout()  # make sure user is logged off...
    test_client.post("ajax/getuser")
    print(test_client.text)
    res = json.loads(test_client.text)[0]

    assert "redirect" in res


def test_Donations(test_client, test_user_1):
    test_user_1.login()
    res = ajaxCall(test_client, "save_donate")
    assert res == None

    res = ajaxCall(test_client, "did_donate")
    assert res["donate"] == True


def test_NonDonor(test_client, test_user_1):
    test_user_1.login()
    res = ajaxCall(test_client, "did_donate")
    assert not res["donate"]


def test_GetAgregateResults(test_client, test_user_1, test_user):
 

creat a bunch of users and have each one answer a multiple choice questions according to this table

    table = [  # sid      correct answer
        ("user_1662", "F", "0"),
        ("user_1662", "T", "1"),
        ("user_1663", "T", "1"),
        ("user_1665", "T", "1"),
        ("user_1667", "F", "0"),
        ("user_1667", "T", "1"),
        ("user_1668", "F", "0"),
        ("user_1668", "T", "1"),
        ("user_1669", "T", "1"),
        ("user_1670", "T", "1"),
        ("user_1671", "T", "1"),
        ("user_1672", "F", "0"),
        ("user_1672", "T", "1"),
        ("user_1673", "F", "0"),
        ("user_1673", "T", "1"),
        ("user_1674", "T", "1"),
        ("user_1675", "F", "0"),
        ("user_1675", "T", "1"),
        ("user_1675", "T", "1"),
        ("user_1676", "T", "1"),
        ("user_1677", "T", "1"),
        ("user_1751", "F", "0"),
        ("user_1751", "T", "1"),
        ("user_2521", "T", "1"),
    ]
    users = {}
    for t in table:

create the user if user has not been created yet

        user_name = t[0]
        correct = t[1]
        answer = t[2]
        logAnswer = "answer:" + answer + ":" + ("correct" if (correct == "T") else "no")
        if user_name not in users.keys():
            user = test_user(user_name, "password", test_user_1.course)
            users[user_name] = user

logon

        user = users[user_name]
        user.login()

enter mchoice answer

        user.hsblog(
            event="mChoice",
            div_id="test_mchoice_1",
            course=user.course.course_name,
            correct=correct,
            act=logAnswer,
            answer=answer,
        )

logout

        user.logout()
 

get a particular user

    user = users["user_1675"]
    user.login()
    kwargs = dict(course=user.course.course_name, div_id="test_mchoice_1")

    test_client.validate("ajax/getaggregateresults", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    res = res[0]
    assert res["misc"]["yourpct"] == 67
    assert res["answerDict"]["0"] == 29
    assert res["answerDict"]["1"] == 71
    user.logout()
 

Now test for the instructor:

    user.make_instructor()
    user.login()
    test_client.validate("ajax/getaggregateresults", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    res = res[0]
    expect = {
        "user_1662": [u"0", u"1"],
        "user_1663": [u"1"],
        "user_1665": [u"1"],
        "user_1667": [u"0", u"1"],
        "user_1668": [u"0", u"1"],
        "user_1669": [u"1"],
        "user_1670": [u"1"],
        "user_1671": [u"1"],
        "user_1672": [u"0", u"1"],
        "user_1673": [u"0", u"1"],
        "user_1674": [u"1"],
        "user_1675": [u"0", u"1", u"1"],
        "user_1676": [u"1"],
        "user_1677": [u"1"],
        "user_1751": [u"0", u"1"],
        "user_2521": [u"1"],
    }
    for student in res["reslist"]:
        assert student[1] == expect[student[0]]


def test_GetCompletionStatus(test_client, test_user_1, runestone_db_tools):
    test_user_1.login()
 

Check an unviewed page

    kwargs = dict(
        lastPageUrl="https://runestone.academy/runestone/books/published/test_course_1/test_chapter_1/subchapter_a.html"
    )

    test_client.validate("ajax/getCompletionStatus", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res[0]["completionStatus"] == -1
 

check that the unviewed page gets added into the database with a start_date of today

    db = runestone_db_tools.db
    row = (
        db(
            (db.user_sub_chapter_progress.chapter_id == "test_chapter_1")
            & (db.user_sub_chapter_progress.sub_chapter_id == "subchapter_a")
        )
        .select()
        .first()
    )
    print(row)
    assert row is not None
    assert row.end_date is None
    today = datetime.datetime.utcnow()
    assert row.start_date.month == today.month
    assert row.start_date.day == today.day
    assert row.start_date.year == today.year
 

Check a viewed page w/ completion status 0 ‘View the page’

    kwargs = dict(
        lastPageUrl="https://runestone.academy/runestone/books/published/test_course_1/test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=0,
        course=test_user_1.course.course_name,
        completionFlag=0,
    )
    test_client.validate("ajax/updatelastpage", data=kwargs)
 

Check it

    test_client.validate("ajax/getCompletionStatus", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res[0]["completionStatus"] == 0
 

Check a viewed page w/ completion status 1 ‘View the page and check the completion button’

    kwargs = dict(
        lastPageUrl="https://runestone.academy/runestone/static/test_course_1/test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=0,
        course=test_user_1.course.course_name,
        completionFlag=1,
    )
    test_client.validate("ajax/updatelastpage", data=kwargs)
 

Check it

    test_client.validate("ajax/getCompletionStatus", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res[0]["completionStatus"] == 1
 

Test getAllCompletionStatus()

    test_client.validate("ajax/getAllCompletionStatus")
    res = json.loads(test_client.text)
    print(res)
    assert len(res) == 2


def test_updatelastpage(test_client, test_user_1, runestone_db_tools):

Check an unviewed page

    kwargs = dict(
        lastPageUrl="https://runestone.academy/runestone/books/published/test_course_1/test_chapter_1/subchapter_a.html"
    )

    test_client.validate("ajax/getCompletionStatus", data=kwargs)

    test_user_1.login()
    kwargs = dict(
        lastPageUrl="https://runestone.academy/runestone/books/published/test_course_1/test_chapter_1/subchapter_a.html",
        lastPageScrollLocation=0,
        course=test_user_1.course.course_name,
        completionFlag=1,
    )
    test_client.validate("ajax/updatelastpage", data=kwargs)
    db = runestone_db_tools.db
    res = (
        db(
            (db.user_sub_chapter_progress.user_id == test_user_1.user_id)
            & (db.user_sub_chapter_progress.sub_chapter_id == "subchapter_a")
            & (
                db.user_sub_chapter_progress.course_name
                == test_user_1.course.course_name
            )
        )
        .select()
        .first()
    )
    print(res)

    now = datetime.datetime.utcnow()

    assert res.status == 1
    assert res.end_date.month == now.month
    assert res.end_date.day == now.day
    assert res.end_date.year == now.year


def test_getassignmentgrade(test_assignment, test_user_1, test_user, test_client):

make a dummy student to do work

    student1 = test_user("student1", "password", test_user_1.course)
    student1.logout()

    test_user_1.make_instructor()
    test_user_1.login()
 

make dummy assignment

    my_ass = test_assignment("test_assignment", test_user_1.course)
    my_ass.addq_to_assignment(question="subc_b_fitb", points=10)
    my_ass.save_assignment()
 

record a grade for that student on an assignment

    sid = student1.username
    acid = "subc_b_fitb"
    grade = 5
    comment = "OK job"
    res = test_client.validate(
        "assignments/record_grade",
        data=dict(sid=sid, acid=acid, grade=grade, comment=comment),
    )

    test_user_1.logout()
 

check unreleased assignment grade

    student1.login()
    kwargs = dict(div_id=acid)
    test_client.validate("ajax/getassignmentgrade", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res[0]["grade"] == "Not graded yet"
    assert res[0]["comment"] == "OK job"
    assert res[0]["avg"] == "None"
    assert res[0]["count"] == "None"
    student1.logout()
 

release grade

    test_user_1.login()
    my_ass.release_grades()
    test_user_1.logout()
 

check grade again

    student1.login()
    kwargs = dict(div_id=acid)
    test_client.validate("ajax/getassignmentgrade", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res[0]["grade"] == 5
    assert res[0]["version"] == 2
    assert res[0]["max"] == 10
    assert res[0]["comment"] == comment


def test_get_datafile(test_client, test_user_1, runestone_db_tools):
 

Create some datafile into the db and then read it out using the ajax/get_datafile()

    db = runestone_db_tools.db
    db.source_code.insert(
        course_id=test_user_1.course.course_name,
        acid="mystery.txt",
        main_code="hello world",
    )

    test_user_1.make_instructor()
    test_user_1.login()
    kwargs = dict(course_id=test_user_1.course.course_name, acid="mystery.txt")
    test_client.validate("ajax/get_datafile", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res["data"] == "hello world"
 

non-existant datafile

    kwargs = dict(
        course_id=test_user_1.course.course_name, acid="thisWillNotBeThere.txt"
    )
    test_client.validate("ajax/get_datafile", data=kwargs)
    print(test_client.text)
    res = json.loads(test_client.text)
    assert res["data"] is None