-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the MkDocs-Test framework (with pytest)
- added tests for the simple, material and superfences test cases
- Loading branch information
Laurent Franceschetti
committed
Nov 2, 2024
1 parent
97db6aa
commit 18b0c2e
Showing
14 changed files
with
390 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,6 +99,7 @@ venv.bak/ | |
|
||
# mkdocs documentation | ||
site/ | ||
__test__/ | ||
|
||
# mypy | ||
.mypy_cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
""" | ||
Specific for MkDocs Projects | ||
(C) Laurent Franceschetti 2024 | ||
""" | ||
|
||
import re | ||
import requests | ||
|
||
from super_collections import SuperDict | ||
from mkdocs_test import DocProject, MkDocsPage | ||
from packaging import version | ||
|
||
|
||
URL_PATTERN = r'https://[^\s"]+' | ||
VERSION_PATTERN = r"@(\d+\.\d+\.\d+)" | ||
|
||
def extract_url(s:str) -> str|None: | ||
"Extract the first url from a string" | ||
match = re.search(URL_PATTERN, s) | ||
if match: | ||
url = match.group(0) | ||
return url | ||
else: | ||
return None | ||
|
||
|
||
def get_last_version(mermaid_url:str) -> version.Version: | ||
"Get the last version from a mermaid url" | ||
response = requests.get(mermaid_url) | ||
version_no = response.url.split('@')[1].split('/')[0] | ||
return version.parse(version_no) | ||
|
||
|
||
|
||
def assert_string_contains(txt:str, items:list) -> bool: | ||
""" | ||
Find items in a string. | ||
All items must be present (AND); however, if one item is an | ||
iterable-non-string, then each subitem will an OR. | ||
['foo', 'bar', ('baz', 'barbaz')] -> 'foo' AND 'bar' AND ('baz' OR 'barbaz') | ||
""" | ||
for item in items: | ||
if isinstance(item, str): | ||
assert item in txt, f"'{item}' not found in:\n{txt}!" | ||
else: | ||
assert any(subitem in txt for subitem in item), f"None of {item} found in:\n{txt}!" | ||
|
||
|
||
|
||
class Mermaid2Page(MkDocsPage): | ||
"Specific for Mermaid2" | ||
|
||
LIB_VERSION_CHANGE = version.parse('10') | ||
|
||
|
||
@property | ||
def mermaid_script(self) -> str: | ||
""" | ||
Get the call to the mermaid javascript library | ||
(in the two versions, pre- and post- 10.0). | ||
Performs checks and initializes the js_version property. | ||
For testing purposes, this function contains INVARIANTS | ||
(principles that should remain the same in time, and | ||
across different configurations). | ||
""" | ||
try: | ||
self._mermaid_script | ||
except AttributeError: | ||
mermaid_script = self.find('script', type="module") | ||
if mermaid_script: | ||
# Version >= 10 | ||
script_txt = mermaid_script.string | ||
FIND_TEXT = ["import mermaid", "esm.min.mjs", | ||
('mermaid.initialize', 'mermaidConfig')] | ||
assert_string_contains(script_txt, FIND_TEXT) | ||
# Get the version number from the string; if not, from the Mermaid url: | ||
mermaid_url = extract_url(script_txt) | ||
assert mermaid_url, "No URL found for mermaid" | ||
assert 'mermaid' in mermaid_url, f"Error in url: {mermaid_url}" | ||
self._js_version = get_last_version(mermaid_url) | ||
return script_txt | ||
else: | ||
# Version < 10 | ||
# Find the script calling the library | ||
mermaid_script = self.find('script', src=lambda x: x and 'mermaid' in x) | ||
assert mermaid_script, "Couldn't find the < 10 Mermaid library!" | ||
src = mermaid_script.get('src') | ||
match = re.search(VERSION_PATTERN, src) | ||
# If < 10, it demands that the script version be explicit (x.y.z) | ||
if match: | ||
version_str = match.group(1) | ||
version = version.Version(version_str) | ||
self._js_version = version | ||
else: | ||
raise ValueError("No version number with < 10 Mermaid library") | ||
return mermaid_script.string | ||
|
||
|
||
|
||
@property | ||
def js_version(self) -> version.Version: | ||
""" | ||
Get the version of the javascript library, while performing checks. | ||
""" | ||
try: | ||
return self._js_version | ||
except AttributeError: | ||
# Initialize | ||
self.mermaid_script | ||
return self._js_version | ||
|
||
|
||
class Mermaid2DocProject(DocProject): | ||
"Specific for MkDocs-Macros" | ||
|
||
@property | ||
def plugin_version(self) -> version.Version|None: | ||
"Get the Mermaid2 javascript library version from the plugin" | ||
plugin = self.get_plugin('mermaid2') | ||
try: | ||
return version.Version(plugin.version) | ||
except AttributeError: | ||
pass | ||
|
||
|
||
@property | ||
def pages(self) -> dict[Mermaid2Page]: | ||
"List of pages" | ||
pages = super().pages | ||
return {key: Mermaid2Page(value) for key, value in pages.items()} | ||
|
||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ nav: | |
|
||
plugins: | ||
- search | ||
- test | ||
- mermaid2: | ||
version: '10.1.0' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
""" | ||
Testing the project | ||
Material theme, otherwise normal | ||
(C) Laurent Franceschetti 2024 | ||
""" | ||
|
||
|
||
import pytest | ||
|
||
from mkdocs_test import DocProject | ||
|
||
from test.fixture import Mermaid2DocProject | ||
|
||
|
||
|
||
|
||
def test_pages(): | ||
"Test this project" | ||
|
||
|
||
|
||
# ---------------- | ||
# First page | ||
# ---------------- | ||
project = Mermaid2DocProject(".") | ||
build_result = project.build(strict=False) | ||
# did not fail | ||
return_code = project.build_result.returncode | ||
assert not return_code, f"Build returned with {return_code} {build_result.args})" | ||
|
||
|
||
|
||
# ---------------- | ||
# First page | ||
# ---------------- | ||
page = project.get_page('index') | ||
|
||
|
||
|
||
# find the diagrams; they are divs | ||
diagrams = page.find_all('div', class_='mermaid') | ||
assert len(diagrams) == 2 | ||
assert diagrams[0].string.startswith('graph TD') | ||
assert diagrams[1].string.startswith('gitGraph') | ||
|
||
# use the fixture: | ||
version = page.js_version | ||
assert version == project.plugin_version | ||
print("Version:", version) | ||
assert version | ||
assert version > page.LIB_VERSION_CHANGE | ||
|
||
# find the piece of Python code | ||
my_code = page.find('code', class_='language-python') | ||
assert 'page.read()' in my_code.string | ||
|
||
|
||
# ---------------- | ||
# Second page | ||
# ---------------- | ||
page = project.get_page('second') | ||
|
||
# find the diagrams; they are divs: | ||
diagrams = page.find_all('div', class_='mermaid') | ||
assert len(diagrams) == 3 | ||
wrong_diagram = diagrams[0].string # this one is wrong | ||
assert wrong_diagram.startswith('graph FG') | ||
assert "A[Client]" in wrong_diagram | ||
# the other two are correct: | ||
assert diagrams[1].string.startswith('graph TD') | ||
assert diagrams[2].string.startswith('graph TD') | ||
|
||
# check that the second page has same version as first | ||
assert page.js_version == version | ||
|
||
|
||
|
||
|
||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ nav: | |
|
||
plugins: | ||
- search | ||
- test | ||
- mermaid2 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
""" | ||
Testing the project | ||
(C) Laurent Franceschetti 2024 | ||
""" | ||
|
||
|
||
import pytest | ||
|
||
from mkdocs_test import DocProject | ||
|
||
|
||
from test.fixture import Mermaid2DocProject | ||
|
||
|
||
|
||
|
||
def test_pages(): | ||
"Test this project" | ||
|
||
FIND_TEXT = ["import mermaid", "mermaid.initialize", "esm.min.mjs"] | ||
|
||
# ---------------- | ||
# First page | ||
# ---------------- | ||
project = Mermaid2DocProject(".") | ||
build_result = project.build(strict=False) | ||
# did not fail | ||
return_code = project.build_result.returncode | ||
assert not return_code, f"Build returned with {return_code} {build_result.args})" | ||
|
||
# ---------------- | ||
# First page | ||
# ---------------- | ||
page = project.get_page('index') | ||
|
||
# find the diagrams; they are divs | ||
diagrams = page.find_all('div', class_='mermaid') | ||
assert len(diagrams) == 2 | ||
|
||
# find the mermaid script | ||
mermaid_script = page.find('script', type="module") | ||
for text in FIND_TEXT: | ||
assert text in mermaid_script.string, f"'{text}' not found!" | ||
|
||
# use the fixture: | ||
version = page.js_version | ||
print("Version:", version) | ||
assert version | ||
assert version > page.LIB_VERSION_CHANGE | ||
|
||
|
||
|
||
# ---------------- | ||
# Second page | ||
# ---------------- | ||
# there is intentionally an error (`foo` does not exist) | ||
page = project.get_page('second') | ||
diagrams = page.find_all('div', class_='mermaid') | ||
assert len(diagrams) == 3 | ||
|
||
# with open('output_file.html', 'w') as f: | ||
# f.write(page.html) | ||
|
||
|
||
|
||
|
||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,4 +25,5 @@ Click on the arrow, to reveal the diagram, | |
graph TD | ||
A[Client] --> B[Load Balancer] | ||
``` | ||
|
||
This is additional text. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.