mirror of
https://github.com/zen-browser/www.git
synced 2025-07-07 08:55:32 +02:00
fix: resolve merge conflict
This commit is contained in:
commit
9f4cab7f7d
23 changed files with 2365 additions and 2387 deletions
111
.github/workflows/ci-pipeline.yml
vendored
Normal file
111
.github/workflows/ci-pipeline.yml
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
name: CI Pipeline
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Cache node_modules
|
||||||
|
id: cache-deps
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
|
||||||
|
- name: Verify npm installation
|
||||||
|
run: npm --version
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
biome:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: setup
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
|
||||||
|
- name: Run Biome check
|
||||||
|
run: npx biome check ./src
|
||||||
|
|
||||||
|
vitest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: setup
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
|
||||||
|
- name: Run Vitest tests
|
||||||
|
run: npx vitest run
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: setup
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
|
||||||
|
- name: Build project
|
||||||
|
run: npm run build
|
||||||
|
- name: Upload build output
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: |
|
||||||
|
dist
|
||||||
|
|
||||||
|
playwright:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: Install Playwright Browsers
|
||||||
|
run: npx playwright install --with-deps
|
||||||
|
- name: Download build output
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build
|
||||||
|
path: dist
|
||||||
|
- name: Run Playwright tests
|
||||||
|
run: npx playwright test
|
28
.github/workflows/prbuildcheck.yml
vendored
28
.github/workflows/prbuildcheck.yml
vendored
|
@ -1,28 +0,0 @@
|
||||||
name: PR Build Check
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
upload:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Verify npm installation
|
|
||||||
run: npm --version
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install --no-frozen-lockfile
|
|
||||||
|
|
||||||
- name: Run Biome check
|
|
||||||
run: npx biome check ./src
|
|
||||||
|
|
||||||
- name: Build project
|
|
||||||
run: npm run build
|
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -22,3 +22,11 @@ npm-debug.log*
|
||||||
|
|
||||||
# jetbrains setting folder
|
# jetbrains setting folder
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|
||||||
|
/coverage
|
3921
package-lock.json
generated
3921
package-lock.json
generated
File diff suppressed because it is too large
Load diff
14
package.json
14
package.json
|
@ -11,7 +11,10 @@
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"lint": "biome lint ./src",
|
"lint": "biome lint ./src",
|
||||||
"format": "biome format ./src",
|
"format": "biome format ./src",
|
||||||
"prepare": "husky"
|
"prepare": "husky",
|
||||||
|
"test": "npx vitest run",
|
||||||
|
"test:coverage": "npx vitest --coverage",
|
||||||
|
"test:playwright": "npx playwright test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.9.4",
|
"@astrojs/check": "^0.9.4",
|
||||||
|
@ -42,8 +45,17 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
|
"@playwright/test": "^1.52.0",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
"@types/jsdom": "^21.1.7",
|
||||||
|
"@types/node": "^22.15.18",
|
||||||
|
"@vitest/coverage-istanbul": "^3.1.3",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
|
"jsdom": "^26.1.0",
|
||||||
"lint-staged": "^15.2.7",
|
"lint-staged": "^15.2.7",
|
||||||
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.1.3",
|
||||||
"wrangler": "^3.94.0"
|
"wrangler": "^3.94.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|
72
playwright.config.ts
Normal file
72
playwright.config.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { defineConfig, devices } from '@playwright/test'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// import path from 'path';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './src/tests',
|
||||||
|
testIgnore: ['**.test.ts'],
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
reporter: 'html',
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000',
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'firefox',
|
||||||
|
use: { ...devices['Desktop Firefox'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'webkit',
|
||||||
|
use: { ...devices['Desktop Safari'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: {
|
||||||
|
command: process.env.CI ? 'npm run start' : 'npm run dev',
|
||||||
|
url: 'http://localhost:3000',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
})
|
|
@ -196,7 +196,7 @@ export default function ModsList({ allMods, locale }: ModsListProps) {
|
||||||
{paginatedMods.length > 0 ? (
|
{paginatedMods.length > 0 ? (
|
||||||
paginatedMods.map((mod) => (
|
paginatedMods.map((mod) => (
|
||||||
<a
|
<a
|
||||||
className="flex w-full flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90"
|
className="mod-card flex w-full flex-col gap-4 border-transparent transition-colors duration-100 hover:opacity-90"
|
||||||
href={`/mods/${mod.id}`}
|
href={`/mods/${mod.id}`}
|
||||||
key={mod.id}
|
key={mod.id}
|
||||||
>
|
>
|
||||||
|
|
|
@ -9,7 +9,14 @@ interface PlatformReleases {
|
||||||
universal?: ReleaseInfo
|
universal?: ReleaseInfo
|
||||||
all?: ReleaseInfo
|
all?: ReleaseInfo
|
||||||
tarball?: ReleaseInfo
|
tarball?: ReleaseInfo
|
||||||
x86_64?: { tarball: ReleaseInfo } | ReleaseInfo
|
x86_64?:
|
||||||
|
| {
|
||||||
|
tarball?: ReleaseInfo
|
||||||
|
}
|
||||||
|
| ReleaseInfo
|
||||||
|
aarch64?: {
|
||||||
|
tarball?: ReleaseInfo
|
||||||
|
}
|
||||||
arm64?: ReleaseInfo
|
arm64?: ReleaseInfo
|
||||||
flathub?: { all: ReleaseInfo }
|
flathub?: { all: ReleaseInfo }
|
||||||
}
|
}
|
||||||
|
@ -27,11 +34,15 @@ import { Image } from 'astro:assets'
|
||||||
import AppIconDark from '../../assets/app-icon-dark.png'
|
import AppIconDark from '../../assets/app-icon-dark.png'
|
||||||
import AppIconLight from '../../assets/app-icon-light.png'
|
import AppIconLight from '../../assets/app-icon-light.png'
|
||||||
import DownloadCard from './ButtonCard.astro'
|
import DownloadCard from './ButtonCard.astro'
|
||||||
|
|
||||||
|
function isFlatReleaseInfo(obj: unknown): obj is ReleaseInfo {
|
||||||
|
return !!obj && typeof obj === 'object' && 'link' in obj
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id={`${platform}-downloads`}
|
id={`${platform}-downloads`}
|
||||||
data-active={platform === 'mac'}
|
data-active={platform === "mac"}
|
||||||
class="platform-section data-[active='false']:hidden"
|
class="platform-section data-[active='false']:hidden"
|
||||||
>
|
>
|
||||||
<div class="items-center gap-8 md:flex">
|
<div class="items-center gap-8 md:flex">
|
||||||
|
@ -45,39 +56,76 @@ import DownloadCard from './ButtonCard.astro'
|
||||||
<p class="text-muted-foreground mb-6" set:html={description} />
|
<p class="text-muted-foreground mb-6" set:html={description} />
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
{
|
{
|
||||||
platform === 'linux' ? (
|
platform === "linux" ? (
|
||||||
<>
|
<>
|
||||||
{releases.flathub && releases.flathub.all.label && <div>
|
{releases.flathub && releases.flathub.all.label && (
|
||||||
<h4 class="mb-3 text-lg font-medium">Package Managers</h4>
|
<div>
|
||||||
<div class="space-y-3">
|
<h4 class="mb-3 text-lg font-medium">Package Managers</h4>
|
||||||
<DownloadCard
|
<div class="space-y-3">
|
||||||
label={releases.flathub.all.label}
|
<DownloadCard
|
||||||
href={releases.flathub.all.link}
|
label={releases.flathub.all.label}
|
||||||
variant="flathub"
|
href={releases.flathub.all.link}
|
||||||
/>
|
variant="flathub"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
)}
|
||||||
{releases.x86_64 && 'tarball' in releases.x86_64 && <div>
|
{releases.x86_64 &&
|
||||||
<h4 class="mb-3 text-lg font-medium">Tarball</h4>
|
typeof releases.x86_64 === "object" &&
|
||||||
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
"tarball" in releases.x86_64 &&
|
||||||
<DownloadCard
|
(releases.x86_64.tarball) && (
|
||||||
label="x86_64"
|
<div>
|
||||||
href={releases.x86_64.tarball.link}
|
<h4 class="mb-3 text-lg font-medium">x86_64</h4>
|
||||||
variant="x86_64"
|
<div class="">
|
||||||
checksum={releases.x86_64.tarball.checksum}
|
{releases.x86_64.tarball && (
|
||||||
/>
|
<DownloadCard
|
||||||
<DownloadCard
|
label={
|
||||||
label="ARM64"
|
releases.x86_64.tarball.label
|
||||||
href={releases.x86_64.tarball.link}
|
? releases.x86_64.tarball.label
|
||||||
variant="aarch64"
|
: ""
|
||||||
checksum={releases.x86_64.tarball.checksum}
|
}
|
||||||
/>
|
href={
|
||||||
</div>
|
releases.x86_64.tarball.link
|
||||||
</div>}
|
? releases.x86_64.tarball.link
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
variant="x86_64"
|
||||||
|
checksum={releases.x86_64.tarball.checksum}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{releases.aarch64 &&
|
||||||
|
typeof releases.aarch64 === "object" &&
|
||||||
|
"tarball" in releases.aarch64 &&
|
||||||
|
(releases.aarch64.tarball) && (
|
||||||
|
<div>
|
||||||
|
<h4 class="mb-3 text-lg font-medium">ARM64</h4>
|
||||||
|
<div class="gap-3">
|
||||||
|
{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}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div class="space-y-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="space-y-3">
|
<div class="flex flex-col gap-3">
|
||||||
{releases.universal && releases.universal.label && (
|
{releases.universal && releases.universal.label && (
|
||||||
<DownloadCard
|
<DownloadCard
|
||||||
label={releases.universal.label}
|
label={releases.universal.label}
|
||||||
|
@ -85,23 +133,15 @@ import DownloadCard from './ButtonCard.astro'
|
||||||
checksum={releases.universal.checksum}
|
checksum={releases.universal.checksum}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{releases.x86_64 && (
|
{releases.x86_64 &&
|
||||||
'tarball' in releases.x86_64
|
isFlatReleaseInfo(releases.x86_64) &&
|
||||||
? releases.x86_64.tarball.label && (
|
releases.x86_64.label && (
|
||||||
<DownloadCard
|
<DownloadCard
|
||||||
label={releases.x86_64.tarball.label}
|
label={releases.x86_64.label}
|
||||||
href={releases.x86_64.tarball.link}
|
href={releases.x86_64.link}
|
||||||
checksum={releases.x86_64.tarball.checksum}
|
checksum={releases.x86_64.checksum}
|
||||||
/>
|
/>
|
||||||
)
|
)}
|
||||||
: 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 && (
|
{releases.arm64 && releases.arm64.label && (
|
||||||
<DownloadCard
|
<DownloadCard
|
||||||
label={releases.arm64.label}
|
label={releases.arm64.label}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
---
|
|
||||||
/**
|
/**
|
||||||
* Returns the releases object, injecting checksums dynamically.
|
* Returns the releases object, injecting checksums dynamically.
|
||||||
* @param checksums Record<string, string> mapping filenames to SHA-256 hashes
|
* @param checksums Record<string, string> mapping filenames to SHA-256 hashes
|
||||||
|
@ -28,26 +27,16 @@ export function getReleasesWithChecksums(checksums: Record<string, string>) {
|
||||||
x86_64: {
|
x86_64: {
|
||||||
tarball: {
|
tarball: {
|
||||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-x86_64.tar.xz',
|
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'],
|
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',
|
|
||||||
checksum: checksums['zen-x86_64.AppImage'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
aarch64: {
|
aarch64: {
|
||||||
tarball: {
|
tarball: {
|
||||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-aarch64.tar.xz',
|
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'],
|
checksum: checksums['zen.linux-aarch64.tar.xz'],
|
||||||
},
|
},
|
||||||
appImage: {
|
|
||||||
link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen-aarch64.AppImage',
|
|
||||||
label: 'AppImage aarch64',
|
|
||||||
checksum: checksums['zen-aarch64.AppImage'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
flathub: {
|
flathub: {
|
||||||
all: {
|
all: {
|
||||||
|
@ -58,4 +47,3 @@ export function getReleasesWithChecksums(checksums: Record<string, string>) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
---
|
|
7
src/constants/checksum.ts
Normal file
7
src/constants/checksum.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
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.linux-aarch64.tar.xz': 'linuxarmsum',
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
import { CHECKSUMS } from './checksum'
|
||||||
import { I18N } from './i18n'
|
import { I18N } from './i18n'
|
||||||
|
|
||||||
export const CONSTANT = {
|
export const CONSTANT = {
|
||||||
I18N,
|
I18N,
|
||||||
|
CHECKSUMS,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import Description from '~/components/Description.astro'
|
import Description from '~/components/Description.astro'
|
||||||
import DownloadScript from '~/components/download/DownloadScript.astro'
|
import DownloadScript from '~/components/download/DownloadScript.astro'
|
||||||
import PlatformDownload from '~/components/download/PlatformDownload.astro'
|
import PlatformDownload from '~/components/download/PlatformDownload.astro'
|
||||||
import { getReleasesWithChecksums } from '~/components/download/release-data.astro'
|
import { getReleasesWithChecksums } from '~/components/download/release-data'
|
||||||
import Layout from '~/layouts/Layout.astro'
|
import Layout from '~/layouts/Layout.astro'
|
||||||
import { getChecksums } from '~/utils/githubChecksums'
|
import { getChecksums } from '~/utils/githubChecksums'
|
||||||
import { getLocale, getUI } from '~/utils/i18n'
|
import { getLocale, getUI } from '~/utils/i18n'
|
||||||
|
|
101
src/tests/components/Button.test.ts
Normal file
101
src/tests/components/Button.test.ts
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { experimental_AstroContainer as AstroContainer } from 'astro/container'
|
||||||
|
import { beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
import Button from '~/components/Button.astro'
|
||||||
|
|
||||||
|
describe('<Button />', () => {
|
||||||
|
let container: Awaited<ReturnType<typeof AstroContainer.create>>
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
container = await AstroContainer.create()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('as <button>', () => {
|
||||||
|
it('renders default <button> with slot', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: {},
|
||||||
|
slots: { default: 'Click me' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('<button')
|
||||||
|
expect(result).toContain('Click me')
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['isPrimary', { isPrimary: true }, 'bg-dark'],
|
||||||
|
['isAlert', { isAlert: true }, 'bg-red-300'],
|
||||||
|
['isBordered', { isBordered: true }, 'border-2'],
|
||||||
|
])('applies %s style', async (_label, propObj, expectedClass) => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: { ...propObj },
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('<button')
|
||||||
|
expect(result).toContain(expectedClass)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('applies id and extra props', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: {
|
||||||
|
id: 'my-btn',
|
||||||
|
extra: { 'data-test': 'foo' },
|
||||||
|
},
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('id="my-btn"')
|
||||||
|
expect(result).toContain('data-test="foo"')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('as <a>', () => {
|
||||||
|
it('renders <a> with slot and href', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: { href: '/link' },
|
||||||
|
slots: { default: 'Go' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('<a')
|
||||||
|
expect(result).toContain('Go')
|
||||||
|
expect(result).toContain('href="/en/link"')
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['isPrimary', { isPrimary: true }, 'bg-dark'],
|
||||||
|
['isAlert', { isAlert: true }, 'bg-red-300'],
|
||||||
|
['isBordered', { isBordered: true }, 'border-2'],
|
||||||
|
])('applies %s style', async (_label, propObj, expectedClass) => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: { href: '/link', ...propObj },
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('<a')
|
||||||
|
expect(result).toContain(expectedClass)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('applies id and extra props', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: {
|
||||||
|
href: '/link',
|
||||||
|
id: 'my-link',
|
||||||
|
extra: { 'data-test': 'bar' },
|
||||||
|
},
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('id="my-link"')
|
||||||
|
expect(result).toContain('data-test="bar"')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('applies custom className', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: { class: 'custom-class' },
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('custom-class')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses locale path for href', async () => {
|
||||||
|
const result = await container.renderToString(Button, {
|
||||||
|
props: { href: '/foo' },
|
||||||
|
slots: { default: 'Test' },
|
||||||
|
})
|
||||||
|
expect(result).toContain('href="/en/foo"')
|
||||||
|
})
|
||||||
|
})
|
47
src/tests/components/ButtonCard.test.ts
Normal file
47
src/tests/components/ButtonCard.test.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { experimental_AstroContainer as AstroContainer } from 'astro/container'
|
||||||
|
import { beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
import ButtonCard from '~/components/download/ButtonCard.astro'
|
||||||
|
|
||||||
|
describe('<ButtonCard />', () => {
|
||||||
|
let container: Awaited<ReturnType<typeof AstroContainer.create>>
|
||||||
|
beforeEach(async () => {
|
||||||
|
container = await AstroContainer.create()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders with required props', async () => {
|
||||||
|
const result = await container.renderToString(ButtonCard, {
|
||||||
|
props: {
|
||||||
|
label: 'Download',
|
||||||
|
href: '/download',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Download')
|
||||||
|
expect(result).toContain('href="/download"')
|
||||||
|
expect(result).not.toContain('Show SHA-256')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders with checksum', async () => {
|
||||||
|
const result = await container.renderToString(ButtonCard, {
|
||||||
|
props: {
|
||||||
|
label: 'Download',
|
||||||
|
href: '/download',
|
||||||
|
checksum: 'sha256sum',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Show SHA-256')
|
||||||
|
expect(result).toContain('sha256sum')
|
||||||
|
expect(result).toContain('Copy')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders with variant', async () => {
|
||||||
|
const result = await container.renderToString(ButtonCard, {
|
||||||
|
props: {
|
||||||
|
label: 'Download',
|
||||||
|
href: '/download',
|
||||||
|
variant: 'flathub',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Download')
|
||||||
|
expect(result).toContain('Beta')
|
||||||
|
})
|
||||||
|
})
|
111
src/tests/components/PlatformDownload.test.ts
Normal file
111
src/tests/components/PlatformDownload.test.ts
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import { experimental_AstroContainer as AstroContainer } from 'astro/container'
|
||||||
|
import { beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
import PlatformDownload from '~/components/download/PlatformDownload.astro'
|
||||||
|
|
||||||
|
const mockIcon = ['<svg></svg>']
|
||||||
|
const mockReleases = {
|
||||||
|
universal: { label: 'Universal', link: '/universal', checksum: 'abc123' },
|
||||||
|
x86_64: { label: 'x86_64', link: '/x86_64', checksum: 'def456' },
|
||||||
|
arm64: { label: 'ARM64', link: '/arm64', checksum: 'ghi789' },
|
||||||
|
flathub: { all: { label: 'Flathub', link: '/flathub' } },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('<PlatformDownload />', () => {
|
||||||
|
let container: Awaited<ReturnType<typeof AstroContainer.create>>
|
||||||
|
beforeEach(async () => {
|
||||||
|
container = await AstroContainer.create()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders mac platform', async () => {
|
||||||
|
const result = await container.renderToString(PlatformDownload, {
|
||||||
|
props: {
|
||||||
|
platform: 'mac',
|
||||||
|
icon: mockIcon,
|
||||||
|
title: 'Mac Title',
|
||||||
|
description: 'Mac Desc',
|
||||||
|
releases: mockReleases,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Mac Title')
|
||||||
|
expect(result).toContain('Mac Desc')
|
||||||
|
expect(result).toContain('Universal')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders windows platform', async () => {
|
||||||
|
const result = await container.renderToString(PlatformDownload, {
|
||||||
|
props: {
|
||||||
|
platform: 'windows',
|
||||||
|
icon: mockIcon,
|
||||||
|
title: 'Win Title',
|
||||||
|
description: 'Win Desc',
|
||||||
|
releases: mockReleases,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Win Title')
|
||||||
|
expect(result).toContain('Win Desc')
|
||||||
|
expect(result).toContain('x86_64')
|
||||||
|
expect(result).toContain('ARM64')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders linux platform with flathub and tarball', async () => {
|
||||||
|
const linuxReleases = {
|
||||||
|
flathub: { all: { label: 'Flathub', link: '/flathub' } },
|
||||||
|
x86_64: { tarball: { label: 'Tarball x86_64', link: '/tarball-x86_64', checksum: 'sha256' } },
|
||||||
|
}
|
||||||
|
const result = await container.renderToString(PlatformDownload, {
|
||||||
|
props: {
|
||||||
|
platform: 'linux',
|
||||||
|
icon: mockIcon,
|
||||||
|
title: 'Linux Title',
|
||||||
|
description: 'Linux Desc',
|
||||||
|
releases: linuxReleases,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(result).toContain('Linux Title')
|
||||||
|
expect(result).toContain('Linux Desc')
|
||||||
|
expect(result).toContain('Flathub')
|
||||||
|
expect(result).toContain('Tarball')
|
||||||
|
expect(result).toContain('x86_64')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders linux platform with all branches', async () => {
|
||||||
|
const linuxReleases = {
|
||||||
|
flathub: { all: { label: 'Flathub', link: '/flathub' } },
|
||||||
|
x86_64: {
|
||||||
|
tarball: { label: 'Tarball x86_64', link: '/tarball-x86_64', checksum: 'sha256' },
|
||||||
|
},
|
||||||
|
aarch64: {
|
||||||
|
tarball: { label: 'Tarball ARM64', link: '/tarball-arm64', checksum: 'sha256-arm64' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const result = await container.renderToString(PlatformDownload, {
|
||||||
|
props: {
|
||||||
|
platform: 'linux',
|
||||||
|
icon: mockIcon,
|
||||||
|
title: 'Linux Title',
|
||||||
|
description: 'Linux Desc',
|
||||||
|
releases: linuxReleases,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test basic content
|
||||||
|
expect(result).toContain('Linux Title')
|
||||||
|
expect(result).toContain('Linux Desc')
|
||||||
|
|
||||||
|
// Test Flathub section
|
||||||
|
expect(result).toContain('Flathub')
|
||||||
|
expect(result).toContain('/flathub')
|
||||||
|
|
||||||
|
// Test x86_64 section
|
||||||
|
expect(result).toContain('x86_64')
|
||||||
|
expect(result).toContain('Tarball x86_64')
|
||||||
|
expect(result).toContain('/tarball-x86_64')
|
||||||
|
expect(result).toContain('sha256')
|
||||||
|
|
||||||
|
// Test ARM64 section
|
||||||
|
expect(result).toContain('ARM64')
|
||||||
|
expect(result).toContain('Tarball ARM64')
|
||||||
|
expect(result).toContain('/tarball-arm64')
|
||||||
|
expect(result).toContain('sha256-arm64')
|
||||||
|
})
|
||||||
|
})
|
22
src/tests/components/release-data.test.ts
Normal file
22
src/tests/components/release-data.test.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { getReleasesWithChecksums } from '~/components/download/release-data'
|
||||||
|
|
||||||
|
describe('getReleasesWithChecksums', () => {
|
||||||
|
it('returns correct structure with checksums', () => {
|
||||||
|
const checksums = {
|
||||||
|
'zen.macos-universal.dmg': 'macsum',
|
||||||
|
'zen.installer.exe': 'winsum',
|
||||||
|
'zen.installer-arm64.exe': 'winarmsum',
|
||||||
|
'zen.linux-x86_64.tar.xz': 'linx86sum',
|
||||||
|
'zen.linux-aarch64.tar.xz': 'linaarchsum',
|
||||||
|
}
|
||||||
|
const releases = getReleasesWithChecksums(checksums)
|
||||||
|
expect(releases.macos.universal.checksum).toBe('macsum')
|
||||||
|
expect(releases.windows.x86_64.checksum).toBe('winsum')
|
||||||
|
expect(releases.windows.arm64.checksum).toBe('winarmsum')
|
||||||
|
expect(releases.linux.x86_64.tarball.checksum).toBe('linx86sum')
|
||||||
|
expect(releases.linux.aarch64.tarball.checksum).toBe('linaarchsum')
|
||||||
|
expect(releases.linux.flathub.all.label).toBe('Flathub')
|
||||||
|
expect(releases.linux.flathub.all.link).toBe('https://flathub.org/apps/app.zen_browser.zen')
|
||||||
|
})
|
||||||
|
})
|
102
src/tests/pages/download.spec.ts
Normal file
102
src/tests/pages/download.spec.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
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) =>
|
||||||
|
page.locator(`#${platform}-downloads.platform-section[data-active='true']`)
|
||||||
|
|
||||||
|
// Helper to get the platform tab button
|
||||||
|
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',
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
platform: 'Win32',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mac',
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15',
|
||||||
|
platform: 'MacIntel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'linux',
|
||||||
|
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
platform: 'Linux x86_64',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
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({
|
||||||
|
userAgent,
|
||||||
|
locale: 'en-US',
|
||||||
|
platform,
|
||||||
|
} as BrowserContextOptions)
|
||||||
|
const page = await context.newPage()
|
||||||
|
await page.goto('/download')
|
||||||
|
await expect(getPlatformSection(page, name)).toBeVisible()
|
||||||
|
await expect(getPlatformButton(page, name)).toHaveAttribute('data-active', 'true')
|
||||||
|
// Other platforms should not be active
|
||||||
|
for (const other of platformConfigs.filter((p) => p.name !== name)) {
|
||||||
|
await expect(getPlatformSection(page, other.name)).toBeHidden()
|
||||||
|
await expect(getPlatformButton(page, other.name)).not.toHaveAttribute('data-active', 'true')
|
||||||
|
}
|
||||||
|
await context.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test.describe('Download page platform detection and tab switching', () => {
|
||||||
|
test('shows correct platform section and tab when switching platforms', async ({ page }) => {
|
||||||
|
await page.goto('/download')
|
||||||
|
const platforms = ['windows', 'mac', 'linux']
|
||||||
|
for (const platform of platforms) {
|
||||||
|
await getPlatformButton(page, platform).click()
|
||||||
|
await expect(getPlatformSection(page, platform)).toBeVisible()
|
||||||
|
await expect(getPlatformButton(page, platform)).toHaveAttribute('data-active', 'true')
|
||||||
|
// other platform sections should be hidden
|
||||||
|
for (const otherPlatform of platforms.filter((p) => p !== platform)) {
|
||||||
|
await expect(getPlatformSection(page, otherPlatform)).toBeHidden()
|
||||||
|
await expect(getPlatformButton(page, otherPlatform)).not.toHaveAttribute('data-active', 'true')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
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.aarch64.tarball, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
11
src/tests/pages/mods.spec.ts
Normal file
11
src/tests/pages/mods.spec.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { expect, test } from '@playwright/test'
|
||||||
|
|
||||||
|
test('clicking back button navigates to previous page', async ({ page }) => {
|
||||||
|
await page.goto('/mods?created=asc')
|
||||||
|
const currentUrl = page.url()
|
||||||
|
const modCards = await page.locator('.mod-card').all()
|
||||||
|
await modCards[0].click()
|
||||||
|
await page.getByRole('button', { name: 'Back' }).click()
|
||||||
|
await page.waitForURL(currentUrl)
|
||||||
|
expect(page.url()).toStrictEqual(currentUrl)
|
||||||
|
})
|
9
src/tests/pages/routes.spec.ts
Normal file
9
src/tests/pages/routes.spec.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { expect, test } from '@playwright/test'
|
||||||
|
|
||||||
|
test('all routes do not return 404', async ({ page }) => {
|
||||||
|
const routes = ['/', '/welcome', '/about', '/privacy-policy', '/download', '/donate', '/whatsnew']
|
||||||
|
for (const route of routes) {
|
||||||
|
const response = await page.goto(route)
|
||||||
|
expect(response?.status()).not.toBe(404)
|
||||||
|
}
|
||||||
|
})
|
8
src/tests/vitest.setup.ts
Normal file
8
src/tests/vitest.setup.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { vi } from 'vitest'
|
||||||
|
import translation from '~/i18n/en/translation.json'
|
||||||
|
|
||||||
|
vi.mock('~/utils/i18n', () => ({
|
||||||
|
getLocale: () => 'en',
|
||||||
|
getPath: () => (href: string) => `/en${href}`,
|
||||||
|
getUI: () => translation,
|
||||||
|
}))
|
|
@ -1,8 +1,13 @@
|
||||||
|
import { CONSTANT } from '~/constants'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the latest release notes from GitHub and parses the SHA-256 checksums.
|
* Fetches the latest release notes from GitHub and parses the SHA-256 checksums.
|
||||||
* Returns a mapping from filename to checksum.
|
* Returns a mapping from filename to checksum.
|
||||||
*/
|
*/
|
||||||
export async function getChecksums() {
|
export async function getChecksums() {
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
return CONSTANT.CHECKSUMS
|
||||||
|
}
|
||||||
const res = await fetch('https://api.github.com/repos/zen-browser/desktop/releases/latest', {
|
const res = await fetch('https://api.github.com/repos/zen-browser/desktop/releases/latest', {
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/vnd.github+json',
|
Accept: 'application/vnd.github+json',
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"~/*": ["./src/*"]
|
"~/*": ["./src/*"]
|
||||||
}
|
},
|
||||||
|
"types": ["@vitest/browser/providers/playwright"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
vitest.config.ts
Normal file
14
vitest.config.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/// <reference types="vitest" />
|
||||||
|
import { getViteConfig } from 'astro/config'
|
||||||
|
import { defaultExclude } from 'vitest/config'
|
||||||
|
|
||||||
|
export default getViteConfig({
|
||||||
|
test: {
|
||||||
|
exclude: [...defaultExclude, '**/*.spec.ts'],
|
||||||
|
setupFiles: ['./src/tests/vitest.setup.ts'],
|
||||||
|
coverage: {
|
||||||
|
provider: 'istanbul',
|
||||||
|
reporter: ['text', 'html'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
Loading…
Add table
Add a link
Reference in a new issue