Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support live server tests with Selenium #2077

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ updates:
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
- dependency-name: "*puppeteer*"
update-types: ["version-update:semver-minor"]
- dependency-name: "sass"
update-types: ["version-update:semver-minor"]
- dependency-name: "@types/sortablejs"
Expand Down
85 changes: 29 additions & 56 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,35 @@ jobs:
- name: Run tests
run: python manage.py test --shuffle

test_frontend:
name: Test Frontend

runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4
with:
submodules: true

- uses: ./.github/setup_evap
with:
shell: .#evap-frontend-dev
start-db: true

- name: Compile assets
run: |
./manage.py ts compile
./manage.py scss
./manage.py collectstatic --noinput

- name: Run tests (shuffled)
run: coverage run manage.py test --shuffle --tag live-server
- name: Upload coverage
uses: codecov/codecov-action@v5
with:
flags: frontend-tests
token: ${{ secrets.CODECOV_TOKEN }}

mypy:
runs-on: ubuntu-22.04

Expand Down Expand Up @@ -144,62 +173,6 @@ jobs:
name: css
path: evap/static/css/evap.css

render_pages:
runs-on: ubuntu-22.04

name: Render Html pages

steps:
- uses: actions/checkout@v4
- uses: ./.github/setup_evap
with:
start-db: true

- name: Render pages
run: coverage run manage.py ts render_pages
- name: Upload coverage
uses: codecov/codecov-action@v5
with:
flags: render-pages
token: ${{ secrets.CODECOV_TOKEN }}
- name: Store rendered pages
uses: actions/upload-artifact@v4
with:
name: rendered-pages
path: evap/static/ts/rendered

typescript:
runs-on: ubuntu-22.04

needs: [ compile_scss, render_pages ]

name: Test Typescript

steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/setup_evap
with:
npm-ci: true

- run: npx puppeteer browsers install chrome

- name: Compile Typescript
run: npx tsc --project evap/static/ts/tsconfig.compile.json
- name: Load rendered pages
uses: actions/download-artifact@v4
with:
name: rendered-pages
path: evap/static/ts/rendered
- name: Load Css
uses: actions/download-artifact@v4
with:
name: css
path: evap/static/css
- name: Run tests
run: xvfb-run --auto-servernum npx jest

macos-nix-build:
runs-on: macos-14
name: Build nix environment on MacOS
Expand Down
2 changes: 1 addition & 1 deletion deployment/manage_autocompletion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# generated using
# ./manage.py | grep -v -E "^\[|^$" | tail -n +3 | sort | xargs
COMMANDS="admin_generator anonymize changepassword check clean_pyc clear_cache clearsessions collectstatic compile_pyc compilemessages create_command create_jobs create_template_tags createcachetable createsuperuser dbshell delete_squashed_migrations describe_form diffsettings drop_test_database dump_testdata dumpdata dumpscript export_emails find_template findstatic flush format generate_password generate_secret_key graph_models inspectdb lint list_model_info list_signals loaddata loaddata_unlogged mail_debug makemessages makemigrations managestate merge_model_instances migrate notes optimizemigration pipchecker precommit print_settings print_user_for_session raise_test_exception refresh_results_cache reload_testdata remove_stale_contenttypes reset_db reset_schema run runjob runjobs runprofileserver runscript runserver runserver_plus scss send_reminders sendtestemail set_default_site set_fake_emails set_fake_passwords shell shell_plus show_template_tags show_urls showmigrations sqlcreate sqldiff sqldsn sqlflush sqlmigrate sqlsequencereset squashmigrations startapp startproject sync_s3 syncdata test testserver tools translate ts typecheck unreferenced_files update_evaluation_states update_permissions validate_templates"
TS_COMMANDS="compile test render_pages"
TS_COMMANDS="compile test"

_managepy_complete()
{
Expand Down
20 changes: 0 additions & 20 deletions evap/contributor/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
WebTest,
WebTestWith200Check,
create_evaluation_with_responsible_and_editor,
render_pages,
submit_with_modal,
)

Expand Down Expand Up @@ -136,8 +135,6 @@ def test_without_questionnaires_assigned(self):


class TestContributorEvaluationEditView(WebTest):
render_pages_url = "/contributor/evaluation/PK/edit"

@classmethod
def setUpTestData(cls):
result = create_evaluation_with_responsible_and_editor()
Expand All @@ -146,23 +143,6 @@ def setUpTestData(cls):
cls.evaluation = result["evaluation"]
cls.url = f"/contributor/evaluation/{cls.evaluation.pk}/edit"

@render_pages
def render_pages(self):
self.evaluation.allow_editors_to_edit = False
self.evaluation.save()

content_without_allow_editors_to_edit = self.app.get(self.url, user=self.editor).content

self.evaluation.allow_editors_to_edit = True
self.evaluation.save()

content_with_allow_editors_to_edit = self.app.get(self.url, user=self.editor).content

return {
"normal": content_without_allow_editors_to_edit,
"allow_editors_to_edit": content_with_allow_editors_to_edit,
}

def test_not_authenticated(self):
"""
Asserts that an unauthorized user gets redirected to the login page.
Expand Down
26 changes: 0 additions & 26 deletions evap/evaluation/management/commands/ts.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import argparse
import os
import subprocess # nosec
import unittest

from django.conf import settings
from django.core.management import call_command
from django.core.management.base import BaseCommand, CommandError
from django.test.runner import DiscoverRunner


class RenderPagesRunner(DiscoverRunner):
"""Test runner which only includes `render_pages.*` methods.
The actual logic of the page rendering is implemented in the `@render_pages` decorator."""

test_loader = unittest.TestLoader()

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.test_loader.testMethodPrefix = "render_pages"


class Command(BaseCommand):
Expand All @@ -32,7 +19,6 @@ def add_arguments(self, parser: argparse.ArgumentParser):
self.add_fresh_argument(compile_parser)
test_parser = subparsers.add_parser("test")
self.add_fresh_argument(test_parser)
subparsers.add_parser("render_pages")

@staticmethod
def add_fresh_argument(parser: argparse.ArgumentParser):
Expand All @@ -48,8 +34,6 @@ def handle(self, *args, **options):
self.compile(**options)
elif options["command"] == "test":
self.test(**options)
elif options["command"] == "render_pages":
self.render_pages(**options)

def run_command(self, command):
try:
Expand Down Expand Up @@ -84,14 +68,4 @@ def compile(self, watch=False, fresh=False, **_options):
def test(self, **options):
call_command("scss")
self.compile(**options)
self.render_pages()
self.run_command(["npx", "jest"])

@staticmethod
def render_pages(**_options):
# Enable debug mode as otherwise a collectstatic beforehand would be necessary,
# as missing static files would result into an error.
test_runner = RenderPagesRunner(debug_mode=True)
failed_tests = test_runner.run_tests([])
if failed_tests > 0:
raise CommandError("Failures during render_pages")
4 changes: 1 addition & 3 deletions evap/evaluation/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,10 @@ def test_ts_compile_with_watch(self, mock_subprocess_run):

@patch("subprocess.run")
@patch("evap.evaluation.management.commands.ts.call_command")
@patch("evap.evaluation.management.commands.ts.Command.render_pages")
def test_ts_test(self, mock_render_pages, mock_call_command, mock_subprocess_run):
def test_ts_test(self, mock_call_command, mock_subprocess_run):
management.call_command("ts", "test")

# Mock render pages to prevent a second call into the test framework
mock_render_pages.assert_called_once()
mock_call_command.assert_called_once_with("scss")
mock_subprocess_run.assert_has_calls(
[
Expand Down
25 changes: 25 additions & 0 deletions evap/evaluation/tests/test_live.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.core import mail
from django.urls import reverse
from selenium.webdriver.common.by import By
from selenium.webdriver.support.expected_conditions import text_to_be_present_in_element, visibility_of_element_located

from evap.evaluation.tests.tools import LiveServerTest


class ContactModalTests(LiveServerTest):
def test_contact_modal(self) -> None:
self.selenium.get(self.live_server_url + reverse("evaluation:index"))
self.selenium.find_element(By.ID, "feedbackModalShowButton").click()
self.wait.until(visibility_of_element_located((By.ID, "feedbackModalMessageText")))
self.selenium.find_element(By.ID, "feedbackModalMessageText").send_keys("Test message")
self.selenium.find_element(By.ID, "feedbackModalActionButton").click()

self.wait.until(
text_to_be_present_in_element(
(By.CSS_SELECTOR, "#successMessageModal_feedbackModal .modal-body"),
"Your message was successfully sent.",
)
)
self.assertEqual(len(mail.outbox), 1)

self.assertEqual(mail.outbox[0].subject, f"[EvaP] Message from {self.manager.email}")
10 changes: 0 additions & 10 deletions evap/evaluation/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,10 @@
WebTestWith200Check,
create_evaluation_with_responsible_and_editor,
make_manager,
store_ts_test_asset,
)
from evap.staff.tests.utils import WebTestStaffMode


class RenderJsTranslationCatalog(WebTest):
url = reverse("javascript-catalog")

def render_pages(self):
# Not using render_pages decorator to manually create a single (special) javascript file
content = self.app.get(self.url).content
store_ts_test_asset("catalog.js", content)


@override_settings(PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"])
class TestIndexView(WebTest):
url = "/"
Expand Down
Loading