Files
upstream-mirror c60cc7ca75
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:19:12 +05:00

433 lines
14 KiB
Bash
Executable File

#!/usr/bin/env bash
echo "Running Ory Kratos E2E Tests..."
echo ""
set -euxo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
make .bin/hydra
export PATH=.bin:$PATH
export KRATOS_PUBLIC_URL=http://localhost:4433/
export KRATOS_BROWSER_URL=http://localhost:4433/
export KRATOS_ADMIN_URL=http://localhost:4434/
export KRATOS_UI_URL=http://localhost:4456/
export KRATOS_UI_REACT_URL=http://localhost:4458/
export KRATOS_UI_REACT_NATIVE_URL=http://localhost:19006/
export LOG_LEAK_SENSITIVE_VALUES=true
export DEV_DISABLE_API_FLOW_ENFORCEMENT=true
export COOKIE_SECRET=kweifawskf23weas
export CSRF_COOKIE_NAME=node_csrf_token
export CSRF_COOKIE_SECRET=lkaw9oe8isedrhq2
base=$(pwd)
setup=yes
dev=no
nokill=no
cleanup=no
for i in "$@"; do
case $i in
--no-kill)
nokill=yes
shift # past argument=value
;;
--only-setup)
setup=only
shift # past argument=value
;;
--no-setup)
setup=no
shift # past argument=value
;;
--dev)
dev=yes
shift # past argument=value
;;
--cleanup)
cleanup=yes
shift # past argument=value
;;
esac
done
cleanup() {
# Temporarily disable exit on error for cleanup (services may not be running)
set +e
echo "=== E2E Cleanup ==="
# Step 1: Kill process supervisors FIRST (they respawn children)
echo "Killing process supervisors (modd, nodemon)..."
pkill -9 -f "modd" 2>/dev/null
pkill -9 -f "nodemon" 2>/dev/null
sleep 2
# Step 2: Kill Kratos and webhook (were managed by modd)
echo "Killing Kratos and webhook..."
pkill -9 -f "kratos serve" 2>/dev/null
pkill -9 -f "\.bin/kratos" 2>/dev/null
pkill -9 -f "\.bin/webhook" 2>/dev/null
killall kratos 2>/dev/null
killall webhook 2>/dev/null
# Step 3: Kill Node.js services
echo "Killing Node.js services..."
pkill -9 -f "node.*proxy" 2>/dev/null
pkill -9 -f "kratos-selfservice-ui-node" 2>/dev/null
pkill -9 -f "kratos-selfservice-ui-react-nextjs" 2>/dev/null
pkill -9 -f "expo" 2>/dev/null
pkill -9 -f "webpack.*19006" 2>/dev/null
# Step 4: Kill Hydra processes
echo "Killing Hydra processes..."
killall hydra 2>/dev/null
killall hydra-login-consent 2>/dev/null
killall hydra-kratos-login-consent 2>/dev/null
pkill -9 -f "hydra serve" 2>/dev/null
# Step 5: Kill any remaining processes on known ports
echo "Cleaning up any remaining port listeners..."
for port in 4433 4434 4444 4445 4446 4455 4456 4458 4744 4745 4746 19006; do
pid=$(lsof -ti:$port 2>/dev/null)
if [ -n "$pid" ]; then
echo " Killing PID $pid on port $port"
kill -9 $pid 2>/dev/null
fi
done
# Step 6: Stop and remove Docker containers
echo "Stopping Docker containers..."
docker stop kratos_test_database_mysql kratos_test_database_postgres kratos_test_database_cockroach mailslurper kratos_test_hydra 2>/dev/null
docker rm kratos_test_database_mysql kratos_test_database_postgres kratos_test_database_cockroach mailslurper kratos_test_hydra 2>/dev/null
echo "=== Cleanup Complete ==="
# Re-enable exit on error
set -e
}
prepare() {
echo "::group::prepare"
if [[ "${nokill}" == "no" ]]; then
cleanup
fi
if [ -z ${TEST_DATABASE_POSTGRESQL-} ]; then
docker rm -f kratos_test_database_mysql kratos_test_database_postgres kratos_test_database_cockroach || true
docker run --name kratos_test_database_mysql -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0
docker run --name kratos_test_database_postgres -p 3445:5432 -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=postgres -d postgres:14 postgres -c log_statement=all
docker run --name kratos_test_database_cockroach -p 3446:26257 -d cockroachdb/cockroach:latest-v25.4 start-single-node --insecure
export TEST_DATABASE_MYSQL="mysql://root:secret@(localhost:3444)/mysql?parseTime=true&multiStatements=true"
export TEST_DATABASE_POSTGRESQL="postgres://postgres:secret@localhost:3445/postgres?sslmode=disable"
export TEST_DATABASE_COCKROACHDB="cockroach://root@localhost:3446/defaultdb?sslmode=disable"
fi
if [ -z "${NODE_UI_PATH-}" ]; then
node_ui_dir="$(mktemp -d -t ci-XXXXXXXXXX)/kratos-selfservice-ui-node"
git clone --depth 1 --branch master https://github.com/ory/kratos-selfservice-ui-node.git "$node_ui_dir"
(cd "$node_ui_dir" && npm i --legacy-peer-deps && npm run build)
else
node_ui_dir="${NODE_UI_PATH}"
fi
if [ -z "${RN_UI_PATH-}" ]; then
rn_ui_dir="$(mktemp -d -t ci-XXXXXXXXXX)/kratos-selfservice-ui-react-native"
git clone --depth 1 --branch master https://github.com/ory/kratos-selfservice-ui-react-native.git "$rn_ui_dir"
(cd "$rn_ui_dir" && npm i)
else
rn_ui_dir="${RN_UI_PATH}"
fi
if [ -z "${REACT_UI_PATH-}" ]; then
react_ui_dir="$(mktemp -d -t ci-XXXXXXXXXX)/ory/kratos-selfservice-ui-react-nextjs"
git clone --depth 1 --branch master https://github.com/ory/kratos-selfservice-ui-react-nextjs.git "$react_ui_dir"
(cd "$react_ui_dir" && npm i)
else
react_ui_dir="${REACT_UI_PATH}"
fi
(
rm test/e2e/proxy.json || true
echo '"express"' > test/e2e/proxy.json
cd test/e2e/proxy
npm i
)
if [ -z ${CI-} ]; then
docker rm mailslurper hydra hydra-ui -f || true
docker run --name mailslurper -p 4436:4436 -p 4437:4437 -p 1025:1025 oryd/mailslurper:latest-smtps > "${base}/test/e2e/mailslurper.e2e.log" 2>&1 &
fi
# Check if any ports that we need are open already
nc -zv localhost 4444 && exit 1
nc -zv localhost 4445 && exit 1
nc -zv localhost 4446 && exit 1
nc -zv localhost 4455 && exit 1
nc -zv localhost 19006 && exit 1
nc -zv localhost 4456 && exit 1
nc -zv localhost 4458 && exit 1
nc -zv localhost 4744 && exit 1
nc -zv localhost 4745 && exit 1
(
cd "$rn_ui_dir"
KRATOS_URL=http://localhost:4433 CI=1 npm run web \
>"${base}/test/e2e/rn-profile-app.e2e.log" 2>&1 &
)
hydra serve all -c test/e2e/hydra.yml --dev >"${base}/test/e2e/hydra.e2e.log" 2>&1 &
(cd test/e2e; npm run wait-on -- -l -t 300000 http-get://localhost:4445/health/alive)
hydra_client=$(hydra create oauth2-client \
--endpoint http://localhost:4445 \
--grant-type authorization_code --grant-type refresh_token \
--response-type code --response-type id_token \
--scope openid --scope offline \
--redirect-uri http://localhost:4455/self-service/methods/oidc/callback/hydra \
--format json)
export OIDC_HYDRA_CLIENT_ID=$(jq -r '.client_id' <<< "$hydra_client" )
export OIDC_HYDRA_CLIENT_SECRET=$(jq -r '.client_secret' <<< "$hydra_client" )
google_client=$(hydra create oauth2-client \
--endpoint http://localhost:4445 \
--grant-type authorization_code --grant-type refresh_token \
--response-type code --response-type id_token \
--scope openid --scope offline \
--redirect-uri http://localhost:4455/self-service/methods/oidc/callback/google \
--format json)
export OIDC_GOOGLE_CLIENT_ID=$(jq -r '.client_id' <<< "$google_client" )
export OIDC_GOOGLE_CLIENT_SECRET=$(jq -r '.client_secret' <<< "$google_client" )
github_client=$(hydra create oauth2-client \
--endpoint http://localhost:4445 \
--grant-type authorization_code --grant-type refresh_token \
--response-type code --response-type id_token \
--scope openid --scope offline \
--redirect-uri http://localhost:4455/self-service/methods/oidc/callback/github \
--format json)
export OIDC_GITHUB_CLIENT_ID=$(jq -r '.client_id' <<< "$github_client" )
export OIDC_GITHUB_CLIENT_SECRET=$(jq -r '.client_secret' <<< "$github_client" )
(
cd test/e2e/hydra-login-consent
go build .
PORT=4446 HYDRA_ADMIN_URL=http://localhost:4445 ./hydra-login-consent >"${base}/test/e2e/hydra-ui.e2e.log" 2>&1 &
)
# Spin up another Hydra instance with the express node app used as the login UI for kratos-hydra OIDC provider tests
DSN=memory SERVE_PUBLIC_PORT=4744 \
SERVE_ADMIN_PORT=4745 \
URLS_SELF_ISSUER=http://localhost:4744 \
LOG_LEVEL=trace \
URLS_LOGIN=http://localhost:4455/login \
URLS_CONSENT=http://localhost:4746/consent \
SECRETS_SYSTEM="[\"1234567890123456789012345678901\"]" \
hydra serve all --dev >"${base}/test/e2e/hydra-kratos.e2e.log" 2>&1 &
(cd test/e2e; npm run wait-on -- -l -t 300000 http-get://127.0.0.1:4745/health/alive)
dummy_client=$(hydra create oauth2-client \
--endpoint http://localhost:4745 \
--token-endpoint-auth-method client_secret_basic \
--grant-type authorization_code --grant-type refresh_token \
--response-type code --response-type id_token \
--scope openid --scope offline --scope email --scope website \
--redirect-uri http://localhost:5555/callback \
--redirect-uri https://ory-network-httpbin-ijakee5waq-ez.a.run.app/anything \
--format json)
export CYPRESS_OIDC_DUMMY_CLIENT_ID=$(jq -r '.client_id' <<< "$dummy_client" )
export CYPRESS_OIDC_DUMMY_CLIENT_SECRET=$(jq -r '.client_secret' <<< "$dummy_client" )
(
cd test/e2e/hydra-kratos-login-consent
go build .
PORT=4746 HYDRA_ADMIN_URL=http://localhost:4745 ./hydra-kratos-login-consent >"${base}/test/e2e/hydra-kratos-ui.e2e.log" 2>&1 &
)
(
cd "$node_ui_dir"
PORT=4456 SECURITY_MODE=cookie npm run start \
>"${base}/test/e2e/ui-node.e2e.log" 2>&1 &
)
if [ -z "${REACT_UI_PATH-}" ]; then
(
cd "$react_ui_dir"
NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run build
NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run start -- --hostname 127.0.0.1 --port 4458 \
>"${base}/test/e2e/react-iu.e2e.log" 2>&1 &
)
else
(
cd "$react_ui_dir"
PORT=4458 NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://localhost:4433 npm run dev \
>"${base}/test/e2e/react-iu.e2e.log" 2>&1 &
)
fi
(
cd test/e2e/proxy
PORT=4455 npm run start \
>"${base}/test/e2e/proxy.e2e.log" 2>&1 &
)
# Make the environment available to Playwright
env | grep KRATOS_ > test/e2e/playwright/playwright.env
env | grep TEST_DATABASE_ >> test/e2e/playwright/playwright.env
env | grep OIDC_ >> test/e2e/playwright/playwright.env
env | grep CYPRESS_ >> test/e2e/playwright/playwright.env
echo LOG_LEAK_SENSITIVE_VALUES=true >> test/e2e/playwright/playwright.env
echo DEV_DISABLE_API_FLOW_ENFORCEMENT=true >> test/e2e/playwright/playwright.env
echo "::endgroup::"
}
run() {
echo "::group::run-prep"
killall modd || true
killall kratos || true
export DSN=${1}
nc -zv localhost 4434 && (echo "Port 4434 unavailable, used by" ; lsof -i:4434 ; exit 1)
nc -zv localhost 4433 && (echo "Port 4433 unavailable, used by" ; lsof -i:4433 ; exit 1)
ls -la .
for profile in code email mobile oidc recovery recovery-mfa verification mfa mfa-optional spa network passwordless passkey webhooks oidc-provider oidc-provider-mfa two-steps; do
go tool yq ea '. as $item ireduce ({}; . * $item )' test/e2e/profiles/kratos.base.yml "test/e2e/profiles/${profile}/.kratos.yml" > test/e2e/kratos.${profile}.yml
cat "test/e2e/kratos.${profile}.yml" | envsubst | sponge "test/e2e/kratos.${profile}.yml"
done
cp test/e2e/kratos.email.yml test/e2e/kratos.generated.yml
(go tool modd -f test/e2e/modd.conf >"${base}/test/e2e/kratos.e2e.log" 2>&1 &)
# Having to wait 10 minutes for cockroach to apply the migrations is ridiculous but sometimes it takes that long in CI
npm run wait-on -- -l -t 10m http-get://127.0.0.1:4434/health/ready \
http-get://127.0.0.1:4444/.well-known/openid-configuration \
http-get://127.0.0.1:4455/health/ready \
http-get://127.0.0.1:4445/health/ready \
http-get://127.0.0.1:4446/ \
http-get://127.0.0.1:4456/health/alive \
http-get://127.0.0.1:19006/ \
http-get://127.0.0.1:4437/mail \
http-get://127.0.0.1:4458/ \
http-get://127.0.0.1:4459/health
echo "::endgroup::"
if [[ $dev == "yes" ]]; then
(cd test/e2e; npm run test:watch --)
else
if [ -z "${CYPRESS_RECORD_KEY-}" ]; then
(cd test/e2e; npx cypress run --browser chrome ${CYPRESS_OPTS-})
else
(cd test/e2e; npx cypress run --browser chrome ${CYPRESS_OPTS-} --record --tag "${2}" )
fi
fi
}
usage() {
echo $"This script runs the e2e tests.
To run the tests just pick a database name:
$0 <database>
Supported databases are 'sqlite', 'mysql', 'postgres', 'cockroach':
$0 sqlite
$0 mysql
$0 postgres
$0 cockroach
...
If you are using a database other than SQLite, you need to set
an environment variable that points to it:
export TEST_DATABASE_MYSQL=...
export TEST_DATABASE_POSTGRESQL=...
export TEST_DATABASE_COCKROACHDB=...
$0 <database>
The Makefile has a helper for that which uses Docker to start the
databases:
make test-resetdb
source script/test-envs.sh
$0 <database>
To run e2e tests in dev mode (useful for writing them), run:
$0 --dev <database>
To set up all the services without running the tests, use:
$0 --only-setup
To then run the tests without the set up steps, use:
$0 --no-setup <database>
To prevent processes from being killed during set up phase, use:
$0 --no-kill
If you are making changes to the kratos-selfservice-ui-node
project as well, point the 'NODE_UI_PATH' environment variable to
the path where the kratos-selfservice-ui-node project is checked out:
export NODE_UI_PATH=$HOME/workspace/kratos-selfservice-ui-node
export RN_UI_PATH=$HOME/workspace/kratos-selfservice-ui-react-native
export REACT_UI_PATH=$HOME/workspace/kratos-selfservice-ui-react-nextjs
$0 ..."
}
if [[ "${cleanup}" == "yes" ]]; then
cleanup
exit 0
fi
export TEST_DATABASE_SQLITE="sqlite:///$(mktemp -d -t ci-XXXXXXXXXX)/db.sqlite?_fk=true&_journal=WAL"
export TEST_DATABASE_MEMORY="memory"
case "${1:-default}" in
sqlite)
echo "Database set up at: $TEST_DATABASE_SQLITE"
dsn="${TEST_DATABASE_SQLITE}"
db="sqlite"
;;
mysql)
dsn="${TEST_DATABASE_MYSQL}"
db="mysql"
;;
postgres)
dsn="${TEST_DATABASE_POSTGRESQL}"
db="postgres"
;;
cockroach)
dsn="${TEST_DATABASE_COCKROACHDB}"
db="cockroach"
;;
*)
usage
if [[ "${setup}" == "only" ]]; then
prepare
exit 0
else
exit 1
fi
;;
esac
if [[ "${setup}" == "yes" ]]; then
prepare
fi
run "${dsn}" "${db}"