"""Run with python3 scripts/test_site.py (Python and Node standard libraries).""" from datetime import datetime, timezone from html.parser import HTMLParser import importlib.util import json from pathlib import Path import re import subprocess import tempfile from urllib.parse import urlsplit import xml.etree.ElementTree as ET ROOT = Path(__file__).resolve().parents[1] subprocess.run(['python3', 'scripts/test_locales.py'], cwd=ROOT, check=True) subprocess.run(['python3', 'scripts/export-locales.py', '--check'], cwd=ROOT, check=True) subprocess.run(['node', 'scripts/test_web_locales.cjs'], cwd=ROOT, check=True) class Page(HTMLParser): def __init__(self, html): super().__init__() self.tags = [] self.ids = set() self.feed(html) def handle_starttag(self, tag, attrs): attrs = dict(attrs) self.tags.append((tag, attrs)) if 'id' in attrs: assert attrs['id'] not in self.ids, attrs['id'] self.ids.add(attrs['id']) with tempfile.TemporaryDirectory() as directory: output = Path(directory) (output / 'app').mkdir() (output / 'app/index.html').write_text('
App') subprocess.run(['sh', 'scripts/assemble-site.sh', str(output)], cwd=ROOT, check=True) catalogs = {p.stem: json.loads(p.read_text()) for p in (ROOT / 'site/locales').glob('*.json')} supported = set(re.findall(r'#\[serde\(rename = "([a-z]{2}-[A-Z]{2})"\)\]', (ROOT / 'src/i18n.rs').read_text())) assert catalogs.keys() == supported spec = importlib.util.spec_from_file_location('charts', ROOT / 'scripts/generate-star-history.py') charts = importlib.util.module_from_spec(spec) spec.loader.exec_module(charts) date = datetime(2026, 1, 1, tzinfo=timezone.utc) for locale, messages in catalogs.items(): for chart in ('stars', 'downloads'): svg = charts.render_svg('HakanSeven12/OpenCADStudio', [date], [('v1', date, 10)], 'dark', chart, messages) tree = ET.fromstring(svg) assert tree.find('{http://www.w3.org/2000/svg}title').text == messages['stars' if chart == 'stars' else 'downloads'] (output / locale / f'{chart[:-1]}-history-dark.svg').write_text(svg) html = (output / locale / 'index.html').read_text() assert '{{' not in html and '{count}' not in html, locale page = Page(html) assert ('html', {'lang': locale, 'dir': 'rtl' if locale == 'ar-SA' else 'ltr'}) in page.tags links = [attrs for tag, attrs in page.tags if tag == 'link'] assert {link['href'] for link in links if link.get('rel') == 'icon'} == {'/favicon.ico', '/favicon.png', '/favicon.svg'} assert {link['hreflang'] for link in links if link.get('rel') == 'alternate'} == supported | {'x-default'} expected_path = '/' if locale == 'en-US' else f'/{locale}/' assert next(link['href'] for link in links if link.get('rel') == 'canonical') == f'https://www.opencadstudio.com{expected_path}' choices = [attrs for tag, attrs in page.tags if tag == 'a' and 'hreflang' in attrs] assert {choice['hreflang'] for choice in choices} == supported assert [choice['hreflang'] for choice in choices if choice.get('aria-current') == 'page'] == [locale] schema = json.loads(re.search(r'', html).group(1)) assert schema['inLanguage'] == locale and schema['description'] == messages['description'] for tag, attrs in page.tags: if tag == 'img': assert 'alt' in attrs and 'width' in attrs and 'height' in attrs for attr in ('src', 'href'): target = attrs.get(attr, '') if target.startswith('#'): assert target[1:] in page.ids, target elif target.startswith('/'): path = output / urlsplit(target).path.lstrip('/') assert path.exists(), (locale, target) manifest = json.loads((output / locale / 'site.webmanifest').read_text()) assert manifest['lang'] == locale and manifest['start_url'] == expected_path for icon in manifest['icons']: assert (output / icon['src'].lstrip('/')).exists() if locale != 'en-US': for key, value in messages.items(): if len(catalogs['en-US'][key]) > 40: assert value != catalogs['en-US'][key], (locale, key) app = (output / 'app/index.html').read_text() assert 'old.svg' not in app and 'integrity="old"' not in app and '>App<' in app icon = next(attrs['href'] for tag, attrs in Page(app).tags if attrs.get('type') == 'image/svg+xml') assert icon == '/favicon.svg' assert (output / icon.lstrip('/')).read_bytes() == (ROOT / 'site/favicon.svg').read_bytes() sitemap = ET.parse(output / 'sitemap.xml') locations = {url[0].text for url in sitemap.getroot()} assert len(locations) == len(supported) assert 'https://www.opencadstudio.com/' in locations assert 'https://www.opencadstudio.com/en-US/' not in locations assert (output / 'index.html').read_bytes() == (output / 'en-US/index.html').read_bytes() homepage_schemas = [json.loads(value) for value in re.findall(r'', (output / 'index.html').read_text())] website = next(schema for schema in homepage_schemas if schema['@type'] == 'WebSite') assert website['url'] == 'https://www.opencadstudio.com/' and 'OpenCADStudio' in website['alternateName'] subprocess.run(['node', 'scripts/test_site.cjs', str(output / 'site.js')], cwd=ROOT, check=True) print(f'All {len(supported)} translations, metadata, local links, charts, manifests and icons passed')