feat: comprehensive Playwright E2E test suite #7
@@ -97,12 +97,14 @@ jobs:
|
|||||||
- name: Start app with seeded content
|
- name: Start app with seeded content
|
||||||
run: |
|
run: |
|
||||||
docker run -d --name pr-e2e-app --network container:pr-e2e-postgres \
|
docker run -d --name pr-e2e-app --network container:pr-e2e-postgres \
|
||||||
|
-v /opt/playwright-tools/browsers:/opt/playwright-tools/browsers:ro \
|
||||||
-e SECRET_KEY=ci-secret-key \
|
-e SECRET_KEY=ci-secret-key \
|
||||||
-e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \
|
-e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \
|
||||||
-e CONSENT_POLICY_VERSION=1 \
|
-e CONSENT_POLICY_VERSION=1 \
|
||||||
-e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \
|
-e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \
|
||||||
-e DEFAULT_FROM_EMAIL=hello@nohypeai.com \
|
-e DEFAULT_FROM_EMAIL=hello@nohypeai.com \
|
||||||
-e NEWSLETTER_PROVIDER=buttondown \
|
-e NEWSLETTER_PROVIDER=buttondown \
|
||||||
|
-e PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-tools/browsers \
|
||||||
"$CI_IMAGE" \
|
"$CI_IMAGE" \
|
||||||
sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000"
|
sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000"
|
||||||
for i in $(seq 1 40); do
|
for i in $(seq 1 40); do
|
||||||
@@ -114,9 +116,6 @@ jobs:
|
|||||||
docker logs pr-e2e-app || true
|
docker logs pr-e2e-app || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
|
||||||
run: docker exec pr-e2e-app python -m playwright install chromium
|
|
||||||
|
|
||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
run: |
|
run: |
|
||||||
docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 pr-e2e-app \
|
docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 pr-e2e-app \
|
||||||
@@ -159,12 +158,14 @@ jobs:
|
|||||||
- name: Start dev server with seeded content
|
- name: Start dev server with seeded content
|
||||||
run: |
|
run: |
|
||||||
docker run -d --name nightly-e2e --network container:nightly-postgres \
|
docker run -d --name nightly-e2e --network container:nightly-postgres \
|
||||||
|
-v /opt/playwright-tools/browsers:/opt/playwright-tools/browsers:ro \
|
||||||
-e SECRET_KEY=ci-secret-key \
|
-e SECRET_KEY=ci-secret-key \
|
||||||
-e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \
|
-e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \
|
||||||
-e CONSENT_POLICY_VERSION=1 \
|
-e CONSENT_POLICY_VERSION=1 \
|
||||||
-e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \
|
-e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \
|
||||||
-e DEFAULT_FROM_EMAIL=hello@nohypeai.com \
|
-e DEFAULT_FROM_EMAIL=hello@nohypeai.com \
|
||||||
-e NEWSLETTER_PROVIDER=buttondown \
|
-e NEWSLETTER_PROVIDER=buttondown \
|
||||||
|
-e PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-tools/browsers \
|
||||||
"$CI_IMAGE" \
|
"$CI_IMAGE" \
|
||||||
sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000"
|
sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000"
|
||||||
for i in $(seq 1 40); do
|
for i in $(seq 1 40); do
|
||||||
@@ -177,7 +178,6 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
- name: Run Playwright E2E tests
|
- name: Run Playwright E2E tests
|
||||||
run: |
|
run: |
|
||||||
docker exec nightly-e2e python -m playwright install chromium
|
|
||||||
docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 nightly-e2e \
|
docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 nightly-e2e \
|
||||||
pytest e2e/ apps/core/tests/test_nightly_e2e_playwright.py -o addopts='' -q --tb=short
|
pytest e2e/ apps/core/tests/test_nightly_e2e_playwright.py -o addopts='' -q --tb=short
|
||||||
- name: Remove nightly container
|
- name: Remove nightly container
|
||||||
|
|||||||
@@ -129,5 +129,7 @@ class Command(BaseCommand):
|
|||||||
site.is_default_site = True
|
site.is_default_site = True
|
||||||
site.site_name = "No Hype AI"
|
site.site_name = "No Hype AI"
|
||||||
site.save()
|
site.save()
|
||||||
|
# Remove any other conflicting default-site entries left by test fixtures
|
||||||
|
Site.objects.exclude(pk=site.pk).filter(is_default_site=True).update(is_default_site=False)
|
||||||
|
|
||||||
self.stdout.write(self.style.SUCCESS("Seeded E2E content."))
|
self.stdout.write(self.style.SUCCESS("Seeded E2E content."))
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ services:
|
|||||||
python manage.py runserver 0.0.0.0:8000"
|
python manage.py runserver 0.0.0.0:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
|
- /opt/playwright-tools/browsers:/opt/playwright-tools/browsers:ro
|
||||||
ports:
|
ports:
|
||||||
- "8035:8000"
|
- "8035:8000"
|
||||||
environment:
|
environment:
|
||||||
@@ -21,6 +22,7 @@ services:
|
|||||||
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
|
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
|
||||||
DEFAULT_FROM_EMAIL: hello@nohypeai.com
|
DEFAULT_FROM_EMAIL: hello@nohypeai.com
|
||||||
NEWSLETTER_PROVIDER: buttondown
|
NEWSLETTER_PROVIDER: buttondown
|
||||||
|
PLAYWRIGHT_BROWSERS_PATH: /opt/playwright-tools/browsers
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def test_article_share_section_present(page: Page, base_url: str) -> None:
|
|||||||
def test_article_comments_section_present(page: Page, base_url: str) -> None:
|
def test_article_comments_section_present(page: Page, base_url: str) -> None:
|
||||||
_go_to_article(page, base_url)
|
_go_to_article(page, base_url)
|
||||||
# The article has comments_enabled=True
|
# The article has comments_enabled=True
|
||||||
expect(page.get_by_role("heading", name="Comments")).to_be_visible()
|
expect(page.get_by_role("heading", name="Comments", exact=True)).to_be_visible()
|
||||||
expect(page.get_by_role("button", name="Post comment")).to_be_visible()
|
expect(page.get_by_role("button", name="Post comment")).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
@@ -64,8 +64,9 @@ def test_article_related_section_present(page: Page, base_url: str) -> None:
|
|||||||
@pytest.mark.e2e
|
@pytest.mark.e2e
|
||||||
def test_copy_link_button_updates_text(page: Page, base_url: str) -> None:
|
def test_copy_link_button_updates_text(page: Page, base_url: str) -> None:
|
||||||
_go_to_article(page, base_url)
|
_go_to_article(page, base_url)
|
||||||
copy_btn = page.get_by_role("button", name="Copy link")
|
copy_btn = page.locator("[data-copy-link]")
|
||||||
expect(copy_btn).to_be_visible()
|
expect(copy_btn).to_be_visible()
|
||||||
|
# Force-override clipboard so writeText always resolves, even in non-HTTPS headless context
|
||||||
|
page.evaluate("navigator.clipboard.writeText = () => Promise.resolve()")
|
||||||
copy_btn.click()
|
copy_btn.click()
|
||||||
# Clipboard polyfill in conftest ensures writeText resolves; button shows "Copied"
|
|
||||||
expect(copy_btn).to_have_text("Copied")
|
expect(copy_btn).to_have_text("Copied")
|
||||||
|
|||||||
@@ -54,6 +54,6 @@ def test_comments_section_absent_when_disabled(page: Page, base_url: str) -> Non
|
|||||||
)
|
)
|
||||||
# Confirm we're on the right page
|
# Confirm we're on the right page
|
||||||
expect(page.get_by_role("heading", level=1)).to_have_text("No Comments Article")
|
expect(page.get_by_role("heading", level=1)).to_have_text("No Comments Article")
|
||||||
# Comments section must be absent
|
# Comments section must be absent — exact=True prevents matching "No Comments Article" h1
|
||||||
expect(page.get_by_role("heading", name="Comments")).to_have_count(0)
|
expect(page.get_by_role("heading", name="Comments", exact=True)).to_have_count(0)
|
||||||
expect(page.get_by_role("button", name="Post comment")).to_have_count(0)
|
expect(page.get_by_role("button", name="Post comment")).to_have_count(0)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pytest-benchmark~=4.0.0
|
|||||||
factory-boy~=3.3.0
|
factory-boy~=3.3.0
|
||||||
wagtail-factories~=4.2.0
|
wagtail-factories~=4.2.0
|
||||||
feedparser~=6.0.0
|
feedparser~=6.0.0
|
||||||
playwright~=1.52.0
|
playwright~=1.57.0
|
||||||
pytest-playwright~=0.7.0
|
pytest-playwright~=0.7.0
|
||||||
ruff~=0.6.0
|
ruff~=0.6.0
|
||||||
mypy~=1.11.0
|
mypy~=1.11.0
|
||||||
|
|||||||
Reference in New Issue
Block a user