|
3 | 3 | import pytest |
4 | 4 | from playwright.sync_api import Browser, Page, ViewportSize, expect |
5 | 5 |
|
| 6 | +from content.docs_projection import docs_projection |
6 | 7 | from content.public_data import public_projection |
7 | 8 |
|
8 | 9 | pytestmark = [pytest.mark.core, pytest.mark.django_db(transaction=True)] |
@@ -112,6 +113,68 @@ def test_public_home_and_hubs( |
112 | 113 | ) |
113 | 114 |
|
114 | 115 |
|
| 116 | +@pytest.mark.core |
| 117 | +@pytest.mark.parametrize( |
| 118 | + "viewport", |
| 119 | + [{"width": 1280, "height": 800}, {"width": 390, "height": 844}], |
| 120 | +) |
| 121 | +def test_docs_and_faq_root_trailing_slash_browser_contract( |
| 122 | + page: Page, |
| 123 | + live_server, |
| 124 | + viewport: ViewportSize, |
| 125 | +) -> None: |
| 126 | + page.set_viewport_size(viewport) |
| 127 | + origin = live_server.url |
| 128 | + query = "utm_source=oncall%2Btest&x=a%2Fb&blank=" |
| 129 | + |
| 130 | + for final_path, alias_path, heading in ( |
| 131 | + ("/docs/", "/docs", "DataTalks.Club Zoomcamps Notes and Resources"), |
| 132 | + ("/faq/", "/faq", "Frequently Asked Questions"), |
| 133 | + ): |
| 134 | + alias = page.request.get(f"{origin}{alias_path}?{query}", max_redirects=0) |
| 135 | + assert alias.status == 301 |
| 136 | + assert alias.headers["location"] == f"{final_path}?{query}" |
| 137 | + head = page.request.head(f"{origin}{alias_path}?{query}", max_redirects=0) |
| 138 | + assert head.status == 301 |
| 139 | + assert head.headers["location"] == f"{final_path}?{query}" |
| 140 | + |
| 141 | + response = page.goto(f"{origin}{final_path}?{query}", wait_until="networkidle") |
| 142 | + assert response is not None and response.status == 200 |
| 143 | + assert "location" not in response.headers |
| 144 | + expect(page).to_have_url(f"{origin}{final_path}?{query}") |
| 145 | + expect(page.get_by_role("heading", name=heading, exact=True)).to_be_visible() |
| 146 | + expect(page.locator('link[rel="canonical"]')).to_have_attribute( |
| 147 | + "href", f"https://datatalks.club{final_path}" |
| 148 | + ) |
| 149 | + expect(page.locator('meta[property="og:url"]')).to_have_attribute( |
| 150 | + "content", f"https://datatalks.club{final_path}" |
| 151 | + ) |
| 152 | + expect(page.locator(f'a[href="{final_path}"]')).to_have_count(1) |
| 153 | + expect(page.locator(f'a[href="{alias_path}"]')).to_have_count(0) |
| 154 | + |
| 155 | + redirected = page.goto(f"{origin}{alias_path}?{query}", wait_until="networkidle") |
| 156 | + assert redirected is not None and redirected.status == 200 |
| 157 | + expect(page).to_have_url(f"{origin}{final_path}?{query}") |
| 158 | + |
| 159 | + docs_detail = page.goto( |
| 160 | + f"{origin}/docs/courses/ai-dev-tools-zoomcamp/getting-started/", |
| 161 | + wait_until="networkidle", |
| 162 | + ) |
| 163 | + assert docs_detail is not None and docs_detail.status == 200 |
| 164 | + assert page.locator('a[href="/docs/"]').count() >= 1 |
| 165 | + docs_asset_path = docs_projection()["assets"][0]["public_path"] |
| 166 | + docs_asset = page.request.get(f"{origin}{docs_asset_path}") |
| 167 | + assert docs_asset.status == 200 |
| 168 | + |
| 169 | + faq_detail = page.goto(f"{origin}/faq/ai-dev-tools-zoomcamp.html", wait_until="networkidle") |
| 170 | + assert faq_detail is not None and faq_detail.status == 200 |
| 171 | + assert page.locator('a[href="/faq/"]').count() >= 1 |
| 172 | + faq_courses = page.request.get(f"{origin}/faq/json/courses.json") |
| 173 | + assert faq_courses.status == 200 |
| 174 | + faq_course = page.request.get(f"{origin}/faq/json/ai-dev-tools-zoomcamp.json") |
| 175 | + assert faq_course.status == 200 |
| 176 | + |
| 177 | + |
115 | 178 | @pytest.mark.core |
116 | 179 | @pytest.mark.parametrize( |
117 | 180 | ("viewport", "suffix"), |
|
0 commit comments