mirror of
https://github.com/zen-browser/www.git
synced 2025-07-08 01:10:02 +02:00
feat(download): enhance download page with checksum integration and platform-specific releases
- Added a new `release-data.ts` file to manage release information with dynamic checksums. - Introduced `CHECKSUMS` constant for easy access to file checksums. - Updated `PlatformDownload.astro` to support additional release types and improved type safety. - Enhanced the download page to correctly display platform-specific download links and checksums. - Refactored tests to validate the new download functionality and checksum integration.
This commit is contained in:
parent
466c829a8a
commit
6a7bd311c0
9 changed files with 231 additions and 103 deletions
|
@ -13,7 +13,8 @@
|
|||
"format": "biome format ./src",
|
||||
"prepare": "husky",
|
||||
"test": "npx vitest run",
|
||||
"test:coverage": "npx vitest --coverage"
|
||||
"test:coverage": "npx vitest --coverage",
|
||||
"test:playwright": "npx playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
|
|
|
@ -9,7 +9,16 @@ interface PlatformReleases {
|
|||
universal?: ReleaseInfo
|
||||
all?: ReleaseInfo
|
||||
tarball?: ReleaseInfo
|
||||
x86_64?: { tarball: ReleaseInfo } | ReleaseInfo
|
||||
x86_64?:
|
||||
| {
|
||||
tarball?: ReleaseInfo
|
||||
appImage?: ReleaseInfo
|
||||
}
|
||||
| ReleaseInfo
|
||||
aarch64?: {
|
||||
tarball?: ReleaseInfo
|
||||
appImage?: ReleaseInfo
|
||||
}
|
||||
arm64?: ReleaseInfo
|
||||
flathub?: { all: ReleaseInfo }
|
||||
}
|
||||
|
@ -27,11 +36,15 @@ import { Image } from 'astro:assets'
|
|||
import AppIconDark from '../../assets/app-icon-dark.png'
|
||||
import AppIconLight from '../../assets/app-icon-light.png'
|
||||
import DownloadCard from './ButtonCard.astro'
|
||||
|
||||
function isFlatReleaseInfo(obj: unknown): obj is ReleaseInfo {
|
||||
return !!obj && typeof obj === 'object' && 'link' in obj
|
||||
}
|
||||
---
|
||||
|
||||
<div
|
||||
id={`${platform}-downloads`}
|
||||
data-active={platform === 'mac'}
|
||||
data-active={platform === "mac"}
|
||||
class="platform-section data-[active='false']:hidden"
|
||||
>
|
||||
<div class="items-center gap-8 md:flex">
|
||||
|
@ -45,9 +58,10 @@ import DownloadCard from './ButtonCard.astro'
|
|||
<p class="text-muted-foreground mb-6" set:html={description} />
|
||||
<div class="space-y-6">
|
||||
{
|
||||
platform === 'linux' ? (
|
||||
platform === "linux" ? (
|
||||
<>
|
||||
{releases.flathub && releases.flathub.all.label && <div>
|
||||
{releases.flathub && releases.flathub.all.label && (
|
||||
<div>
|
||||
<h4 class="mb-3 text-lg font-medium">Package Managers</h4>
|
||||
<div class="space-y-3">
|
||||
<DownloadCard
|
||||
|
@ -56,28 +70,96 @@ import DownloadCard from './ButtonCard.astro'
|
|||
variant="flathub"
|
||||
/>
|
||||
</div>
|
||||
</div>}
|
||||
{releases.x86_64 && 'tarball' in releases.x86_64 && <div>
|
||||
<h4 class="mb-3 text-lg font-medium">Tarball</h4>
|
||||
</div>
|
||||
)}
|
||||
{releases.x86_64 &&
|
||||
typeof releases.x86_64 === "object" &&
|
||||
"tarball" in releases.x86_64 &&
|
||||
(releases.x86_64.tarball || releases.x86_64.appImage) && (
|
||||
<div>
|
||||
<h4 class="mb-3 text-lg font-medium">x86_64</h4>
|
||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
{releases.x86_64.tarball && (
|
||||
<DownloadCard
|
||||
label="x86_64"
|
||||
href={releases.x86_64.tarball.link}
|
||||
label={
|
||||
releases.x86_64.tarball.label
|
||||
? releases.x86_64.tarball.label
|
||||
: ""
|
||||
}
|
||||
href={
|
||||
releases.x86_64.tarball.link
|
||||
? releases.x86_64.tarball.link
|
||||
: ""
|
||||
}
|
||||
variant="x86_64"
|
||||
checksum={releases.x86_64.tarball.checksum}
|
||||
/>
|
||||
)}
|
||||
{releases.x86_64.appImage && (
|
||||
<DownloadCard
|
||||
label="ARM64"
|
||||
href={releases.x86_64.tarball.link}
|
||||
variant="aarch64"
|
||||
checksum={releases.x86_64.tarball.checksum}
|
||||
label={
|
||||
releases.x86_64.appImage.label
|
||||
? releases.x86_64.appImage.label
|
||||
: ""
|
||||
}
|
||||
href={
|
||||
releases.x86_64.appImage.link
|
||||
? releases.x86_64.appImage.link
|
||||
: ""
|
||||
}
|
||||
variant="x86_64"
|
||||
checksum={releases.x86_64.appImage.checksum}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
)}
|
||||
{releases.aarch64 &&
|
||||
typeof releases.aarch64 === "object" &&
|
||||
"tarball" in releases.aarch64 &&
|
||||
(releases.aarch64.tarball || releases.aarch64.appImage) && (
|
||||
<div>
|
||||
<h4 class="mb-3 text-lg font-medium">ARM64</h4>
|
||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
{releases.aarch64.tarball && (
|
||||
<DownloadCard
|
||||
label={
|
||||
releases.aarch64.tarball.label
|
||||
? releases.aarch64.tarball.label
|
||||
: ""
|
||||
}
|
||||
href={
|
||||
releases.aarch64.tarball.link
|
||||
? releases.aarch64.tarball.link
|
||||
: ""
|
||||
}
|
||||
variant="aarch64"
|
||||
checksum={releases.aarch64.tarball.checksum}
|
||||
/>
|
||||
)}
|
||||
{releases.aarch64.appImage && (
|
||||
<DownloadCard
|
||||
label={
|
||||
releases.aarch64.appImage.label
|
||||
? releases.aarch64.appImage.label
|
||||
: ""
|
||||
}
|
||||
href={
|
||||
releases.aarch64.appImage.link
|
||||
? releases.aarch64.appImage.link
|
||||
: ""
|
||||
}
|
||||
variant="aarch64"
|
||||
checksum={releases.aarch64.appImage.checksum}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-3">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-3">
|
||||
{releases.universal && releases.universal.label && (
|
||||
<DownloadCard
|
||||
label={releases.universal.label}
|
||||
|
@ -85,22 +167,14 @@ import DownloadCard from './ButtonCard.astro'
|
|||
checksum={releases.universal.checksum}
|
||||
/>
|
||||
)}
|
||||
{releases.x86_64 && (
|
||||
'tarball' in releases.x86_64
|
||||
? releases.x86_64.tarball.label && (
|
||||
<DownloadCard
|
||||
label={releases.x86_64.tarball.label}
|
||||
href={releases.x86_64.tarball.link}
|
||||
checksum={releases.x86_64.tarball.checksum}
|
||||
/>
|
||||
)
|
||||
: releases.x86_64.label && (
|
||||
{releases.x86_64 &&
|
||||
isFlatReleaseInfo(releases.x86_64) &&
|
||||
releases.x86_64.label && (
|
||||
<DownloadCard
|
||||
label={releases.x86_64.label}
|
||||
href={releases.x86_64.link}
|
||||
checksum={releases.x86_64.checksum}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{releases.arm64 && releases.arm64.label && (
|
||||
<DownloadCard
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
---
|
||||
/**
|
||||
* Returns the releases object, injecting checksums dynamically.
|
||||
* @param checksums Record<string, string> mapping filenames to SHA-256 hashes
|
||||
|
@ -28,24 +27,24 @@ export function getReleasesWithChecksums(checksums: Record<string, string>) {
|
|||
x86_64: {
|
||||
tarball: {
|
||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-x86_64.tar.xz',
|
||||
label: 'Tarball x86_64',
|
||||
label: 'Tarball',
|
||||
checksum: checksums['zen.linux-x86_64.tar.xz'],
|
||||
},
|
||||
appImage: {
|
||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen-x86_64.AppImage',
|
||||
label: 'AppImage x86_64',
|
||||
label: 'AppImage',
|
||||
checksum: checksums['zen-x86_64.AppImage'],
|
||||
},
|
||||
},
|
||||
aarch64: {
|
||||
tarball: {
|
||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-aarch64.tar.xz',
|
||||
label: 'Tarball aarch64',
|
||||
label: 'Tarball',
|
||||
checksum: checksums['zen.linux-aarch64.tar.xz'],
|
||||
},
|
||||
appImage: {
|
||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen-aarch64.AppImage',
|
||||
label: 'AppImage aarch64',
|
||||
label: 'AppImage',
|
||||
checksum: checksums['zen-aarch64.AppImage'],
|
||||
},
|
||||
},
|
||||
|
@ -58,4 +57,3 @@ export function getReleasesWithChecksums(checksums: Record<string, string>) {
|
|||
},
|
||||
}
|
||||
}
|
||||
---
|
9
src/constants/checksum.ts
Normal file
9
src/constants/checksum.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export const CHECKSUMS = {
|
||||
'zen.macos-universal.dmg': 'macsum',
|
||||
'zen.installer.exe': 'winsum',
|
||||
'zen.installer-arm64.exe': 'winarmsum',
|
||||
'zen.linux-x86_64.tar.xz': 'linuxsum',
|
||||
'zen-x86_64.AppImage': 'linuxappsum',
|
||||
'zen.linux-aarch64.tar.xz': 'linuxarmsum',
|
||||
'zen-aarch64.AppImage': 'linuxarmappsum',
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import { CHECKSUMS } from './checksum'
|
||||
import { I18N } from './i18n'
|
||||
|
||||
export const CONSTANT = {
|
||||
I18N,
|
||||
CHECKSUMS,
|
||||
}
|
||||
|
|
|
@ -1,36 +1,41 @@
|
|||
---
|
||||
import Description from '~/components/Description.astro'
|
||||
import DownloadScript from '~/components/download/DownloadScript.astro'
|
||||
import PlatformDownload from '~/components/download/PlatformDownload.astro'
|
||||
import { getReleasesWithChecksums } from '~/components/download/release-data.astro'
|
||||
import Layout from '~/layouts/Layout.astro'
|
||||
import { getChecksums } from '~/utils/githubChecksums'
|
||||
import { getLocale, getUI } from '~/utils/i18n'
|
||||
import Description from "~/components/Description.astro";
|
||||
import DownloadScript from "~/components/download/DownloadScript.astro";
|
||||
import PlatformDownload from "~/components/download/PlatformDownload.astro";
|
||||
import { getReleasesWithChecksums } from "~/components/download/release-data";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import { getChecksums } from "~/utils/githubChecksums";
|
||||
import { getLocale, getUI } from "~/utils/i18n";
|
||||
|
||||
import { icon, library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faApple, faGithub, faLinux, faWindows } from '@fortawesome/free-brands-svg-icons'
|
||||
import ExternalLinkIcon from '~/icons/ExternalLink.astro'
|
||||
import LockIcon from '~/icons/LockIcon.astro'
|
||||
import { icon, library } from "@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faApple,
|
||||
faGithub,
|
||||
faLinux,
|
||||
faWindows,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
import ExternalLinkIcon from "~/icons/ExternalLink.astro";
|
||||
import LockIcon from "~/icons/LockIcon.astro";
|
||||
|
||||
export { getStaticPaths } from '~/utils/i18n'
|
||||
export { getStaticPaths } from "~/utils/i18n";
|
||||
|
||||
const locale = getLocale(Astro)
|
||||
const locale = getLocale(Astro);
|
||||
const {
|
||||
routes: { download },
|
||||
layout,
|
||||
} = getUI(locale)
|
||||
} = getUI(locale);
|
||||
|
||||
library.add(faWindows, faLinux, faApple, faGithub)
|
||||
const windowsIcon = icon({ prefix: 'fab', iconName: 'windows' })
|
||||
const linuxIcon = icon({ prefix: 'fab', iconName: 'linux' })
|
||||
const appleIcon = icon({ prefix: 'fab', iconName: 'apple' })
|
||||
const githubIcon = icon({ prefix: 'fab', iconName: 'github' })
|
||||
library.add(faWindows, faLinux, faApple, faGithub);
|
||||
const windowsIcon = icon({ prefix: "fab", iconName: "windows" });
|
||||
const linuxIcon = icon({ prefix: "fab", iconName: "linux" });
|
||||
const appleIcon = icon({ prefix: "fab", iconName: "apple" });
|
||||
const githubIcon = icon({ prefix: "fab", iconName: "github" });
|
||||
|
||||
const checksums = await getChecksums()
|
||||
const releases = getReleasesWithChecksums(checksums)
|
||||
const checksums = await getChecksums();
|
||||
const releases = getReleasesWithChecksums(checksums);
|
||||
|
||||
const platformNames = download.platformNames
|
||||
const platformDescriptions = download.platformDescriptions
|
||||
const platformNames = download.platformNames;
|
||||
const platformDescriptions = download.platformDescriptions;
|
||||
---
|
||||
|
||||
<DownloadScript />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { getReleasesWithChecksums } from '~/components/download/release-data.astro'
|
||||
import { getReleasesWithChecksums } from '~/components/download/release-data'
|
||||
|
||||
describe('getReleasesWithChecksums', () => {
|
||||
it('returns correct structure with checksums', () => {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { expect, test } from '@playwright/test'
|
||||
import type { BrowserContextOptions, Page } from '@playwright/test'
|
||||
import { getReleasesWithChecksums } from '~/components/download/release-data'
|
||||
import { CONSTANT } from '~/constants'
|
||||
|
||||
// Helper to get the platform section by id
|
||||
const getPlatformSection = (page: Page, platform: string) =>
|
||||
|
@ -9,6 +11,10 @@ const getPlatformSection = (page: Page, platform: string) =>
|
|||
const getPlatformButton = (page: Page, platform: string) =>
|
||||
page.locator(`button.platform-selector[data-platform='${platform}']`)
|
||||
|
||||
// Helper to get the platform download link
|
||||
const getPlatformDownloadLink = (page: Page, platform: string, label: string) =>
|
||||
page.locator(`#${platform}-downloads .download-link:has-text('${label}')`)
|
||||
|
||||
const platformConfigs: { name: string; userAgent: string; platform: string }[] = [
|
||||
{
|
||||
name: 'windows',
|
||||
|
@ -29,6 +35,7 @@ const platformConfigs: { name: string; userAgent: string; platform: string }[] =
|
|||
},
|
||||
]
|
||||
|
||||
test.describe('Download page default tab per platform', () => {
|
||||
for (const { name, userAgent, platform } of platformConfigs) {
|
||||
test(`shows correct default tab for ${name} platform`, async ({ browser }) => {
|
||||
const context = await browser.newContext({
|
||||
|
@ -48,6 +55,7 @@ for (const { name, userAgent, platform } of platformConfigs) {
|
|||
await context.close()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test.describe('Download page platform detection and tab switching', () => {
|
||||
test('shows correct platform section and tab when switching platforms', async ({ page }) => {
|
||||
|
@ -65,3 +73,36 @@ test.describe('Download page platform detection and tab switching', () => {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Download page download links', () => {
|
||||
const releases = getReleasesWithChecksums(CONSTANT.CHECKSUMS)
|
||||
|
||||
function getPlatformLinks(releases: ReturnType<typeof getReleasesWithChecksums>) {
|
||||
return {
|
||||
mac: [releases.macos.universal],
|
||||
windows: [releases.windows.x86_64, releases.windows.arm64],
|
||||
linux: [
|
||||
releases.linux.x86_64.tarball,
|
||||
releases.linux.x86_64.appImage,
|
||||
releases.linux.aarch64.tarball,
|
||||
releases.linux.aarch64.appImage,
|
||||
releases.linux.flathub.all,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
test('all platform download links are correct', async ({ page }) => {
|
||||
const platforms = ['windows', 'mac', 'linux']
|
||||
const platformLinkSelectors = getPlatformLinks(releases)
|
||||
await page.goto('/download')
|
||||
await page.waitForLoadState('domcontentloaded')
|
||||
for (const platform of platforms) {
|
||||
await getPlatformButton(page, platform).click()
|
||||
for (const { label, link } of platformLinkSelectors[platform as keyof typeof platformLinkSelectors]) {
|
||||
const downloadLink = page.locator(`#${platform}-downloads .download-link[href="${link}"]`)
|
||||
await expect(downloadLink).toContainText(label)
|
||||
await expect(downloadLink).toHaveAttribute('href', link)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import { CONSTANT } from '~/constants'
|
||||
|
||||
/**
|
||||
* Fetches the latest release notes from GitHub and parses the SHA-256 checksums.
|
||||
* Returns a mapping from filename to checksum.
|
||||
*/
|
||||
export async function getChecksums() {
|
||||
if (import.meta.env.DEV) {
|
||||
return {
|
||||
'zen.macos-universal.dmg': 'macsum',
|
||||
'zen.installer.exe': 'winsum',
|
||||
'zen.installer-arm64.exe': 'winarmsum',
|
||||
}
|
||||
return CONSTANT.CHECKSUMS
|
||||
}
|
||||
const res = await fetch('https://api.github.com/repos/zen-browser/desktop/releases/latest', {
|
||||
headers: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue