diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 921c235d4c..905ee415d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,14 +38,75 @@ jobs: # Ref: https://github.com/rdmorganiser/.github/blob/main/.github/workflows/_lint.yml uses: rdmorganiser/.github/.github/workflows/_lint.yml@main + build-wheel: + name: Build python wheel + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + # update the version + - name: Get short commit SHA + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + SHA="${{ github.event.pull_request.head.sha }}" + else + SHA="${{ github.sha }}" + fi + echo "SHA=$(git rev-parse --short $SHA)" >> $GITHUB_ENV + - name: Get current version (MAJOR.MINOR.PATCH) + id: current-version + run: echo "current_version=$(grep -Po '(?<=__version__ = ")[\d\w.]+(?=")' rdmo/__init__.py)" >> $GITHUB_OUTPUT + - name: Generate new version (current version + SHA) + id: new-version + run: echo "new_version=${{ steps.current-version.outputs.current_version }}+$SHA" >> $GITHUB_OUTPUT + - name: Update version in rdmo/__init__.py + run: | + sed -i "s/__version__ = .*/__version__ = \"${{ steps.new-version.outputs.new_version }}\"/" rdmo/__init__.py + # build the webpack bundle + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: npm + - run: npm install && npm run build:prod + # build the wheel + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: pip + - run: | + python -m pip install --upgrade pip build[uv] twine + python -m pip --version + - name: Build the wheel + run: python -m build --installer=uv + - name: Check the metadata of wheel and sdist + run: python -m twine check --strict dist/* + - name: Install package from built wheel + run: python -m pip install --no-compile dist/rdmo*.whl # do not create __pycache__/*.pyc files + - name: Write info to step summary + run: | + { + echo -e "# ✓ Wheel successfully built (v${{ steps.new-version.outputs.new_version }})\n\n" + echo '
Information about installed wheel' + echo -e "\n\`\`\`console" + echo "$ python -m pip show --files --verbose rdmo" + python -m pip show --files --verbose rdmo + echo -e "\`\`\`\n
" + } >> $GITHUB_STEP_SUMMARY + - name: Upload wheel as artifact + uses: actions/upload-artifact@v4 + with: + name: wheel + path: dist/rdmo*.whl + if-no-files-found: error + retention-days: 30 + test: + name: "Test (Python: ${{ matrix.python-version }}, DB: ${{ matrix.db-backend }})" + needs: build-wheel runs-on: ubuntu-24.04 strategy: matrix: python-version: ['3.8', '3.12'] db-backend: [mysql, postgres] - name: "Test (Python: ${{ matrix.python-version }}, DB: ${{ matrix.db-backend }})" - needs: lint steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -53,32 +114,35 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: pip + - name: Download wheel + uses: actions/download-artifact@v4 + with: + name: wheel + path: dist - name: Install Dependencies run: | - sudo apt update - sudo apt install --yes pandoc texlive-xetex librsvg2-bin - python -m pip install --upgrade pip + sudo apt-get update && sudo apt-get install --yes pandoc texlive-xetex librsvg2-bin pandoc --version - - name: Install rdmo[mysql] and start mysql + python -m pip install --upgrade pip + python -m pip --version + - name: Install rdmo[mysql] from wheel and start mysql run: | - python -m pip install --editable .[ci,mysql] + python -m pip install "$(ls dist/*.whl)[ci,mysql]" sudo systemctl start mysql.service if: matrix.db-backend == 'mysql' - - name: Install rdmo[postgres] and start postgresql + - name: Install rdmo[postgres] from wheel and start postgresql run: | - python -m pip install --editable .[ci,postgres] + python -m pip install "$(ls dist/*.whl)[ci,postgres]" sudo systemctl start postgresql.service pg_isready sudo -u postgres psql --command="CREATE USER postgres_user PASSWORD 'postgres_password' CREATEDB" if: matrix.db-backend == 'postgres' - name: Prepare Env run: | - cp -r testing/media testing/media_root - mkdir testing/log + cp -r testing/media testing/media_root && mkdir testing/log - name: Run package status tests first run: | - pytest rdmo/core/tests/test_package_status.py::test_package_json_and_pre_commit_versions_match \ - --nomigrations --verbose + pytest rdmo/core/tests/test_package_status.py --nomigrations --verbose if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres' - name: Run Tests run: | @@ -90,22 +154,48 @@ jobs: with: flag-name: '${{ matrix.db-backend }}: ${{ matrix.python-version }}' parallel: true - # end-to-end tests - - uses: actions/setup-node@v4 + + test-e2e: + name: "End-to-end Test (Python: ${{ matrix.python-version }}, DB: ${{ matrix.db-backend }})" + needs: build-wheel + runs-on: ubuntu-24.04 + strategy: + matrix: + python-version: ['3.12'] + db-backend: [postgres] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 with: - node-version: 18 - cache: npm - if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres' + python-version: ${{ matrix.python-version }} + cache: pip + - name: Download wheel + uses: actions/download-artifact@v4 + with: + name: wheel + path: dist + - name: Install Dependencies + run: | + sudo apt-get update && sudo apt install --yes pandoc texlive-xetex librsvg2-bin + python -m pip install --upgrade pip + - name: Install rdmo[postgres] from wheel and start postgresql + run: | + python -m pip install "$(ls dist/*.whl)[ci,postgres]" + sudo systemctl start postgresql.service + pg_isready + sudo -u postgres psql --command="CREATE USER postgres_user PASSWORD 'postgres_password' CREATEDB" + - name: Prepare Env + run: | + cp -r testing/media testing/media_root && mkdir testing/log - name: Install e2e tests dependencies run: | - npm install - npm run build:prod - playwright install chromium - if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres' + playwright install --with-deps chromium - run: mkdir screenshots + - name: Collect static files into static root (only required if rdmo is installed from wheel) + run: python testing/manage.py collectstatic --noinput - name: Run end-to-end tests run: pytest -p randomly -p no:cacheprovider --reuse-db --numprocesses=auto --dist=loadscope -m e2e --nomigrations - if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres' env: DJANGO_DEBUG: True GITHUB_DB_BACKEND: ${{ matrix.db-backend }} @@ -113,7 +203,6 @@ jobs: with: name: screenshots path: screenshots/*.png - if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres' coveralls: name: Indicate completion to coveralls @@ -126,68 +215,6 @@ jobs: with: parallel-finished: true - build-wheel: - name: Build python wheel - needs: test - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - # update the version - - name: Get short commit SHA - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - SHA="${{ github.event.pull_request.head.sha }}" - else - SHA="${{ github.sha }}" - fi - echo "SHA=$(git rev-parse --short $SHA)" >> $GITHUB_ENV - - name: Get current version (MAJOR.MINOR.PATCH) - id: current-version - run: echo "current_version=$(grep -Po '(?<=__version__ = ")[\d\w.]+(?=")' rdmo/__init__.py)" >> $GITHUB_OUTPUT - - name: Generate new version (current version + SHA) - id: new-version - run: echo "new_version=${{ steps.current-version.outputs.current_version }}+$SHA" >> $GITHUB_OUTPUT - - name: Update version in rdmo/__init__.py - run: | - sed -i "s/__version__ = .*/__version__ = \"${{ steps.new-version.outputs.new_version }}\"/" rdmo/__init__.py - # build the webpack bundle - - uses: actions/setup-node@v4 - with: - node-version: 18 - cache: npm - - run: npm install && npm run build:prod - # build the wheel - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - cache: pip - - run: | - python -m pip install --upgrade pip build[uv] twine - pip --version - - name: Build the wheel - run: python -m build --installer=uv - - name: Check the metadata of wheel and sdist - run: python -m twine check --strict dist/* - - name: Install package from built wheel - run: python -m pip install --no-compile dist/rdmo*.whl # do not create __pycache__/*.pyc files - - name: Write info to step summary - run: | - { - echo -e "# ✓ Wheel successfully built (v${{ steps.new-version.outputs.new_version }})\n\n" - echo '
Information about installed wheel' - echo -e "\n\`\`\`console" - echo "$ python -m pip show --files --verbose rdmo" - python -m pip show --files --verbose rdmo - echo -e "\`\`\`\n
" - } >> $GITHUB_STEP_SUMMARY - - name: Upload wheel as artifact - uses: actions/upload-artifact@v4 - with: - name: wheel - path: dist/rdmo*.whl - if-no-files-found: error - retention-days: 30 - dev-setup: # Ref: structlog (MIT licensed) name: "Test dev setup on ${{ matrix.os }}" @@ -206,6 +233,7 @@ jobs: dependencies: name: Test installation of all dependencies + needs: build-wheel runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -213,12 +241,18 @@ jobs: with: python-version: "3.12" cache: pip + - name: Download wheel + uses: actions/download-artifact@v4 + with: + name: wheel + path: dist - name: Install os requirements for python-ldap - run: | - sudo apt update - sudo apt install --yes libldap2-dev libsasl2-dev + run: sudo apt-get update && sudo apt-get install --yes libldap2-dev libsasl2-dev - run: python -m pip install --upgrade pip - - run: python -m pip install .[allauth,ci,dev,gunicorn,ldap,mysql,postgres,pytest] + - name: Install rdmo wheel with all optional dependency groups + run: python -m pip install --no-compile "$(ls dist/*.whl)[allauth,ci,dev,gunicorn,ldap,mysql,postgres,pytest]" + - name: Verify installed packages have compatible dependencies + run: python -m pip check - uses: actions/setup-node@v4 with: node-version: 18 @@ -254,9 +288,10 @@ jobs: if: always() needs: - lint + - build-wheel - test - coveralls - - build-wheel + - test-e2e - dev-setup - dependencies runs-on: ubuntu-24.04 diff --git a/rdmo/management/tests/conftest.py b/rdmo/management/tests/conftest.py deleted file mode 100644 index 79cbc2d4aa..0000000000 --- a/rdmo/management/tests/conftest.py +++ /dev/null @@ -1,49 +0,0 @@ -import pytest - -from django.core.management import call_command - -from playwright.sync_api import BrowserType, Page, expect -from pytest_django.live_server_helper import LiveServer - -from rdmo.accounts.utils import set_group_permissions - - -@pytest.fixture -def _e2e_tests_django_db_setup(django_db_setup, django_db_blocker, fixtures): - """Set up database and populate with fixtures, that get restored for every test case.""" - with django_db_blocker.unblock(): - call_command("loaddata", *fixtures) - set_group_permissions() - - - -@pytest.fixture -def base_url_page(live_server: LiveServer, browser: BrowserType) -> Page: - """Enable playwright to address URLs with base URL automatically prefixed.""" - context = browser.new_context(base_url=live_server.url) - page = context.new_page() - yield page - context.close() - - -# helper function for logging in the user -def login_user(page: Page, username: str, password: str) -> Page: - page.goto("/account/login") - page.get_by_label("Username").fill(username, timeout=5000) - page.get_by_label("Password").fill(password) - page.get_by_role("button", name="Login").click() - page.goto("/management") - return page - -def logout_user(page: Page): - page.goto("/account/logout") - page.get_by_role("button", name="Logout").click() - expect(page).to_have_url('/') - return page - -@pytest.fixture -def logged_in_user(_e2e_tests_django_db_setup, base_url_page, username:str, password: str) -> Page: - """Log in as admin user through Django login UI, returns logged in page for e2e tests.""" - page = login_user(base_url_page, username, password) - yield page - logout_user(page) diff --git a/rdmo/management/tests/e2e/__init__.py b/rdmo/management/tests/e2e/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rdmo/management/tests/e2e/conftest.py b/rdmo/management/tests/e2e/conftest.py new file mode 100644 index 0000000000..44d1321a2f --- /dev/null +++ b/rdmo/management/tests/e2e/conftest.py @@ -0,0 +1,72 @@ +import os + +import pytest + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.management import call_command +from django.test import Client + +from playwright.sync_api import Page + +from rdmo.accounts.utils import set_group_permissions + +USERNAME = "editor" # the user needs exist in the database +PLAYWRIGHT_TIMEOUT = 10_000 # timeout in ms + + +@pytest.fixture(scope="session", autouse=True) +def _set_django_allow_async_unsafe(): + """pytest-playwright needs this setting to be enabled.""" + os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") + + +@pytest.fixture +def django_db_setup(django_db_setup, django_db_blocker, fixtures): # noqa: PT004 - pytest-django requires this name "django_db_setup" + """Set up database and populate with fixtures, that get restored for every test case. + + This fixture overrides the django_db_setup in the main conftest.py, this only applies to the e2e tests + in this directory. + """ + with django_db_blocker.unblock(): + call_command("loaddata", *fixtures, verbosity=0) + set_group_permissions() + + +@pytest.fixture +def authenticated_client(db) -> Client: + """An authenticated test client, used to bypass the login page.""" + user = get_user_model().objects.get(username=USERNAME) + client = Client() + client.user = user # attach user to client to access in other fixtures + client.force_login(user) + return client + + +@pytest.fixture +def page(live_server, browser, authenticated_client) -> Page: + """An authenticated playwright page. + + The page is authenticated with session cookies from authenticated_client. + The page has access to the live server and starts at "/management". + The page has the authenticated user attached to it. + """ + + # retrieve the session cookie from the authenticated client + session_cookie = authenticated_client.cookies[settings.SESSION_COOKIE_NAME] + cookie = { + "name": session_cookie.key, + "value": session_cookie.value, + "url": live_server.url, + } + context = browser.new_context(base_url=live_server.url) + # the browser context is now "authenticated" with the session cookie + context.add_cookies([cookie]) + page = context.new_page() + page.set_default_timeout(PLAYWRIGHT_TIMEOUT) + page.set_default_navigation_timeout(PLAYWRIGHT_TIMEOUT) + page.user = authenticated_client.user # attach user to page to access in tests + # the page starts at base_url + /management + page.goto("/management") + yield page + context.close() diff --git a/rdmo/management/tests/test_frontend_import_options.py b/rdmo/management/tests/e2e/test_frontend_import_options.py similarity index 76% rename from rdmo/management/tests/test_frontend_import_options.py rename to rdmo/management/tests/e2e/test_frontend_import_options.py index 2cf980de61..b3f2dab3ba 100644 --- a/rdmo/management/tests/test_frontend_import_options.py +++ b/rdmo/management/tests/e2e/test_frontend_import_options.py @@ -1,46 +1,35 @@ # ruff: noqa: F811 -import os - import pytest from playwright.sync_api import Page, expect +from rdmo.management.tests.helpers_import_elements import IMPORT_ELEMENT_PANELS_LOCATOR +from rdmo.management.tests.helpers_models import delete_all_objects from rdmo.options.models import Option, OptionSet -from .helpers_import_elements import IMPORT_ELEMENT_PANELS_LOCATOR -from .helpers_models import delete_all_objects - pytestmark = pytest.mark.e2e -# needed for playwright to run -os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") - -test_users = [('editor', 'editor')] import_xml = "./testing/xml/elements/optionsets.xml" import_xml_1 = "./testing/xml/elements/updated-and-changed/optionsets-1.xml" -OPTIONSETS_COUNTS = { - "total": 13, - "updated": 13, - "changed": 5, - "warnings": 2 -} -OPTIONSETS_COUNTS_HEADER_INFOS = [f"{k.capitalize()}: {v}" for k,v in OPTIONSETS_COUNTS.items()] +OPTIONSETS_COUNTS = {"total": 13, "updated": 13, "changed": 5, "warnings": 2} +OPTIONSETS_COUNTS_HEADER_INFOS = [f"{k.capitalize()}: {v}" for k, v in OPTIONSETS_COUNTS.items()] # Defined in filterCheckBoxText in rdmo/management/assets/js/components/import/common/ImportFilters.js IMPORT_FILTER_LABEL_TEXT = 'Show only new and changed elements (%s)' -@pytest.mark.parametrize("username,password", test_users) # consumed by fixture -def test_import_and_update_optionsets_in_management(logged_in_user: Page) -> None: + +def test_import_and_update_optionsets_in_management(page: Page) -> None: """Test that each content type is available through the navigation.""" delete_all_objects([OptionSet, Option]) - page = logged_in_user expect(page.get_by_role("heading", name="Management")).to_be_visible() expect(page.locator("strong").filter(has_text="Catalogs")).to_be_visible() ## 1. Import fresh optionset.xml # choose the file to be imported - page.locator("input[name=\"uploaded_file\"]").set_input_files(import_xml) + page.locator('input[name="uploaded_file"]').set_input_files(import_xml) # click the import form submit button, this will take some time - page.locator('#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary').click() # noqa: E501 + page.locator( + "#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary" + ).click() # wait for import to be finished with timeout 30s expect(page.get_by_text("Import from: optionsets.xml")).to_be_visible(timeout=30_000) ## TODO test if ImportInfo numbers are correct @@ -51,7 +40,7 @@ def test_import_and_update_optionsets_in_management(logged_in_user: Page) -> Non page.get_by_role("link", name="Select all", exact=True).click() page.get_by_role("link", name="Show all", exact=True).click() rows_displayed_in_ui = page.locator(IMPORT_ELEMENT_PANELS_LOCATOR) - expect(rows_displayed_in_ui).to_have_count(OPTIONSETS_COUNTS['total']) + expect(rows_displayed_in_ui).to_have_count(OPTIONSETS_COUNTS["total"]) # click the import button to start saving the instances to the db page.get_by_role("button", name=f"Import {OPTIONSETS_COUNTS['total']} elements").click() expect(page.get_by_role("heading", name="Import successful")).to_be_visible() @@ -66,9 +55,11 @@ def test_import_and_update_optionsets_in_management(logged_in_user: Page) -> Non ## 2. import optionset-1.xml with changes # choose the file to be imported - page.locator("input[name=\"uploaded_file\"]").set_input_files(import_xml_1) + page.locator('input[name="uploaded_file"]').set_input_files(import_xml_1) # click the import form submit button, this will take some time - page.locator('#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary').click() # noqa: E501 + page.locator( + "#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary" + ).click() expect(page.get_by_text("Import from: optionsets-1.xml")).to_be_visible(timeout=40_000) # assert changed elements for text in OPTIONSETS_COUNTS_HEADER_INFOS: diff --git a/rdmo/management/tests/test_frontend_import_questions.py b/rdmo/management/tests/e2e/test_frontend_import_questions.py similarity index 75% rename from rdmo/management/tests/test_frontend_import_questions.py rename to rdmo/management/tests/e2e/test_frontend_import_questions.py index 7b04e42489..3de152050c 100644 --- a/rdmo/management/tests/test_frontend_import_questions.py +++ b/rdmo/management/tests/e2e/test_frontend_import_questions.py @@ -1,36 +1,30 @@ # ruff: noqa: F811 -import os - import pytest -from playwright.sync_api import Page, expect +from playwright.sync_api import expect +from rdmo.management.tests.helpers_import_elements import IMPORT_ELEMENT_PANELS_LOCATOR_SHOWN +from rdmo.management.tests.helpers_models import delete_all_objects from rdmo.questions.models import Catalog, Question, Section from rdmo.questions.models import Page as PageModel from rdmo.questions.models.questionset import QuestionSet -from .helpers_import_elements import IMPORT_ELEMENT_PANELS_LOCATOR_SHOWN -from .helpers_models import delete_all_objects - pytestmark = pytest.mark.e2e -# needed for playwright to run -os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") -test_users = [('editor', 'editor')] - -@pytest.mark.parametrize("username,password", test_users) # consumed by fixture -def test_import_catalogs_in_management(logged_in_user: Page) -> None: +def test_import_catalogs_in_management(page) -> None: """Test that the catalogs.xml can be imported correctly.""" + delete_all_objects([Catalog, Section, PageModel, QuestionSet, Question]) - page = logged_in_user expect(page.get_by_role("heading", name="Management")).to_be_visible() expect(page.locator("strong").filter(has_text="Catalogs")).to_be_visible() # choose the file to be imported - page.locator("input[name=\"uploaded_file\"]").set_input_files("./testing/xml/elements/catalogs.xml") + page.locator('input[name="uploaded_file"]').set_input_files("./testing/xml/elements/catalogs.xml") # click the import form submit button, this will take some time - page.locator('#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary').click() # noqa: E501 + page.locator( + "#sidebar div.elements-sidebar form.upload-form.sidebar-form div.sidebar-form-button button.btn.btn-primary" + ).click() # wait for import to be finished with timeout 30s expect(page.get_by_text("Import from: catalogs.xml")).to_be_visible(timeout=30_000) ## TODO test if ImportInfo numbers are correct diff --git a/rdmo/management/tests/test_frontend_management_elements.py b/rdmo/management/tests/e2e/test_frontend_management_elements.py similarity index 75% rename from rdmo/management/tests/test_frontend_management_elements.py rename to rdmo/management/tests/e2e/test_frontend_management_elements.py index e735598e9c..47c51e9483 100644 --- a/rdmo/management/tests/test_frontend_management_elements.py +++ b/rdmo/management/tests/e2e/test_frontend_management_elements.py @@ -1,5 +1,4 @@ # ruff: noqa: F811 -import os import re from urllib.parse import urlparse @@ -9,22 +8,15 @@ from rdmo.conditions.models import Condition from rdmo.domain.models import Attribute +from rdmo.management.tests.helpers_models import ModelHelper, model_helpers from rdmo.questions.models import Catalog -from .helpers_models import ModelHelper, model_helpers - pytestmark = pytest.mark.e2e -# needed for playwright to run -os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") - -test_users = [('editor', 'editor')] -@pytest.mark.parametrize("username,password", test_users) @pytest.mark.parametrize("helper", model_helpers) -def test_management_navigation(logged_in_user: Page, helper: ModelHelper, username: str, password: str) -> None: +def test_management_navigation(page: Page, helper: ModelHelper) -> None: """Test that each content type is available through the navigation.""" - page = logged_in_user expect(page.get_by_role("heading", name="Management")).to_be_visible() # click a link in the navigation @@ -43,25 +35,18 @@ def test_management_navigation(logged_in_user: Page, helper: ModelHelper, userna page.screenshot(path="screenshots/management-navigation-catalog.png", full_page=True) - -@pytest.mark.parametrize("username,password", test_users) @pytest.mark.parametrize("helper", model_helpers) -def test_management_has_items(logged_in_user: Page, helper: ModelHelper) -> None: +def test_management_has_items(page: Page, helper: ModelHelper) -> None: """Test all items in database are visible in management UI.""" - page = logged_in_user num_items_in_database = helper.model.objects.count() page.goto(f"/management/{helper.url}") items_in_ui = page.locator(".list-group > .list-group-item") expect(items_in_ui).to_have_count(num_items_in_database) -@pytest.mark.parametrize("username,password", test_users) @pytest.mark.parametrize("helper", model_helpers) -def test_management_nested_view( - logged_in_user: Page, helper: ModelHelper -) -> None: +def test_management_nested_view(page: Page, helper: ModelHelper) -> None: """For each element type, that has a nested view, click the first example.""" - page = logged_in_user page.goto(f"/management/{helper.url}") # Open nested view for element type if helper.has_nested: @@ -70,13 +55,9 @@ def test_management_nested_view( expect(page.locator(".panel-default > .panel-body").first).to_be_visible() -@pytest.mark.parametrize("username,password", test_users) @pytest.mark.parametrize("helper", model_helpers) -def test_management_create_model( - logged_in_user: Page, helper: ModelHelper -) -> None: +def test_management_create_model(page: Page, helper: ModelHelper) -> None: """Test management UI can create objects in the database.""" - page = logged_in_user num_objects_at_start = helper.model.objects.count() page.goto(f"/management/{helper.url}") # click "New" button @@ -86,11 +67,7 @@ def test_management_create_model( page.get_by_label(helper.form_field).fill(value) if helper.model == Condition: # conditions need to have a source attribute - source_form = ( - page.locator(".form-group") - .filter(has_text="Source") - .locator(".select-item > .react-select") - ) + source_form = page.locator(".form-group").filter(has_text="Source").locator(".select-item > .react-select") source_form.click() page.keyboard.type(Attribute.objects.first().uri) page.keyboard.press("Enter") @@ -107,10 +84,8 @@ def test_management_create_model( assert helper.model.objects.get(**query) -@pytest.mark.parametrize("username,password", test_users) @pytest.mark.parametrize("helper", model_helpers) -def test_management_edit_model(logged_in_user: Page, helper: ModelHelper) -> None: - page = logged_in_user +def test_management_edit_model(page: Page, helper: ModelHelper) -> None: page.goto(f"/management/{helper.url}") # click edit edit_button_title = f"Edit {helper.verbose_name}" diff --git a/testing/manage.py b/testing/manage.py new file mode 100644 index 0000000000..0004541852 --- /dev/null +++ b/testing/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv)