Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

promote qa to prod #338

Merged
merged 6 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions acceptance/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ echo "ZITADEL_API_URL=${ZITADEL_API_URL}
ZITADEL_SERVICE_USER_ID=${ZITADEL_SERVICE_USER_ID}
ZITADEL_SERVICE_USER_TOKEN=${PAT}
SINK_NOTIFICATION_URL=${SINK_NOTIFICATION_URL}
EMAIL_VERIFICATION=true
eliobischof marked this conversation as resolved.
Show resolved Hide resolved
DEBUG=true"| tee "${WRITE_ENVIRONMENT_FILE}" "${WRITE_TEST_ENVIRONMENT_FILE}" > /dev/null
echo "Wrote environment file ${WRITE_ENVIRONMENT_FILE}"
cat ${WRITE_ENVIRONMENT_FILE}
Expand Down
12 changes: 12 additions & 0 deletions acceptance/tests/email-verify-screen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect, Page } from "@playwright/test";

const codeTextInput = "code-text-input";

export async function emailVerifyScreen(page: Page, code: string) {
await page.getByTestId(codeTextInput).pressSequentially(code);
}

export async function emailVerifyScreenExpect(page: Page, code: string) {
await expect(page.getByTestId(codeTextInput)).toHaveValue(code);
await expect(page.getByTestId("error").locator("div")).toContainText("Could not verify email");
}
73 changes: 73 additions & 0 deletions acceptance/tests/email-verify.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { faker } from "@faker-js/faker";
import { test as base } from "@playwright/test";
import dotenv from "dotenv";
import path from "path";
import { emailVerify, emailVerifyResend } from "./email-verify";
import { emailVerifyScreenExpect } from "./email-verify-screen";
import { loginScreenExpect, loginWithPassword } from "./login";
import { getCodeFromSink } from "./sink";
import { PasswordUser } from "./user";

// Read from ".env" file.
dotenv.config({ path: path.resolve(__dirname, ".env.local") });

const test = base.extend<{ user: PasswordUser }>({
user: async ({ page }, use) => {
const user = new PasswordUser({
email: faker.internet.email(),
isEmailVerified: false,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
organization: "",
phone: faker.phone.number(),
isPhoneVerified: false,
password: "Password1!",
passwordChangeRequired: false,
});
await user.ensure(page);
await use(user);
await user.cleanup();
},
});

test("user email not verified, verify", async ({ user, page }) => {
await loginWithPassword(page, user.getUsername(), user.getPassword());
// auto-redirect on /verify
// wait for send of the code
await page.waitForTimeout(3000);
eliobischof marked this conversation as resolved.
Show resolved Hide resolved
const c = await getCodeFromSink(user.getUsername());
await emailVerify(page, c);
await loginScreenExpect(page, user.getFullName());
});

test("user email not verified, resend, verify", async ({ user, page }) => {
await loginWithPassword(page, user.getUsername(), user.getPassword());
// auto-redirect on /verify
await emailVerifyResend(page);
// wait for send of the code
await page.waitForTimeout(3000);
const c = await getCodeFromSink(user.getUsername());
await emailVerify(page, c);
await loginScreenExpect(page, user.getFullName());
});

test("user email not verified, resend, old code", async ({ user, page }) => {
await loginWithPassword(page, user.getUsername(), user.getPassword());
// auto-redirect on /verify
// wait for send of the code
await page.waitForTimeout(3000);
const c = await getCodeFromSink(user.getUsername());
await emailVerifyResend(page);
// wait for resend of the code
await page.waitForTimeout(1000);
await emailVerify(page, c);
await emailVerifyScreenExpect(page, c);
});

test("user email not verified, wrong code", async ({ user, page }) => {
await loginWithPassword(page, user.getUsername(), user.getPassword());
// auto-redirect on /verify
const code = "wrong";
await emailVerify(page, code);
await emailVerifyScreenExpect(page, code);
});
15 changes: 15 additions & 0 deletions acceptance/tests/email-verify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Page } from "@playwright/test";
import { emailVerifyScreen } from "./email-verify-screen";

export async function startEmailVerify(page: Page, loginname: string) {
await page.goto("/verify");
}

export async function emailVerify(page: Page, code: string) {
await emailVerifyScreen(page, code);
await page.getByTestId("submit-button").click();
}

export async function emailVerifyResend(page: Page) {
await page.getByTestId("resend-button").click();
}
33 changes: 26 additions & 7 deletions acceptance/tests/password-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { getCodeFromSink } from "./sink";
const codeField = "code-text-input";
const passwordField = "password-text-input";
const passwordConfirmField = "password-confirm-text-input";
const passwordChangeField = "password-change-text-input";
const passwordChangeConfirmField = "password-change-confirm-text-input";
const passwordSetField = "password-set-text-input";
const passwordSetConfirmField = "password-set-confirm-text-input";
const lengthCheck = "length-check";
const symbolCheck = "symbol-check";
const numberCheck = "number-check";
Expand All @@ -15,8 +19,8 @@ const matchText = "Matches";
const noMatchText = "Doesn't match";

export async function changePasswordScreen(page: Page, password1: string, password2: string) {
await page.getByTestId(passwordField).pressSequentially(password1);
await page.getByTestId(passwordConfirmField).pressSequentially(password2);
await page.getByTestId(passwordChangeField).pressSequentially(password1);
await page.getByTestId(passwordChangeConfirmField).pressSequentially(password2);
}

export async function passwordScreen(page: Page, password: string) {
Expand All @@ -39,9 +43,21 @@ export async function changePasswordScreenExpect(
lowercase: boolean,
equals: boolean,
) {
await expect(page.getByTestId(passwordField)).toHaveValue(password1);
await expect(page.getByTestId(passwordConfirmField)).toHaveValue(password2);
await expect(page.getByTestId(passwordChangeField)).toHaveValue(password1);
await expect(page.getByTestId(passwordChangeConfirmField)).toHaveValue(password2);

await checkComplexity(page, length, symbol, number, uppercase, lowercase, equals);
}

async function checkComplexity(
page: Page,
length: boolean,
symbol: boolean,
number: boolean,
uppercase: boolean,
lowercase: boolean,
equals: boolean,
) {
await checkContent(page, lengthCheck, length);
await checkContent(page, symbolCheck, symbol);
await checkContent(page, numberCheck, number);
Expand All @@ -63,8 +79,8 @@ export async function resetPasswordScreen(page: Page, username: string, password
await page.waitForTimeout(3000);
const c = await getCodeFromSink(username);
await page.getByTestId(codeField).pressSequentially(c);
await page.getByTestId(passwordField).pressSequentially(password1);
await page.getByTestId(passwordConfirmField).pressSequentially(password2);
await page.getByTestId(passwordSetField).pressSequentially(password1);
await page.getByTestId(passwordSetConfirmField).pressSequentially(password2);
}

export async function resetPasswordScreenExpect(
Expand All @@ -78,5 +94,8 @@ export async function resetPasswordScreenExpect(
lowercase: boolean,
equals: boolean,
) {
await changePasswordScreenExpect(page, password1, password2, length, symbol, number, uppercase, lowercase, equals);
await expect(page.getByTestId(passwordSetField)).toHaveValue(password1);
await expect(page.getByTestId(passwordSetConfirmField)).toHaveValue(password2);

await checkComplexity(page, length, symbol, number, uppercase, lowercase, equals);
}
3 changes: 1 addition & 2 deletions acceptance/tests/password.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export async function startChangePassword(page: Page, loginname: string) {
await page.goto("/password/change?" + new URLSearchParams({ loginName: loginname }));
}

export async function changePassword(page: Page, loginname: string, password: string) {
await startChangePassword(page, loginname);
export async function changePassword(page: Page, password: string) {
await changePasswordScreen(page, password, password);
await page.getByTestId(passwordSubmitButton).click();
}
Expand Down
17 changes: 15 additions & 2 deletions acceptance/tests/register.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Page } from "@playwright/test";
import { emailVerify } from "./email-verify";
import { passkeyRegister } from "./passkey";
import { registerPasswordScreen, registerUserScreenPasskey, registerUserScreenPassword } from "./register-screen";
import { getCodeFromSink } from "./sink";

export async function registerWithPassword(
page: Page,
Expand All @@ -15,6 +17,9 @@ export async function registerWithPassword(
await page.getByTestId("submit-button").click();
await registerPasswordScreen(page, password1, password2);
await page.getByTestId("submit-button").click();
await page.waitForTimeout(3000);

await verifyEmail(page, email);
}

export async function registerWithPasskey(page: Page, firstname: string, lastname: string, email: string): Promise<string> {
Expand All @@ -23,7 +28,15 @@ export async function registerWithPasskey(page: Page, firstname: string, lastnam
await page.getByTestId("submit-button").click();

// wait for projection of user
await page.waitForTimeout(2000);
await page.waitForTimeout(3000);
const authId = await passkeyRegister(page);

await verifyEmail(page, email);
return authId;
}

return await passkeyRegister(page);
async function verifyEmail(page: Page, email: string) {
await page.waitForTimeout(1000);
const c = await getCodeFromSink(email);
await emailVerify(page, c);
}
13 changes: 13 additions & 0 deletions acceptance/tests/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { activateOTP, addTOTP, addUser, getUserByUsername, removeUser } from "./

export interface userProps {
email: string;
isEmailVerified?: boolean;
firstName: string;
lastName: string;
organization: string;
password: string;
passwordChangeRequired?: boolean;
phone: string;
isPhoneVerified?: boolean;
}

class User {
Expand Down Expand Up @@ -77,11 +80,14 @@ export enum OtpType {

export interface otpUserProps {
email: string;
isEmailVerified?: boolean;
firstName: string;
lastName: string;
organization: string;
password: string;
passwordChangeRequired?: boolean;
phone: string;
isPhoneVerified?: boolean;
type: OtpType;
}

Expand All @@ -96,6 +102,9 @@ export class PasswordUserWithOTP extends User {
organization: props.organization,
password: props.password,
phone: props.phone,
isEmailVerified: props.isEmailVerified,
isPhoneVerified: props.isPhoneVerified,
passwordChangeRequired: props.passwordChangeRequired,
});
this.type = props.type;
}
Expand Down Expand Up @@ -133,6 +142,8 @@ export interface passkeyUserProps {
lastName: string;
organization: string;
phone: string;
isEmailVerified?: boolean;
isPhoneVerified?: boolean;
}

export class PasskeyUser extends User {
Expand All @@ -146,6 +157,8 @@ export class PasskeyUser extends User {
organization: props.organization,
password: "",
phone: props.phone,
isEmailVerified: props.isEmailVerified,
isPhoneVerified: props.isPhoneVerified,
});
}

Expand Down
2 changes: 2 additions & 0 deletions acceptance/tests/username-passkey.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ const test = base.extend<{ user: PasskeyUser }>({
user: async ({ page }, use) => {
const user = new PasskeyUser({
email: faker.internet.email(),
isEmailVerified: true,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
organization: "",
phone: faker.phone.number(),
isPhoneVerified: false,
});
await user.ensure(page);
await use(user);
Expand Down
41 changes: 41 additions & 0 deletions acceptance/tests/username-password-change-required.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { faker } from "@faker-js/faker";
import { test as base } from "@playwright/test";
import dotenv from "dotenv";
import path from "path";
import { loginScreenExpect, loginWithPassword } from "./login";
import { changePassword } from "./password";
import { PasswordUser } from "./user";

// Read from ".env" file.
dotenv.config({ path: path.resolve(__dirname, ".env.local") });

const test = base.extend<{ user: PasswordUser }>({
user: async ({ page }, use) => {
const user = new PasswordUser({
email: faker.internet.email(),
isEmailVerified: true,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
organization: "",
phone: faker.phone.number(),
isPhoneVerified: false,
password: "Password1!",
passwordChangeRequired: true,
});
await user.ensure(page);
await use(user);
await user.cleanup();
},
});

test("username and password login, change required", async ({ user, page }) => {
const changedPw = "ChangedPw1!";

await loginWithPassword(page, user.getUsername(), user.getPassword());
await page.waitForTimeout(100);
await changePassword(page, changedPw);
await loginScreenExpect(page, user.getFullName());

await loginWithPassword(page, user.getUsername(), changedPw);
await loginScreenExpect(page, user.getFullName());
});
27 changes: 14 additions & 13 deletions acceptance/tests/username-password-changed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { faker } from "@faker-js/faker";
import { test as base } from "@playwright/test";
import dotenv from "dotenv";
import path from "path";
import { loginWithPassword } from "./login";
import { startChangePassword } from "./password";
import { loginScreenExpect, loginWithPassword } from "./login";
import { changePassword, startChangePassword } from "./password";
import { changePasswordScreen, changePasswordScreenExpect } from "./password-screen";
import { PasswordUser } from "./user";

Expand All @@ -14,11 +14,14 @@ const test = base.extend<{ user: PasswordUser }>({
user: async ({ page }, use) => {
const user = new PasswordUser({
email: faker.internet.email(),
isEmailVerified: true,
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
organization: "",
phone: faker.phone.number(),
isPhoneVerified: false,
password: "Password1!",
passwordChangeRequired: false,
});
await user.ensure(page);
await use(user);
Expand All @@ -27,20 +30,18 @@ const test = base.extend<{ user: PasswordUser }>({
});

test("username and password changed login", async ({ user, page }) => {
// commented, fix in https://github.com/zitadel/zitadel/pull/8807
/*
const changedPw = "ChangedPw1!";
await loginWithPassword(page, user.getUsername(), user.getPassword());
const changedPw = "ChangedPw1!";
await loginWithPassword(page, user.getUsername(), user.getPassword());

// wait for projection of token
await page.waitForTimeout(2000);
// wait for projection of token
await page.waitForTimeout(2000);

await changePassword(page, user.getUsername(), changedPw);
await loginScreenExpect(page, user.getFullName());
await startChangePassword(page, user.getUsername());
await changePassword(page, changedPw);
await loginScreenExpect(page, user.getFullName());

await loginWithPassword(page, user.getUsername(), changedPw);
await loginScreenExpect(page, user.getFullName());
*/
await loginWithPassword(page, user.getUsername(), changedPw);
await loginScreenExpect(page, user.getFullName());
});

test("password change not with desired complexity", async ({ user, page }) => {
Expand Down
Loading
Loading