Merge remote-tracking branch 'origin/develop' into biome
This commit is contained in:
commit
851c100a24
15 changed files with 576 additions and 65 deletions
12
.dockerignore
Normal file
12
.dockerignore
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
node_modules/
|
||||
dist/
|
||||
logs/
|
||||
.DS_Store
|
||||
.git/
|
||||
config/local.json
|
||||
pleroma-backend/
|
||||
test/e2e/reports/
|
||||
test/e2e-playwright/test-results/
|
||||
test/e2e-playwright/playwright-report/
|
||||
__screenshots__/
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,8 +4,11 @@ dist/
|
|||
npm-debug.log
|
||||
test/unit/coverage
|
||||
test/e2e/reports
|
||||
test/e2e-playwright/test-results
|
||||
test/e2e-playwright/playwright-report
|
||||
selenium-debug.log
|
||||
.idea/
|
||||
.gitlab-ci-local/
|
||||
config/local.json
|
||||
src/assets/emoji.json
|
||||
logs/
|
||||
|
|
|
|||
129
.gitlab-ci.yml
129
.gitlab-ci.yml
|
|
@ -71,6 +71,135 @@ test:
|
|||
- test/**/__screenshots__
|
||||
when: on_failure
|
||||
|
||||
e2e-pleroma:
|
||||
stage: test
|
||||
image: mcr.microsoft.com/playwright:v1.55.0-jammy
|
||||
services:
|
||||
- name: postgres:15-alpine
|
||||
alias: db
|
||||
- name: $PLEROMA_IMAGE
|
||||
alias: pleroma
|
||||
entrypoint: ["/bin/ash", "-c"]
|
||||
command:
|
||||
- |
|
||||
set -eu
|
||||
|
||||
SEED_SENTINEL_PATH=/var/lib/pleroma/.e2e_seeded
|
||||
CONFIG_OVERRIDE_PATH=/var/lib/pleroma/config.exs
|
||||
|
||||
echo '-- Waiting for database...'
|
||||
while ! pg_isready -U ${DB_USER:-pleroma} -d postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma} -t 1; do
|
||||
sleep 1s
|
||||
done
|
||||
|
||||
echo '-- Writing E2E config overrides...'
|
||||
cat > $CONFIG_OVERRIDE_PATH <<EOF
|
||||
import Config
|
||||
|
||||
config :pleroma, Pleroma.Captcha,
|
||||
enabled: false
|
||||
|
||||
config :pleroma, :instance,
|
||||
registrations_open: true,
|
||||
account_activation_required: false,
|
||||
approval_required: false
|
||||
EOF
|
||||
|
||||
echo '-- Running migrations...'
|
||||
/opt/pleroma/bin/pleroma_ctl migrate
|
||||
|
||||
echo '-- Starting!'
|
||||
/opt/pleroma/bin/pleroma start &
|
||||
PLEROMA_PID=$!
|
||||
|
||||
cleanup() {
|
||||
if kill -0 $PLEROMA_PID 2>/dev/null; then
|
||||
kill -TERM $PLEROMA_PID
|
||||
wait $PLEROMA_PID || true
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup INT TERM
|
||||
|
||||
echo '-- Waiting for API...'
|
||||
api_ok=false
|
||||
for _i in $(seq 1 120); do
|
||||
if wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null 2>&1; then
|
||||
api_ok=true
|
||||
break
|
||||
fi
|
||||
sleep 1s
|
||||
done
|
||||
|
||||
if [ $api_ok != true ]; then
|
||||
echo 'Timed out waiting for Pleroma API to become available'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f $SEED_SENTINEL_PATH ]; then
|
||||
if [ -n ${E2E_ADMIN_USERNAME:-} ] && [ -n ${E2E_ADMIN_PASSWORD:-} ] && [ -n ${E2E_ADMIN_EMAIL:-} ]; then
|
||||
echo '-- Seeding admin user' $E2E_ADMIN_USERNAME '...'
|
||||
if ! /opt/pleroma/bin/pleroma_ctl user new $E2E_ADMIN_USERNAME $E2E_ADMIN_EMAIL --admin --password $E2E_ADMIN_PASSWORD -y; then
|
||||
echo '-- User already exists or creation failed, ensuring admin + confirmed...'
|
||||
/opt/pleroma/bin/pleroma_ctl user set $E2E_ADMIN_USERNAME --admin --confirmed
|
||||
fi
|
||||
else
|
||||
echo '-- Skipping admin seeding (missing E2E_ADMIN_* env)'
|
||||
fi
|
||||
|
||||
touch $SEED_SENTINEL_PATH
|
||||
fi
|
||||
|
||||
wait $PLEROMA_PID
|
||||
tags:
|
||||
- amd64
|
||||
- himem
|
||||
variables:
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
FF_NETWORK_PER_BUILD: "true"
|
||||
PLEROMA_IMAGE: git.pleroma.social:5050/pleroma/pleroma:stable
|
||||
POSTGRES_USER: pleroma
|
||||
POSTGRES_PASSWORD: pleroma
|
||||
POSTGRES_DB: pleroma
|
||||
DB_USER: pleroma
|
||||
DB_PASS: pleroma
|
||||
DB_NAME: pleroma
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DOMAIN: localhost
|
||||
INSTANCE_NAME: Pleroma E2E
|
||||
E2E_ADMIN_USERNAME: admin
|
||||
E2E_ADMIN_PASSWORD: adminadmin
|
||||
E2E_ADMIN_EMAIL: admin@example.com
|
||||
ADMIN_EMAIL: $E2E_ADMIN_EMAIL
|
||||
NOTIFY_EMAIL: $E2E_ADMIN_EMAIL
|
||||
VITE_PROXY_TARGET: http://pleroma:4000
|
||||
VITE_PROXY_ORIGIN: http://localhost:4000
|
||||
E2E_BASE_URL: http://localhost:8080
|
||||
script:
|
||||
- npm install -g yarn@1.22.22
|
||||
- yarn --frozen-lockfile
|
||||
- |
|
||||
echo "-- Waiting for Pleroma API..."
|
||||
api_ok="false"
|
||||
for _i in $(seq 1 120); do
|
||||
if wget -qO- http://pleroma:4000/api/v1/instance >/dev/null 2>&1; then
|
||||
api_ok="true"
|
||||
break
|
||||
fi
|
||||
sleep 1s
|
||||
done
|
||||
if [ "$api_ok" != "true" ]; then
|
||||
echo "Timed out waiting for Pleroma API to become available"
|
||||
exit 1
|
||||
fi
|
||||
- yarn e2e:pw
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- test/e2e-playwright/test-results
|
||||
- test/e2e-playwright/playwright-report
|
||||
|
||||
build:
|
||||
stage: build
|
||||
tags:
|
||||
|
|
|
|||
1
changelog.d/e2e-tests.add
Normal file
1
changelog.d/e2e-tests.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add playwright E2E-tests with an optional docker-based backend
|
||||
57
docker-compose.e2e.yml
Normal file
57
docker-compose.e2e.yml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
services:
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
environment:
|
||||
POSTGRES_USER: pleroma
|
||||
POSTGRES_PASSWORD: pleroma
|
||||
POSTGRES_DB: pleroma
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U pleroma -d pleroma"]
|
||||
interval: 2s
|
||||
timeout: 2s
|
||||
retries: 30
|
||||
|
||||
pleroma:
|
||||
image: ${PLEROMA_IMAGE:-git.pleroma.social:5050/pleroma/pleroma:stable}
|
||||
environment:
|
||||
DB_USER: pleroma
|
||||
DB_PASS: pleroma
|
||||
DB_NAME: pleroma
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DOMAIN: localhost
|
||||
INSTANCE_NAME: Pleroma E2E
|
||||
ADMIN_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com}
|
||||
NOTIFY_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com}
|
||||
E2E_ADMIN_USERNAME: ${E2E_ADMIN_USERNAME:-admin}
|
||||
E2E_ADMIN_PASSWORD: ${E2E_ADMIN_PASSWORD:-adminadmin}
|
||||
E2E_ADMIN_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./docker/pleroma/entrypoint.e2e.sh:/opt/pleroma/entrypoint.e2e.sh:ro
|
||||
entrypoint: ["/bin/ash", "/opt/pleroma/entrypoint.e2e.sh"]
|
||||
healthcheck:
|
||||
# NOTE: "localhost" may resolve to ::1 in some images (IPv6) while Pleroma only
|
||||
# listens on IPv4 in this container. Use 127.0.0.1 to avoid false negatives.
|
||||
test: ["CMD-SHELL", "test -f /var/lib/pleroma/.e2e_seeded && wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null || exit 1"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 60
|
||||
|
||||
e2e:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/e2e/Dockerfile.e2e
|
||||
depends_on:
|
||||
pleroma:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
CI: "1"
|
||||
VITE_PROXY_TARGET: http://pleroma:4000
|
||||
VITE_PROXY_ORIGIN: http://localhost:4000
|
||||
E2E_BASE_URL: http://localhost:8080
|
||||
E2E_ADMIN_USERNAME: ${E2E_ADMIN_USERNAME:-admin}
|
||||
E2E_ADMIN_PASSWORD: ${E2E_ADMIN_PASSWORD:-adminadmin}
|
||||
command: ["yarn", "e2e:pw"]
|
||||
17
docker/e2e/Dockerfile.e2e
Normal file
17
docker/e2e/Dockerfile.e2e
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
FROM mcr.microsoft.com/playwright:v1.55.0-jammy
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
||||
|
||||
RUN npm install -g yarn@1.22.22
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
ENV CI=1
|
||||
|
||||
CMD ["yarn", "e2e:pw"]
|
||||
|
||||
71
docker/pleroma/entrypoint.e2e.sh
Normal file
71
docker/pleroma/entrypoint.e2e.sh
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#!/bin/ash
|
||||
|
||||
set -eu
|
||||
|
||||
SEED_SENTINEL_PATH="/var/lib/pleroma/.e2e_seeded"
|
||||
CONFIG_OVERRIDE_PATH="/var/lib/pleroma/config.exs"
|
||||
|
||||
echo "-- Waiting for database..."
|
||||
while ! pg_isready -U "${DB_USER:-pleroma}" -d "postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma}" -t 1; do
|
||||
sleep 1s
|
||||
done
|
||||
|
||||
echo "-- Writing E2E config overrides..."
|
||||
cat > "$CONFIG_OVERRIDE_PATH" <<'EOF'
|
||||
import Config
|
||||
|
||||
config :pleroma, Pleroma.Captcha,
|
||||
enabled: false
|
||||
|
||||
config :pleroma, :instance,
|
||||
registrations_open: true,
|
||||
account_activation_required: false,
|
||||
approval_required: false
|
||||
EOF
|
||||
|
||||
echo "-- Running migrations..."
|
||||
/opt/pleroma/bin/pleroma_ctl migrate
|
||||
|
||||
echo "-- Starting!"
|
||||
/opt/pleroma/bin/pleroma start &
|
||||
PLEROMA_PID="$!"
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${PLEROMA_PID:-}" ] && kill -0 "$PLEROMA_PID" 2>/dev/null; then
|
||||
kill -TERM "$PLEROMA_PID"
|
||||
wait "$PLEROMA_PID" || true
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup INT TERM
|
||||
|
||||
echo "-- Waiting for API..."
|
||||
api_ok="false"
|
||||
for _i in $(seq 1 120); do
|
||||
if wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null 2>&1; then
|
||||
api_ok="true"
|
||||
break
|
||||
fi
|
||||
sleep 1s
|
||||
done
|
||||
|
||||
if [ "$api_ok" != "true" ]; then
|
||||
echo "Timed out waiting for Pleroma API to become available"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$SEED_SENTINEL_PATH" ]; then
|
||||
if [ -n "${E2E_ADMIN_USERNAME:-}" ] && [ -n "${E2E_ADMIN_PASSWORD:-}" ] && [ -n "${E2E_ADMIN_EMAIL:-}" ]; then
|
||||
echo "-- Seeding admin user (${E2E_ADMIN_USERNAME})..."
|
||||
if ! /opt/pleroma/bin/pleroma_ctl user new "$E2E_ADMIN_USERNAME" "$E2E_ADMIN_EMAIL" --admin --password "$E2E_ADMIN_PASSWORD" -y; then
|
||||
echo "-- User already exists (or creation failed), ensuring admin + confirmed..."
|
||||
/opt/pleroma/bin/pleroma_ctl user set "$E2E_ADMIN_USERNAME" --admin --confirmed
|
||||
fi
|
||||
else
|
||||
echo "-- Skipping admin seeding (missing E2E_ADMIN_* env)"
|
||||
fi
|
||||
|
||||
touch "$SEED_SENTINEL_PATH"
|
||||
fi
|
||||
|
||||
wait "$PLEROMA_PID"
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
"unit": "node build/update-emoji.js && vitest --run",
|
||||
"unit-ci": "node build/update-emoji.js && vitest --run --browser.headless",
|
||||
"unit:watch": "node build/update-emoji.js && vitest",
|
||||
"e2e": "node test/e2e/runner.js",
|
||||
"e2e:pw": "playwright test --config test/e2e-playwright/playwright.config.mjs",
|
||||
"e2e": "sh ./tools/e2e/run.sh",
|
||||
"test": "yarn run unit && yarn run e2e",
|
||||
"ci-biome": "yarn exec biome check",
|
||||
"ci-eslint": "yarn exec eslint",
|
||||
|
|
|
|||
|
|
@ -30,60 +30,61 @@
|
|||
</p>
|
||||
<div class="setting-control">
|
||||
<table>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.period') }}
|
||||
</th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.amount') }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td v-if="isSeparate">
|
||||
{{ $t('admin_dash.rate_limit.unauthenticated') }}
|
||||
</td>
|
||||
<td v-else>
|
||||
{{ $t('admin_dash.rate_limit.rate_limit') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="isSeparate">
|
||||
<td>
|
||||
{{ $t('admin_dash.rate_limit.authenticated') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.period') }}
|
||||
</th>
|
||||
<th>
|
||||
{{ $t('admin_dash.rate_limit.amount') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{{ isSeparate ? $t('admin_dash.rate_limit.unauthenticated') : $t('admin_dash.rate_limit.rate_limit') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[0][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 0, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="isSeparate">
|
||||
<td>
|
||||
{{ $t('admin_dash.rate_limit.authenticated') }}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][0]"
|
||||
@change="e => update({ event: e, index: 0, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="input string-input"
|
||||
type="number"
|
||||
:value="normalizedState[1][1]"
|
||||
@change="e => update({ event: e, index: 1, side: 1, eventType: 'edit' })"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Checkbox
|
||||
:model-value="isSeparate"
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ const users = {
|
|||
if (data.access_token) {
|
||||
store.commit('signUpSuccess')
|
||||
oauthStore.setToken(data.access_token)
|
||||
store.dispatch('loginUser', data.access_token)
|
||||
await store.dispatch('loginUser', data.access_token)
|
||||
return 'ok'
|
||||
} else {
|
||||
// Request succeeded, but user cannot login yet.
|
||||
|
|
|
|||
50
test/e2e-playwright/playwright.config.mjs
Normal file
50
test/e2e-playwright/playwright.config.mjs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* global process */
|
||||
import { defineConfig, devices } from 'playwright/test'
|
||||
|
||||
const baseURL = process.env.E2E_BASE_URL || 'http://localhost:8080'
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './specs',
|
||||
// Paths are resolved relative to this config file directory.
|
||||
outputDir: 'test-results',
|
||||
timeout: 60_000,
|
||||
expect: {
|
||||
timeout: 10_000,
|
||||
},
|
||||
retries: process.env.CI ? 1 : 0,
|
||||
reporter: process.env.CI
|
||||
? [['line'], ['html', { outputFolder: 'playwright-report', open: 'never' }]]
|
||||
: [
|
||||
['list'],
|
||||
['html', { outputFolder: 'playwright-report', open: 'never' }],
|
||||
],
|
||||
use: {
|
||||
baseURL,
|
||||
screenshot: 'only-on-failure',
|
||||
trace: 'on-first-retry',
|
||||
video: 'retain-on-failure',
|
||||
},
|
||||
webServer: {
|
||||
command: 'yarn dev -- --host 0.0.0.0 --port 8080 --strictPort',
|
||||
url: baseURL,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
timeout: 120_000,
|
||||
env: {
|
||||
...process.env,
|
||||
VITE_PROXY_TARGET:
|
||||
process.env.VITE_PROXY_TARGET || 'http://localhost:4000',
|
||||
VITE_PROXY_ORIGIN:
|
||||
process.env.VITE_PROXY_ORIGIN ||
|
||||
process.env.VITE_PROXY_TARGET ||
|
||||
'http://localhost:4000',
|
||||
},
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'firefox',
|
||||
use: {
|
||||
...devices['Desktop Firefox'],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
27
test/e2e-playwright/specs/admin_smoke.spec.js
Normal file
27
test/e2e-playwright/specs/admin_smoke.spec.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* global process */
|
||||
import { expect, test } from 'playwright/test'
|
||||
|
||||
const adminUsername = process.env.E2E_ADMIN_USERNAME || 'admin'
|
||||
const adminPassword = process.env.E2E_ADMIN_PASSWORD || 'adminadmin'
|
||||
|
||||
test('admin can open the admin settings modal', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
const loginForm = page.locator('#main-scroller form.login-form')
|
||||
await loginForm.locator('#username').fill(adminUsername)
|
||||
await loginForm.locator('#password').fill(adminPassword)
|
||||
await loginForm.getByRole('button', { name: 'Log in' }).click()
|
||||
|
||||
await page.waitForURL(/\/main\/friends/)
|
||||
|
||||
await expect(page.getByTitle('Administration')).toBeVisible()
|
||||
await page.getByTitle('Administration').click()
|
||||
|
||||
const modal = page.locator('.settings-modal-panel')
|
||||
await expect(
|
||||
modal.getByRole('heading', { name: 'Administration' }),
|
||||
).toBeVisible()
|
||||
|
||||
await modal.getByRole('tab', { name: 'Emoji' }).click()
|
||||
await expect(modal.getByText('Emoji packs')).toBeVisible()
|
||||
})
|
||||
90
test/e2e-playwright/specs/user_smoke.spec.js
Normal file
90
test/e2e-playwright/specs/user_smoke.spec.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import { randomUUID } from 'node:crypto'
|
||||
import { expect, test } from 'playwright/test'
|
||||
|
||||
const createTestUser = () => {
|
||||
const id = randomUUID().slice(0, 8)
|
||||
return {
|
||||
username: `e2e_${id}`,
|
||||
fullname: `E2E ${id}`,
|
||||
email: `e2e_${id}@example.com`,
|
||||
password: 'e2e-password',
|
||||
}
|
||||
}
|
||||
|
||||
const register = async (page, user) => {
|
||||
await page.goto('/registration')
|
||||
|
||||
const registrationForm = page.locator('#main-scroller form.registration-form')
|
||||
await registrationForm.locator('#sign-up-username').fill(user.username)
|
||||
await registrationForm.locator('#sign-up-fullname').fill(user.fullname)
|
||||
await registrationForm.locator('#email').fill(user.email)
|
||||
await registrationForm.locator('#sign-up-password').fill(user.password)
|
||||
await registrationForm
|
||||
.locator('#sign-up-password-confirmation')
|
||||
.fill(user.password)
|
||||
await Promise.all([
|
||||
page.waitForURL(/\/main\/friends/),
|
||||
registrationForm.getByRole('button', { name: 'Register' }).click(),
|
||||
])
|
||||
}
|
||||
|
||||
const logout = async (page) => {
|
||||
await page.getByTitle('Log out').click()
|
||||
const confirmLogout = page.getByRole('button', {
|
||||
name: 'Logout',
|
||||
exact: true,
|
||||
})
|
||||
if (await confirmLogout.isVisible()) {
|
||||
await Promise.all([
|
||||
page.waitForURL(/\/main\/(public|all)/),
|
||||
confirmLogout.click(),
|
||||
])
|
||||
} else {
|
||||
await page.waitForURL(/\/main\/(public|all)/)
|
||||
}
|
||||
|
||||
await expect(page.locator('#sidebar form.login-form')).toBeVisible()
|
||||
}
|
||||
|
||||
const login = async (page, user) => {
|
||||
await page.goto('/login')
|
||||
|
||||
const loginForm = page.locator('#main-scroller form.login-form')
|
||||
await loginForm.locator('#username').fill(user.username)
|
||||
await loginForm.locator('#password').fill(user.password)
|
||||
await loginForm.getByRole('button', { name: 'Log in' }).click()
|
||||
|
||||
await page.waitForURL(/\/main\/friends/)
|
||||
}
|
||||
|
||||
test('user can register, log out, and log back in', async ({ page }) => {
|
||||
const user = createTestUser()
|
||||
await register(page, user)
|
||||
await expect(page.getByTitle('Log out')).toBeVisible()
|
||||
|
||||
await logout(page)
|
||||
|
||||
await login(page, user)
|
||||
await expect(page.getByTitle('Log out')).toBeVisible()
|
||||
})
|
||||
|
||||
test('user can post a status', async ({ page }) => {
|
||||
const user = createTestUser()
|
||||
await register(page, user)
|
||||
|
||||
const statusText = `Hello from ${user.username} (${randomUUID().slice(0, 8)})`
|
||||
const composer = page.locator('#sidebar .user-panel .post-status-form')
|
||||
await composer.locator('textarea.form-post-body').fill(statusText)
|
||||
await Promise.all([
|
||||
page.waitForResponse(
|
||||
(resp) =>
|
||||
resp.request().method() === 'POST' &&
|
||||
resp.url().includes('/api/v1/statuses') &&
|
||||
resp.ok(),
|
||||
),
|
||||
composer.getByRole('button', { name: 'Post', exact: true }).click(),
|
||||
])
|
||||
|
||||
await page.goto(`/users/${user.username}`)
|
||||
await expect(page.getByText(statusText)).toBeVisible()
|
||||
})
|
||||
35
tools/e2e/run.sh
Normal file
35
tools/e2e/run.sh
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
COMPOSE_FILE="docker-compose.e2e.yml"
|
||||
|
||||
: "${COMPOSE_MENU:=false}"
|
||||
: "${PLEROMA_IMAGE:=git.pleroma.social:5050/pleroma/pleroma:stable}"
|
||||
: "${E2E_ADMIN_USERNAME:=admin}"
|
||||
: "${E2E_ADMIN_PASSWORD:=adminadmin}"
|
||||
: "${E2E_ADMIN_EMAIL:=admin@example.com}"
|
||||
|
||||
cleanup() {
|
||||
docker compose -f "$COMPOSE_FILE" down -v --remove-orphans >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
cleanup
|
||||
|
||||
trap 'cleanup; exit 130' INT TERM
|
||||
|
||||
set +e
|
||||
COMPOSE_MENU="$COMPOSE_MENU" docker compose -f "$COMPOSE_FILE" up --build --remove-orphans --attach e2e --no-log-prefix --abort-on-container-exit --exit-code-from e2e
|
||||
result="$?"
|
||||
set -e
|
||||
|
||||
if [ "$result" -ne 0 ]; then
|
||||
docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/test-results test/e2e-playwright >/dev/null 2>&1 || true
|
||||
docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/playwright-report test/e2e-playwright >/dev/null 2>&1 || true
|
||||
mkdir -p test/e2e-playwright/test-results
|
||||
docker compose -f "$COMPOSE_FILE" logs --no-color pleroma db > test/e2e-playwright/test-results/docker-compose.log 2>/dev/null || true
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
||||
exit "$result"
|
||||
|
|
@ -5,6 +5,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
|
|||
import { defineConfig } from 'vite'
|
||||
import eslint from 'vite-plugin-eslint2'
|
||||
import stylelint from 'vite-plugin-stylelint'
|
||||
import { configDefaults } from 'vitest/config'
|
||||
import { getCommitHash } from './build/commit_hash.js'
|
||||
import copyPlugin from './build/copy_plugin.js'
|
||||
import emojisPlugin from './build/emojis_plugin.js'
|
||||
|
|
@ -16,23 +17,37 @@ import {
|
|||
} from './build/sw_plugin.js'
|
||||
|
||||
const localConfigPath = '<projectRoot>/config/local.json'
|
||||
const normalizeTarget = (target) => {
|
||||
if (!target || typeof target !== 'string') return target
|
||||
return target.endsWith('/') ? target.replace(/\/$/, '') : target
|
||||
}
|
||||
|
||||
const getLocalDevSettings = async () => {
|
||||
const envTarget = normalizeTarget(process.env.VITE_PROXY_TARGET)
|
||||
const envOrigin = normalizeTarget(process.env.VITE_PROXY_ORIGIN)
|
||||
try {
|
||||
const settings = (await import('./config/local.json')).default
|
||||
if (settings.target && settings.target.endsWith('/')) {
|
||||
// replacing trailing slash since it can conflict with some apis
|
||||
// and that's how actual BE reports its url
|
||||
settings.target = settings.target.replace(/\/$/, '')
|
||||
}
|
||||
settings.target = normalizeTarget(settings.target)
|
||||
settings.origin = normalizeTarget(settings.origin)
|
||||
if (envTarget) settings.target = envTarget
|
||||
if (envOrigin) settings.origin = envOrigin
|
||||
console.info(`Using local dev server settings (${localConfigPath}):`)
|
||||
console.info(JSON.stringify(settings, null, 2))
|
||||
return settings
|
||||
} catch (e) {
|
||||
if (!envTarget && !envOrigin) {
|
||||
console.info(
|
||||
`Local dev server settings not found (${localConfigPath}), using default`,
|
||||
e,
|
||||
)
|
||||
return {}
|
||||
}
|
||||
const settings = { target: envTarget, origin: envOrigin }
|
||||
console.info(
|
||||
`Local dev server settings not found (${localConfigPath}), using default`,
|
||||
e,
|
||||
'Using dev server settings from VITE_PROXY_TARGET/VITE_PROXY_ORIGIN:',
|
||||
)
|
||||
return {}
|
||||
console.info(JSON.stringify(settings, null, 2))
|
||||
return settings
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +73,7 @@ const getTransformSWSettings = (settings) => {
|
|||
export default defineConfig(async ({ mode, command }) => {
|
||||
const settings = await getLocalDevSettings()
|
||||
const target = settings.target || 'http://localhost:4000/'
|
||||
const origin = settings.origin || target
|
||||
const transformSW = getTransformSWSettings(settings)
|
||||
const proxy = {
|
||||
'/api': {
|
||||
|
|
@ -77,7 +93,7 @@ export default defineConfig(async ({ mode, command }) => {
|
|||
cookieDomainRewrite: 'localhost',
|
||||
ws: true,
|
||||
headers: {
|
||||
Origin: target,
|
||||
Origin: origin,
|
||||
},
|
||||
},
|
||||
'/oauth': {
|
||||
|
|
@ -225,6 +241,7 @@ export default defineConfig(async ({ mode, command }) => {
|
|||
},
|
||||
test: {
|
||||
globals: true,
|
||||
exclude: [...configDefaults.exclude, 'test/e2e-playwright/**'],
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: 'playwright',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue