Skip to content

Commit 54fe52e

Browse files
committed
Add user setup
1 parent 3846588 commit 54fe52e

File tree

5 files changed

+336
-20
lines changed

5 files changed

+336
-20
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ node_modules/
2222
/playwright-report/
2323
/blob-report/
2424
/playwright/.cache/
25+
# Authentication state files
26+
/tests/auth/*.json
27+
/tests/auth/

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"@playwright/test": "^1.53.0",
44
"@types/node": "^24.0.0",
55
"@woocommerce/e2e-utils-playwright": "^0.3.1",
6+
"@wordpress/e2e-test-utils-playwright": "^1.25.0",
67
"@wordpress/scripts": "^29.0.0",
78
"dotenv": "^16.5.0"
89
},

tests/setup/global-setup.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,36 @@
1-
// tests/setup/global-setup.ts
21
import { chromium, FullConfig } from '@playwright/test';
32
import { WordPressApiClient } from './wordpress-api-client';
43
import { TestDataManager } from './test-data-manager';
4+
import { UserAuthenticationManager } from './user-setup';
55

66
async function globalSetup(config: FullConfig) {
77
const browser = await chromium.launch();
8-
const context = await browser.newContext();
9-
const page = await context.newPage();
8+
const baseUrl = process.env.TESTSITE_URL || 'https://staging-site.ddev.site';
109

1110
const apiClient = new WordPressApiClient();
1211
const testDataManager = new TestDataManager(apiClient);
13-
const baseUrl = process.env.TESTSITE_URL || 'https://staging-site.ddev.site';
12+
const userManager = new UserAuthenticationManager(apiClient, baseUrl);
13+
14+
try {
15+
await apiClient.healthCheck();
1416

15-
// Authenticate as admin - use full URL
16-
await page.goto(`${baseUrl}/wp-admin`);
17-
await page.fill('#user_login', process.env.WP_ADMIN_USER || 'admin');
18-
await page.fill('#user_pass', process.env.WP_ADMIN_PASS || 'admin');
19-
await page.click('#wp-submit');
17+
await testDataManager.setupTestProducts();
18+
await testDataManager.setupTestPages();
19+
await testDataManager.setupMoneiPaymentMethods();
2020

21-
// Save authentication state
22-
await context.storageState({ path: 'tests/auth/admin-state.json' });
21+
await userManager.setupTestUsers();
2322

24-
// test api client
25-
await apiClient.healthCheck();
23+
const authStates = await userManager.createAllAuthStates(browser);
2624

27-
// Setup test data
28-
await testDataManager.setupTestProducts();
29-
// await testDataManager.setupProductsByType('simple');
30-
// await testDataManager.setupSubscriptionProducts('woocommerce');
31-
//await testDataManager.setupTestPages();
32-
//await testDataManager.setupMoneiPaymentMethods();
25+
console.log('🎉 Global setup complete!');
26+
console.log('Available auth states:', Object.keys(authStates));
3327

34-
await browser.close();
28+
} catch (error) {
29+
console.error('💥 Global setup failed:', error.message);
30+
throw error;
31+
} finally {
32+
await browser.close();
33+
}
3534
}
3635

3736
export default globalSetup;

tests/setup/user-setup.ts

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
import { Browser, BrowserContext, Page } from '@playwright/test';
2+
import { RequestUtils } from '@wordpress/e2e-test-utils-playwright';
3+
import { WordPressApiClient } from './wordpress-api-client';
4+
5+
export interface TestUser {
6+
username: string;
7+
email: string;
8+
password: string;
9+
role: 'administrator' | 'customer' | 'shop_manager';
10+
displayName: string;
11+
firstName: string;
12+
lastName: string;
13+
country: string;
14+
state?: string;
15+
city: string;
16+
address: string;
17+
postcode: string;
18+
phone: string;
19+
}
20+
21+
export const TEST_USERS: Record<string, TestUser> = {
22+
ADMIN: {
23+
username: 'admin',
24+
email: 'admin@test.local',
25+
password: process.env.WP_ADMIN_PASS || 'admin',
26+
role: 'administrator',
27+
displayName: 'Test Admin',
28+
firstName: 'Test',
29+
lastName: 'Admin',
30+
country: 'ES',
31+
state: 'Barcelona',
32+
city: 'Barcelona',
33+
address: 'Test Street 123',
34+
postcode: '08001',
35+
phone: '+34666777888'
36+
},
37+
ES_CUSTOMER: {
38+
username: 'es_customer',
39+
email: 'customer@test.local',
40+
password: 'customer123',
41+
role: 'customer',
42+
displayName: 'Spanish Customer',
43+
firstName: 'Carlos',
44+
lastName: 'García',
45+
country: 'ES',
46+
state: 'Madrid',
47+
city: 'Madrid',
48+
address: 'Calle Mayor 1',
49+
postcode: '28001',
50+
phone: '+34600123456'
51+
},
52+
PT_CUSTOMER: {
53+
username: 'pt_customer',
54+
email: 'portugal@test.local',
55+
password: 'customer123',
56+
role: 'customer',
57+
displayName: 'Portuguese Customer',
58+
firstName: 'João',
59+
lastName: 'Silva',
60+
country: 'PT',
61+
city: 'Lisboa',
62+
address: 'Rua da Liberdade 1',
63+
postcode: '1250-096',
64+
phone: '+351911234567'
65+
},
66+
US_CUSTOMER: {
67+
username: 'us_customer',
68+
email: 'usa@test.local',
69+
password: 'customer123',
70+
role: 'customer',
71+
displayName: 'US Customer',
72+
firstName: 'John',
73+
lastName: 'Smith',
74+
country: 'US',
75+
state: 'CA',
76+
city: 'Los Angeles',
77+
address: '123 Main St',
78+
postcode: '90210',
79+
phone: '+1555123456'
80+
}
81+
};
82+
83+
export class UserAuthenticationManager {
84+
private apiClient: WordPressApiClient;
85+
private requestUtils: RequestUtils | null = null;
86+
private baseUrl: string;
87+
88+
constructor(apiClient: WordPressApiClient, baseUrl: string) {
89+
this.apiClient = apiClient;
90+
this.baseUrl = baseUrl;
91+
}
92+
93+
async initializeRequestUtils(requestContext: any): Promise<void> {
94+
this.requestUtils = new RequestUtils(requestContext, {
95+
storageStatePath: 'tests/auth/admin-state.json'
96+
});
97+
await this.requestUtils.setupRest();
98+
}
99+
100+
/**
101+
* Setup all test users during global setup
102+
*/
103+
async setupTestUsers(): Promise<void> {
104+
console.log('🧑‍💼 Setting up test users...');
105+
106+
for (const [userKey, userData] of Object.entries(TEST_USERS)) {
107+
if (userKey === 'ADMIN') {
108+
// Skip admin as it should already exist
109+
console.log(` ✅ Admin user exists: ${userData.username}`);
110+
continue;
111+
}
112+
113+
await this.ensureUserExists(userData);
114+
}
115+
116+
console.log('✅ Test users setup complete');
117+
}
118+
119+
/**
120+
* Create user if it doesn't exist
121+
*/
122+
private async ensureUserExists(userData: TestUser): Promise<void> {
123+
try {
124+
// Check if user exists via API
125+
const existingUser = await this.getUserByUsername(userData.username);
126+
127+
if (!existingUser) {
128+
console.log(` 🆕 Creating user: ${userData.username}`);
129+
await this.createUser(userData);
130+
} else {
131+
console.log(` ✅ User exists: ${userData.username} (ID: ${existingUser.id})`);
132+
// Optionally update user data
133+
await this.updateUserBillingInfo(existingUser.id, userData);
134+
}
135+
} catch (error) {
136+
console.error(` ❌ Failed to setup user ${userData.username}:`, error.message);
137+
}
138+
}
139+
140+
/**
141+
* Get user by username via WordPress API
142+
*/
143+
private async getUserByUsername(username: string): Promise<any | null> {
144+
try {
145+
const response = await fetch(`${this.baseUrl}/wp-json/wp/v2/users?search=${username}`, {
146+
headers: {
147+
'Authorization': `Basic ${Buffer.from(`${process.env.WORDPRESS_ADMIN_USER}:${process.env.WP_API_APP_PASSWORD || process.env.WORDPRESS_ADMIN_PASSWORD}`).toString('base64')}`,
148+
'Content-Type': 'application/json'
149+
}
150+
});
151+
152+
if (response.ok) {
153+
const users = await response.json();
154+
return users.find((user: any) => user.slug === username) || null;
155+
}
156+
return null;
157+
} catch (error) {
158+
console.warn(`Could not fetch user ${username}:`, error.message);
159+
return null;
160+
}
161+
}
162+
163+
/**
164+
* Create new user via WordPress API
165+
*/
166+
private async createUser(userData: TestUser): Promise<any> {
167+
const userPayload = {
168+
username: userData.username,
169+
email: userData.email,
170+
password: userData.password,
171+
roles: [userData.role],
172+
first_name: userData.firstName,
173+
last_name: userData.lastName,
174+
name: userData.displayName
175+
};
176+
177+
const response = await fetch(`${this.baseUrl}/wp-json/wp/v2/users`, {
178+
method: 'POST',
179+
headers: {
180+
'Authorization': `Basic ${Buffer.from(`${process.env.WORDPRESS_ADMIN_USER}:${process.env.WP_API_APP_PASSWORD || process.env.WORDPRESS_ADMIN_PASSWORD}`).toString('base64')}`,
181+
'Content-Type': 'application/json'
182+
},
183+
body: JSON.stringify(userPayload)
184+
});
185+
186+
if (!response.ok) {
187+
const errorText = await response.text();
188+
throw new Error(`Failed to create user ${userData.username}: ${errorText}`);
189+
}
190+
191+
const user = await response.json();
192+
console.log(` ✅ User created: ${user.name} (ID: ${user.id})`);
193+
194+
// Set up billing information for WooCommerce
195+
await this.updateUserBillingInfo(user.id, userData);
196+
197+
return user;
198+
}
199+
200+
/**
201+
* Update user's WooCommerce billing information
202+
*/
203+
private async updateUserBillingInfo(userId: number, userData: TestUser): Promise<void> {
204+
try {
205+
const customerData = {
206+
billing: {
207+
first_name: userData.firstName,
208+
last_name: userData.lastName,
209+
email: userData.email,
210+
phone: userData.phone,
211+
country: userData.country,
212+
state: userData.state || '',
213+
city: userData.city,
214+
address_1: userData.address,
215+
postcode: userData.postcode
216+
},
217+
shipping: {
218+
first_name: userData.firstName,
219+
last_name: userData.lastName,
220+
country: userData.country,
221+
state: userData.state || '',
222+
city: userData.city,
223+
address_1: userData.address,
224+
postcode: userData.postcode
225+
}
226+
};
227+
228+
// Use WooCommerce API to update customer
229+
const response = await this.apiClient.wooCommerce.put(`customers/${userId}`, customerData);
230+
console.log(` 💳 Billing info updated for user ${userData.username}`);
231+
} catch (error) {
232+
console.warn(` ⚠️ Could not update billing info for ${userData.username}:`, error.message);
233+
}
234+
}
235+
236+
/**
237+
* Authenticate user and save storage state
238+
*/
239+
async authenticateUser(browser: Browser, userKey: string): Promise<string> {
240+
const userData = TEST_USERS[userKey];
241+
if (!userData) {
242+
throw new Error(`User ${userKey} not found in TEST_USERS`);
243+
}
244+
245+
console.log(`🔐 Authenticating user: ${userData.username}`);
246+
247+
const context = await browser.newContext({
248+
baseURL: this.baseUrl
249+
});
250+
const page = await context.newPage();
251+
252+
try {
253+
// Go to login page
254+
await page.goto('/wp-login.php');
255+
256+
// Fill login form
257+
await page.fill('#user_login', userData.username);
258+
await page.fill('#user_pass', userData.password);
259+
await page.click('#wp-submit');
260+
261+
// Wait for successful login (redirect to dashboard or profile)
262+
await page.waitForURL(url =>
263+
url.pathname.includes('/wp-admin/') ||
264+
url.pathname.includes('/my-account/') ||
265+
url.pathname === '/'
266+
);
267+
268+
// Save authentication state
269+
const storageStatePath = `tests/auth/${userKey.toLowerCase()}-state.json`;
270+
await context.storageState({ path: storageStatePath });
271+
272+
console.log(` ✅ Authentication saved: ${storageStatePath}`);
273+
return storageStatePath;
274+
275+
} catch (error) {
276+
throw new Error(`Failed to authenticate user ${userData.username}: ${error.message}`);
277+
} finally {
278+
await context.close();
279+
}
280+
}
281+
282+
/**
283+
* Create all authentication states during global setup
284+
*/
285+
async createAllAuthStates(browser: Browser): Promise<Record<string, string>> {
286+
const authStates: Record<string, string> = {};
287+
288+
// Create guest state (no authentication)
289+
const guestContext = await browser.newContext({ baseURL: this.baseUrl });
290+
const guestPage = await guestContext.newPage();
291+
await guestPage.goto('/');
292+
const guestStatePath = 'tests/auth/guest-state.json';
293+
await guestContext.storageState({ path: guestStatePath });
294+
await guestContext.close();
295+
authStates['GUEST'] = guestStatePath;
296+
console.log(' ✅ Guest state saved');
297+
298+
// Create authenticated states for each user
299+
for (const userKey of Object.keys(TEST_USERS)) {
300+
try {
301+
const statePath = await this.authenticateUser(browser, userKey);
302+
authStates[userKey] = statePath;
303+
} catch (error) {
304+
console.error(` ❌ Failed to create auth state for ${userKey}:`, error.message);
305+
// Use guest state as fallback
306+
authStates[userKey] = guestStatePath;
307+
}
308+
}
309+
310+
return authStates;
311+
}
312+
}

0 commit comments

Comments
 (0)