From 0abda4d5e428e737d8d3d882bacdfadddb942cdb Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Wed, 30 Dec 2020 00:22:34 +0300 Subject: [PATCH 1/4] support for python 3.5/3.8 and django 2.2 + basic tests --- .github/workflows/tests.yml | 27 +++++++++++++++ .gitignore | 6 +++- feedback/feedback.py | 6 ++-- feedbacktests/__init__.py | 1 - feedbacktests/conftest.py | 27 +++++++++++++++ feedbacktests/test_feedback.py | 4 +-- feedbacktests/test_feedback_unit.py | 52 +++++++++++++++++++++++++++++ geckodriver.log | 0 makeicons/test_icons.py | 2 +- test_settings.py | 7 ++++ tox.ini | 37 ++++++++++++++++++++ 11 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 feedbacktests/conftest.py create mode 100644 feedbacktests/test_feedback_unit.py create mode 100644 geckodriver.log create mode 100644 test_settings.py create mode 100644 tox.ini diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..eacd4e8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,27 @@ +name: feedbackxblock + +on: + push: + branches: [master, main] + pull_request: + +jobs: + test: + runs-on: ubuntu-18.04 + strategy: + matrix: + python-version: [3.5] + tox-env: + - quality + - django22 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install tox + - name: Test with tox + run: tox -e ${{ matrix.tox-env }} diff --git a/.gitignore b/.gitignore index 915fc00..e3b41d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ *pyc rate_xblock.egg-info -*~ \ No newline at end of file +*~ +.coverage +.tox +*.egg-info +__pycache__ \ No newline at end of file diff --git a/feedback/feedback.py b/feedback/feedback.py index f0c2892..6ef3515 100644 --- a/feedback/feedback.py +++ b/feedback/feedback.py @@ -7,8 +7,8 @@ import cgi import random - import pkg_resources +import six from xblock.core import XBlock from xblock.fields import Scope, Integer, String, List, Float @@ -264,9 +264,9 @@ def studio_view(self, context): prompt = self.get_prompt(0) for idx in range(len(prompt['scale_text'])): prompt['likert{i}'.format(i=idx)] = prompt['scale_text'][idx] - frag = Fragment(unicode(html_str).format(**prompt)) + frag = Fragment(six.text_type(html_str).format(**prompt)) js_str = self.resource_string("static/js/src/studio.js") - frag.add_javascript(unicode(js_str)) + frag.add_javascript(six.text_type(js_str)) frag.initialize_js('FeedbackBlock', {'icon_set': prompt['icon_set']}) return frag diff --git a/feedbacktests/__init__.py b/feedbacktests/__init__.py index 823129e..e69de29 100644 --- a/feedbacktests/__init__.py +++ b/feedbacktests/__init__.py @@ -1 +0,0 @@ -from .test_feedback import TestFeedback diff --git a/feedbacktests/conftest.py b/feedbacktests/conftest.py new file mode 100644 index 0000000..1328b5f --- /dev/null +++ b/feedbacktests/conftest.py @@ -0,0 +1,27 @@ +import pytest +from mock import Mock + +from workbench.runtime import WorkbenchRuntime +from xblock.fields import ScopeIds +from xblock.runtime import DictKeyValueStore, KvsFieldData + +from feedback.feedback import FeedbackXBlock + + +def generate_scope_ids(runtime, block_type): + """ helper to generate scope IDs for an XBlock """ + def_id = runtime.id_generator.create_definition(block_type) + usage_id = runtime.id_generator.create_usage(def_id) + return ScopeIds('user', block_type, def_id, usage_id) + + +@pytest.fixture +def feedback_xblock(): + """Feedback XBlock pytest fixture.""" + runtime = WorkbenchRuntime() + key_store = DictKeyValueStore() + db_model = KvsFieldData(key_store) + ids = generate_scope_ids(runtime, 'feedback') + feedback_xblock = FeedbackXBlock(runtime, db_model, scope_ids=ids) + feedback_xblock.usage_id = Mock() + return feedback_xblock diff --git a/feedbacktests/test_feedback.py b/feedbacktests/test_feedback.py index cd467ad..90f5019 100644 --- a/feedbacktests/test_feedback.py +++ b/feedbacktests/test_feedback.py @@ -1,5 +1,5 @@ ''' -Tests for the FeedbackXBlock. +Tests for the FeedbackXBlock that needs to run in Open edX. ''' import json @@ -31,7 +31,7 @@ def set_random(self, random_patch_value): # pylint: disable=abstract-method -class TestFeedback(PatchRandomMixin, XBlockTestCase): +class FeedbackTestCase(PatchRandomMixin, XBlockTestCase): """ Basic tests for the FeedbackXBlock. We set up a page with two of the block, make sure the page renders, toggle a few ratings, diff --git a/feedbacktests/test_feedback_unit.py b/feedbacktests/test_feedback_unit.py new file mode 100644 index 0000000..2de642c --- /dev/null +++ b/feedbacktests/test_feedback_unit.py @@ -0,0 +1,52 @@ +""" +Tests for the Feedback XBlock with heavy mocking. +""" + +from mock import Mock + + +def test_template_content(feedback_xblock): + """ Test content of FeedbackXBlock's student view """ + student_fragment = feedback_xblock.render('student_view', Mock()) + assert 'feedback' in student_fragment.content + + +def test_studio_view(feedback_xblock): + """ Test content of FeedbackXBlock's author view """ + student_fragment = feedback_xblock.render('studio_view', Mock()) + assert 'feedback' in student_fragment.content + + +def test_studio_submit(feedback_xblock): + """ Test the FeedbackXBlock's save action """ + request_body = b"""{ + "display_name": "foo" + }""" + request = Mock(method='POST', body=request_body) + response = feedback_xblock.studio_submit(request) + assert response.status_code == 200 and {'result': 'success'} == response.json, response.json + + +def test_vote(feedback_xblock): + """ Test content of FeedbackXBlock's vote() method """ + feedback_xblock.vote({'vote': 1}) + + +def test_feedback_method(feedback_xblock): + """ Test content of FeedbackXBlock's feedback() method """ + request_body = b"""{ + "freeform": "yes", + "vote": 1 + }""" + request = Mock(method='POST', body=request_body) + response = feedback_xblock.feedback(request) + + expected_response_json = { + "aggregate": [0, 1, 0, 0, 0], + "freeform": "yes", + "response": "Thank you for your feedback!", + "success": True, + "vote": 1, + } + + assert response.status_code == 200 and response.json == expected_response_json, response.json diff --git a/geckodriver.log b/geckodriver.log new file mode 100644 index 0000000..e69de29 diff --git a/makeicons/test_icons.py b/makeicons/test_icons.py index b59d1a5..cf2a621 100644 --- a/makeicons/test_icons.py +++ b/makeicons/test_icons.py @@ -9,7 +9,7 @@ import unittest from bok_choy.web_app_test import WebAppTest -from pages import IconsPage +from .pages import IconsPage class TestIcons(WebAppTest): diff --git a/test_settings.py b/test_settings.py new file mode 100644 index 0000000..37a7563 --- /dev/null +++ b/test_settings.py @@ -0,0 +1,7 @@ +""" +Test settings for the Feedback XBlock. +""" + +from workbench.settings import * + +from django.conf.global_settings import LOGGING diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..60752ac --- /dev/null +++ b/tox.ini @@ -0,0 +1,37 @@ +[tox] +envlist = py{35,38}-django22,py38-django3 +skipsdist = True + +[pytest] +# 58, 228-229, 250, 279-288, 307-317, 330-363, 373, 391-396 +addopts = --cov=feedback --cov-report=term-missing + +[testenv] +usedevelop=True +passenv = + SELENIUM_BROWSER +setenv = + DJANGO_SETTINGS_MODULE = test_settings +deps = + django11: Django>=1.11,<2 + django22: Django>=2.2,<2.3 + bok-choy + six + django-pyfs + flake8 + mock + pytest + pytest-cov + pytest-django + xblock + xblock-sdk +commands = + # TODO: Activate the rest of the tests once they're fixed + {posargs:pytest feedbacktests/test_feedback_unit.py} + +[flake8] +max-line-length = 160 + +[testenv:quality] +commands = + flake8 feedback feedbacktests makeicons setup.py From e3b10ad59c9fec609a129d79081c6d99a4866be3 Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Mon, 4 Jan 2021 12:13:04 +0300 Subject: [PATCH 2/4] merge tess files --- .github/workflows/test.yml | 36 ++++++++++++++++++++---------------- .github/workflows/tests.yml | 27 --------------------------- 2 files changed, 20 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0bd32f..eacd4e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,23 +1,27 @@ -name: Python application +name: feedbackxblock on: push: - branches: [ master, main ] + branches: [master, main] pull_request: - branches: [ master, main ] jobs: - build: - - runs-on: ubuntu-latest - + test: + runs-on: ubuntu-18.04 + strategy: + matrix: + python-version: [3.5] + tox-env: + - quality + - django22 steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.5 - uses: actions/setup-python@v2 - with: - python-version: 3.5 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install flake8 pytest + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install tox + - name: Test with tox + run: tox -e ${{ matrix.tox-env }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index eacd4e8..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: feedbackxblock - -on: - push: - branches: [master, main] - pull_request: - -jobs: - test: - runs-on: ubuntu-18.04 - strategy: - matrix: - python-version: [3.5] - tox-env: - - quality - - django22 - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install tox - - name: Test with tox - run: tox -e ${{ matrix.tox-env }} From 0b4782e3e82b6aa8977a0ff6f7c9e158455beaff Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Mon, 4 Jan 2021 15:49:58 +0300 Subject: [PATCH 3/4] refactor tests --- .github/workflows/test.yml | 4 ++-- feedback/__init__.py | 2 -- feedback/feedback.py | 7 ++++--- feedbacktests/test_feedback.py | 2 -- makeicons/test_icons.py | 1 + requirements.txt | 25 +++++++++++++++++++++++++ setup.py | 2 +- tox.ini | 17 +++-------------- 8 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 requirements.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eacd4e8..c30a07b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-18.04 strategy: matrix: - python-version: [3.5] + python-version: [2.7, 3.5, 3.8] tox-env: - quality - - django22 + - py steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/feedback/__init__.py b/feedback/__init__.py index 90a76c1..a7e02e6 100644 --- a/feedback/__init__.py +++ b/feedback/__init__.py @@ -3,5 +3,3 @@ course resources, and to think and synthesize about their experience in the course. """ - -from .feedback import FeedbackXBlock diff --git a/feedback/feedback.py b/feedback/feedback.py index 6ef3515..7e684d7 100644 --- a/feedback/feedback.py +++ b/feedback/feedback.py @@ -12,7 +12,8 @@ from xblock.core import XBlock from xblock.fields import Scope, Integer, String, List, Float -from xblock.fragment import Fragment +from web_fragments.fragment import Fragment + # We provide default text which is designed to elicit student thought. We'd # like instructors to customize this to something highly structured (not @@ -31,7 +32,7 @@ # Unicode alt faces are cute, but we do nulls instead for a11y. ICON_SETS = {'face': [""]*5, # u"😁😊😐😞😭", 'num': u"12345", - 'midface': [""]*5} #u"😞😐😊😐😞"} + 'midface': [""]*5} # u"😞😐😊😐😞"} @XBlock.needs('i18n') @@ -304,7 +305,7 @@ def vote(self, data): """ # prompt_choice is initialized by student view. # Ideally, we'd break this out into a function. - prompt = self.get_prompt(self.prompt_choice) + prompt = self.get_prompt(self.prompt_choice) # noqa # Make sure we're initialized self.init_vote_aggregate() diff --git a/feedbacktests/test_feedback.py b/feedbacktests/test_feedback.py index 90f5019..96b44e4 100644 --- a/feedbacktests/test_feedback.py +++ b/feedbacktests/test_feedback.py @@ -2,8 +2,6 @@ Tests for the FeedbackXBlock that needs to run in Open edX. ''' -import json -import sys from openedx.tests.xblock_integration.xblock_testcase import XBlockTestCase import mock diff --git a/makeicons/test_icons.py b/makeicons/test_icons.py index cf2a621..a07fc03 100644 --- a/makeicons/test_icons.py +++ b/makeicons/test_icons.py @@ -29,5 +29,6 @@ def test_page_existence(self): self.assertScreenshot("#"+style+icon+str(i+1), style+icon+str(i+1)) + if __name__ == '__main__': unittest.main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..04fe982 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,25 @@ +bok-choy==1.1.1 + +Django>=1.11,<2; python_version < '3' +Django>=2.2,<2.3; python_version >= '3' + +django-pyfs==2.2 +flake8==3.8.4 +mock==3.0.5 + +pytest==4.6.11; python_version < '3' +pytest==6.1.2; python_version >= '3' + +pytest-cov==2.10.1 + +pytest-django==3.10.0; python_version < '3' +pytest-django==4.1.0; python_version >= '3' + +six==1.15.0 + +web-fragments==0.3.2 + +XBlock==1.2.1; python_version < '3' +XBlock==1.4.0; python_version >= '3' + +xblock-sdk==0.2.2 diff --git a/setup.py b/setup.py index d5bf8a1..a26cc6d 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def package_data(pkg, roots): ], entry_points={ 'xblock.v1': [ - 'feedback = feedback:FeedbackXBlock', + 'feedback = feedback.feedback:FeedbackXBlock', ], 'xblock.test.v0': [ 'feedbacktest = feedbacktests:TestFeedback', diff --git a/tox.ini b/tox.ini index 60752ac..4e19a66 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,8 @@ [tox] -envlist = py{35,38}-django22,py38-django3 +envlist = py{27,35,38},quality skipsdist = True [pytest] -# 58, 228-229, 250, 279-288, 307-317, 330-363, 373, 391-396 addopts = --cov=feedback --cov-report=term-missing [testenv] @@ -13,18 +12,7 @@ passenv = setenv = DJANGO_SETTINGS_MODULE = test_settings deps = - django11: Django>=1.11,<2 - django22: Django>=2.2,<2.3 - bok-choy - six - django-pyfs - flake8 - mock - pytest - pytest-cov - pytest-django - xblock - xblock-sdk + -r{toxinidir}/requirements.txt commands = # TODO: Activate the rest of the tests once they're fixed {posargs:pytest feedbacktests/test_feedback_unit.py} @@ -33,5 +21,6 @@ commands = max-line-length = 160 [testenv:quality] +deps = flake8 commands = flake8 feedback feedbacktests makeicons setup.py From cbd24d225c143a4eecef202574fe6d631ccf1bc2 Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Tue, 5 Jan 2021 12:39:51 +0300 Subject: [PATCH 4/4] use looser requirements for development --- requirements.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 04fe982..8543341 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,25 +1,25 @@ -bok-choy==1.1.1 +bok-choy>=1.1.1 Django>=1.11,<2; python_version < '3' Django>=2.2,<2.3; python_version >= '3' -django-pyfs==2.2 -flake8==3.8.4 -mock==3.0.5 +django-pyfs>=2.2 +flake8>=3.8.4 +mock>=3.0.5 pytest==4.6.11; python_version < '3' -pytest==6.1.2; python_version >= '3' +pytest>=6.1.2; python_version >= '3' -pytest-cov==2.10.1 +pytest-cov>=2.10.1 -pytest-django==3.10.0; python_version < '3' -pytest-django==4.1.0; python_version >= '3' +pytest-django>=3.10.0; python_version < '3' +pytest-django>=4.1.0; python_version >= '3' -six==1.15.0 +six>=1.15.0 -web-fragments==0.3.2 +web-fragments>=0.3.2 XBlock==1.2.1; python_version < '3' -XBlock==1.4.0; python_version >= '3' +XBlock>=1.4.0; python_version >= '3' -xblock-sdk==0.2.2 +xblock-sdk>=0.2.2