mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 06:37:31 +00:00
contributing
This commit is contained in:
135
CONTRIBUTING.md
135
CONTRIBUTING.md
@@ -28,39 +28,6 @@ Please consider the following guidelines when creating a pull request.
|
|||||||
- We use ESLint/Prettier for linting/formatting, so please run `pnpm lint:fix` before committing to make resolving conflicts easier (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development)
|
- We use ESLint/Prettier for linting/formatting, so please run `pnpm lint:fix` before committing to make resolving conflicts easier (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development)
|
||||||
- If you add new functionality, please provide the corresponding documentation as well and make it part of the pull request
|
- If you add new functionality, please provide the corresponding documentation as well and make it part of the pull request
|
||||||
|
|
||||||
## Setting Up The ZITADEL API
|
|
||||||
|
|
||||||
If you want to have a one-liner to get you up and running,
|
|
||||||
or if you want to develop against a ZITADEL API with the latest features,
|
|
||||||
or even add changes to ZITADEL itself at the same time,
|
|
||||||
you should develop against your local ZITADEL process.
|
|
||||||
However, it might be easier to develop against your ZITADEL Cloud instance
|
|
||||||
if you don't have docker installed
|
|
||||||
or have limited resources on your local machine.
|
|
||||||
|
|
||||||
### Developing Against Your Local ZITADEL Instance
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# To have your service user key and environment file written with the correct ownership, export your current users ID.
|
|
||||||
export ZITADEL_DEV_UID="$(id -u)"
|
|
||||||
|
|
||||||
# Pull images
|
|
||||||
docker compose --file ./acceptance/docker-compose.yaml pull
|
|
||||||
|
|
||||||
# Run ZITADEL with local notification sink and configure ./apps/login/.env.local
|
|
||||||
pnpm run-sink
|
|
||||||
```
|
|
||||||
|
|
||||||
### Developing Against Your ZITADEL Cloud Instance
|
|
||||||
|
|
||||||
Configure your shell by exporting the following environment variables:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
export ZITADEL_API_URL=<your cloud instance URL here>
|
|
||||||
export ZITADEL_ORG_ID=<your service accounts organization id here>
|
|
||||||
export ZITADEL_SERVICE_USER_TOKEN=<your service account personal access token here>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Setting up local environment
|
### Setting up local environment
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -76,36 +43,94 @@ pnpm dev
|
|||||||
|
|
||||||
The application is now available at `http://localhost:3000`
|
The application is now available at `http://localhost:3000`
|
||||||
|
|
||||||
### Adding applications and IDPs
|
Configure apps/login/.env.local to target the Zitadel instance of your choice.
|
||||||
|
The login app live-reloads on changes, so you can start developing right away.
|
||||||
|
|
||||||
|
<!-- Console doesn't load
|
||||||
|
|
||||||
|
### Developing Against Your Local ZITADEL Instance
|
||||||
|
|
||||||
|
The following command uses Docker to run a local ZITADEL instance and the login application in live-reloading dev mode.
|
||||||
|
Additionally, it runs a Traefik reverse proxy that exposes the login at https://localhost with a self-signed certificate.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# OPTIONAL Run SAML SP
|
pnpm test:acceptance:setup
|
||||||
pnpm run-samlsp
|
```
|
||||||
|
-->
|
||||||
|
|
||||||
# OPTIONAL Run OIDC RP
|
### Quality Assurance
|
||||||
pnpm run-oidcrp
|
|
||||||
|
|
||||||
# OPTIONAL Run SAML IDP
|
Use `make` commands to test the quality of your code without installing any dependencies besides Docker.
|
||||||
pnpm run-samlidp
|
Using `make` commands, you can reproduce and debug the CI pipelines locally.
|
||||||
|
```sh
|
||||||
# OPTIONAL Run OIDC OP
|
# Reproduce the whole CI pipeline in docker
|
||||||
pnpm run-oidcop
|
make login-quality
|
||||||
|
# Show other options with make
|
||||||
|
make help
|
||||||
```
|
```
|
||||||
|
|
||||||
### Testing
|
Use `pnpm` commands to run the tests in dev mode with live reloading and debugging capabilities.
|
||||||
|
|
||||||
To test the quality of your code, make sure
|
#### Linting and formatting
|
||||||
|
|
||||||
You can execute the following commands `pnpm test` for a single test run or `pnpm test:watch` in the following directories:
|
Check the formatting and linting of the code in docker
|
||||||
|
|
||||||
- apps/login
|
```sh
|
||||||
- packages/zitadel-proto
|
make login-lint
|
||||||
- packages/zitadel-client
|
```
|
||||||
- packages/zitadel-node
|
|
||||||
- The projects root directory: all tests in the project are executed
|
|
||||||
|
|
||||||
In apps/login, these commands also spin up the application and a ZITADEL gRPC API mock server to run integration tests using [Cypress](https://www.cypress.io/) against them.
|
Check the linting of the code using pnpm
|
||||||
If you want to run the integration tests standalone against an environment of your choice, navigate to ./apps/login, [configure your shell as you like](# Developing Against Your ZITADEL Cloud Instance) and run `pnpm test:integration:run` or `pnpm test:integration:open`.
|
|
||||||
Then you need to lifecycle the mock process using the command `pnpm mock` or the more fine grained commands `pnpm mock:build`, `pnpm mock:build:nocache`, `pnpm mock:run` and `pnpm mock:destroy`.
|
|
||||||
|
|
||||||
That's it! 🎉
|
```sh
|
||||||
|
pnpm lint
|
||||||
|
pnpm format
|
||||||
|
```
|
||||||
|
|
||||||
|
Fix the linting of your code
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm lint:fix
|
||||||
|
pnpm format:fix
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Running Unit Tests
|
||||||
|
|
||||||
|
Run the tests in docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make login-test-unit
|
||||||
|
```
|
||||||
|
|
||||||
|
Run unit tests with live-reloading
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm test:unit
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Running Integration Tests
|
||||||
|
|
||||||
|
Run the test in docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make login-test-integration
|
||||||
|
```
|
||||||
|
|
||||||
|
Open the Cypress test suite to run the integration tests in interactive mode.
|
||||||
|
First, set up your local test environment.
|
||||||
|
This runs a mock server in docker and the login application in dev mode with live-reloading enabled.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm test:integration:setup
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, in another terminal session, open the interactive Cypress integration test suite.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm test:integration open
|
||||||
|
```
|
||||||
|
|
||||||
|
Show more options with Cypress
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm test:integration help
|
||||||
|
```
|
||||||
|
6
Makefile
6
Makefile
@@ -23,7 +23,7 @@ export LOGIN_TEST_ACCEPTANCE_SAMLSP_TAG := login-test-acceptance-samlsp:${DOCKER
|
|||||||
export LOGIN_TEST_ACCEPTANCE_SAMLIDP_TAG := login-test-acceptance-samlidp:${DOCKER_METADATA_OUTPUT_VERSION}
|
export LOGIN_TEST_ACCEPTANCE_SAMLIDP_TAG := login-test-acceptance-samlidp:${DOCKER_METADATA_OUTPUT_VERSION}
|
||||||
export POSTGRES_TAG := postgres:17.0-alpine3.19
|
export POSTGRES_TAG := postgres:17.0-alpine3.19
|
||||||
export GOLANG_TAG := golang:1.24-alpine
|
export GOLANG_TAG := golang:1.24-alpine
|
||||||
export ZITADEL_TAG ?= ghcr.io/zitadel/zitadel:02617cf17fdde849378c1a6b5254bbfb2745b164
|
export ZITADEL_TAG ?= ghcr.io/zitadel/zitadel:v3.3.0
|
||||||
export CORE_MOCK_TAG := core-mock:${DOCKER_METADATA_OUTPUT_VERSION}
|
export CORE_MOCK_TAG := core-mock:${DOCKER_METADATA_OUTPUT_VERSION}
|
||||||
|
|
||||||
.PHONY: login-help
|
.PHONY: login-help
|
||||||
@@ -95,6 +95,10 @@ login-test-acceptance: login-test-acceptance-build
|
|||||||
$(LOGIN_TEST_ACCEPTANCE_OIDCRP_TAG) \
|
$(LOGIN_TEST_ACCEPTANCE_OIDCRP_TAG) \
|
||||||
$(LOGIN_TEST_ACCEPTANCE_SAMLSP_TAG)"
|
$(LOGIN_TEST_ACCEPTANCE_SAMLSP_TAG)"
|
||||||
|
|
||||||
|
.PHONY: login-quality
|
||||||
|
login-quality: login-lint login-test-unit login-test-integration
|
||||||
|
@:
|
||||||
|
|
||||||
.PHONY: login-standalone-build
|
.PHONY: login-standalone-build
|
||||||
login-standalone-build:
|
login-standalone-build:
|
||||||
$(BAKE_CLI_WITH_COMMON_ARGS) login-standalone
|
$(BAKE_CLI_WITH_COMMON_ARGS) login-standalone
|
||||||
|
@@ -2,7 +2,7 @@ services:
|
|||||||
|
|
||||||
zitadel:
|
zitadel:
|
||||||
user: "${UID:-1000}:${GID:-1000}"
|
user: "${UID:-1000}:${GID:-1000}"
|
||||||
image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}"
|
image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:v3.3.0}"
|
||||||
container_name: acceptance-zitadel
|
container_name: acceptance-zitadel
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml'
|
command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml'
|
||||||
@@ -12,7 +12,6 @@ services:
|
|||||||
# - "traefik.http.middlewares.zitadel.headers.customrequestheaders.Host=localhost"
|
# - "traefik.http.middlewares.zitadel.headers.customrequestheaders.Host=localhost"
|
||||||
# - "traefik.http.routers.zitadel.middlewares=zitadel@docker"
|
# - "traefik.http.routers.zitadel.middlewares=zitadel@docker"
|
||||||
- "traefik.http.services.zitadel-service.loadbalancer.server.scheme=h2c"
|
- "traefik.http.services.zitadel-service.loadbalancer.server.scheme=h2c"
|
||||||
- "traefik.http.services.zitadel-service.loadbalancer.passHostHeader=false"
|
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
|
@@ -21,7 +21,7 @@ export default defineConfig({
|
|||||||
timeout: 300 * 1000, // 5 minutes
|
timeout: 300 * 1000, // 5 minutes
|
||||||
globalTimeout: 30 * 60_000, // 30 minutes
|
globalTimeout: 30 * 60_000, // 30 minutes
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: [["line"], ["html", { open: process.env.CI ? "never" : "on-failure", host: "0.0.0.0" }]],
|
reporter: [["line"], ["html", { open: process.env.CI ? "never" : "on-failure", host: "0.0.0.0", outputFolder: "./playwright-report/html" }]],
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
@@ -32,7 +32,7 @@ export default defineConfig({
|
|||||||
video: "retain-on-failure",
|
video: "retain-on-failure",
|
||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
},
|
},
|
||||||
outputDir: "test-results",
|
outputDir: "test-results/results",
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
/* Configure projects for major browsers */
|
||||||
projects: [
|
projects: [
|
||||||
|
@@ -45,7 +45,8 @@ test("user email not verified, resend, verify", async ({ user, page }) => {
|
|||||||
await emailVerifyResend(page);
|
await emailVerifyResend(page);
|
||||||
const c = await getCodeFromSink(user.getUsername());
|
const c = await getCodeFromSink(user.getUsername());
|
||||||
// wait for resend of the code
|
// wait for resend of the code
|
||||||
await page.waitForTimeout(2000); await emailVerify(page, c);
|
await page.waitForTimeout(2000);
|
||||||
|
await emailVerify(page, c);
|
||||||
await loginScreenExpect(page, user.getFullName());
|
await loginScreenExpect(page, user.getFullName());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,39 +1,39 @@
|
|||||||
import {Gaxios, GaxiosResponse} from 'gaxios';
|
import { Gaxios, GaxiosResponse } from "gaxios";
|
||||||
|
|
||||||
const awaitNotification = new Gaxios({
|
const awaitNotification = new Gaxios({
|
||||||
url: process.env.SINK_NOTIFICATION_URL,
|
url: process.env.SINK_NOTIFICATION_URL,
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
retryConfig: {
|
retryConfig: {
|
||||||
httpMethodsToRetry: ['POST'],
|
httpMethodsToRetry: ["POST"],
|
||||||
statusCodesToRetry: [[404, 404]],
|
statusCodesToRetry: [[404, 404]],
|
||||||
retry: Number.MAX_SAFE_INTEGER, // totalTimeout limits the number of retries
|
retry: Number.MAX_SAFE_INTEGER, // totalTimeout limits the number of retries
|
||||||
totalTimeout: 10000, // 10 seconds
|
totalTimeout: 10000, // 10 seconds
|
||||||
onRetryAttempt: (error) => {
|
onRetryAttempt: (error) => {
|
||||||
console.warn(`Retrying request to sink notification service: ${error.message}`);
|
console.warn(`Retrying request to sink notification service: ${error.message}`);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getOtpFromSink(recipient: string): Promise<any> {
|
export async function getOtpFromSink(recipient: string): Promise<any> {
|
||||||
return awaitNotification.request({data: {recipient}}).then((response) => {
|
return awaitNotification.request({ data: { recipient } }).then((response) => {
|
||||||
expectSuccess(response);
|
expectSuccess(response);
|
||||||
const otp = response?.data?.args?.otp
|
const otp = response?.data?.args?.otp;
|
||||||
if (!otp) {
|
if (!otp) {
|
||||||
throw new Error(`Response does not contain an otp property: ${JSON.stringify(response.data, null, 2)}`);
|
throw new Error(`Response does not contain an otp property: ${JSON.stringify(response.data, null, 2)}`);
|
||||||
}
|
}
|
||||||
return otp;
|
return otp;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCodeFromSink(recipient: string): Promise<any> {
|
export async function getCodeFromSink(recipient: string): Promise<any> {
|
||||||
return awaitNotification.request({data: {recipient}}).then((response) => {
|
return awaitNotification.request({ data: { recipient } }).then((response) => {
|
||||||
expectSuccess(response);
|
expectSuccess(response);
|
||||||
const code = response?.data?.args?.code
|
const code = response?.data?.args?.code;
|
||||||
if (!code) {
|
if (!code) {
|
||||||
throw new Error(`Response does not contain a code property: ${JSON.stringify(response.data, null, 2)}`);
|
throw new Error(`Response does not contain a code property: ${JSON.stringify(response.data, null, 2)}`);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectSuccess(response: GaxiosResponse): void {
|
function expectSuccess(response: GaxiosResponse): void {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { Page } from "@playwright/test";
|
import { Page } from "@playwright/test";
|
||||||
import { registerWithPasskey } from "./register";
|
import { registerWithPasskey } from "./register";
|
||||||
import {activateOTP, addTOTP, addUser, eventualNewUser, getUserByUsername, removeUser} from "./zitadel";
|
import { activateOTP, addTOTP, addUser, eventualNewUser, getUserByUsername, removeUser } from "./zitadel";
|
||||||
import {request} from 'gaxios';
|
|
||||||
|
|
||||||
export interface userProps {
|
export interface userProps {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -112,7 +111,7 @@ export class PasswordUserWithOTP extends User {
|
|||||||
async ensure(page: Page) {
|
async ensure(page: Page) {
|
||||||
await super.ensure(page);
|
await super.ensure(page);
|
||||||
await activateOTP(this.getUserId(), this.type);
|
await activateOTP(this.getUserId(), this.type);
|
||||||
await eventualNewUser(this.getUserId())
|
await eventualNewUser(this.getUserId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +121,7 @@ export class PasswordUserWithTOTP extends User {
|
|||||||
async ensure(page: Page) {
|
async ensure(page: Page) {
|
||||||
await super.ensure(page);
|
await super.ensure(page);
|
||||||
this.secret = await addTOTP(this.getUserId());
|
this.secret = await addTOTP(this.getUserId());
|
||||||
await eventualNewUser(this.getUserId())
|
await eventualNewUser(this.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSecret(): string {
|
public getSecret(): string {
|
||||||
|
@@ -3,11 +3,11 @@ import { createDigest, createRandomBytes } from "@otplib/plugin-crypto";
|
|||||||
import { keyDecoder, keyEncoder } from "@otplib/plugin-thirty-two"; // use your chosen base32 plugin
|
import { keyDecoder, keyEncoder } from "@otplib/plugin-thirty-two"; // use your chosen base32 plugin
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
import { request } from "gaxios";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { OtpType, userProps } from "./user";
|
import { OtpType, userProps } from "./user";
|
||||||
import {request} from "gaxios";
|
|
||||||
|
|
||||||
dotenv.config({ path: path.resolve(__dirname, "../env/.env") })
|
dotenv.config({ path: path.resolve(__dirname, "../env/.env") });
|
||||||
|
|
||||||
export async function addUser(props: userProps) {
|
export async function addUser(props: userProps) {
|
||||||
const body = {
|
const body = {
|
||||||
@@ -173,10 +173,10 @@ export function totp(secret: string) {
|
|||||||
export async function eventualNewUser(id: string) {
|
export async function eventualNewUser(id: string) {
|
||||||
return request({
|
return request({
|
||||||
url: `${process.env.ZITADEL_API_URL}/v2/users/${id}`,
|
url: `${process.env.ZITADEL_API_URL}/v2/users/${id}`,
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${process.env.ZITADEL_ADMIN_TOKEN}`,
|
Authorization: `Bearer ${process.env.ZITADEL_ADMIN_TOKEN}`,
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
retryConfig: {
|
retryConfig: {
|
||||||
statusCodesToRetry: [[404, 404]],
|
statusCodesToRetry: [[404, 404]],
|
||||||
@@ -184,7 +184,7 @@ export async function eventualNewUser(id: string) {
|
|||||||
totalTimeout: 10000, // 10 seconds
|
totalTimeout: 10000, // 10 seconds
|
||||||
onRetryAttempt: (error) => {
|
onRetryAttempt: (error) => {
|
||||||
console.warn(`Retrying to query new user ${id}: ${error.message}`);
|
console.warn(`Retrying to query new user ${id}: ${error.message}`);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,15 @@ DefaultInstance:
|
|||||||
HelpLink: "https://zitadel.com/docs"
|
HelpLink: "https://zitadel.com/docs"
|
||||||
SupportEmail: "support@zitadel.com"
|
SupportEmail: "support@zitadel.com"
|
||||||
DocsLink: "https://zitadel.com/docs"
|
DocsLink: "https://zitadel.com/docs"
|
||||||
|
Features:
|
||||||
|
LoginV2:
|
||||||
|
Required: true
|
||||||
|
|
||||||
|
OIDC:
|
||||||
|
DefaultLoginURLV2: "/ui/v2/login/login?authRequest="
|
||||||
|
|
||||||
|
SAML:
|
||||||
|
DefaultLoginURLV2: "/ui/v2/login/login?authRequest="
|
||||||
|
|
||||||
Database:
|
Database:
|
||||||
EventPushConnRatio: 0.2 # 4
|
EventPushConnRatio: 0.2 # 4
|
||||||
|
@@ -93,7 +93,7 @@ describe("verify invite", () => {
|
|||||||
stub("zitadel.user.v2.UserService", "VerifyInviteCode");
|
stub("zitadel.user.v2.UserService", "VerifyInviteCode");
|
||||||
|
|
||||||
cy.visit("/verify?userId=221394658884845598&code=abc&invite=true");
|
cy.visit("/verify?userId=221394658884845598&code=abc&invite=true");
|
||||||
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl +"/authenticator/set");
|
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/authenticator/set");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows an error if invite code validation failed", () => {
|
it("shows an error if invite code validation failed", () => {
|
||||||
|
@@ -95,7 +95,7 @@ describe("login", () => {
|
|||||||
});
|
});
|
||||||
it("should redirect a user with password authentication to /password", () => {
|
it("should redirect a user with password authentication to /password", () => {
|
||||||
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
|
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
|
||||||
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl +"/password");
|
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/password");
|
||||||
});
|
});
|
||||||
describe("with passkey prompt", () => {
|
describe("with passkey prompt", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -166,7 +166,7 @@ describe("login", () => {
|
|||||||
|
|
||||||
it("should redirect a user with passwordless authentication to /passkey", () => {
|
it("should redirect a user with passwordless authentication to /passkey", () => {
|
||||||
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
|
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
|
||||||
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl +"/passkey");
|
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/passkey");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -68,6 +68,6 @@ describe("register", () => {
|
|||||||
cy.get('input[type="checkbox"][value="privacypolicy"]').check();
|
cy.get('input[type="checkbox"][value="privacypolicy"]').check();
|
||||||
cy.get('input[type="checkbox"][value="tos"]').check();
|
cy.get('input[type="checkbox"][value="tos"]').check();
|
||||||
cy.get('button[type="submit"]').click();
|
cy.get('button[type="submit"]').click();
|
||||||
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl +"/passkey/set");
|
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/passkey/set");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -54,7 +54,7 @@ variable "CORE_MOCK_TAG" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
target "core-mock" {
|
target "core-mock" {
|
||||||
context = "apps/core-mock"
|
context = "apps/login-test-integration/core-mock"
|
||||||
contexts = {
|
contexts = {
|
||||||
protos = "target:proto-files"
|
protos = "target:proto-files"
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
*
|
*
|
||||||
|
|
||||||
!/apps/login-test-integration
|
!/apps/login-test-integration
|
||||||
|
/apps/login-test-integration/core-mock
|
||||||
|
|
||||||
**/*.md
|
**/*.md
|
||||||
**/*.png
|
**/*.png
|
||||||
|
Reference in New Issue
Block a user