Merge pull request #227 from zitadel/acceptance-test-suite

test(acceptance): username password
This commit is contained in:
Max Peintner
2024-10-28 08:29:44 +01:00
committed by GitHub
18 changed files with 349 additions and 197 deletions

View File

@@ -4,6 +4,10 @@ on: pull_request
jobs:
quality:
env:
ZITADEL_IMAGE: ghcr.io/zitadel/zitadel:v2.63.4
POSTGRES_IMAGE: postgres:17.0-alpine3.19
name: Ensure Quality
runs-on: ubuntu-latest
@@ -21,6 +25,7 @@ jobs:
- lint
- test:unit
- test:integration
- test:acceptance
steps:
- name: Checkout Repo
@@ -37,12 +42,6 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4.0.0
- uses: pnpm/action-setup@v4.0.0
name: Install pnpm
id: pnpm-install
with:
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
@@ -57,17 +56,52 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install Dependencies
run: CYPRESS_INSTALL_BINARY=0 pnpm install
- run: echo "CYPRESS_VERSION=$(pnpm list -r | grep cypress | cut -d ' ' -f 2)" >> $GITHUB_ENV
if: ${{ matrix.command == 'test:integration' }}
- uses: actions/cache@v4.0.2
name: Setup Cypress binary cache
with:
path: ~/.cache/Cypress
key: ${{ runner.os }}-cypress-binary-${{ hashFiles('**/pnpm-lock.yaml') }}
key: ${{ runner.os }}-cypress-binary-${{ env.CYPRESS_VERSION }}
restore-keys: |
${{ runner.os }}-cypress-binary-
if: ${{ matrix.command }} == "test:integration"
if: ${{ matrix.command == 'test:integration' }}
- name: Install Dependencies
- name: Install Cypress Browsers
run: pnpm install
if: ${{ matrix.command == 'test:integration' }}
- run: echo "PLAYWRIGHT_VERSION=$(npx playwright --version | cut -d ' ' -f 2)" >> $GITHUB_ENV
if: ${{ matrix.command == 'test:acceptance' }}
- uses: actions/cache@v4.0.2
name: Setup Playwright binary cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-binary-${{ env.PLAYWRIGHT_VERSION }}
restore-keys: |
${{ runner.os }}-playwright-binary-
if: ${{ matrix.command == 'test:acceptance' }}
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
if: ${{ matrix.command == 'test:acceptance' }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
if: ${{ matrix.command == 'test:acceptance' }}
- name: Run ZITADEL
run: ZITADEL_DEV_UID=root pnpm run-zitadel
if: ${{ matrix.command == 'test:acceptance' }}
- name: Install Playwright Browsers
run: pnpm build
if: ${{ matrix.command == 'test:acceptance' }}
- name: Check
id: check

4
.gitignore vendored
View File

@@ -18,3 +18,7 @@ packages/zitadel-server/src/app/proto
.idea
.vercel
.env*.local
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

View File

@@ -178,32 +178,57 @@ To run the application make sure to install the dependencies with
pnpm install
```
then setup the environment for the login application which needs a `.env.local` in `/apps/login`.
Go to your instance and create a service user for the application having the `IAM_OWNER` manager role.
This user is required to have access to create users on your primary organization and reading policy data so it can be
restricted to your personal use case but we'll stick with `IAM_OWNER` for convenience. Create a PAT and copy the value to
paste it under the `ZITADEL_SERVICE_USER_TOKEN` key.
The file should look as follows:
```
ZITADEL_API_URL=[yourinstanceurl]
ZITADEL_ORG_ID=[yourprimaryorg]
ZITADEL_SERVICE_USER_TOKEN=[yourserviceuserpersonalaccesstoken]
```
then generate the GRPC stubs with
```sh
pnpm generate
```
and then run it with
To run the application against a local ZITADEL instance, run the following command:
```sh
pnpm run-zitadel
```
This sets up ZITADEL using docker compose and writes the configuration to the file `apps/login/.env.local`.
<details>
<summary>Alternatively, use another environment</summary>
You can develop against any ZITADEL instance in which you have sufficient rights to execute the following steps.
Just create or overwrite the file `apps/login/.env.local` yourself.
Add your instances base URL to the file at the key `ZITADEL_API_URL`.
Go to your instance and create a service user for the login application.
The login application creates users on your primary organization and reads policy data.
For the sake of simplicity, just make the service user an instance member with the role `IAM_OWNER`.
Create a PAT and copy it to the file `apps/login/.env.local` using the key `ZITADEL_SERVICE_USER_TOKEN`.
Also add the users ID to the file using the key `ZITADEL_SERVICE_USER_ID`.
The file should look similar to this:
```
ZITADEL_API_URL=https://zitadel-tlx3du.us1.zitadel.cloud
ZITADEL_SERVICE_USER_ID=289106423158521850
ZITADEL_SERVICE_USER_TOKEN=1S6w48thfWFI2klgfwkCnhXJLf9FQ457E-_3H74ePQxfO3Af0Tm4V5Xi-ji7urIl_xbn-Rk
```
</details>
Start the login application in dev mode:
```sh
pnpm dev
```
Open the login application with your favorite browser at `localhost:3000`.
Change the source code and see the changes live in your browser.
Make sure the application still behaves as expected by running all tests
```sh
pnpm test
```
To satisfy your unique workflow requirements, check out the package.json in the root directory for more detailed scripts.
### Deploy to Vercel

View File

@@ -1,6 +1,5 @@
FROM golang:1.19-alpine
RUN apk add curl jq
RUN go install github.com/zitadel/zitadel-tools@v0.4.0
COPY setup.sh /setup.sh
RUN chmod +x /setup.sh
ENTRYPOINT [ "/setup.sh" ]

View File

@@ -1,5 +1,3 @@
version: "3.8"
services:
zitadel:
user: "${ZITADEL_DEV_UID}"
@@ -8,24 +6,29 @@ services:
ports:
- "8080:8080"
volumes:
- ./machinekey:/machinekey
- ./pat:/pat
- ./zitadel.yaml:/zitadel.yaml
depends_on:
db:
condition: "service_healthy"
db:
image: "cockroachdb/cockroach:v22.2.2"
command: "start-single-node --insecure --http-addr :9090"
restart: 'always'
image: "${POSTGRES_IMAGE:-postgres:latest}"
environment:
- POSTGRES_USER=zitadel
- PGUSER=zitadel
- POSTGRES_DB=zitadel
- POSTGRES_HOST_AUTH_METHOD=trust
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c shared_buffers=1GB -c work_mem=16MB -c effective_io_concurrency=100 -c wal_level=minimal -c archive_mode=off -c max_wal_senders=0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9090/health?ready=1"]
interval: "10s"
timeout: "30s"
test: ["CMD-SHELL", "pg_isready"]
interval: '10s'
timeout: '30s'
retries: 5
start_period: "20s"
start_period: '20s'
ports:
- "26257:26257"
- "9090:9090"
- 5432:5432
wait_for_zitadel:
image: curlimages/curl:8.00.1
@@ -33,7 +36,7 @@ services:
[
"/bin/sh",
"-c",
"i=0; while ! curl http://zitadel:8080/debug/ready && [ $$i -lt 30 ]; do sleep 1; i=$$((i+1)); done; [ $$i -eq 30 ] && exit 1 || exit 0",
"i=0; while ! curl http://zitadel:8080/debug/ready && [ $$i -lt 30 ]; do sleep 1; i=$$((i+1)); done; [ $$i -eq 120 ] && exit 1 || exit 0",
]
depends_on:
- zitadel
@@ -43,11 +46,11 @@ services:
container_name: setup
build: .
environment:
KEY: /key/zitadel-admin-sa.json
SERVICE: http://zitadel:8080
WRITE_ENVIRONMENT_FILE: /apps/login/.env.acceptance
PAT_FILE: /pat/zitadel-admin-sa.pat
ZITADEL_API_INTERNAL_URL: http://zitadel:8080
WRITE_ENVIRONMENT_FILE: /apps/login/.env.local
volumes:
- "./machinekey:/key"
- "./pat:/pat"
- "../apps/login:/apps/login"
depends_on:
wait_for_zitadel:

View File

@@ -1 +0,0 @@
zitadel-admin-sa.json

2
acceptance/pat/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitkeep

View File

@@ -1,125 +1,34 @@
#!/bin/sh
set -e
set -ex
KEY=${KEY:-./machinekey/zitadel-admin-sa.json}
echo "Using key path ${KEY} to the instance admin service account."
PAT_FILE=${PAT_FILE:-./pat/zitadel-admin-sa.pat}
ZITADEL_API_PROTOCOL="${ZITADEL_API_PROTOCOL:-http}"
ZITADEL_API_DOMAIN="${ZITADEL_API_DOMAIN:-localhost}"
ZITADEL_API_PORT="${ZITADEL_API_PORT:-8080}"
ZITADEL_API_URL="${ZITADEL_API_URL:-${ZITADEL_API_PROTOCOL}://${ZITADEL_API_DOMAIN}:${ZITADEL_API_PORT}}"
ZITADEL_API_INTERNAL_URL="${ZITADEL_API_INTERNAL_URL:-${ZITADEL_API_URL}}"
AUDIENCE=${AUDIENCE:-http://localhost:8080}
echo "Using audience ${AUDIENCE} for which the key is used."
if [ -z "${PAT}" ]; then
echo "Reading PAT from file ${PAT_FILE}"
PAT=$(cat ${PAT_FILE})
fi
SERVICE=${SERVICE:-$AUDIENCE}
echo "Using the service ${SERVICE} to connect to ZITADEL. For example in docker compose this can differ from the audience."
if [ -z "${ZITADEL_SERVICE_USER_ID}" ]; then
echo "Reading ZITADEL_SERVICE_USER_ID from userinfo endpoint"
USERINFO_RESPONSE=$(curl -s --request POST \
--url "${ZITADEL_API_INTERNAL_URL}/oidc/v1/userinfo" \
--header "Authorization: Bearer ${PAT}" \
--header "Host: ${ZITADEL_API_DOMAIN}")
echo "Received userinfo response: ${USERINFO_RESPONSE}"
ZITADEL_SERVICE_USER_ID=$(echo "${USERINFO_RESPONSE}" | jq --raw-output '.sub')
fi
WRITE_ENVIRONMENT_FILE=${WRITE_ENVIRONMENT_FILE:-$(dirname "$0")/../apps/login/.env.acceptance}
WRITE_ENVIRONMENT_FILE=${WRITE_ENVIRONMENT_FILE:-$(dirname "$0")/../apps/login/.env.local}
echo "Writing environment file to ${WRITE_ENVIRONMENT_FILE} when done."
AUDIENCE_HOST="$(echo $AUDIENCE | cut -d/ -f3)"
echo "Deferred the Host header ${AUDIENCE_HOST} which will be sent in requests that ZITADEL then maps to a virtual instance"
JWT=$(zitadel-tools key2jwt --key ${KEY} --audience ${AUDIENCE})
echo "Created JWT from Admin service account key ${JWT}"
TOKEN_RESPONSE=$(curl -s --request POST \
--url ${SERVICE}/oauth/v2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header "Host: ${AUDIENCE_HOST}" \
--data grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
--data scope='openid profile email urn:zitadel:iam:org:project:id:zitadel:aud' \
--data assertion="${JWT}")
echo "Got response from token endpoint:"
echo "${TOKEN_RESPONSE}" | jq
TOKEN=$(echo -n ${TOKEN_RESPONSE} | jq --raw-output '.access_token')
echo "Extracted access token ${TOKEN}"
ORG_RESPONSE=$(curl -s --request GET \
--url ${SERVICE}/admin/v1/orgs/default \
--header 'Accept: application/json' \
--header "Authorization: Bearer ${TOKEN}" \
--header "Host: ${AUDIENCE_HOST}")
echo "Got default org response:"
echo "${ORG_RESPONSE}" | jq
ORG_ID=$(echo -n ${ORG_RESPONSE} | jq --raw-output '.org.id')
echo "Extracted default org id ${ORG_ID}"
echo "ZITADEL_API_URL=${AUDIENCE}
ZITADEL_ORG_ID=${ORG_ID}
ZITADEL_SERVICE_USER_TOKEN=${TOKEN}" > ${WRITE_ENVIRONMENT_FILE}
echo "ZITADEL_API_URL=${ZITADEL_API_URL}
ZITADEL_SERVICE_USER_ID=${ZITADEL_SERVICE_USER_ID}
ZITADEL_SERVICE_USER_TOKEN=${PAT}" > ${WRITE_ENVIRONMENT_FILE}
echo "Wrote environment file ${WRITE_ENVIRONMENT_FILE}"
cat ${WRITE_ENVIRONMENT_FILE}
if ! grep -q 'localhost' ${WRITE_ENVIRONMENT_FILE}; then
echo "Not developing against localhost, so creating a human user might not be necessary"
exit 0
fi
HUMAN_USER_USERNAME="zitadel-admin@zitadel.localhost"
HUMAN_USER_PASSWORD="Password1!"
HUMAN_USER_PAYLOAD=$(cat << EOM
{
"userName": "${HUMAN_USER_USERNAME}",
"profile": {
"firstName": "ZITADEL",
"lastName": "Admin",
"displayName": "ZITADEL Admin",
"preferredLanguage": "en"
},
"email": {
"email": "zitadel-admin@zitadel.localhost",
"isEmailVerified": true
},
"password": "${HUMAN_USER_PASSWORD}",
"passwordChangeRequired": false
}
EOM
)
echo "Creating human user"
echo "${HUMAN_USER_PAYLOAD}" | jq
HUMAN_USER_RESPONSE=$(curl -s --request POST \
--url ${SERVICE}/management/v1/users/human/_import \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header "Authorization: Bearer ${TOKEN}" \
--header "Host: ${AUDIENCE_HOST}" \
--data-raw "${HUMAN_USER_PAYLOAD}")
echo "Create human user response"
echo "${HUMAN_USER_RESPONSE}" | jq
if [ "$(echo -n "${HUMAN_USER_RESPONSE}" | jq --raw-output '.code')" == "6" ]; then
echo "admin user already exists"
exit 0
fi
HUMAN_USER_ID=$(echo -n ${HUMAN_USER_RESPONSE} | jq --raw-output '.userId')
echo "Extracted human user id ${HUMAN_USER_ID}"
HUMAN_ADMIN_PAYLOAD=$(cat << EOM
{
"userId": "${HUMAN_USER_ID}",
"roles": [
"IAM_OWNER"
]
}
EOM
)
echo "Granting iam owner to human user"
echo "${HUMAN_ADMIN_PAYLOAD}" | jq
HUMAN_ADMIN_RESPONSE=$(curl -s --request POST \
--url ${SERVICE}/admin/v1/members \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header "Authorization: Bearer ${TOKEN}" \
--header "Host: ${AUDIENCE_HOST}" \
--data-raw "${HUMAN_ADMIN_PAYLOAD}")
echo "Grant iam owner to human user response"
echo "${HUMAN_ADMIN_RESPONSE}" | jq
echo "You can now log in at ${AUDIENCE}/ui/login"
echo "username: ${HUMAN_USER_USERNAME}"
echo "password: ${HUMAN_USER_PASSWORD}"

View File

@@ -0,0 +1,12 @@
import { test } from "@playwright/test";
test("username and password", async ({ page }) => {
await page.goto("/");
const loginname = page.getByLabel("Loginname");
await loginname.pressSequentially("zitadel-admin@zitadel.localhost");
await loginname.press("Enter");
const password = page.getByLabel("Password");
await password.pressSequentially("Password1!");
await password.press("Enter");
await page.getByRole("heading", { name: "Welcome ZITADEL Admin!" }).click();
});

View File

@@ -0,0 +1,6 @@
import { test } from "@playwright/test";
test("login is accessible", async ({ page }) => {
await page.goto("http://localhost:3000/");
await page.getByRole("heading", { name: "Welcome back!" }).isVisible();
});

View File

@@ -1,22 +1,41 @@
FirstInstance:
MachineKeyPath: /machinekey/zitadel-admin-sa.json
PatPath: /pat/zitadel-admin-sa.pat
Org:
Human:
UserName: zitadel-admin
FirstName: ZITADEL
LastName: Admin
Password: Password1!
PasswordChangeRequired: false
PreferredLanguage: en
Machine:
Machine:
Username: zitadel-admin-sa
Name: Admin
MachineKey:
Type: 1
Pat:
ExpirationDate: 2099-01-01T00:00:00Z
Database:
Cockroach:
EventPushConnRatio: 0.2 # 4
ProjectionSpoolerConnRatio: 0.3 # 6
postgres:
Host: db
Port: 5432
Database: zitadel
MaxOpenConns: 20
MaxIdleConns: 20
MaxConnLifetime: 1h
MaxConnIdleTime: 5m
User:
Username: zitadel
SSL:
Mode: disable
Admin:
Username: zitadel
SSL:
Mode: disable
Logstore:
Access:
Stdout:
Enabled: true
DefaultInstance:
LoginPolicy:
MfaInitSkipLifetime: 0h

View File

@@ -24,6 +24,7 @@
"build": "next build",
"prestart": "pnpm build",
"start": "next start",
"start:built": "next start",
"clean": "pnpm mock:destroy && rm -rf .turbo && rm -rf node_modules && rm -rf .next"
},
"git": {

View File

@@ -6,17 +6,22 @@
"generate": "turbo run generate",
"build": "turbo run build",
"test": "turbo run test",
"start": "turbo run start",
"start:built": "turbo run start:built",
"test:unit": "turbo run test:unit -- --passWithNoTests",
"test:integration": "turbo run test:integration",
"test:acceptance": "pnpm exec playwright test",
"test:watch": "turbo run test:watch",
"dev": "turbo run dev --no-cache --continue",
"lint": "turbo run lint",
"lint:fix": "turbo run lint:fix",
"clean": "turbo run clean && rm -rf node_modules",
"format:fix": "prettier --write \"**/*.{ts,tsx,md}\"",
"format": "prettier --check \"**/*.{ts,tsx,md}\"",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "turbo run build --filter=login^... && changeset publish"
"release": "turbo run build --filter=login^... && changeset publish",
"run-zitadel": "docker compose -f ./acceptance/docker-compose.yaml run setup"
},
"pnpm": {
"overrides": {
@@ -25,10 +30,12 @@
},
"devDependencies": {
"@changesets/cli": "^2.27.8",
"@playwright/test": "^1.48.1",
"@types/node": "^22.7.5",
"@vitejs/plugin-react": "^4.2.1",
"@zitadel/prettier-config": "workspace:*",
"eslint": "8.57.1",
"eslint-config-zitadel": "workspace:*",
"@zitadel/prettier-config": "workspace:*",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0",
"tsup": "^8.3.0",

81
playwright.config.ts Normal file
View File

@@ -0,0 +1,81 @@
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: "./acceptance/tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://127.0.0.1:3000",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
/* TODO: webkit fails. Is this a bug?
{
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 local dev server before starting the tests */
webServer: {
command: "pnpm start:built",
url: "http://127.0.0.1:3000",
reuseExistingServer: !process.env.CI,
timeout: 5 * 60_000,
},
});

111
pnpm-lock.yaml generated
View File

@@ -14,9 +14,15 @@ importers:
'@changesets/cli':
specifier: ^2.27.8
version: 2.27.8
'@playwright/test':
specifier: ^1.48.1
version: 1.48.1
'@types/node':
specifier: ^22.7.5
version: 22.7.6
'@vitejs/plugin-react':
specifier: ^4.2.1
version: 4.3.1(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))
version: 4.3.1(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))
'@zitadel/prettier-config':
specifier: workspace:*
version: link:packages/zitadel-prettier-config
@@ -43,10 +49,10 @@ importers:
version: 5.6.2
vite-tsconfig-paths:
specifier: ^5.0.1
version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))
version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))
vitest:
specifier: ^2.1.1
version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(sass@1.79.1)
version: 2.1.1(@types/node@22.7.6)(jsdom@25.0.0)(sass@1.79.1)
apps/login:
dependencies:
@@ -61,7 +67,7 @@ importers:
version: 0.5.7(tailwindcss@3.4.13)
'@vercel/analytics':
specifier: ^1.2.2
version: 1.3.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)
version: 1.3.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)
'@zitadel/client':
specifier: workspace:*
version: link:../../packages/zitadel-client
@@ -85,13 +91,13 @@ importers:
version: 2.30.1
next:
specifier: 14.2.14
version: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
version: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
next-intl:
specifier: ^3.20.0
version: 3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)
version: 3.20.0(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)
next-themes:
specifier: ^0.2.1
version: 0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 0.2.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nice-grpc:
specifier: 2.0.1
version: 2.0.1
@@ -1050,6 +1056,11 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, tarball: https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz}
engines: {node: '>=14'}
'@playwright/test@1.48.1':
resolution: {integrity: sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==}
engines: {node: '>=18'}
hasBin: true
'@protobufjs/aspromise@1.1.2':
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
@@ -1284,6 +1295,9 @@ packages:
'@types/node@22.5.5':
resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==}
'@types/node@22.7.6':
resolution: {integrity: sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -2420,6 +2434,11 @@ packages:
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -3490,6 +3509,16 @@ packages:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
playwright-core@1.48.1:
resolution: {integrity: sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==}
engines: {node: '>=18'}
hasBin: true
playwright@1.48.1:
resolution: {integrity: sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==}
engines: {node: '>=18'}
hasBin: true
possible-typed-array-names@1.0.0:
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
engines: {node: '>= 0.4'}
@@ -5404,6 +5433,10 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
'@playwright/test@1.48.1':
dependencies:
playwright: 1.48.1
'@protobufjs/aspromise@1.1.2': {}
'@protobufjs/base64@1.1.2': {}
@@ -5618,6 +5651,10 @@ snapshots:
dependencies:
undici-types: 6.19.8
'@types/node@22.7.6':
dependencies:
undici-types: 6.19.8
'@types/normalize-package-data@2.4.4': {}
'@types/prop-types@15.7.12': {}
@@ -5643,7 +5680,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 22.5.5
'@types/node': 22.7.6
optional: true
'@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.2)':
@@ -5688,23 +5725,23 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vercel/analytics@1.3.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)':
'@vercel/analytics@1.3.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)':
dependencies:
server-only: 0.0.1
optionalDependencies:
next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
react: 18.3.1
'@vercel/git-hooks@1.0.0': {}
'@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))':
'@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))':
dependencies:
'@babel/core': 7.25.2
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2)
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1)
vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1)
transitivePeerDependencies:
- supports-color
@@ -5715,13 +5752,13 @@ snapshots:
chai: 5.1.1
tinyrainbow: 1.2.0
'@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))':
'@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))':
dependencies:
'@vitest/spy': 2.1.1
estree-walker: 3.0.3
magic-string: 0.30.11
optionalDependencies:
vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1)
vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1)
'@vitest/pretty-format@2.1.1':
dependencies:
@@ -7038,6 +7075,9 @@ snapshots:
fs.realpath@1.0.0: {}
fsevents@2.3.2:
optional: true
fsevents@2.3.3:
optional: true
@@ -7823,21 +7863,21 @@ snapshots:
negotiator@0.6.3: {}
next-intl@3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1):
next-intl@3.20.0(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1):
dependencies:
'@formatjs/intl-localematcher': 0.5.4
negotiator: 0.6.3
next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
react: 18.3.1
use-intl: 3.20.0(react@18.3.1)
next-themes@0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next-themes@0.2.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1):
next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1):
dependencies:
'@next/env': 14.2.14
'@swc/helpers': 0.5.5
@@ -7858,6 +7898,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 14.2.14
'@next/swc-win32-ia32-msvc': 14.2.14
'@next/swc-win32-x64-msvc': 14.2.14
'@playwright/test': 1.48.1
sass: 1.79.1
transitivePeerDependencies:
- '@babel/core'
@@ -8096,6 +8137,14 @@ snapshots:
pirates@4.0.6: {}
playwright-core@1.48.1: {}
playwright@1.48.1:
dependencies:
playwright-core: 1.48.1
optionalDependencies:
fsevents: 2.3.2
possible-typed-array-names@1.0.0: {}
postcss-import@15.1.0(postcss@8.4.47):
@@ -8194,7 +8243,7 @@ snapshots:
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 22.5.5
'@types/node': 22.7.6
long: 5.2.3
proxy-from-env@1.0.0: {}
@@ -9048,12 +9097,12 @@ snapshots:
core-util-is: 1.0.2
extsprintf: 1.3.0
vite-node@2.1.1(@types/node@22.5.5)(sass@1.79.1):
vite-node@2.1.1(@types/node@22.7.6)(sass@1.79.1):
dependencies:
cac: 6.7.14
debug: 4.3.7(supports-color@5.5.0)
pathe: 1.1.2
vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1)
vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1)
transitivePeerDependencies:
- '@types/node'
- less
@@ -9065,31 +9114,31 @@ snapshots:
- supports-color
- terser
vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1)):
vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1)):
dependencies:
debug: 4.3.6
globrex: 0.1.2
tsconfck: 3.1.1(typescript@5.6.2)
optionalDependencies:
vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1)
vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1)
transitivePeerDependencies:
- supports-color
- typescript
vite@5.4.6(@types/node@22.5.5)(sass@1.79.1):
vite@5.4.6(@types/node@22.7.6)(sass@1.79.1):
dependencies:
esbuild: 0.21.5
postcss: 8.4.47
rollup: 4.21.3
optionalDependencies:
'@types/node': 22.5.5
'@types/node': 22.7.6
fsevents: 2.3.3
sass: 1.79.1
vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(sass@1.79.1):
vitest@2.1.1(@types/node@22.7.6)(jsdom@25.0.0)(sass@1.79.1):
dependencies:
'@vitest/expect': 2.1.1
'@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))
'@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))
'@vitest/pretty-format': 2.1.1
'@vitest/runner': 2.1.1
'@vitest/snapshot': 2.1.1
@@ -9104,11 +9153,11 @@ snapshots:
tinyexec: 0.3.0
tinypool: 1.0.1
tinyrainbow: 1.2.0
vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1)
vite-node: 2.1.1(@types/node@22.5.5)(sass@1.79.1)
vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1)
vite-node: 2.1.1(@types/node@22.7.6)(sass@1.79.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.5.5
'@types/node': 22.7.6
jsdom: 25.0.0
transitivePeerDependencies:
- less

View File

@@ -21,6 +21,8 @@
},
"build": {},
"test": {},
"start": {},
"start:built": {},
"test:unit": {},
"test:integration": {},
"test:watch": {