173 lines
5.1 KiB
TypeScript
173 lines
5.1 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import {
|
|
detectMobileStorePlatform,
|
|
linuxArchitectures,
|
|
storeOptionsForPlatform
|
|
} from '../src/lib/content/downloads';
|
|
import {
|
|
faqSchemaMainEntity,
|
|
faqs,
|
|
watchTogetherFaqAnswer
|
|
} from '../src/lib/content/faqs';
|
|
import {
|
|
buildSoftwareApplicationOffers,
|
|
normalizeUsdStorePrice
|
|
} from '../src/lib/content/software_app_offers';
|
|
import { csr as privacyCsr } from '../src/routes/privacy/+page';
|
|
|
|
describe('mobile store selection', () => {
|
|
test('treats missing and unrecognized client evidence as unknown', () => {
|
|
expect(detectMobileStorePlatform()).toBe('unknown');
|
|
expect(
|
|
detectMobileStorePlatform({
|
|
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
|
|
platform: 'Win32',
|
|
maxTouchPoints: 0
|
|
})
|
|
).toBe('unknown');
|
|
});
|
|
|
|
test('detects iOS and Android user agents', () => {
|
|
expect(
|
|
detectMobileStorePlatform({
|
|
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)'
|
|
})
|
|
).toBe('ios');
|
|
expect(
|
|
detectMobileStorePlatform({
|
|
userAgent: 'Mozilla/5.0 (Linux; Android 15; Pixel 9)'
|
|
})
|
|
).toBe('android');
|
|
});
|
|
|
|
test('distinguishes desktop-mode iPadOS from a non-touch Mac', () => {
|
|
const desktopSafari = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)';
|
|
expect(
|
|
detectMobileStorePlatform({
|
|
userAgent: desktopSafari,
|
|
platform: 'MacIntel',
|
|
maxTouchPoints: 5
|
|
})
|
|
).toBe('ios');
|
|
expect(
|
|
detectMobileStorePlatform({
|
|
userAgent: desktopSafari,
|
|
platform: 'MacIntel',
|
|
maxTouchPoints: 0
|
|
})
|
|
).toBe('unknown');
|
|
});
|
|
|
|
test('shows only the matching store when known and both stores when unknown', () => {
|
|
expect(storeOptionsForPlatform('ios').map((option) => option.id)).toEqual(['app-store']);
|
|
expect(storeOptionsForPlatform('android').map((option) => option.id)).toEqual([
|
|
'play-store'
|
|
]);
|
|
expect(storeOptionsForPlatform('unknown').map((option) => option.id)).toEqual([
|
|
'app-store',
|
|
'play-store'
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Linux download inventory', () => {
|
|
test('keeps a unique four-format artifact matrix for x64 and ARM64', () => {
|
|
const artifactNames = linuxArchitectures.map((architecture) =>
|
|
architecture.formats.map(({ url }) => url.slice(url.lastIndexOf('/') + 1))
|
|
);
|
|
|
|
expect(linuxArchitectures.map(({ label }) => label)).toEqual(['x64 (Intel/AMD)', 'ARM64']);
|
|
expect(artifactNames).toEqual([
|
|
[
|
|
'plezy-linux-x64.deb',
|
|
'plezy-linux-x64.rpm',
|
|
'plezy-linux-x64.pkg.tar.zst',
|
|
'plezy-linux-x64.tar.gz'
|
|
],
|
|
[
|
|
'plezy-linux-arm64.deb',
|
|
'plezy-linux-arm64.rpm',
|
|
'plezy-linux-arm64.pkg.tar.zst',
|
|
'plezy-linux-arm64.tar.gz'
|
|
]
|
|
]);
|
|
|
|
const urls = linuxArchitectures.flatMap((architecture) =>
|
|
architecture.formats.map(({ url }) => url)
|
|
);
|
|
expect(new Set(urls).size).toBe(8);
|
|
expect(
|
|
urls.every((url) =>
|
|
url.startsWith('https://github.com/edde746/plezy/releases/latest/download/')
|
|
)
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('software application offers', () => {
|
|
test('accepts only finite nonnegative numeric USD prices', () => {
|
|
expect(normalizeUsdStorePrice(0, 'USD')).toBe('0');
|
|
expect(normalizeUsdStorePrice(4.99, 'USD')).toBe('4.99');
|
|
|
|
for (const value of [-1, Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, '4.99', null]) {
|
|
expect(normalizeUsdStorePrice(value, 'USD')).toBeNull();
|
|
}
|
|
for (const currency of ['EUR', 'usd', '', null, undefined]) {
|
|
expect(normalizeUsdStorePrice(4.99, currency)).toBeNull();
|
|
}
|
|
});
|
|
|
|
test('keeps unavailable paid-store links without describing them as free', () => {
|
|
const offers = buildSoftwareApplicationOffers({
|
|
appStorePrice: null,
|
|
playStorePrice: null
|
|
});
|
|
|
|
expect(offers.find(({ category }) => category === 'App Store')).toEqual({
|
|
'@type': 'Offer',
|
|
url: 'https://apps.apple.com/us/app/id6754315964',
|
|
category: 'App Store'
|
|
});
|
|
expect(offers.find(({ category }) => category === 'Google Play')).toEqual({
|
|
'@type': 'Offer',
|
|
url: 'https://play.google.com/store/apps/details?id=com.edde746.plezy',
|
|
category: 'Google Play'
|
|
});
|
|
expect(offers.filter(({ price }) => price === '0').map(({ category }) => category)).toEqual([
|
|
'GitHub'
|
|
]);
|
|
});
|
|
|
|
test('attaches valid USD prices to each paid mobile store', () => {
|
|
const offers = buildSoftwareApplicationOffers({
|
|
appStorePrice: '4.99',
|
|
playStorePrice: '3.99'
|
|
});
|
|
|
|
expect(offers.find(({ category }) => category === 'App Store')).toMatchObject({
|
|
price: '4.99',
|
|
priceCurrency: 'USD'
|
|
});
|
|
expect(offers.find(({ category }) => category === 'Google Play')).toMatchObject({
|
|
price: '3.99',
|
|
priceCurrency: 'USD'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('route content contracts', () => {
|
|
test('uses the same Watch Together answer in the visible FAQ and FAQ schema', () => {
|
|
const visibleFaq = faqs.find(({ id }) => id === 'watch-together');
|
|
expect(visibleFaq).toBeDefined();
|
|
expect(visibleFaq?.answer).toBe(watchTogetherFaqAnswer);
|
|
|
|
const schemaFaq = faqSchemaMainEntity.find(({ name }) => name === visibleFaq?.question);
|
|
expect(schemaFaq).toBeDefined();
|
|
expect(schemaFaq?.acceptedAnswer.text).toBe(watchTogetherFaqAnswer);
|
|
});
|
|
|
|
test('keeps the privacy route server-rendered without client hydration', () => {
|
|
expect(privacyCsr).toBe(false);
|
|
});
|
|
});
|