diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml index dea6f1f3e2..66fc264fc4 100644 --- a/.github/workflows/ui-e2e-tests.yml +++ b/.github/workflows/ui-e2e-tests.yml @@ -18,6 +18,8 @@ jobs: AUTH_TRUST_HOST: true NEXTAUTH_URL: 'http://localhost:3000' NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1' + E2E_GITHUB_USER: ${{ secrets.E2E_GITHUB_USER }} + E2E_GITHUB_PASSWORD: ${{ secrets.E2E_GITHUB_PASSWORD }} steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/ui/tests/sign-up/sign-up-page.ts b/ui/tests/sign-up/sign-up-page.ts index 58e77c8cd6..e86b98dbf8 100644 --- a/ui/tests/sign-up/sign-up-page.ts +++ b/ui/tests/sign-up/sign-up-page.ts @@ -25,6 +25,9 @@ export class SignUpPage extends BasePage { readonly submitButton: Locator; readonly loginLink: Locator; readonly termsCheckbox: Locator; + + // Social login buttons + readonly githubButton: Locator; constructor(page: Page) { super(page); @@ -40,6 +43,9 @@ export class SignUpPage extends BasePage { this.submitButton = page.getByRole("button", { name: "Sign up" }); this.loginLink = page.getByRole("link", { name: "Log in" }); this.termsCheckbox = page.getByText("I agree with the"); + + // Social login buttons + this.githubButton = page.getByRole("button", { name: "Continue with Github" }); } async goto(): Promise { @@ -47,9 +53,31 @@ export class SignUpPage extends BasePage { } async verifyPageLoaded(): Promise { - await expect(this.page.getByText("Sign up", { exact: true })).toBeVisible(); + // Verify unique title - only appears on sign-up page + await expect(this.page.locator('p').getByText("Sign up", { exact: true }).first()).toBeVisible(); + + // Verify all required form fields are present + await expect(this.nameInput).toBeVisible(); await expect(this.emailInput).toBeVisible(); + await expect(this.passwordInput).toBeVisible(); + await expect(this.confirmPasswordInput).toBeVisible(); + + // Verify primary action button await expect(this.submitButton).toBeVisible(); + + // Verify distinctive separator between form and social login + await expect(this.page.getByText("OR", { exact: true })).toBeVisible(); + + // Verify social login options are available (distinctive of sign-up vs other pages) + await expect(this.page.getByText("Continue with Github")).toBeVisible(); + await expect(this.page.getByText("Continue with Google")).toBeVisible(); + + // Verify sign-up specific link (different from sign-in page) + await expect(this.page.getByText("Already have an account?")).toBeVisible(); + await expect(this.loginLink).toBeVisible(); + + // Verify correct URL + expect(this.page.url()).toContain('/sign-up'); } async fillName(name: string): Promise { @@ -111,6 +139,63 @@ export class SignUpPage extends BasePage { async verifyRedirectToEmailVerification(): Promise { await expect(this.page).toHaveURL("/email-verification"); } + + // Social login methods + async clickGithubLogin(): Promise { + await this.githubButton.click(); + } + + async verifyGithubButtonVisible(): Promise { + await expect(this.githubButton).toBeVisible(); + } + + async verifyGithubButtonEnabled(): Promise { + await expect(this.githubButton).toBeEnabled(); + } + + async verifyRedirectToGithubOAuth(): Promise { + // Verify redirect to Github OAuth page + await expect(this.page).toHaveURL(/github\.com\/login/); + } + + async verifyGithubOAuthFlow(): Promise { + // Verify Github OAuth page elements + await expect(this.page.getByText("Sign in to GitHub")).toBeVisible(); + await expect(this.page.getByText("to continue to Prowler")).toBeVisible(); + } + + async fillGithubCredentials(username: string, password: string): Promise { + // Fill Github login form based on MCP exploration + await this.page.getByRole("textbox", { name: "Username or email address" }).fill(username); + await this.page.getByRole("textbox", { name: "Password" }).fill(password); + } + + async submitGithubLogin(): Promise { + // Click Github Sign in button + await this.page.getByRole("button", { name: "Sign in" }).click(); + } + + async completeGithubOAuth(username: string, password: string): Promise { + // Complete the Github OAuth flow + await this.fillGithubCredentials(username, password); + await this.submitGithubLogin(); + } + + async verifyGithubApplicationInfo(): Promise { + // Verify Prowler application info is displayed on GitHub OAuth page + await expect(this.page.locator('img[alt*="Prowler"]')).toBeVisible(); + + // Verify the OAuth consent message shows Prowler app name + await expect(this.page.getByText(/to continue to.*Prowler/i)).toBeVisible(); + + // Verify "Sign in to GitHub" text is present + await expect(this.page.getByText("Sign in to GitHub")).toBeVisible(); + + // Verify GitHub OAuth form elements are present + await expect(this.page.getByRole("textbox", { name: /username or email/i })).toBeVisible(); + await expect(this.page.getByRole("textbox", { name: /password/i })).toBeVisible(); + await expect(this.page.getByRole("button", { name: "Sign in" })).toBeVisible(); + } } diff --git a/ui/tests/sign-up/sign-up.md b/ui/tests/sign-up/sign-up.md index 4b0d8b38de..0bf17a0bfa 100644 --- a/ui/tests/sign-up/sign-up.md +++ b/ui/tests/sign-up/sign-up.md @@ -1,4 +1,4 @@ -### E2E Tests: User Sign-Up +# E2E Tests: User Sign-Up **Suite ID:** `SIGNUP-E2E` **Feature:** New user registration flow. @@ -13,7 +13,7 @@ - type → @e2e - feature → @signup -**Description/Objetive:** Registers a new user with valid data, verifies redirect to Login (OSS), and confirms the user can authenticate. +**Description/Objetive:** Registers a new user with valid data, verifies redirect to Login, and confirms the user can authenticate. **Preconditions:** - Application is running, email domain & password is acceptable for sign-up. @@ -38,4 +38,59 @@ ### Notes: - Test data uses a random base36 suffix to avoid collisions with email. +--- + +## Test Case: `SIGNUP-E2E-002` - Github Social Sign-up OAuth Flow + +**Priority:** `critical` + +**Tags:** +- type → @e2e +- feature → @signup +- social → @social + +**Description/Objective:** Validates that users can complete the full Github OAuth flow for social sign-up, including authentication and successful return to Prowler + +**Preconditions:** +- Application is running +- Github OAuth app is configured +- E2E_GITHUB_USER and E2E_GITHUB_PASSWORD environment variables are set with valid Github credentials + +### Flow Steps: +1. Navigate to sign-up page +2. Verify page loads with social login options +3. Verify Github login button is visible and enabled +4. Click "Continue with Github" button +5. Verify redirect to Github OAuth page +6. Verify OAuth configuration parameters +7. Fill Github credentials (username and password) +8. Submit Github login form +9. Verify successful redirect back to Prowler + +### Expected Result: +- User is redirected to Github OAuth authorization page +- OAuth URL contains correct client_id, redirect_uri, and scope parameters +- Github OAuth page displays proper application information +- User can successfully authenticate with Github credentials +- User is redirected back to Prowler application after successful authentication + + +### Key verification points: +- Github button is visible and clickable on sign-up page +- Redirect to github.com/login occurs correctly +- OAuth URL structure follows GitHub OAuth format (https://github.com/login) +- GitHub OAuth page displays Prowler application logo and information +- GitHub OAuth page shows correct consent message "to continue to Prowler" +- GitHub OAuth page shows "Sign in to GitHub" header +- GitHub login form elements are present and accessible (username/email, password, sign in button) +- Github login form accepts credentials correctly +- Successful authentication redirects back to Prowler home +- After redirect, verify authenticated area is visible (e.g., main dashboard content) + +### Notes: +- Test requires E2E_GITHUB_USER and E2E_GITHUB_PASSWORD environment variables +- Test completes full OAuth flow including Github authentication +- Test verifies successful social sign-up integration +- Github credentials must be valid for test to pass + diff --git a/ui/tests/sign-up/sign-up.spec.ts b/ui/tests/sign-up/sign-up.spec.ts index e0f8f4e462..b62eff41dc 100644 --- a/ui/tests/sign-up/sign-up.spec.ts +++ b/ui/tests/sign-up/sign-up.spec.ts @@ -1,7 +1,7 @@ -import { test } from "@playwright/test"; +import { test, expect } from "@playwright/test"; import { SignUpPage } from "./sign-up-page"; import { SignInPage } from "../sign-in/sign-in-page"; -import { makeSuffix } from "../helpers"; +import { makeSuffix, TEST_CREDENTIALS } from "../helpers"; test.describe("Sign Up Flow", () => { test("should register a new user successfully", { tag: ['@critical', '@e2e', '@signup', '@SIGNUP-E2E-001'] }, async ({ page }) => { @@ -25,7 +25,7 @@ test.describe("Sign Up Flow", () => { // Verify no errors occurred during sign-up await signUpPage.verifyNoErrors(); - // Verify redirect to login page (OSS environment) + // Verify redirect to login page await signUpPage.verifyRedirectToLogin(); // Verify the newly created user can log in successfully @@ -36,6 +36,46 @@ test.describe("Sign Up Flow", () => { }); await signInPage.verifySuccessfulLogin(); }); + + test("should complete Github OAuth flow for social sign-up", { tag: ['@critical', '@e2e', '@signup', '@social', '@SIGNUP-E2E-002'] }, async ({ page }) => { + // Verify Github credentials are available + const githubUsername = process.env.E2E_GITHUB_USER; + const githubPassword = process.env.E2E_GITHUB_PASSWORD; + + if (!githubUsername || !githubPassword) { + throw new Error('E2E_GITHUB_USER and E2E_GITHUB_PASSWORD environment variables are required for Github OAuth tests'); + } + + const signUpPage = new SignUpPage(page); + await signUpPage.goto(); + + // Verify page loaded correctly + await signUpPage.verifyPageLoaded(); + + // Verify Github social login button is visible and enabled + await signUpPage.verifyGithubButtonVisible(); + await signUpPage.verifyGithubButtonEnabled(); + + // Click on Github login button + await signUpPage.clickGithubLogin(); + + // Verify redirect to Github OAuth + await signUpPage.verifyRedirectToGithubOAuth(); + + // Verify Github OAuth page loaded correctly + await signUpPage.verifyGithubOAuthFlow(); + + + // Verify GitHub displays correct application information + await signUpPage.verifyGithubApplicationInfo(); + + // Complete Github OAuth login + await signUpPage.completeGithubOAuth(githubUsername, githubPassword); + + // Verify the user is redirected to the home page after successful authentication + const signInPage = new SignInPage(page); + await signInPage.verifySuccessfulLogin(); + }); });