diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_search_files_unmerged.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_search_files_unmerged.py | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_search_files_unmerged.py b/packages/meshbay-hub/tests/test_search_files_unmerged.py new file mode 100644 index 0000000..6956dde --- /dev/null +++ b/packages/meshbay-hub/tests/test_search_files_unmerged.py @@ -0,0 +1,80 @@ +""" +The Files explorer in the Search view is not merged, and must not become so. + +The Search view folds a file several groups share into one entry, so a film +shared by two groups is one poster instead of two. The Files tab is the one +place where that would be wrong: there each group is a top-level folder, the +two copies live in two different folders, and walking into one is how a member +browses *that group*. Merging would silently delete one of the two branches of +the tree. + +This is the guarantee a later refactor is most likely to break — the four entry +lists in `search-page.js` are near-identical, and tidying them into one shared +builder is the obvious cleanup. It would also be the last thing anyone tests by +hand, because the Files tab looks unchanged until you notice a group's folder +has fewer files in it than the group does. + +So: read the source, and refuse a build where `fileEntries` goes through the +merge. Weak evidence, and the only kind available for the SPA — but the failure +it guards against is a one-line edit, which is exactly what a source-reading +test catches well. + +See docs/refactoring-search.md §6.1. +""" + +import re +from pathlib import Path + +import pytest + +STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" +SEARCH_PAGE = STATIC / "search-page.js" + +pytestmark = pytest.mark.skipif( + not SEARCH_PAGE.exists(), reason="the SPA sources are not available") + +MERGE_CALL = "mergeUnitEntries" + + +def _memo(name): + """The body of `const <name> = useMemo(() => { ... }, [...]);`.""" + src = SEARCH_PAGE.read_text() + m = re.search( + r"^ const " + re.escape(name) + r" = useMemo\(\(\) => \{.*?^ \}, \[.*?\]\);", + src, re.M | re.S) + assert m, ( + f"{name} is no longer a useMemo where this test reads it — the Files " + "explorer's exemption from the merge is untested until this is fixed") + return m.group(0) + + +def test_the_files_list_is_not_merged(): + body = _memo("fileEntries") + assert MERGE_CALL not in body, ( + "fileEntries now goes through the source merge. The Files explorer " + "shows one folder per group and a member navigates into it; merging " + "two groups' copies of a file would remove it from one of those " + "folders. See docs/refactoring-search.md §6.1") + + +@pytest.mark.parametrize("name", ["videoEntries", "musicEntries", "photoEntries"]) +def test_the_media_lists_are_merged(name): + """ + The other half of the check. Without it, deleting the merge outright would + leave the test above passing and saying nothing. + """ + assert MERGE_CALL in _memo(name), ( + f"{name} no longer goes through the source merge — a file shared by " + "two groups is two entries again") + + +def test_the_files_list_still_carries_one_group_per_entry(): + """ + What makes the explorer work: the path is prefixed with the group's name, + so the top level of the tree is the set of groups. A merged entry could not + be prefixed with anything, having several. + """ + body = _memo("fileEntries") + assert "data.groupName + (e.path ? '/' + e.path : '')" in body, ( + "fileEntries no longer prefixes paths with the group name — the " + "explorer's per-group top level is what this whole exemption is for") |