-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* **Playwright testing** - Changed env.example - update eslint rules - gitignore updated - auth.config.ts with updated env var - removed kv rate limit - Changed prisma relations - User with passwordResetTokens, verificationTokens, twoFactorTokens - playwright tests - github actions playwright.yml - better approach for handling the registration restriction - with allure reports
- Loading branch information
Showing
24 changed files
with
1,229 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,14 @@ | ||
DATABASE_URL= | ||
AUTH_SECRET= | ||
|
||
GITHUB_CLIENT_SECRET= | ||
GITHUB_CLIENT_ID= | ||
AUTH_GITHUB_CLIENT_SECRET= | ||
AUTH_GITHUB_CLIENT_ID= | ||
|
||
GOOGLE_CLIENT_SECRET= | ||
GOOGLE_CLIENT_ID= | ||
AUTH_GOOGLE_CLIENT_SECRET= | ||
AUTH_GOOGLE_CLIENT_ID= | ||
|
||
RESEND_API_KEY= | ||
|
||
NEXT_PUBLIC_APP_URL= | ||
|
||
KV_REST_API_READ_ONLY_TOKEN="" | ||
KV_REST_API_TOKEN="" | ||
KV_REST_API_URL="" | ||
KV_URL="" | ||
MAILSAC_API_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
name: E2E Tests | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
branches: [main] | ||
|
||
permissions: | ||
contents: read | ||
pages: write | ||
id-token: write | ||
|
||
jobs: | ||
test: | ||
name: Run E2E Tests | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Node.js | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: '20' | ||
cache: 'npm' | ||
|
||
- name: Install dependencies | ||
run: npm ci | ||
|
||
- name: Install Playwright browsers | ||
run: npx playwright install --with-deps | ||
|
||
- name: Install Allure Commandline | ||
run: npm install -g allure-commandline | ||
|
||
- name: Run Playwright tests | ||
env: | ||
DATABASE_URL: ${{ secrets.DATABASE_URL }} | ||
AUTH_SECRET: ${{ secrets.AUTH_SECRET }} | ||
AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.AUTH_GITHUB_CLIENT_SECRET }} | ||
AUTH_GITHUB_CLIENT_ID: ${{ secrets.AUTH_GITHUB_CLIENT_ID }} | ||
AUTH_GOOGLE_CLIENT_SECRET: ${{ secrets.AUTH_GOOGLE_CLIENT_SECRET }} | ||
AUTH_GOOGLE_CLIENT_ID: ${{ secrets.AUTH_GOOGLE_CLIENT_ID }} | ||
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} | ||
MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }} | ||
NEXT_PUBLIC_APP_URL: http://localhost:3000 | ||
KV_REST_API_READ_ONLY_TOKEN: ${{ secrets.KV_REST_API_READ_ONLY_TOKEN }} | ||
KV_REST_API_TOKEN: ${{ secrets.KV_REST_API_TOKEN }} | ||
KV_REST_API_URL: ${{ secrets.KV_REST_API_URL }} | ||
KV_URL: ${{ secrets.KV_URL }} | ||
run: npx playwright test | ||
continue-on-error: true | ||
|
||
- name: Generate Allure Report | ||
if: always() | ||
run: | | ||
allure generate allure-results -o allure-report --clean | ||
# Optional: Upload allure-results as artifact for debugging | ||
- name: Upload Allure Results | ||
if: always() | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: allure-results | ||
path: allure-results/ | ||
retention-days: 30 | ||
|
||
# Setup Pages | ||
- name: Setup Pages | ||
if: always() | ||
uses: actions/configure-pages@v4 | ||
|
||
# Upload to GitHub Pages | ||
- name: Upload Pages artifact | ||
if: always() | ||
uses: actions/upload-pages-artifact@v3 | ||
with: | ||
path: allure-report | ||
|
||
# Deploy job | ||
deploy: | ||
needs: test # Wait for test job to complete | ||
runs-on: ubuntu-latest | ||
if: github.ref == 'refs/heads/main' # Only deploy on main branch | ||
|
||
environment: | ||
name: github-pages | ||
url: ${{ steps.deployment.outputs.page_url }} | ||
|
||
steps: | ||
- name: Deploy to GitHub Pages | ||
id: deployment | ||
uses: actions/deploy-pages@v4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export const TEST_CONFIG = { | ||
MAILSAC_API_KEY: process.env.MAILSAC_API_KEY!, | ||
DATABASE_URL: process.env.DATABASE_URL!, | ||
TEST_EMAIL: '[email protected]', | ||
TEST_PASSWORD: '1234567', | ||
TEST_NAME: 'faketesting', | ||
}; | ||
|
||
if (!TEST_CONFIG.MAILSAC_API_KEY) { | ||
throw new Error('MAILSAC_API_KEY is required'); | ||
} | ||
|
||
if (!TEST_CONFIG.DATABASE_URL) { | ||
throw new Error('DATABASE_URL is required'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { expect, Page, test } from '@playwright/test'; | ||
|
||
import { TEST_CONFIG } from '@/e2e-tests/config/test-config'; | ||
import { cleanupTestUserFromDB, createCredentialsTestUser } from '@/e2e-tests/helpers/helper-functions'; | ||
import { cleanupMailsacInbox, getEmailContent } from '@/e2e-tests/helpers/mailsac/mailsac'; | ||
import { fillLoginForm } from '@/e2e-tests/helpers/tests'; | ||
|
||
test.describe('2FA Authentication Flow', () => { | ||
const { MAILSAC_API_KEY, TEST_EMAIL, TEST_PASSWORD, TEST_NAME } = TEST_CONFIG; | ||
|
||
async function cleanupState() { | ||
await cleanupTestUserFromDB(TEST_EMAIL); | ||
const mailsacResponseStatus = await cleanupMailsacInbox(TEST_EMAIL, MAILSAC_API_KEY); | ||
expect(mailsacResponseStatus).toBe(204); | ||
} | ||
|
||
async function createTwoFactorUser() { | ||
await createCredentialsTestUser(TEST_NAME, TEST_EMAIL, TEST_PASSWORD, { | ||
isTwoFactorEnabled: true, | ||
emailVerified: true, | ||
}); | ||
} | ||
|
||
async function initiateLogin(page: Page) { | ||
await page.goto('/login'); | ||
await fillLoginForm(page, { | ||
email: TEST_EMAIL, | ||
password: TEST_PASSWORD, | ||
}); | ||
await page.locator('button[type="submit"]').click(); | ||
} | ||
|
||
async function getTwoFactorCode(): Promise<string> { | ||
const emailContent = await getEmailContent(TEST_EMAIL, MAILSAC_API_KEY, '2FA Code', { | ||
retries: 5, | ||
delay: 2000, | ||
exactMatch: false, | ||
}); | ||
|
||
const twoFactorCode = emailContent.match(/(\d{6})/)?.[1]; | ||
|
||
if (!twoFactorCode) { | ||
throw new Error('Could not extract 2FA code from email'); | ||
} | ||
|
||
return twoFactorCode; | ||
} | ||
|
||
async function submitTwoFactorCode(page: Page, code: string) { | ||
await page.locator('input[name="code"]').fill(code); | ||
await page.locator('button[type="submit"]').click(); | ||
} | ||
|
||
test('should successfully authenticate user with valid 2FA code', async ({ page }) => { | ||
await test.step('Setup test environment', async () => { | ||
await cleanupState(); | ||
await createTwoFactorUser(); | ||
}); | ||
|
||
await test.step('Initiate login process', async () => { | ||
await initiateLogin(page); | ||
}); | ||
|
||
await test.step('Process 2FA verification', async () => { | ||
const twoFactorCode = await getTwoFactorCode(); | ||
await submitTwoFactorCode(page, twoFactorCode); | ||
await page.waitForURL('**/settings'); | ||
await expect(page).toHaveURL('/settings'); | ||
}); | ||
}); | ||
|
||
test('should reject login attempt with invalid 2FA code', async ({ page }) => { | ||
await test.step('Setup test environment', async () => { | ||
await cleanupState(); | ||
await createTwoFactorUser(); | ||
}); | ||
|
||
await test.step('Attempt login with invalid 2FA code', async () => { | ||
await initiateLogin(page); | ||
await submitTwoFactorCode(page, '000000'); | ||
await expect(page.getByText('Invalid code')).toBeVisible(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.