diff --git a/images/preview.jpg b/images/preview.jpg new file mode 100644 index 0000000..574e128 Binary files /dev/null and b/images/preview.jpg differ diff --git a/ops/deployment/deploy.py b/ops/deployment/deploy.py index 9f8438b..bea3e2c 100644 --- a/ops/deployment/deploy.py +++ b/ops/deployment/deploy.py @@ -42,7 +42,7 @@ RUNTIME = frozenset('server.js package.json package-lock.json index.html support.html ' 'privacy.html terms.html admin.html cancel.html script.js style.css ' 'bg3.jpeg btc.jpg eth.jpg favicon.png paypal.jpg sol.jpg ' - '.well-known/brave-rewards-verification.txt'.split()) + 'images/preview.jpg .well-known/brave-rewards-verification.txt'.split()) SHA_RE = re.compile(r'[0-9a-f]{40}', re.ASCII) ERROR_RE = re.compile(r'\berror\b|\bfatal\b|uncaught|unhandled|EACCES|EADDRINUSE|' r'SQLITE_\w+|\bfailed\b|MODULE_NOT_FOUND|invalid_grant', re.I) diff --git a/ops/deployment/test_deploy.py b/ops/deployment/test_deploy.py index b3fa6f7..336eca9 100644 --- a/ops/deployment/test_deploy.py +++ b/ops/deployment/test_deploy.py @@ -24,6 +24,27 @@ def load(name, filename): class Controls(unittest.TestCase): + def test_runtime_includes_og_preview_image(self): + self.assertIn('images/preview.jpg', d.RUNTIME) + + def test_unpack_runtime_writes_nested_preview_path(self): + with tempfile.TemporaryDirectory() as tmp: + stream = io.BytesIO() + with tarfile.open(fileobj=stream, mode='w') as tar: + for name in sorted(d.RUNTIME): + payload = b'preview' if name == 'images/preview.jpg' else b'x' + member = tarfile.TarInfo(name) + member.size = len(payload) + tar.addfile(member, io.BytesIO(payload)) + dest = Path(tmp) + d.unpack_runtime(stream.getvalue(), dest) + preview = dest / 'images' / 'preview.jpg' + self.assertTrue(preview.is_file()) + self.assertEqual(preview.read_bytes(), b'preview') + self.assertEqual( + {str(path.relative_to(dest)) for path in dest.rglob('*') if path.is_file()}, + d.RUNTIME) + def test_public_html_probes_include_cancel(self): urls = [] with patch.object(d, 'http', side_effect=lambda url, sha=None: urls.append(url)): diff --git a/test/ui.test.js b/test/ui.test.js index 0ef99f8..3f32c90 100644 --- a/test/ui.test.js +++ b/test/ui.test.js @@ -87,6 +87,27 @@ test('static pages declare matching HTTPS canonical URLs in head', () => { } }); +test('homepage Open Graph and Twitter images point at /images/preview.jpg', () => { + const root = path.resolve(__dirname, '..'); + const previewPath = path.join(root, 'images', 'preview.jpg'); + assert.equal(fs.existsSync(previewPath), true, 'images/preview.jpg must exist'); + + const dom = new JSDOM(fs.readFileSync(path.join(root, 'index.html'), 'utf8'), { + url: 'https://dextech.invalid/', + }); + const { document } = dom.window; + try { + const ogImage = document.querySelector('meta[property="og:image"]'); + const twitterImage = document.querySelector('meta[name="twitter:image"]'); + assert.ok(ogImage, 'og:image meta tag must exist'); + assert.ok(twitterImage, 'twitter:image meta tag must exist'); + assert.equal(ogImage.getAttribute('content'), 'https://dextech.cloud/images/preview.jpg'); + assert.equal(twitterImage.getAttribute('content'), 'https://dextech.cloud/images/preview.jpg'); + } finally { + dom.window.close(); + } +}); + test('support.html footer includes privacy, terms, and Express cancel route', () => { const root = path.resolve(__dirname, '..'); const dom = new JSDOM(fs.readFileSync(path.join(root, 'support.html'), 'utf8'), {