2022-03-30 19:16:39 +00:00
|
|
|
import aqt
|
|
|
|
import pytest
|
2018-05-09 01:16:36 +00:00
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
from conftest import ac, wait, wait_until, \
|
|
|
|
close_all_dialogs_and_wait_for_them_to_run_closing_callbacks
|
2018-05-09 01:16:36 +00:00
|
|
|
|
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
def test_guiBrowse(setup):
|
|
|
|
ac.guiBrowse()
|
2018-05-09 01:16:36 +00:00
|
|
|
|
2021-12-06 16:59:10 +00:00
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
def test_guiDeckBrowser(setup):
|
|
|
|
ac.guiDeckBrowser()
|
2018-05-09 01:16:36 +00:00
|
|
|
|
2021-06-21 03:35:09 +00:00
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
# todo executing this test without running background tasks on main thread
|
|
|
|
# rarely causes media server (`aqt.mediasrv`) to fail:
|
|
|
|
# its `run` method raises OSError: invalid file descriptor.
|
|
|
|
# this can cause other tests to fail to tear down;
|
|
|
|
# particularly, any dialogs with editor may fail to close
|
|
|
|
# due to their trying to save the note first, which is done via web view,
|
|
|
|
# which fails to complete due to corrupt media server. investigate?
|
|
|
|
def test_guiCheckDatabase(setup, run_background_tasks_on_main_thread):
|
|
|
|
ac.guiCheckDatabase()
|
2018-05-09 01:16:36 +00:00
|
|
|
|
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
def test_guiDeckOverview(setup):
|
|
|
|
assert ac.guiDeckOverview(name="test_deck") is True
|
2018-05-09 01:16:36 +00:00
|
|
|
|
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
class TestAddCards:
|
|
|
|
note = {
|
|
|
|
"deckName": "test_deck",
|
|
|
|
"modelName": "Basic",
|
|
|
|
"fields": {"Front": "new front1", "Back": "new back1"},
|
|
|
|
"tags": ["tag1"]
|
|
|
|
}
|
2018-05-09 01:16:36 +00:00
|
|
|
|
2022-03-30 19:16:39 +00:00
|
|
|
options_closeAfterAdding = {
|
|
|
|
"options": {
|
|
|
|
"closeAfterAdding": True
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# an actual small image, you can see it if you run the test with GUI
|
|
|
|
# noinspection SpellCheckingInspection
|
|
|
|
base64_gif = "R0lGODlhBQAEAHAAACwAAAAABQAEAIH///8AAAAAAAAAAAACB0QMqZcXDwoAOw=="
|
|
|
|
|
|
|
|
picture = {
|
|
|
|
"picture": [
|
|
|
|
{
|
|
|
|
"data": base64_gif,
|
|
|
|
"filename": "smiley.gif",
|
|
|
|
"fields": ["Front"],
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def click_on_add_card_dialog_save_button(dialog_name="AddCards"):
|
|
|
|
dialog = aqt.dialogs._dialogs[dialog_name][1]
|
|
|
|
dialog.addButton.click()
|
|
|
|
|
|
|
|
# todo previously, these tests were verifying
|
|
|
|
# that the return value of `guiAddCards` is `int`.
|
|
|
|
# while it is indeed `int`, on modern Anki it is also always a `0`,
|
|
|
|
# so we consider it useless. update documentation?
|
|
|
|
def test_without_note(self, setup):
|
|
|
|
ac.guiAddCards()
|
|
|
|
|
|
|
|
def test_with_note(self, setup):
|
|
|
|
ac.guiAddCards(note=self.note)
|
|
|
|
self.click_on_add_card_dialog_save_button()
|
|
|
|
close_all_dialogs_and_wait_for_them_to_run_closing_callbacks()
|
|
|
|
|
|
|
|
assert len(ac.findCards(query="new")) == 1
|
|
|
|
|
|
|
|
def test_with_note_and_a_picture(self, setup):
|
|
|
|
ac.guiAddCards(note={**self.note, **self.picture})
|
|
|
|
self.click_on_add_card_dialog_save_button()
|
|
|
|
close_all_dialogs_and_wait_for_them_to_run_closing_callbacks()
|
|
|
|
|
|
|
|
assert len(ac.findCards(query="new")) == 1
|
|
|
|
assert ac.retrieveMediaFile(filename="smiley.gif") == self.base64_gif
|
|
|
|
|
|
|
|
# todo the tested method, when called with option `closeAfterAdding=True`,
|
|
|
|
# is broken for the following reasons:
|
|
|
|
# * it uses the note that comes with dialog's Editor.
|
|
|
|
# this note might be of a different model than the proposed note,
|
|
|
|
# and field values from the proposed note can't be put into it.
|
|
|
|
# * most crucially, `AddCardsAndClose` is trying to override the method
|
|
|
|
# `_addCards` that is no longer present or called by the superclass.
|
|
|
|
# also, it creates and registers a new class each time it is called.
|
|
|
|
# todo fix the method, or ignore/disallow the option `closeAfterAdding`?
|
|
|
|
@pytest.mark.skip("API method `guiAddCards` is broken "
|
|
|
|
"when called with note option `closeAfterAdding=True`")
|
|
|
|
def test_with_note_and_closeAfterAdding(self, setup):
|
|
|
|
def find_AddCardsAndClose_dialog_registered_name():
|
|
|
|
for name in aqt.dialogs._dialogs.keys():
|
|
|
|
if name.startswith("AddCardsAndClose"):
|
|
|
|
return name
|
|
|
|
|
|
|
|
def dialog_is_open(name):
|
|
|
|
return aqt.dialogs._dialogs[name][1] is not None
|
|
|
|
|
|
|
|
ac.guiAddCards(note={**self.note, **self.options_closeAfterAdding})
|
|
|
|
|
|
|
|
dialog_name = find_AddCardsAndClose_dialog_registered_name()
|
|
|
|
assert dialog_is_open(dialog_name)
|
|
|
|
self.click_on_add_card_dialog_save_button(dialog_name)
|
|
|
|
wait_until(aqt.dialogs.allClosed)
|
|
|
|
|
|
|
|
|
|
|
|
class TestReviewActions:
|
|
|
|
@pytest.fixture
|
|
|
|
def reviewing_started(self, setup):
|
|
|
|
assert ac.guiDeckReview(name="test_deck") is True
|
|
|
|
|
|
|
|
def test_startCardTimer(self, reviewing_started):
|
|
|
|
assert ac.guiStartCardTimer() is True
|
|
|
|
|
|
|
|
def test_guiShowQuestion(self, reviewing_started):
|
|
|
|
assert ac.guiShowQuestion() is True
|
|
|
|
assert ac.reviewer().state == "question"
|
|
|
|
|
|
|
|
def test_guiShowAnswer(self, reviewing_started):
|
|
|
|
assert ac.guiShowAnswer() is True
|
|
|
|
assert ac.reviewer().state == "answer"
|
|
|
|
|
|
|
|
def test_guiAnswerCard(self, reviewing_started):
|
|
|
|
ac.guiShowAnswer()
|
|
|
|
reviews_before = ac.cardReviews(deck="test_deck", startID=0)
|
|
|
|
assert ac.guiAnswerCard(ease=4) is True
|
|
|
|
|
|
|
|
reviews_after = ac.cardReviews(deck="test_deck", startID=0)
|
|
|
|
assert len(reviews_after) == len(reviews_before) + 1
|
|
|
|
|
|
|
|
|
|
|
|
class TestSelectedNotes:
|
|
|
|
def test_with_valid_deck_query(self, setup):
|
|
|
|
ac.guiBrowse(query="deck:test_deck")
|
|
|
|
wait_until(ac.guiSelectedNotes)
|
|
|
|
assert ac.guiSelectedNotes()[0] in {setup.note1_id, setup.note2_id}
|
|
|
|
|
|
|
|
|
|
|
|
def test_with_invalid_deck_query(self, setup):
|
|
|
|
ac.guiBrowse(query="deck:test_deck")
|
|
|
|
wait_until(ac.guiSelectedNotes)
|
|
|
|
|
|
|
|
ac.guiBrowse(query="deck:invalid")
|
|
|
|
wait_until(lambda: not ac.guiSelectedNotes())
|