Skip to content
Draft
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
5 changes: 5 additions & 0 deletions e2e/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TEST_BASE_URL=https://testnet.test
WALLET_BACKEND_CONTAINER=wallet-backend-local
ENABLE_SCREENSHOTS=false
# Set to true only if your local cert trust is not configured.
PLAYWRIGHT_IGNORE_HTTPS_ERRORS=true
5 changes: 5 additions & 0 deletions e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
node_modules
playwright-report
test-results
.features-gen
19 changes: 19 additions & 0 deletions e2e/features/auth-signup-dashboard.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Wallet authentication onboarding
As a new wallet user
I want to sign up, verify my email, complete KYC, and reach my default account
So that I can access my wallet dashboard

Scenario: New user completes signup, verification, login, KYC, and account access
Given I am a new unique wallet user
When I open the signup page
And I complete the signup form
And I submit signup
Then I should see signup confirmation
When I open the verification link from backend logs
Then I should see verification success
When I continue to login
And I login with my new credentials
And I complete KYC if I am redirected to KYC
Then I should see the accounts dashboard
When I open the EUR default account
Then I should see the account balance page
12 changes: 12 additions & 0 deletions e2e/features/cross-currency-transfer.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Feature: Cross-currency payment transfers
As a wallet user
I want to send payments between accounts in different currencies
So that I can transfer value across currency boundaries

Scenario: User can navigate to send page and select accounts
Given I am a verified and logged-in wallet user
When I navigate to the send page
And I select a source account
Then I should see the wallet address selector
When I select a wallet address
Then I should see the recipient address input field
30 changes: 30 additions & 0 deletions e2e/features/deposit-transactions-regression.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Feature: Deposit transaction regressions
As a wallet user
I want deposits to create one transaction and a correct balance delta
So that transaction history and balances stay consistent

Scenario: Iframe deposit creates a single transaction row with matching balance delta
Given I am a verified and logged-in wallet user
When I open the EUR default account for deposit checks
And I record the current account balance
And I record the current transactions count
And I complete a deposit of 11.00 EUR via the GateHub iframe
And I open the transactions page for deposit checks
Then the transaction count should increase by exactly 1
When I wait 10 seconds and refresh transactions
Then the transaction count should still increase by exactly 1
And the latest transaction amount should match the deposit amount
And the account balance increase should match the deposit amount

Scenario: Local dialog deposit creates a single transaction row with matching balance delta
Given I am a verified and logged-in wallet user
When I open the EUR default account for deposit checks
And I record the current account balance
And I record the current transactions count
And I complete a deposit of 11.00 EUR via the local dialog
And I open the transactions page for deposit checks
Then the transaction count should increase by exactly 1
When I wait 10 seconds and refresh transactions
Then the transaction count should still increase by exactly 1
And the latest transaction amount should match the deposit amount
And the account balance increase should match the deposit amount
146 changes: 146 additions & 0 deletions e2e/features/steps/auth-signup-dashboard.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { expect } from '@playwright/test'
import {
completeLocalMockKyc,
waitForVerificationLinkFromLogs
} from '../../helpers/local-wallet'
import { Given, Then, When } from './fixtures'

Given('I am a new unique wallet user', async ({ flow }) => {
expect(flow.credentials.email).toContain('e2e-')
expect(flow.credentials.password).toContain('Testnet!')
})

When('I open the signup page', async ({ page, flow }) => {
await page.goto('/auth/signup')
await expect(
page.getByRole('heading', { name: 'Create Account' })
).toBeVisible()
await flow.takeScreenshot('signup-page')
})

When('I complete the signup form', async ({ page, flow }) => {
const signUpForm = page.locator('form')

await signUpForm
.getByLabel('E-mail *', { exact: true })
.fill(flow.credentials.email)
await flow.takeScreenshot('signup-email-filled')
await signUpForm
.getByLabel('Password *', { exact: true })
.fill(flow.credentials.password)
await flow.takeScreenshot('signup-password-filled')
await signUpForm
.getByLabel('Confirm password *', { exact: true })
.fill(flow.credentials.password)
await flow.takeScreenshot('signup-confirm-password-filled')
})

When('I submit signup', async ({ page, flow }) => {
const signUpForm = page.locator('form')

await Promise.all([
page.waitForResponse(
(response) =>
response.url().endsWith('/signup') &&
response.request().method() === 'POST' &&
response.status() === 201
),
signUpForm.locator('button[type="submit"]').click()
])

await flow.takeScreenshot('signup-submitted')
})

Then('I should see signup confirmation', async ({ page, flow }) => {
await expect(
page.getByText('A verification link has been sent to your email account.')
).toBeVisible()
await flow.takeScreenshot('signup-success')
})

When(
'I open the verification link from backend logs',
async ({ page, flow }) => {
const verificationLink = await waitForVerificationLinkFromLogs({
since: flow.logMarker,
containerName: flow.containerName
})

flow.verificationLink = verificationLink

await page.goto(verificationLink)
await flow.takeScreenshot('verification-page-opened')
}
)

Then('I should see verification success', async ({ page, flow }) => {
await expect(
page.getByText(
'Your email has been verified. Continue to login to use Interledger Test Wallet.'
)
).toBeVisible()
await flow.takeScreenshot('verify-success')
})

When('I continue to login', async ({ page, flow }) => {
await page.locator('a[href="/auth/login"]').first().click()
await expect(page).toHaveURL(/\/auth\/login$/)
await flow.takeScreenshot('login-page-opened')
})

When('I login with my new credentials', async ({ page, flow }) => {
const loginForm = page.locator('form')

await loginForm
.getByLabel('E-mail *', { exact: true })
.fill(flow.credentials.email)
await flow.takeScreenshot('login-email-filled')
await loginForm
.getByLabel('Password *', { exact: true })
.fill(flow.credentials.password)
await flow.takeScreenshot('login-password-filled')

await Promise.all([
page.waitForResponse(
(response) =>
response.url().endsWith('/login') &&
response.request().method() === 'POST' &&
response.status() === 200
),
loginForm.locator('button[type="submit"]').click()
])

await flow.takeScreenshot('login-submitted')
await page.waitForURL(/\/(kyc)?$/, { timeout: 60_000 })
await flow.takeScreenshot('post-login')
})

When('I complete KYC if I am redirected to KYC', async ({ page, flow }) => {
if (page.url().endsWith('/kyc')) {
await completeLocalMockKyc(page, flow.takeScreenshot)
}
})

Then('I should see the accounts dashboard', async ({ page, flow }) => {
await expect(page.getByRole('heading', { name: 'Accounts' })).toBeVisible()
await expect(page.getByText('Here is your account overview!')).toBeVisible()
await flow.takeScreenshot('dashboard-confirmed')
})

When('I open the EUR default account', async ({ page, flow }) => {
const defaultAccount = page
.locator('a[href*="/account/"]')
.filter({ hasText: 'EUR Account' })
.first()

await expect(defaultAccount).toBeVisible()
await flow.takeScreenshot('dashboard')
await defaultAccount.click()
await flow.takeScreenshot('default-account-opened')
})

Then('I should see the account balance page', async ({ page, flow }) => {
await expect(page).toHaveURL(/\/account\/.+/)
await expect(page.getByRole('heading', { name: 'Balance' })).toBeVisible()
await flow.takeScreenshot('account-page')
})
110 changes: 110 additions & 0 deletions e2e/features/steps/cross-currency-transfer.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { expect } from '@playwright/test'
import { completeLocalMockKyc, setupVerifiedUser } from '../../helpers/local-wallet'
import { Given, Then, When } from './fixtures'

Given('I am a verified and logged-in wallet user', async ({ page, flow }) => {
const containerName = flow.containerName

// Use the helper to quickly set up a verified user
const credentials = await setupVerifiedUser({
page,
takeScreenshot: flow.takeScreenshot,
containerName,
skipScreenshots: false
})

// Store credentials in flow for later use if needed
flow.credentials = credentials

// Validate authenticated access to protected routes; recover by logging in again if needed.
await page.goto('/send')

if (page.url().includes('/auth/login')) {
const loginForm = page.locator('form')

await loginForm
.getByLabel('E-mail *', { exact: true })
.fill(credentials.email)
await loginForm
.getByLabel('Password *', { exact: true })
.fill(credentials.password)

await Promise.all([
page.waitForResponse(
(response) =>
response.url().endsWith('/login') &&
response.request().method() === 'POST' &&
response.status() === 200
),
loginForm.locator('button[type="submit"]').click()
])

if (page.url().endsWith('/kyc')) {
await completeLocalMockKyc(page, flow.takeScreenshot)
await page.goto('/send')
} else {
await page.waitForURL(/\/send$/, { timeout: 60_000 })
}
}

await expect(page).toHaveURL(/\/send$/)
await flow.takeScreenshot('verified-user-ready')
})

When('I navigate to the send page', async ({ page, flow }) => {
await page.goto('/send')
await expect(page).toHaveURL(/\/send$/)
await expect(page.getByRole('heading', { name: 'Send' })).toBeVisible()
await flow.takeScreenshot('send-page-loaded')
})

When('I select a source account', async ({ page, flow }) => {
// Click on the account selector
const accountSelect = page.locator('#selectAccount')
await expect(accountSelect).toBeVisible()
await flow.takeScreenshot('before-select-account')

await accountSelect.click()
await flow.takeScreenshot('account-dropdown-opened')

// Select the first account (EUR Account or whatever is available)
const firstAccountOption = page.locator('[role="option"]').first()
await expect(firstAccountOption).toBeVisible()
await firstAccountOption.click()
await flow.takeScreenshot('account-selected')
})

Then('I should see the wallet address selector', async ({ page, flow }) => {
const walletAddressSelect = page.locator('#selectWalletAddress')
await expect(walletAddressSelect).toBeVisible()
await flow.takeScreenshot('wallet-address-selector-visible')
})

When('I select a wallet address', async ({ page, flow }) => {
const walletAddressSelect = page.locator('#selectWalletAddress')
await expect(walletAddressSelect).toBeVisible()
await flow.takeScreenshot('before-select-wallet-address')

await walletAddressSelect.click()
await flow.takeScreenshot('wallet-address-dropdown-opened')

// Select the first wallet address option
const firstWalletOption = page.locator('[role="option"]').first()
await expect(firstWalletOption).toBeVisible()
await firstWalletOption.click()
await flow.takeScreenshot('wallet-address-selected')
})

Then(
'I should see the recipient address input field',
async ({ page, flow }) => {
const recipientInput = page.locator('#addRecipientWalletAddress')
await expect(recipientInput).toBeVisible()
await flow.takeScreenshot('recipient-address-input-visible')

// Verify amount input is also visible
const amountInput = page.locator('#addAmount')
await expect(amountInput).toBeVisible()
await flow.takeScreenshot('amount-input-visible')
}
)
Loading
Loading