fix(pw): skip onboarding flow if not available in signin step

This commit is contained in:
Ramesh Mane
2025-08-21 07:57:25 +00:00
parent 04077d58db
commit 017ed34cdf
6 changed files with 77 additions and 10 deletions

View File

@@ -1,9 +1,13 @@
import { Page } from '@playwright/test';
import BasePage from '../Base';
import { OnboardingFlowPage } from '../OnboardingFlowPage';
export class LoginPage extends BasePage {
readonly onboardingFlowPage: OnboardingFlowPage;
constructor(rootPage: Page) {
super(rootPage);
this.onboardingFlowPage = new OnboardingFlowPage(rootPage);
}
prefixEmail(email: string) {
@@ -40,11 +44,13 @@ export class LoginPage extends BasePage {
password,
withoutPrefix,
skipReload = false,
skipOnboardingFlow = true,
}: {
email: string;
password: string;
withoutPrefix?: boolean;
skipReload?: boolean;
skipOnboardingFlow?: boolean;
}) {
if (!skipReload) await this.goto();
@@ -53,5 +59,14 @@ export class LoginPage extends BasePage {
await this.fillEmail({ email, withoutPrefix });
await this.fillPassword(password);
await this.submit();
await this.rootPage.waitForLoadState('networkidle');
// It's possible that user can see onboarding flow after login if they have not attempted that after signup
if (skipOnboardingFlow) {
await this.onboardingFlowPage.skipOnboardingFlow();
} else {
await this.onboardingFlowPage.completeOnboardingFlow();
}
}
}

View File

@@ -52,6 +52,10 @@ export class OnboardingFlowPage extends BasePage {
return this.rootPage.getByTestId('nc-onboarding-flow-container');
}
async isOnboardingFlowVisible() {
return (await this.get().count()) > 0;
}
/**
* Check if current question is single select
*/
@@ -156,7 +160,18 @@ export class OnboardingFlowPage extends BasePage {
/**
* Complete the onboarding flow by navigating through all questions
*/
async completeOnboardingFlow() {
async completeOnboardingFlow({ ifAvailable = true }: { ifAvailable?: boolean } = {}) {
/**
* `ifAvailable` signup flow can be available at signin page also sometimes to we have to check first and then act
*/
if (ifAvailable) {
await this.rootPage.waitForLoadState('networkidle');
if (await this.isOnboardingFlowVisible()) {
return;
}
}
await this.get().waitFor({ state: 'visible' });
// Navigate through all questions
@@ -195,7 +210,24 @@ export class OnboardingFlowPage extends BasePage {
/**
* Skip the onboarding flow
*/
async skipOnboardingFlow({ verify = false }: { verify?: boolean } = {}) {
async skipOnboardingFlow({
verify = false,
ifAvailable = true,
}: {
verify?: boolean;
/**
* `ifAvailable` signup flow can be available at signin page also sometimes to we have to check first and then act
*/
ifAvailable?: boolean;
} = {}) {
if (ifAvailable) {
await this.rootPage.waitForLoadState('networkidle');
if (await this.isOnboardingFlowVisible()) {
return;
}
}
await this.get().waitFor({ state: 'visible' });
await this.waitForResponse({

View File

@@ -54,9 +54,11 @@ export class SignupPage extends BasePage {
await this.rootPage.waitForLoadState('networkidle');
if (skipOnboardingFlow) {
await this.onboardingFlowPage.skipOnboardingFlow();
// Singup flow has to be visible after signup so we have to make `ifAvailable = false` so that it doesn't check for onboarding flow visibility
await this.onboardingFlowPage.skipOnboardingFlow({ ifAvailable: false });
} else {
await this.onboardingFlowPage.completeOnboardingFlow();
// Singup flow has to be visible after signup so we have to make `ifAvailable = false` so that it doesn't check for onboarding flow visibility
await this.onboardingFlowPage.completeOnboardingFlow({ ifAvailable: false });
}
}
}

View File

@@ -1,13 +1,16 @@
import { Page } from '@playwright/test';
import BasePage from '../Base';
import { ProjectsPage } from '../ProjectsPage';
import { OnboardingFlowPage } from '../OnboardingFlowPage';
export class GoogleLoginPage extends BasePage {
readonly projectsPage: ProjectsPage;
readonly onboardingFlowPage: OnboardingFlowPage;
constructor(rootPage: Page) {
super(rootPage);
this.projectsPage = new ProjectsPage(rootPage);
this.onboardingFlowPage = new OnboardingFlowPage(rootPage);
}
async goto(title = 'test') {
@@ -23,8 +26,12 @@ export class GoogleLoginPage extends BasePage {
return this.rootPage.locator('html');
}
async signIn(_: { email: string }) {
async signIn({ email, skipOnboardingFlow = true }: { email: string; skipOnboardingFlow?: boolean }) {
// skipping for now as it requires google account
// todo: later we can mock backend(google oauth2 endpoint calls) to test this
if (skipOnboardingFlow) {
await this.onboardingFlowPage.skipOnboardingFlow();
}
}
}

View File

@@ -1,13 +1,16 @@
import { expect, Page } from '@playwright/test';
import BasePage from '../Base';
import { ProjectsPage } from '../ProjectsPage';
import { OnboardingFlowPage } from '../OnboardingFlowPage';
export class OpenIDLoginPage extends BasePage {
readonly projectsPage: ProjectsPage;
readonly onboardingFlowPage: OnboardingFlowPage;
constructor(rootPage: Page) {
super(rootPage);
this.projectsPage = new ProjectsPage(rootPage);
this.onboardingFlowPage = new OnboardingFlowPage(rootPage);
}
async goto(title = 'test') {
@@ -21,7 +24,7 @@ export class OpenIDLoginPage extends BasePage {
return this.rootPage.locator('html');
}
async signIn({ email }: { email: string }) {
async signIn({ email, skipOnboardingFlow = true }: { email: string; skipOnboardingFlow?: boolean }) {
const signIn = this.get();
const loginLocator = signIn.locator('[name="login"]');
await loginLocator.waitFor({ state: 'visible' });
@@ -40,9 +43,10 @@ export class OpenIDLoginPage extends BasePage {
authorize.locator(`[type="submit"]`).click(),
]);
const userInfoMenu = this.rootPage.locator(`[data-testid="nc-sidebar-userinfo"]`);
await userInfoMenu.waitFor();
if (skipOnboardingFlow) {
await this.onboardingFlowPage.skipOnboardingFlow();
}
await expect(userInfoMenu).toHaveAttribute('data-email', email);
await this.rootPage.locator(`[data-testid="nc-sidebar-userinfo"]:has-text("${email.split('@')[0]}")`);
}
}

View File

@@ -2,13 +2,16 @@ import { Page } from '@playwright/test';
import BasePage from '../Base';
import { ProjectsPage } from '../ProjectsPage';
import { expect } from '@playwright/test';
import { OnboardingFlowPage } from '../OnboardingFlowPage';
export class SAMLLoginPage extends BasePage {
readonly projectsPage: ProjectsPage;
readonly onboardingFlowPage: OnboardingFlowPage;
constructor(rootPage: Page) {
super(rootPage);
this.projectsPage = new ProjectsPage(rootPage);
this.onboardingFlowPage = new OnboardingFlowPage(rootPage);
}
async goto(title = 'test') {
@@ -22,7 +25,7 @@ export class SAMLLoginPage extends BasePage {
return this.rootPage.locator('html');
}
async signIn({ email }: { email: string }) {
async signIn({ email, skipOnboardingFlow = true }: { email: string; skipOnboardingFlow?: boolean }) {
const signIn = this.get();
await signIn.locator('#userName').waitFor();
@@ -33,6 +36,10 @@ export class SAMLLoginPage extends BasePage {
signIn.locator(`#btn-sign-in`).click(),
]);
if (skipOnboardingFlow) {
await this.onboardingFlowPage.skipOnboardingFlow();
}
const userInfoMenu = this.rootPage.locator(`[data-testid="nc-sidebar-userinfo"]`);
await userInfoMenu.waitFor();