mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-06 14:05:21 +02:00
fix: Missing Title and Metadata (#2770)
* add document title to server spa meta * removed conflicting useMeta * replaced head with useMeta * formalized metadata injection * small injection refactor * added tests * added missing global tag * fixed setting tab title for logged-in users * simplified metadata update * remove duplicate tag and fix for foreign users * add metadata for shared recipes * added default recipe image * fixed shared URL --------- Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
2751e8318a
commit
1d1d61df77
5 changed files with 207 additions and 27 deletions
|
@ -22,6 +22,8 @@ images_test_image_1 = CWD / "images/test-image-1.jpg"
|
|||
|
||||
images_test_image_2 = CWD / "images/test-image-2.png"
|
||||
|
||||
html_mealie_recipe = CWD / "html/mealie-recipe.html"
|
||||
|
||||
html_sous_vide_smoked_beef_ribs = CWD / "html/sous-vide-smoked-beef-ribs.html"
|
||||
|
||||
html_sous_vide_shrimp = CWD / "html/sous-vide-shrimp.html"
|
||||
|
|
41
tests/data/html/mealie-recipe.html
Normal file
41
tests/data/html/mealie-recipe.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-n-head="%7B%22lang%22:%7B%221%22:%22en%22%7D%7D">
|
||||
<head>
|
||||
<meta data-n-head="1" data-hid="og:type" property="og:type" content="website">
|
||||
<meta data-n-head="1" data-hid="og:title" property="og:title" content="Mealie">
|
||||
<meta data-n-head="1" data-hid="og:site_name" property="og:site_name" content="Mealie">
|
||||
<meta data-n-head="1" data-hid="og:description" property="og:description" content="Mealie is a recipe management app for your kitchen.">
|
||||
<meta data-n-head="1" data-hid="og:image" property="og:image" content="https://raw.githubusercontent.com/hay-kot/mealie/dev/frontend/public/img/icons/android-chrome-512x512.png">
|
||||
<meta data-n-head="1" charset="utf-8">
|
||||
<meta data-n-head="1" name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta data-n-head="1" data-hid="description" name="description" content="Mealie is a recipe management app for your kitchen.">
|
||||
<meta data-n-head="1" data-hid="charset" charset="utf-8">
|
||||
<meta data-n-head="1" data-hid="mobile-web-app-capable" name="mobile-web-app-capable" content="yes">
|
||||
<meta data-n-head="1" data-hid="apple-mobile-web-app-title" name="apple-mobile-web-app-title" content="Mealie">
|
||||
<meta data-n-head="1" data-hid="theme-color" name="theme-color" content="#E58325">
|
||||
<title>Mealie</title>
|
||||
<link data-n-head="1" data-hid="favicon" rel="icon" type="image/x-icon" href="/favicon.ico" data-n-head="ssr">
|
||||
<link data-n-head="1" data-hid="shortcut icon" rel="shortcut icon" type="image/png" href="/icons/icon-x64.png" data-n-head="ssr">
|
||||
<link data-n-head="1" data-hid="apple-touch-icon" rel="apple-touch-icon" type="image/png" href="/icons/apple-touch-icon.png" data-n-head="ssr">
|
||||
<link data-n-head="1" data-hid="mask-icon" rel="mask-icon" href="/icons/safari-pinned-tab.svg" data-n-head="ssr">
|
||||
<link data-n-head="1" rel="shortcut icon" href="/icons/android-chrome-192x192.png">
|
||||
<link data-n-head="1" rel="apple-touch-icon" href="/icons/android-chrome-maskable-512x512.png" sizes="512x512">
|
||||
<link data-n-head="1" rel="manifest" href="/_nuxt/manifest.260e8103.json" data-hid="manifest">
|
||||
<base href="/">
|
||||
<link rel="preload" href="/_nuxt/4134a9b.js" as="script">
|
||||
<link rel="preload" href="/_nuxt/caa94a4.js" as="script">
|
||||
<link rel="preload" href="/_nuxt/90b93a8.js" as="script">
|
||||
<link rel="preload" href="/_nuxt/9da1d16.js" as="script">
|
||||
</head>
|
||||
<body>
|
||||
<div id="__nuxt">
|
||||
<style>#nuxt-loading{background:#fff;visibility:hidden;opacity:0;position:absolute;left:0;right:0;top:0;bottom:0;display:flex;justify-content:center;align-items:center;flex-direction:column;animation:nuxtLoadingIn 10s ease;-webkit-animation:nuxtLoadingIn 10s ease;animation-fill-mode:forwards;overflow:hidden}@keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}@-webkit-keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}#nuxt-loading>div,#nuxt-loading>div:after{border-radius:50%;width:5rem;height:5rem}#nuxt-loading>div{font-size:10px;position:relative;text-indent:-9999em;border:.5rem solid #f5f5f5;border-left:.5rem solid #000;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:nuxtLoading 1.1s infinite linear;animation:nuxtLoading 1.1s infinite linear}#nuxt-loading.error>div{border-left:.5rem solid #ff4500;animation-duration:5s}@-webkit-keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}</style>
|
||||
<script>window.addEventListener("error",function(){var e=document.getElementById("nuxt-loading");e&&(e.className+=" error")})</script>
|
||||
<div id="nuxt-loading" aria-live="polite" role="status">
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>window.__NUXT__=function(r,n,a,s,e,c,o){return{config:{GLOBAL_MIDDLEWARE:null,SUB_PATH:"",axios:{browserBaseURL:""},useDark:!1,themes:{dark:{primary:r,accent:n,secondary:a,success:s,info:e,warning:c,error:o,background:"#1E1E1E"},light:{primary:r,accent:n,secondary:a,success:s,info:e,warning:c,error:o}},_app:{basePath:"/",assetsPath:"/_nuxt/",cdnURL:null}}}}("#E58325","#007A99","#973542","#43A047","#1976d2","#FF6D00","#EF5350")</script>
|
||||
<script src="/_nuxt/4134a9b.js"></script><script src="/_nuxt/caa94a4.js"></script><script src="/_nuxt/90b93a8.js"></script><script src="/_nuxt/9da1d16.js"></script>
|
||||
</body>
|
||||
</html>
|
70
tests/integration_tests/test_spa.py
Normal file
70
tests/integration_tests/test_spa.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
from bs4 import BeautifulSoup
|
||||
|
||||
from mealie.routes.spa import MetaTag, inject_meta, inject_recipe_json
|
||||
from tests import data as test_data
|
||||
from tests.utils.factories import random_string
|
||||
|
||||
|
||||
def test_spa_metadata_injection():
|
||||
fp = test_data.html_mealie_recipe
|
||||
with open(fp) as f:
|
||||
soup = BeautifulSoup(f, "lxml")
|
||||
assert soup.html and soup.html.head
|
||||
|
||||
tags = soup.find_all("meta")
|
||||
assert tags
|
||||
|
||||
title_tag = None
|
||||
for tag in tags:
|
||||
if tag.get("data-hid") == "og:title":
|
||||
title_tag = tag
|
||||
break
|
||||
|
||||
assert title_tag and title_tag["content"]
|
||||
|
||||
new_title_tag = MetaTag(hid="og:title", property_name="og:title", content=random_string())
|
||||
new_arbitrary_tag = MetaTag(hid=random_string(), property_name=random_string(), content=random_string())
|
||||
new_html = inject_meta(str(soup), [new_title_tag, new_arbitrary_tag])
|
||||
|
||||
# verify changes were injected
|
||||
soup = BeautifulSoup(new_html, "lxml")
|
||||
assert soup.html and soup.html.head
|
||||
|
||||
tags = soup.find_all("meta")
|
||||
assert tags
|
||||
|
||||
title_tag = None
|
||||
for tag in tags:
|
||||
if tag.get("data-hid") == "og:title":
|
||||
title_tag = tag
|
||||
break
|
||||
|
||||
assert title_tag and title_tag["content"] == new_title_tag.content
|
||||
|
||||
arbitrary_tag = None
|
||||
for tag in tags:
|
||||
if tag.get("data-hid") == new_arbitrary_tag.hid:
|
||||
arbitrary_tag = tag
|
||||
break
|
||||
|
||||
assert arbitrary_tag and arbitrary_tag["content"] == new_arbitrary_tag.content
|
||||
|
||||
|
||||
def test_spa_recipe_json_injection():
|
||||
recipe_name = random_string()
|
||||
schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Recipe",
|
||||
"name": recipe_name,
|
||||
}
|
||||
|
||||
fp = test_data.html_mealie_recipe
|
||||
with open(fp) as f:
|
||||
soup = BeautifulSoup(f, "lxml")
|
||||
assert "https://schema.org" not in str(soup)
|
||||
|
||||
html = inject_recipe_json(str(soup), schema)
|
||||
|
||||
assert "@context" in html
|
||||
assert "https://schema.org" in html
|
||||
assert recipe_name in html
|
Loading…
Add table
Add a link
Reference in a new issue