test(e2e): admin user registration (#338)
Some checks failed
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
Some checks failed
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
* test(e2e): admin user registration * ci: e2e workflow * feat: disable rate limiting env var * test(e2e): fix order of execution in registration tests * ci: run e2e tests before release
This commit is contained in:
parent
c9a6a11831
commit
bb2bdb9724
15 changed files with 377 additions and 9 deletions
|
|
@ -1,3 +1,4 @@
|
|||
SERVER_IP=localhost
|
||||
DATABASE_URL=./data/zerobyte.db
|
||||
RESTIC_PASS_FILE=./data/restic.pass
|
||||
RESTIC_CACHE_DIR=./data/restic/cache
|
||||
|
|
|
|||
74
.github/workflows/e2e.yml
vendored
Normal file
74
.github/workflows/e2e.yml
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
name: E2E Tests
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
playwright:
|
||||
name: Playwright
|
||||
timeout-minutes: 20
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
uses: "./.github/actions/install-dependencies"
|
||||
|
||||
- name: Get Playwright version
|
||||
id: playwright-version
|
||||
shell: bash
|
||||
run: |
|
||||
playwright_version=$(bun -e "console.log((await Bun.file('./package.json').json()).devDependencies['@playwright/test'])")
|
||||
echo "version=$playwright_version" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache Playwright Browsers
|
||||
id: playwright-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: bunx playwright install --with-deps
|
||||
|
||||
- name: Install Playwright System Dependencies
|
||||
if: steps.playwright-cache.outputs.cache-hit == 'true'
|
||||
run: bunx playwright install-deps
|
||||
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
mkdir -p data
|
||||
touch .env.local
|
||||
echo "SERVER_IP=localhost" >> .env.local
|
||||
echo "DATABASE_URL=./data/zerobyte.db" >> .env.local
|
||||
|
||||
- name: Start zerobyte-e2e service
|
||||
run: bun run start:e2e -- -d
|
||||
|
||||
- name: Wait for zerobyte to be ready
|
||||
run: |
|
||||
timeout 30s bash -c 'until curl -f http://localhost:4096/healthcheck; do echo "Waiting for server..." && sleep 2; done'
|
||||
continue-on-error: false
|
||||
|
||||
- name: Make data directory writable
|
||||
run: sudo chmod -R 777 data
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: bun run test:e2e
|
||||
|
||||
- name: Stop Docker Compose
|
||||
if: always()
|
||||
run: docker compose down
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
|
|
@ -34,9 +34,12 @@ jobs:
|
|||
checks:
|
||||
uses: ./.github/workflows/checks.yml
|
||||
|
||||
e2e-tests:
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
|
||||
build-images:
|
||||
timeout-minutes: 15
|
||||
needs: [determine-release-type, checks]
|
||||
needs: [determine-release-type, checks, e2e-tests]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
|
|
|||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -20,3 +20,11 @@ data/
|
|||
.env*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Playwright
|
||||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
/playwright/.auth/
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export const scalarDescriptor = Scalar({
|
|||
});
|
||||
|
||||
export const createApp = () => {
|
||||
const app = new Hono();
|
||||
const app = new Hono().use(secureHeaders());
|
||||
|
||||
if (config.trustedOrigins) {
|
||||
app.use(cors({ origin: config.trustedOrigins }));
|
||||
|
|
@ -47,9 +47,8 @@ export const createApp = () => {
|
|||
app.use(honoLogger());
|
||||
}
|
||||
|
||||
app
|
||||
.use(secureHeaders())
|
||||
.use(
|
||||
if (!config.disableRateLimiting) {
|
||||
app.use(
|
||||
rateLimiter({
|
||||
windowMs: 60 * 5 * 1000,
|
||||
limit: 1000,
|
||||
|
|
@ -58,7 +57,10 @@ export const createApp = () => {
|
|||
return config.__prod__ === false;
|
||||
},
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
app
|
||||
.get("healthcheck", (c) => c.json({ status: "ok" }))
|
||||
.route("/api/v1/auth", authController)
|
||||
.route("/api/v1/volumes", volumeController)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const envSchema = type({
|
|||
MIGRATIONS_PATH: "string?",
|
||||
APP_VERSION: "string = 'dev'",
|
||||
TRUSTED_ORIGINS: "string?",
|
||||
DISABLE_RATE_LIMITING: 'string = "false"',
|
||||
}).pipe((s) => ({
|
||||
__prod__: s.NODE_ENV === "production",
|
||||
environment: s.NODE_ENV,
|
||||
|
|
@ -43,6 +44,7 @@ const envSchema = type({
|
|||
migrationsPath: s.MIGRATIONS_PATH,
|
||||
appVersion: s.APP_VERSION,
|
||||
trustedOrigins: s.TRUSTED_ORIGINS?.split(",").map((origin) => origin.trim()),
|
||||
disableRateLimiting: s.DISABLE_RATE_LIMITING === "true",
|
||||
}));
|
||||
|
||||
const parseConfig = (env: unknown) => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const REPOSITORY_BASE = process.env.ZEROBYTE_REPOSITORIES_DIR || "/var/li
|
|||
|
||||
export const RESTIC_CACHE_DIR = process.env.RESTIC_CACHE_DIR || "/var/lib/zerobyte/restic/cache";
|
||||
|
||||
export const DATABASE_URL = process.env.DATABASE_URL || "/var/lib/zerobyte/data/ironmount.db";
|
||||
export const DATABASE_URL = process.env.DATABASE_URL || "/var/lib/zerobyte/data/zerobyte.db";
|
||||
export const RESTIC_PASS_FILE = process.env.RESTIC_PASS_FILE || "/var/lib/zerobyte/data/restic.pass";
|
||||
|
||||
export const DEFAULT_EXCLUDES = [DATABASE_URL, RESTIC_PASS_FILE, REPOSITORY_BASE];
|
||||
|
|
|
|||
|
|
@ -27,7 +27,13 @@ const initDb = () => {
|
|||
if (!_schema) {
|
||||
throw new Error("Database schema not set. Call setSchema() before accessing the database.");
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.dirname(DATABASE_URL), { recursive: true });
|
||||
|
||||
if (fs.existsSync(path.join(path.dirname(DATABASE_URL), "ironmount.db")) && !fs.existsSync(DATABASE_URL)) {
|
||||
fs.renameSync(path.join(path.dirname(DATABASE_URL), "ironmount.db"), DATABASE_URL);
|
||||
}
|
||||
|
||||
_sqlite = new Database(DATABASE_URL);
|
||||
return drizzle({ client: _sqlite, schema: _schema });
|
||||
};
|
||||
|
|
|
|||
72
bun.lock
72
bun.lock
|
|
@ -70,6 +70,8 @@
|
|||
"@faker-js/faker": "^10.2.0",
|
||||
"@happy-dom/global-registrator": "^20.1.0",
|
||||
"@hey-api/openapi-ts": "^0.90.2",
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@playwright/test": "^1.57.0",
|
||||
"@react-router/dev": "^7.12.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
|
|
@ -314,8 +316,36 @@
|
|||
|
||||
"@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="],
|
||||
|
||||
"@libsql/client": ["@libsql/client@0.17.0", "", { "dependencies": { "@libsql/core": "^0.17.0", "@libsql/hrana-client": "^0.9.0", "js-base64": "^3.7.5", "libsql": "^0.5.22", "promise-limit": "^2.7.0" } }, "sha512-TLjSU9Otdpq0SpKHl1tD1Nc9MKhrsZbCFGot3EbCxRa8m1E5R1mMwoOjKMMM31IyF7fr+hPNHLpYfwbMKNusmg=="],
|
||||
|
||||
"@libsql/core": ["@libsql/core@0.17.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-hnZRnJHiS+nrhHKLGYPoJbc78FE903MSDrFJTbftxo+e52X+E0Y0fHOCVYsKWcg6XgB7BbJYUrz/xEkVTSaipw=="],
|
||||
|
||||
"@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA=="],
|
||||
|
||||
"@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA=="],
|
||||
|
||||
"@libsql/hrana-client": ["@libsql/hrana-client@0.9.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "cross-fetch": "^4.0.0", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw=="],
|
||||
|
||||
"@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="],
|
||||
|
||||
"@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA=="],
|
||||
|
||||
"@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg=="],
|
||||
|
||||
"@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA=="],
|
||||
|
||||
"@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw=="],
|
||||
|
||||
"@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew=="],
|
||||
|
||||
"@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg=="],
|
||||
|
||||
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.22", "", { "os": "win32", "cpu": "x64" }, "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA=="],
|
||||
|
||||
"@mjackson/node-fetch-server": ["@mjackson/node-fetch-server@0.2.0", "", {}, "sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng=="],
|
||||
|
||||
"@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@2.1.1", "", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||
|
|
@ -364,6 +394,8 @@
|
|||
|
||||
"@oxlint/win32-x64": ["@oxlint/win32-x64@1.38.0", "", { "os": "win32", "cpu": "x64" }, "sha512-7IuZMYiZiOcgg5zHvpJY6jRlEwh8EB/uq7GsoQJO9hANq96TIjyntGByhIjFSsL4asyZmhTEki+MO/u5Fb/WQA=="],
|
||||
|
||||
"@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="],
|
||||
|
||||
"@prisma/client": ["@prisma/client@5.22.0", "", { "peerDependencies": { "prisma": "*" }, "optionalPeers": ["prisma"] }, "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||
|
|
@ -566,6 +598,8 @@
|
|||
|
||||
"@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="],
|
||||
|
||||
"@types/better-sqlite3": ["@types/better-sqlite3@7.6.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
|
||||
|
||||
"@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
|
||||
|
|
@ -660,7 +694,7 @@
|
|||
|
||||
"better-call": ["better-call@1.1.7", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.7.10", "set-cookie-parser": "^2.7.1" }, "peerDependencies": { "zod": "^4.0.0" }, "optionalPeers": ["zod"] }, "sha512-6gaJe1bBIEgVebQu/7q9saahVzvBsGaByEnE8aDVncZEDiJO7sdNB28ot9I6iXSbR25egGmmZ6aIURXyQHRraQ=="],
|
||||
|
||||
"better-sqlite3": ["better-sqlite3@12.5.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-WwCZ/5Diz7rsF29o27o0Gcc1Du+l7Zsv7SYtVPG0X3G/uUI1LqdxrQI7c9Hs2FWpqXXERjW9hp6g3/tH7DlVKg=="],
|
||||
"better-sqlite3": ["better-sqlite3@12.6.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-FXI191x+D6UPWSze5IzZjhz+i9MK9nsuHsmTX9bXVl52k06AfZ2xql0lrgIUuzsMsJ7Vgl5kIptvDgBLIV3ZSQ=="],
|
||||
|
||||
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
|
||||
|
||||
|
|
@ -750,6 +784,8 @@
|
|||
|
||||
"cron-parser": ["cron-parser@5.4.0", "", { "dependencies": { "luxon": "^3.7.1" } }, "sha512-HxYB8vTvnQFx4dLsZpGRa0uHp6X3qIzS3ZJgJ9v6l/5TJMgeWQbLkR5yiJ5hOxGbc9+jCADDnydIe15ReLZnJA=="],
|
||||
|
||||
"cross-fetch": ["cross-fetch@4.1.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||
|
|
@ -778,6 +814,8 @@
|
|||
|
||||
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
|
||||
|
||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||
|
||||
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
|
@ -884,12 +922,16 @@
|
|||
|
||||
"fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="],
|
||||
|
||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||
|
||||
"file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="],
|
||||
|
||||
"finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="],
|
||||
|
||||
"fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="],
|
||||
|
||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||
|
||||
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||
|
||||
"fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
|
||||
|
|
@ -992,6 +1034,8 @@
|
|||
|
||||
"jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
|
||||
|
||||
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||
|
|
@ -1004,6 +1048,8 @@
|
|||
|
||||
"kysely": ["kysely@0.28.9", "", {}, "sha512-3BeXMoiOhpOwu62CiVpO6lxfq4eS6KMYfQdMsN/2kUCRNuF2YiEr7u0HLHaQU+O4Xu8YXE3bHVkwaQ85i72EuA=="],
|
||||
|
||||
"libsql": ["libsql@0.5.22", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.22", "@libsql/darwin-x64": "0.5.22", "@libsql/linux-arm-gnueabihf": "0.5.22", "@libsql/linux-arm-musleabihf": "0.5.22", "@libsql/linux-arm64-gnu": "0.5.22", "@libsql/linux-arm64-musl": "0.5.22", "@libsql/linux-x64-gnu": "0.5.22", "@libsql/linux-x64-musl": "0.5.22", "@libsql/win32-x64-msvc": "0.5.22" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA=="],
|
||||
|
||||
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
|
||||
|
||||
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
|
||||
|
|
@ -1174,6 +1220,10 @@
|
|||
|
||||
"node-cron": ["node-cron@4.2.1", "", {}, "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
|
|
@ -1238,6 +1288,10 @@
|
|||
|
||||
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||
|
||||
"playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="],
|
||||
|
||||
"playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="],
|
||||
|
||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
|
||||
|
|
@ -1258,6 +1312,8 @@
|
|||
|
||||
"pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
|
||||
|
||||
"promise-limit": ["promise-limit@2.7.0", "", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="],
|
||||
|
||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||
|
||||
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||
|
|
@ -1424,6 +1480,8 @@
|
|||
|
||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||
|
||||
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
|
||||
|
||||
"triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="],
|
||||
|
|
@ -1490,8 +1548,14 @@
|
|||
|
||||
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.3", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-7bL7FPX/DSviaZGYUKowWF1AiDVWjMjxNbE8lyaVGDezkedWqfGhlnQ4BZXre0ZN5P4kAgIJfAlgFDVyjrCIyg=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"winston": ["winston@3.19.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA=="],
|
||||
|
|
@ -1574,6 +1638,8 @@
|
|||
|
||||
"compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||
|
|
@ -1586,6 +1652,8 @@
|
|||
|
||||
"happy-dom/@types/node": ["@types/node@20.19.27", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug=="],
|
||||
|
||||
"libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
|
||||
|
||||
"mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"morgan/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
|
@ -1598,6 +1666,8 @@
|
|||
|
||||
"pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
|
||||
"pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
|
||||
|
||||
"raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
|
||||
|
|
|
|||
|
|
@ -39,3 +39,22 @@ services:
|
|||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/lib/zerobyte:/var/lib/zerobyte
|
||||
- ~/.config/rclone:/root/.config/rclone
|
||||
|
||||
zerobyte-e2e:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: production
|
||||
container_name: zerobyte
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DISABLE_RATE_LIMITING=true
|
||||
devices:
|
||||
- /dev/fuse:/dev/fuse
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
ports:
|
||||
- "4096:4096"
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- ./data:/var/lib/zerobyte
|
||||
|
|
|
|||
82
e2e/0001-initial-setup.spec.ts
Normal file
82
e2e/0001-initial-setup.spec.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import fs from "fs";
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { resetDatabase } from "./helpers/db";
|
||||
|
||||
// TODO: Run these tests with different users once multi-user support is added
|
||||
|
||||
// Run tests in serial mode to avoid conflicts during onboarding
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await resetDatabase();
|
||||
});
|
||||
|
||||
test("should redirect to onboarding", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
await page.waitForURL(/onboarding/);
|
||||
|
||||
await expect(page).toHaveTitle(/Zerobyte - Onboarding/);
|
||||
});
|
||||
|
||||
test("user can register a new account", async ({ page }) => {
|
||||
await page.goto("/onboarding");
|
||||
|
||||
await page.getByRole("textbox", { name: "Email" }).click();
|
||||
await page.getByRole("textbox", { name: "Email" }).fill("test@test.com");
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill("test");
|
||||
|
||||
await page.getByRole("textbox", { name: "Password", exact: true }).fill("password");
|
||||
await page.getByRole("textbox", { name: "Confirm Password" }).fill("password");
|
||||
|
||||
await page.getByRole("button", { name: "Create admin user" }).click();
|
||||
|
||||
await expect(page.getByText("Download Your Recovery Key")).toBeVisible();
|
||||
});
|
||||
|
||||
test("user can download recovery key", async ({ page }) => {
|
||||
await page.goto("/login");
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill("test");
|
||||
await page.getByRole("textbox", { name: "Password" }).fill("password");
|
||||
await page.getByRole("button", { name: "Login" }).click();
|
||||
|
||||
await expect(page.getByText("Download Your Recovery Key")).toBeVisible();
|
||||
|
||||
await page.getByRole("textbox", { name: "Confirm Your Password" }).fill("test");
|
||||
await page.getByRole("button", { name: "Download Recovery Key" }).click();
|
||||
|
||||
// Should not be able to download with invalid confirm password
|
||||
await expect(page.getByText("Invalid password")).toBeVisible();
|
||||
|
||||
await page.getByRole("textbox", { name: "Confirm Your Password" }).fill("password");
|
||||
|
||||
const downloadPromise = page.waitForEvent("download");
|
||||
await page.getByRole("button", { name: "Download Recovery Key" }).click();
|
||||
|
||||
const download = await downloadPromise;
|
||||
|
||||
expect(download.suggestedFilename()).toBe("restic.pass");
|
||||
await download.saveAs("./data/restic.pass");
|
||||
|
||||
const fileContent = await fs.promises.readFile("./data/restic.pass", "utf8");
|
||||
|
||||
expect(fileContent).toHaveLength(64);
|
||||
});
|
||||
|
||||
test("can't create another admin user after initial setup", async ({ page }) => {
|
||||
await page.goto("/onboarding");
|
||||
|
||||
await page.getByRole("textbox", { name: "Email" }).click();
|
||||
await page.getByRole("textbox", { name: "Email" }).fill("test@test.com");
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill("test");
|
||||
|
||||
await page.getByRole("textbox", { name: "Password", exact: true }).fill("password");
|
||||
await page.getByRole("textbox", { name: "Confirm Password" }).fill("password");
|
||||
|
||||
await page.getByRole("button", { name: "Create admin user" }).click();
|
||||
|
||||
await expect(page.getByText("Failed to create admin user")).toBeVisible();
|
||||
});
|
||||
24
e2e/helpers/account.ts
Normal file
24
e2e/helpers/account.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { expect, type Page } from "@playwright/test";
|
||||
import { db } from "./db";
|
||||
|
||||
export const createTestAccount = async (page: Page) => {
|
||||
const existingUsers = await db.query.usersTable.findFirst();
|
||||
|
||||
if (existingUsers) {
|
||||
return;
|
||||
}
|
||||
|
||||
await page.goto("/onboarding");
|
||||
|
||||
await page.getByRole("textbox", { name: "Email" }).click();
|
||||
await page.getByRole("textbox", { name: "Email" }).fill("test@test.com");
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill("test");
|
||||
|
||||
await page.getByRole("textbox", { name: "Password", exact: true }).fill("password");
|
||||
await page.getByRole("textbox", { name: "Confirm Password" }).fill("password");
|
||||
|
||||
await page.getByRole("button", { name: "Create admin user" }).click();
|
||||
|
||||
await expect(page.getByText("Download Your Recovery Key")).toBeVisible();
|
||||
};
|
||||
20
e2e/helpers/db.ts
Normal file
20
e2e/helpers/db.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { createClient } from "@libsql/client";
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import path from "node:path";
|
||||
import { DATABASE_URL } from "~/server/core/constants";
|
||||
import * as schema from "~/server/db/schema";
|
||||
|
||||
const sqlite = createClient({ url: `file:${path.join(process.cwd(), "data", DATABASE_URL)}` });
|
||||
|
||||
export const db = drizzle({ client: sqlite, schema: schema });
|
||||
|
||||
export const resetDatabase = async () => {
|
||||
const cursor = await sqlite.execute("SELECT name FROM sqlite_master WHERE type='table'");
|
||||
const tables = cursor.rows
|
||||
.map((row) => row.name)
|
||||
.filter((name) => name !== "sqlite_sequence" && name !== "__drizzle_migrations") as string[];
|
||||
|
||||
for (const table of tables) {
|
||||
await sqlite.execute(`DELETE FROM ${table}`);
|
||||
}
|
||||
};
|
||||
|
|
@ -12,12 +12,16 @@
|
|||
"tsc": "react-router typegen && tsc",
|
||||
"start:dev": "docker compose down && docker compose up --build zerobyte-dev",
|
||||
"start:prod": "docker compose down && docker compose up --build zerobyte-prod",
|
||||
"start:e2e": "docker compose down && docker compose up --build zerobyte-e2e",
|
||||
"gen:api-client": "openapi-ts",
|
||||
"gen:migrations": "drizzle-kit generate",
|
||||
"studio": "drizzle-kit studio",
|
||||
"test:server": "dotenv -e .env.test -- bun test app/server --preload ./app/test/setup.ts",
|
||||
"test:client": "dotenv -e .env.test -- bun test app/client --preload ./app/test/setup-client.ts",
|
||||
"test": "bun run test:server && bun run test:client"
|
||||
"test": "bun run test:server && bun run test:client",
|
||||
"test:e2e": "NODE_ENV=test dotenv -e .env.local -- playwright test",
|
||||
"test:e2e:ui": "NODE_ENV=test dotenv -e .env.local -- playwright test --ui",
|
||||
"test:codegen": "playwright codegen localhost:4096"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
|
|
@ -85,6 +89,8 @@
|
|||
"@faker-js/faker": "^10.2.0",
|
||||
"@happy-dom/global-registrator": "^20.1.0",
|
||||
"@hey-api/openapi-ts": "^0.90.2",
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@playwright/test": "^1.57.0",
|
||||
"@react-router/dev": "^7.12.0",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
|
|
|
|||
51
playwright.config.ts
Normal file
51
playwright.config.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import "dotenv/config";
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
export default defineConfig({
|
||||
testDir: "./e2e",
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: "html",
|
||||
use: {
|
||||
baseURL: `http://${process.env.SERVER_IP}:4096`,
|
||||
video: "retain-on-failure",
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
// {
|
||||
// name: "firefox",
|
||||
// use: { ...devices["Desktop Firefox"] },
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
|
||||
// {
|
||||
// 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' },
|
||||
// },
|
||||
],
|
||||
});
|
||||
Loading…
Reference in a new issue