Skip to content

Commit eba6ecf

Browse files
authored
Merge branch 'main' into fix/primary-name-address-mismatch
2 parents 7bffced + 73f3fd8 commit eba6ecf

File tree

4 files changed

+137
-78
lines changed

4 files changed

+137
-78
lines changed

e2e/specs/stateless/addressPageErrorHandling.spec.ts renamed to e2e/specs/stateless/addressPage.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,30 @@ test.describe('Address page error handling', () => {
176176
expect(requestCount).toBeGreaterThanOrEqual(3) // At least 2 failures + 1 success
177177
})
178178

179+
test('should display no-profile-snippet when no primary name set with invalid resolver', async ({
180+
page,
181+
login,
182+
makeName,
183+
makePageObject,
184+
}) => {
185+
test.slow()
186+
187+
// SETUP: Create name with invalid resolver (triggers ContractFunctionExecutionError)
188+
// Deliberately NOT setting as primary name to test no-primary-name scenario
189+
const name = await createUserName(makeName, 'no-primary-invalid-resolver')
190+
await setInvalidResolver(page, name, login, makePageObject)
191+
192+
// ACTION: Navigate to address page
193+
const userAddress = getUserAddress()
194+
await page.goto(`/${userAddress}`)
195+
196+
// ASSERT: Page loads gracefully showing no-profile-snippet (not profile-snippet)
197+
await expect(page.getByTestId('no-profile-snippet')).toBeVisible()
198+
199+
// ASSERT: Names list loads despite invalid resolver on owned name
200+
await expect(page.getByTestId('names-list')).toBeVisible({ timeout: NAMES_LIST_TIMEOUT })
201+
})
202+
179203
test.afterEach(async () => {
180204
// Clean up: reset primary name after each test
181205
await setPrimaryName(walletClient, {

e2e/specs/stateless/extendNames.spec.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,4 +1151,51 @@ test.describe('Wrapped Name Renewal with Referrer', () => {
11511151
// Note: Bulk renewals should use the legacy bulk renewal contract
11521152
// which doesn't support referrers
11531153
})
1154+
1155+
test('should extend wrapped name in grace period with referrer', async ({
1156+
page,
1157+
login,
1158+
makeName,
1159+
makePageObject,
1160+
}) => {
1161+
const name = await makeName({
1162+
label: 'wrapped-grace-referrer',
1163+
type: 'wrapped',
1164+
owner: 'user',
1165+
duration: -24 * 60 * 60, // Expired 1 day ago
1166+
})
1167+
1168+
const referrerAddress = '0x1234567890123456789012345678901234567890'
1169+
1170+
const profilePage = makePageObject('ProfilePage')
1171+
const transactionModal = makePageObject('TransactionModal')
1172+
1173+
await profilePage.goto(name)
1174+
await login.connect()
1175+
1176+
// Verify name is in grace period
1177+
await expect(page.getByText(`${name} has expired`)).toBeVisible()
1178+
1179+
// Add referrer to URL and navigate
1180+
await page.goto(`/${name}?referrer=${referrerAddress}`)
1181+
1182+
// Click extend button
1183+
await profilePage.getExtendButton.click()
1184+
1185+
// Set extension and proceed
1186+
await expect(page.getByTestId('plus-minus-control-label')).toHaveText('1 year')
1187+
await page.locator('button:has-text("Next")').click()
1188+
1189+
// Complete transaction
1190+
await transactionModal.confirm()
1191+
1192+
await expect(page.getByText('Your "Extend names" transaction was successful')).toBeVisible({
1193+
timeout: 10000,
1194+
})
1195+
1196+
// Verify referrer included in the transaction calldata
1197+
const latestTransaction = await publicClient.getTransaction({ blockTag: 'latest', index: 0 })
1198+
const referrerHex = addressToBytes32(referrerAddress)
1199+
expect(latestTransaction.input).toContain(referrerHex.slice(2)) // Remove '0x' prefix for comparison
1200+
})
11541201
})

e2e/specs/wallets/registerName-metamask.spec.ts

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
1-
import { BrowserContext, expect, Page, test } from '@playwright/test'
1+
import { expect, test } from '@playwright/test'
22
import dappwright from '@tenkeylabs/dappwright'
33
import type { Dappwright } from '@tenkeylabs/dappwright'
44

55
import { SafeEnsConfig } from './config/safe-ens-config'
6-
import { confirmTransactionWithMetaMask, connectWalletToEns } from './config/wallet-ens-config'
6+
import { navigateToHome, openWalletAndConfirm, searchForName } from './config/test-utilities'
7+
import { connectWalletToEns } from './config/wallet-ens-config'
78

89
// Global variables to share state
910
let metaMask: Dappwright
10-
let page: Page
11-
let context: BrowserContext
11+
let page: any // Using any to avoid Playwright version conflicts with dappwright
12+
let context: any
1213
let ensName: string
1314

1415
// Register unowned name
1516
async function performRegistration(name: string): Promise<void> {
1617
console.log(`🎯 Starting registration for ${name}`)
1718

1819
// Search for name
19-
const searchInput = page.locator('input[placeholder="Search for a name"]')
20-
await searchInput.waitFor({ timeout: 15000 })
21-
await searchInput.fill(name)
22-
await searchInput.press('Enter')
20+
await searchForName(page, name)
2321

2422
// Wait for registration page
2523
await page.getByRole('heading', { name: `Register ${name}` }).waitFor({ timeout: 15000 })
@@ -40,12 +38,8 @@ async function performRegistration(name: string): Promise<void> {
4038
// Proceed to commit step
4139
await page.locator('[data-testid="next-button"]').click()
4240

43-
// Wait for "Open Wallet" and confirm commit
44-
await page.locator('text=Open Wallet').waitFor({ timeout: 10000 })
45-
await page.locator('text=Open Wallet').click()
46-
47-
// Confirm transaction
48-
await confirmTransactionWithMetaMask(page, 'commit', name)
41+
// Open wallet and confirm commit transaction
42+
await openWalletAndConfirm(page, { type: 'commit', name })
4943

5044
// Wait 60s for commit
5145
await page.waitForTimeout(75000)
@@ -55,12 +49,14 @@ async function performRegistration(name: string): Promise<void> {
5549
await finishButton.waitFor({ timeout: 10000 })
5650
await finishButton.click()
5751

58-
// Open wallet modal and click
59-
await page.locator('text=Open Wallet').waitFor({ timeout: 10000 })
60-
await page.locator('text=Open Wallet').click()
52+
// Open wallet and confirm register transaction
53+
await openWalletAndConfirm(page, { type: 'register', name })
6154

62-
// Confirm transaction
63-
await confirmTransactionWithMetaMask(page, 'register', name)
55+
// Wait for registration completion page to load
56+
// Registration flow auto-closes the modal and navigates to the completion step
57+
// We wait for the "View Name" button which appears on the completion page
58+
const viewNameButton = page.getByTestId('view-name')
59+
await viewNameButton.waitFor({ state: 'visible', timeout: 120000 })
6460

6561
console.log('🎉 ENS registration completed!')
6662
}
@@ -71,15 +67,8 @@ async function registerOwnedName() {
7167

7268
console.log(`🎯 Starting registration for ${registeredName}`)
7369

74-
// Search for name
75-
const searchInput = page.locator('input[placeholder="Search for a name"]')
76-
const searchResult = page.getByTestId('search-result-name')
77-
78-
await searchInput.waitFor({ timeout: 15000 })
79-
await searchInput.fill(registeredName)
80-
await expect(searchResult).toHaveText(registeredName)
81-
await expect(searchResult).toContainText('Registered')
82-
await searchInput.press('Enter')
70+
// Search for name and verify it shows as registered
71+
await searchForName(page, registeredName)
8372

8473
// Register should not appear, profile shows instead
8574
await expect(page.getByRole('heading', { name: `Register ${registeredName}` })).not.toBeVisible({
@@ -136,6 +125,11 @@ test.describe('ENS Name Registration', () => {
136125
ensName = `registername-${Date.now()}.eth`
137126
})
138127

128+
test.beforeEach('Navigate to home page', async () => {
129+
// Use utility function instead of manual navigation + timeout
130+
await navigateToHome(page)
131+
})
132+
139133
test('Connect MetaMask to ENS localhost', async () => {
140134
await expect(
141135
page.locator('button:has-text("Connect"), [data-testid="connect-button"]'),

e2e/specs/wallets/subName-metamask.spec.ts

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
import { BrowserContext, expect, Page, test } from '@playwright/test'
1+
import { expect, test } from '@playwright/test'
22
import dappwright from '@tenkeylabs/dappwright'
33
import type { Dappwright } from '@tenkeylabs/dappwright'
44

55
import { SafeEnsConfig } from './config/safe-ens-config'
6-
import { confirmTransactionWithMetaMask, connectWalletToEns } from './config/wallet-ens-config'
6+
import {
7+
closeTransactionModal,
8+
navigateToHome,
9+
openWalletAndConfirm,
10+
searchForName,
11+
waitForTransactionComplete,
12+
} from './config/test-utilities'
13+
import { connectWalletToEns } from './config/wallet-ens-config'
714

8-
// Global variables to share state
915
let metaMask: Dappwright
10-
let page: Page
11-
let context: BrowserContext
16+
let page: any
17+
let context: any
1218
let ensName: string
1319

1420
// Create subname
@@ -18,10 +24,7 @@ async function createSubName(name: string): Promise<void> {
1824
console.log(`🎯 Creating a new subname for ${walletName}`)
1925

2026
// Search for name
21-
const searchInput = page.locator('input[placeholder="Search for a name"]')
22-
await searchInput.waitFor({ timeout: 15000 })
23-
await searchInput.fill(walletName)
24-
await searchInput.press('Enter')
27+
await searchForName(page, walletName)
2528

2629
// Navigate to subname tab
2730
const subnameTab = page.getByTestId('subnames-tab')
@@ -35,85 +38,77 @@ async function createSubName(name: string): Promise<void> {
3538

3639
// Enter subname name
3740
const subnameInput = page.getByTestId('add-subname-input')
38-
const subnameNext = page.getByTestId('create-subname-next')
39-
await subnameInput.waitFor()
41+
await subnameInput.waitFor({ state: 'visible', timeout: 15000 })
4042
await subnameInput.fill(name)
43+
44+
const subnameNext = page.getByTestId('create-subname-next')
45+
await subnameNext.waitFor({ state: 'visible', timeout: 15000 })
4146
await subnameNext.click()
4247

4348
// Skip profile creation
4449
const subnameProfileNext = page.getByTestId('create-subname-profile-next')
50+
await subnameProfileNext.waitFor({ state: 'visible', timeout: 15000 })
4551
await subnameProfileNext.click()
4652

47-
// Start and confirm transaction
48-
await page.locator('text=Open Wallet').waitFor({ timeout: 10000 })
49-
await page.locator('text=Open Wallet').click()
50-
await confirmTransactionWithMetaMask(page)
53+
// Open wallet and confirm transaction
54+
await openWalletAndConfirm(page, { type: 'subname creation' })
5155

52-
// Wait for transaction to complete
53-
await page.waitForTimeout(25000)
56+
// Wait for transaction to complete using event-driven approach
57+
await waitForTransactionComplete(page, { action: 'subname creation' })
5458

5559
// Check subname is opened after transaction complete
5660
const nameProfileName = page.getByTestId('profile-snippet-name')
5761
const expectedSubname = `${ensName}.subname-test.eth`
58-
await expect(nameProfileName).toHaveText(expectedSubname)
62+
await expect(nameProfileName).toHaveText(expectedSubname, { timeout: 30000 })
5963

6064
// Check parent is correct
6165
const parentLabel = page.getByTestId('owner-profile-button-name.parent')
62-
await expect(parentLabel).toBeVisible()
63-
await expect(parentLabel).toContainText('subname-test.eth')
66+
await expect(parentLabel).toBeVisible({ timeout: 15000 })
67+
await expect(parentLabel).toContainText('subname-test.eth', { timeout: 10000 })
6468
}
6569

6670
// Delete subname
6771
async function deleteSubName(name: string): Promise<void> {
6872
const walletName = 'subname-test.eth'
73+
const fullSubname = `${name}.subname-test.eth`
6974

70-
console.log(`🎯 Deleting ${name}.subname-test.eth`)
75+
console.log(`🎯 Deleting ${fullSubname}`)
7176

7277
// Access created subname through search bar
73-
const searchInput = page.locator('input[placeholder="Search for a name"]')
74-
await searchInput.waitFor({ timeout: 15000 })
75-
await searchInput.fill(`${name}.subname-test.eth`)
76-
await searchInput.press('Enter')
78+
await searchForName(page, fullSubname)
7779

78-
// Confirm subname then click delete
80+
// Confirm subname profile loaded before deleting
7981
const profileName = page.getByTestId('profile-snippet-name')
8082
const expectedSubname = `${ensName}.subname-test.eth`
81-
await expect(profileName).toHaveText(expectedSubname)
83+
await expect(profileName).toHaveText(expectedSubname, { timeout: 30000 })
8284

8385
const deleteSubnameButton = page.getByTestId('profile-action-Delete subname')
86+
await deleteSubnameButton.waitFor({ state: 'visible', timeout: 15000 })
8487
await deleteSubnameButton.click()
8588

86-
// Start and confirm transaction
87-
await page.locator('text=Open Wallet').waitFor({ timeout: 10000 })
88-
await page.locator('text=Open Wallet').click()
89-
await confirmTransactionWithMetaMask(page)
89+
// Open wallet and confirm transaction
90+
await openWalletAndConfirm(page, { type: 'subname deletion' })
9091

91-
// Wait for transaction to complete
92-
await page.waitForTimeout(25000)
92+
// Wait for transaction to complete using event-driven approach
93+
await waitForTransactionComplete(page, { action: 'subname deletion' })
9394

94-
// Click done to return to subname profile
95-
const transactionCompleteButton = page.getByTestId('transaction-modal-complete-button')
96-
await transactionCompleteButton.click()
95+
// Close the completion modal
96+
await closeTransactionModal(page)
9797

98-
// Check expiry has no expiry
99-
const expiryBox = page.getByTestId('owner-profile-button-name.expiry')
100-
await expect(expiryBox).toContainText('no expiry', { timeout: 15000 })
101-
102-
// Enter parent name profile
103-
const parentSubnameTab = page.getByTestId('subnames-tab')
104-
await searchInput.waitFor({ timeout: 15000 })
105-
await searchInput.fill(walletName)
106-
await searchInput.press('Enter')
107-
await expect(profileName).toHaveText(walletName, { timeout: 10000 })
98+
// Navigate to parent name profile
99+
await searchForName(page, walletName)
100+
await expect(profileName).toHaveText(walletName, { timeout: 30000 })
108101

109102
// Switch to subname tab
103+
const parentSubnameTab = page.getByTestId('subnames-tab')
104+
await parentSubnameTab.waitFor({ state: 'visible', timeout: 15000 })
110105
await parentSubnameTab.click()
111106

112107
// Check deleted subname is no longer appearing
113108
const subnameItem = page.getByTestId(`name-item-${ensName}.subname-test.eth`)
114109
await expect(subnameItem).not.toBeVisible({ timeout: 15000 })
115110

116-
console.log(`⚔️ {name} has been deleted`)
111+
console.log(`⚔️ ${name} has been deleted`)
117112
}
118113

119114
test.describe('ENS Subname Checks', () => {
@@ -157,9 +152,8 @@ test.describe('ENS Subname Checks', () => {
157152
})
158153

159154
test.beforeEach('Navigate to home page', async () => {
160-
// Navigate back to home page before each test to ensure clean state
161-
await page.goto('http://localhost:3000/')
162-
await page.waitForTimeout(2000)
155+
// Use utility function instead of manual navigation + timeout
156+
await navigateToHome(page)
163157
})
164158

165159
test('Connect MetaMask to ENS localhost', async () => {

0 commit comments

Comments
 (0)