WebHost: fix links on sitemap, switch to url_for and add test to prevent future breakage (#5318)
This commit is contained in:
@@ -11,32 +11,32 @@
|
||||
<h1>Site Map</h1>
|
||||
<h2>Base Pages</h2>
|
||||
<ul>
|
||||
<li><a href="/discord">Discord Link</a></li>
|
||||
<li><a href="/faq/en">F.A.Q. Page</a></li>
|
||||
<li><a href="/favicon.ico">Favicon</a></li>
|
||||
<li><a href="/generate">Generate Game Page</a></li>
|
||||
<li><a href="/">Homepage</a></li>
|
||||
<li><a href="/uploads">Host Game Page</a></li>
|
||||
<li><a href="/datapackage">Raw Data Package</a></li>
|
||||
<li><a href="{{ url_for('check')}}">Settings Validator</a></li>
|
||||
<li><a href="/sitemap">Site Map</a></li>
|
||||
<li><a href="/start-playing">Start Playing</a></li>
|
||||
<li><a href="/games">Supported Games Page</a></li>
|
||||
<li><a href="/tutorial">Tutorials Page</a></li>
|
||||
<li><a href="/user-content">User Content</a></li>
|
||||
<li><a href="{{url_for('stats')}}">Game Statistics</a></li>
|
||||
<li><a href="/glossary/en">Glossary</a></li>
|
||||
<li><a href="{{url_for("show_session")}}">Session / Login</a></li>
|
||||
<li><a href="{{ url_for('discord') }}">Discord Link</a></li>
|
||||
<li><a href="{{ url_for('faq', lang='en') }}">F.A.Q. Page</a></li>
|
||||
<li><a href="{{ url_for('favicon') }}">Favicon</a></li>
|
||||
<li><a href="{{ url_for('generate') }}">Generate Game Page</a></li>
|
||||
<li><a href="{{ url_for('landing') }}">Homepage</a></li>
|
||||
<li><a href="{{ url_for('uploads') }}">Host Game Page</a></li>
|
||||
<li><a href="{{ url_for('get_datapackage') }}">Raw Data Package</a></li>
|
||||
<li><a href="{{ url_for('check') }}">Settings Validator</a></li>
|
||||
<li><a href="{{ url_for('get_sitemap') }}">Site Map</a></li>
|
||||
<li><a href="{{ url_for('start_playing') }}">Start Playing</a></li>
|
||||
<li><a href="{{ url_for('games') }}">Supported Games Page</a></li>
|
||||
<li><a href="{{ url_for('tutorial_landing') }}">Tutorials Page</a></li>
|
||||
<li><a href="{{ url_for('user_content') }}">User Content</a></li>
|
||||
<li><a href="{{ url_for('stats') }}">Game Statistics</a></li>
|
||||
<li><a href="{{ url_for('glossary', lang='en') }}">Glossary</a></li>
|
||||
<li><a href="{{ url_for('show_session') }}">Session / Login</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Tutorials</h2>
|
||||
<ul>
|
||||
<li><a href="/tutorial/Archipelago/setup/en">Multiworld Setup Tutorial</a></li>
|
||||
<li><a href="/tutorial/Archipelago/mac/en">Setup Guide for Mac</a></li>
|
||||
<li><a href="/tutorial/Archipelago/commands/en">Server and Client Commands</a></li>
|
||||
<li><a href="/tutorial/Archipelago/advanced_settings/en">Advanced YAML Guide</a></li>
|
||||
<li><a href="/tutorial/Archipelago/triggers/en">Triggers Guide</a></li>
|
||||
<li><a href="/tutorial/Archipelago/plando/en">Plando Guide</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='setup_en') }}">Multiworld Setup Tutorial</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='mac_en') }}">Setup Guide for Mac</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='commands_en') }}">Server and Client Commands</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='advanced_settings_en') }}">Advanced YAML Guide</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='triggers_en') }}">Triggers Guide</a></li>
|
||||
<li><a href="{{ url_for('tutorial', game='Archipelago', file='plando_en') }}">Plando Guide</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Game Info Pages</h2>
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import List, Optional, Tuple, Type, Union
|
||||
|
||||
from BaseClasses import CollectionState, Item, ItemClassification, Location, MultiWorld, Region
|
||||
from worlds import network_data_package
|
||||
from worlds.AutoWorld import World, call_all
|
||||
from worlds.AutoWorld import World, WebWorld, call_all
|
||||
|
||||
gen_steps = (
|
||||
"generate_early",
|
||||
@@ -17,7 +17,7 @@ gen_steps = (
|
||||
|
||||
|
||||
def setup_solo_multiworld(
|
||||
world_type: Type[World], steps: Tuple[str, ...] = gen_steps, seed: Optional[int] = None
|
||||
world_type: Type[World], steps: Tuple[str, ...] = gen_steps, seed: Optional[int] = None
|
||||
) -> MultiWorld:
|
||||
"""
|
||||
Creates a multiworld with a single player of `world_type`, sets default options, and calls provided gen steps.
|
||||
@@ -62,11 +62,16 @@ def setup_multiworld(worlds: Union[List[Type[World]], Type[World]], steps: Tuple
|
||||
return multiworld
|
||||
|
||||
|
||||
class TestWebWorld(WebWorld):
|
||||
tutorials = []
|
||||
|
||||
|
||||
class TestWorld(World):
|
||||
game = f"Test Game"
|
||||
item_name_to_id = {}
|
||||
location_name_to_id = {}
|
||||
hidden = True
|
||||
web = TestWebWorld()
|
||||
|
||||
|
||||
# add our test world to the data package, so we can test it later
|
||||
|
||||
63
test/webhost/test_sitemap.py
Normal file
63
test/webhost/test_sitemap.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import urllib.parse
|
||||
import html
|
||||
import re
|
||||
from flask import url_for
|
||||
|
||||
import WebHost
|
||||
from . import TestBase
|
||||
|
||||
|
||||
class TestSitemap(TestBase):
|
||||
|
||||
# Codes for OK and some redirects that we use
|
||||
valid_status_codes = [200, 302, 308]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
super().setUpClass()
|
||||
WebHost.copy_tutorials_files_to_static()
|
||||
|
||||
def test_sitemap_route(self) -> None:
|
||||
"""Verify that the sitemap route works correctly and renders the template without errors."""
|
||||
with self.app.test_request_context():
|
||||
# Test the /sitemap route
|
||||
with self.client.open("/sitemap") as response:
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b"Site Map", response.data)
|
||||
|
||||
# Test the /index route which should also serve the sitemap
|
||||
with self.client.open("/index") as response:
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b"Site Map", response.data)
|
||||
|
||||
# Test using url_for with the function name
|
||||
with self.client.open(url_for('get_sitemap')) as response:
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b'Site Map', response.data)
|
||||
|
||||
def test_sitemap_links(self) -> None:
|
||||
"""
|
||||
Verify that all links in the sitemap are valid by making a request to each one.
|
||||
"""
|
||||
with self.app.test_request_context():
|
||||
with self.client.open(url_for("get_sitemap")) as response:
|
||||
self.assertEqual(response.status_code, 200)
|
||||
html_content = response.data.decode()
|
||||
|
||||
# Extract all href links using regex
|
||||
href_pattern = re.compile(r'href=["\'](.*?)["\']')
|
||||
links = href_pattern.findall(html_content)
|
||||
|
||||
self.assertTrue(len(links) > 0, "No links found in sitemap")
|
||||
|
||||
# Test each link
|
||||
for link in links:
|
||||
# Skip external links
|
||||
if link.startswith(("http://", "https://")):
|
||||
continue
|
||||
|
||||
link = urllib.parse.unquote(html.unescape(link))
|
||||
|
||||
with self.client.open(link) as response, self.subTest(link=link):
|
||||
self.assertIn(response.status_code, self.valid_status_codes,
|
||||
f"Link {link} returned invalid status code {response.status_code}")
|
||||
Reference in New Issue
Block a user