Files
SealShare/tests/Feature/WebsiteTest.php
T
Andreas Reinhold / reiniandClaude Opus 5 606cc766f2
docker / test (8.5) (push) Successful in 2m5s
docker / build-and-push (push) Failing after 9m38s
docker / release (push) Has been skipped
linter / quality (push) Successful in 1m8s
tests / ci (8.5) (push) Successful in 2m4s
Add the SealShare website for sealshare.nonameweb.ch
website/ is hand-written HTML and CSS, uploaded as it is, like the
MailifySMS site: SealShare as software a company installs for its own
upload platform, how it works, features, a desktop/phone and light/dark
gallery of the generated screenshots, a dated and sourced comparison with
hosted transfer services and self-hosted tools, the Docker quick start,
FAQ and a privacy page for Plausible. Colours come from the app's scheme,
Google Sans Flex is served locally, nothing else loads from other hosts.

The README shows three screenshots and no longer calls the encryption
end-to-end. WebsiteTest guards missing files, other hosts, the screenshot
set and the encryption wording.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 12:38:49 +02:00

130 lines
4.9 KiB
PHP

<?php
/*
* website/ is uploaded by hand as it is, so these guard what a broken upload would show: files that
* are not there, requests to other hosts, and claims the application does not keep.
*/
/**
* The site's HTML pages, by name.
*
* @return array<string, string>
*/
function websitePages(): array
{
return [
'index.html' => file_get_contents(base_path('website/index.html')),
'privacy.html' => file_get_contents(base_path('website/privacy.html')),
];
}
/**
* Every URL an HTML document refers to in `src`, `href`, `srcset` and the gallery's `data-*-src` and
* `data-*-srcset`, with each srcset entry on its own.
*
* @return list<string>
*/
function websiteReferences(string $html): array
{
preg_match_all('/\s(src|href|srcset|data-[a-z]+-src|data-[a-z]+-srcset)="([^"]*)"/', $html, $matches, PREG_SET_ORDER);
return collect($matches)
->flatMap(fn (array $match): array => str_ends_with($match[1], 'srcset')
? array_map(fn (string $candidate): string => strtok(trim($candidate), ' '), explode(',', $match[2]))
: [$match[2]])
->map(fn (string $url): string => html_entity_decode($url))
->values()
->all();
}
test('every file the pages, their stylesheets and the README refer to exists', function () {
$missing = [];
foreach (websitePages() as $page => $html) {
foreach (websiteReferences($html) as $url) {
if (preg_match('/^(#|https?:|mailto:)/', $url) === 1) {
continue;
}
if (! is_file(base_path('website/'.strtok($url, '#?')))) {
$missing[] = "{$page}: {$url}";
}
}
}
foreach (glob(base_path('website/css/*.css')) as $stylesheet) {
preg_match_all('/url\([\'"]?([^\'")]+)[\'"]?\)/', file_get_contents($stylesheet), $matches);
foreach ($matches[1] as $url) {
if (! str_starts_with($url, 'data:') && ! is_file(dirname($stylesheet).'/'.strtok($url, '#?'))) {
$missing[] = basename($stylesheet).": {$url}";
}
}
}
foreach (websiteReferences(file_get_contents(base_path('README.md'))) as $url) {
if (str_starts_with($url, 'website/') && ! is_file(base_path($url))) {
$missing[] = "README.md: {$url}";
}
}
expect($missing)->toBe([]);
});
test('the screenshots are all there, for both themes and both widths', function () {
$expected = collect([
'desktop' => ['01-upload', '02-share-created', '03-qr-code', '04-download', '05-admin-dashboard', '06-admin-settings'],
'phone' => ['01-upload', '02-password', '03-download', '04-qr-code'],
])->flatMap(fn (array $names, string $device): array => collect(['light', 'dark'])
->crossJoin($names, $device === 'desktop' ? [1600, 800] : [1080, 540])
->map(fn (array $shot): string => "{$device}/{$shot[0]}/{$shot[1]}-{$shot[2]}.webp")
->all())
->sort()->values()->all();
$published = collect(glob(base_path('website/img/screenshots/*/*/*.webp')))
->map(fn (string $path): string => str($path)->after('website/img/screenshots/')->toString())
->sort()->values()->all();
expect($published)->toBe($expected);
});
test('the pages load nothing from another host but Plausible', function () {
foreach (websitePages() as $page => $html) {
preg_match_all('/<(?:script|img|source|link)\b[^>]*\s(?:src|srcset|href)="(https?:[^"]*)"/', $html, $matches);
expect(collect($matches[1])->reject(fn (string $url): bool => str_starts_with($url, 'https://plausible.io/'))->all())
->toBe([], "{$page} loads from another host");
}
foreach (glob(base_path('website/css/*.css')) as $stylesheet) {
expect(file_get_contents($stylesheet))->not->toMatch('/(url\(\s*[\'"]?https?:|@import)/');
}
});
test('the pages are titled, described and in English', function () {
foreach (websitePages() as $page => $html) {
expect($html)
->toContain('<html lang="en"')
->toMatch('/<title>[^<]+<\/title>/')
->toMatch('/<meta name="description" content="[^"]+"/')
->toContain('data-domain="sealshare.nonameweb.ch"');
}
});
test('neither the site nor the README calls the encryption end-to-end', function () {
$index = websitePages()['index.html'];
preg_match('/<section[^>]*id="features".*?<\/section>/s', $index, $features);
preg_match_all('/data-compare="sealshare-e2e">([^<]*)</', $index, $cells);
expect($features[0])->not->toMatch('/end-to-end/i')
->and($cells[1])->not->toBeEmpty()->each->toBe('No')
->and(file_get_contents(base_path('README.md')))->not->toContain('End-to-End Encryption');
});
test('nothing is left to fill in', function () {
foreach ([...websitePages(), 'theme.css' => file_get_contents(base_path('website/css/theme.css'))] as $file => $contents) {
expect(str_contains($contents, 'TODO'))->toBeFalse("{$file} still has a TODO");
}
});