# Instructions - Following Playwright test failed. - Explain why, be concise, respect Playwright best practices. - Provide a snippet of code with the fix, if possible. # Test info - Name: onboarding.spec.ts >> Supplier Portal Onboarding & Feature E2E Flow >> completes the registration, contact verification, document upload, location pinning, welcome tour, order acceptance, and barcode generation - Location: playwright/e2e/onboarding.spec.ts:4:3 # Error details ``` Error: expect(locator).toBeVisible() failed Locator: getByText('Shipping Label Preview') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for getByText('Shipping Label Preview') ``` ```yaml - banner: - text: A Global Artisans Hub - navigation: - button "Platform" - button "Pricing" - button "Success Stories" - button "Support" - button "Logout" - complementary: - text: SELLER PANEL - heading "Teak Wood Craft Store" [level=4] - list: - listitem: - button "📊 Overview & Analytics" - listitem: - button "📦 Manage Products" - listitem: - button "🚚 Orders & Transit" - listitem: - button "🔄 Returns Management" - listitem: - button "💼 Wallet & Payouts" - listitem: - button "🖨️ Customer Address Printer" - listitem: - button "⚙️ Store Settings" - heading "Customer Address Printer" [level=2] - paragraph: Select an accepted order to view and print the shipping address label for the customer. - heading "Print Configuration" [level=3] - text: Select Accepted Order * - combobox "Select Accepted Order *": - option "-- Choose an accepted order --" - option "22 - Alice Smith (Handmade Wool Blanket)" [selected] - button "Print Address Label" - contentinfo: - text: Global Artisans Hub - link "About Us": - /url: "#about" - link "Careers": - /url: "#careers" - link "Press": - /url: "#press" - link "Terms": - /url: "#terms" - link "Privacy": - /url: "#privacy" - text: © 2026 Global Artisans Hub. All rights reserved. ``` # Test source ```ts 12 | const randPhone = `9${Math.floor(100000000 + Math.random() * 900000000)}`; 13 | await page.locator('input#reg-email').fill(randUser); 14 | await page.locator('input#reg-phone').fill(randPhone); 15 | await page.locator('input#reg-pass').fill('Super_secure_pass_123!'); 16 | await page.locator('input#reg-confirm-pass').fill('Super_secure_pass_123!'); 17 | await page.locator('input#reg-policy').check(); 18 | await page.locator('button').filter({ hasText: 'Register Business' }).click(); 19 | 20 | // 3. Step 1: Contact Verification 21 | await expect(page.getByText('Step 1 of 3: Contact Verification')).toBeVisible(); 22 | await page.locator('button').filter({ hasText: 'Send WhatsApp OTP' }).click(); 23 | await page.locator('input[placeholder="Enter 123456"]').first().fill('123456'); 24 | await page.locator('button').filter({ hasText: 'Verify Code' }).first().click(); 25 | await expect(page.getByText('✓ Mobile & WhatsApp Verified')).toBeVisible(); 26 | 27 | await page.locator('button').filter({ hasText: 'Send Email OTP' }).click(); 28 | await page.locator('input[placeholder="Enter 123456"]').last().fill('123456'); 29 | await page.locator('button').filter({ hasText: 'Verify Code' }).last().click(); 30 | await expect(page.getByText('✓ Email Verified')).toBeVisible(); 31 | await page.locator('button').filter({ hasText: 'Next Step: Identity Verification' }).click(); 32 | 33 | // 4. Step 2: Tax & Identity Verification 34 | await expect(page.getByText('Step 2 of 3: Tax & Identity Verification')).toBeVisible(); 35 | await page.locator('input#verify-gst').clear(); 36 | await page.locator('input#verify-gst').fill('29AAAAA1111A1Z1'); 37 | await page.locator('button').filter({ hasText: 'Submit GSTIN' }).click(); 38 | await expect(page.getByText('verification will be completed within next 24 hrs')).toBeVisible(); 39 | 40 | // Upload mock Aadhaar & PAN files 41 | await page.setInputFiles('input#aadhar-upload', { 42 | name: 'aadhar_card.pdf', 43 | mimeType: 'application/pdf', 44 | buffer: Buffer.from('mock aadhaar pdf'), 45 | }); 46 | await expect(page.getByText('Selected: aadhar_card.pdf')).toBeVisible(); 47 | 48 | await page.setInputFiles('input#pan-upload', { 49 | name: 'pan_card.pdf', 50 | mimeType: 'application/pdf', 51 | buffer: Buffer.from('mock pan pdf'), 52 | }); 53 | await expect(page.getByText('Selected: pan_card.pdf')).toBeVisible(); 54 | 55 | await page.locator('button').filter({ hasText: 'Next Step: Store & Location' }).click(); 56 | 57 | // 5. Step 3: Store & Pickup Location Setup 58 | await expect(page.getByText('Step 3 of 3: Store & Pickup Location')).toBeVisible(); 59 | await page.locator('input#store-name').clear(); 60 | await page.locator('input#store-name').fill('Teak Wood Craft Store'); 61 | await page.locator('textarea#store-bio').clear(); 62 | await page.locator('textarea#store-bio').fill('Teak wood hand-carved home decor elements.'); 63 | 64 | // Test interactive map coordinate pinning 65 | await expect(page.getByText('Store Location on Map *')).toBeVisible(); 66 | const mapGridParent = page.locator('span').filter({ hasText: 'Click anywhere on the map grid to pin location' }).locator('..'); 67 | await mapGridParent.click({ position: { x: 100, y: 80 } }); 68 | await expect(page.getByText('Coordinates: Lat')).toBeVisible(); 69 | 70 | await expect(page.locator('input#location-text')).not.toHaveValue(''); 71 | await page.locator('input#loc-city').clear(); 72 | await page.locator('input#loc-city').fill('Bangalore'); 73 | await page.locator('input#loc-pincode').clear(); 74 | await page.locator('input#loc-pincode').fill('560001'); 75 | await page.locator('button').filter({ hasText: 'Submit Supplier Profile' }).click(); 76 | 77 | // 6. Setup Welcome Tour Stepper 78 | await expect(page.getByText('Supplier Account Under Review ⏳')).toBeVisible(); 79 | await page.locator('button').filter({ hasText: 'Start Guided Tour 🎬' }).click(); 80 | await expect(page.getByText('📦 Products & Inventory Management')).toBeVisible(); 81 | await page.locator('button').filter({ hasText: 'Next: Order Management' }).click(); 82 | await expect(page.getByText('🚚 Order Acceptance Control')).toBeVisible(); 83 | await page.locator('button').filter({ hasText: 'Next: Barcode Generation' }).click(); 84 | await expect(page.getByText('🏷️ Barcode Identification & Tracking')).toBeVisible(); 85 | await page.locator('button').filter({ hasText: 'Next: Earnings & Wallet' }).click(); 86 | await expect(page.getByText('💼 Wallet & Payout Withdrawals')).toBeVisible(); 87 | await page.locator('button').filter({ hasText: 'Explore Dashboard 🚀' }).click(); 88 | 89 | // 7. Check Active Dashboard Tab 90 | await expect(page.getByText('Performance Analytics')).toBeVisible(); 91 | 92 | // 8. Manage Products tab & Bulk template download 93 | await page.locator('button, a').filter({ hasText: 'Manage Products' }).click(); 94 | await expect(page.getByText('Active Inventory')).toBeVisible(); 95 | 96 | const downloadPromise = page.waitForEvent('download'); 97 | await page.locator('button, a').filter({ hasText: 'Download Sample Excel Template' }).click(); 98 | const download = await downloadPromise; 99 | expect(download.suggestedFilename()).toBeDefined(); 100 | 101 | // 9. Orders Acceptance Flow 102 | await page.locator('button, a').filter({ hasText: 'Orders & Transit' }).click(); 103 | await expect(page.getByText('Active Orders & Payout status')).toBeVisible(); 104 | await expect(page.getByText('Pending Acceptance').first()).toBeVisible(); 105 | await page.locator('button').filter({ hasText: 'Accept' }).first().click(); 106 | await expect(page.getByText('Ready to Ship')).toBeVisible(); 107 | 108 | // 10. Customer Address Printer 109 | await page.locator('button, a').filter({ hasText: 'Customer Address Printer' }).click(); 110 | await expect(page.getByRole('heading', { name: 'Customer Address Printer' })).toBeVisible(); 111 | await page.locator('select#print-order').selectOption({ index: 1 }); > 112 | await expect(page.getByText('Shipping Label Preview')).toBeVisible(); | ^ Error: expect(locator).toBeVisible() failed 113 | await expect(page.getByRole('button', { name: 'Print Address Label' })).toBeVisible(); 114 | }); 115 | 116 | test('enforces security constraints and validation rules (negative test cases)', async ({ page }) => { 117 | // 1. Visit Home and verify dashboard components are not in DOM (route guarding) 118 | await page.goto('/'); 119 | await expect(page.locator('.dashboard-container')).toBeHidden(); 120 | await expect(page.locator('.sidebar-menu')).toBeHidden(); 121 | 122 | // 2. Go to Registration 123 | await page.locator('button, a').filter({ hasText: 'Get Started Today' }).first().click(); 124 | const randSecurityUser = `security_test_${Date.now()}_${Math.floor(Math.random() * 1000000)}@example.com`; 125 | const randSecurityPhone = `9${Math.floor(100000000 + Math.random() * 900000000)}`; 126 | await page.locator('input#reg-email').fill(randSecurityUser); 127 | await page.locator('input#reg-phone').fill(randSecurityPhone); 128 | await page.locator('input#reg-pass').fill('Password123!'); 129 | await page.locator('input#reg-confirm-pass').fill('Password123!'); 130 | await page.locator('input#reg-policy').check(); 131 | await page.locator('button').filter({ hasText: 'Register Business' }).click(); 132 | 133 | // 3. Step 1: Negative OTP validations 134 | await expect(page.getByText('Step 1 of 3: Contact Verification')).toBeVisible(); 135 | 136 | // Proceed button must be disabled initially 137 | await expect(page.locator('button').filter({ hasText: 'Next Step: Identity Verification' })).toBeDisabled(); 138 | 139 | // Submit invalid WhatsApp OTP 140 | await page.locator('button').filter({ hasText: 'Send WhatsApp OTP' }).click(); 141 | await page.locator('input[placeholder="Enter 123456"]').first().fill('000000'); 142 | 143 | // Capture dialog 144 | let alertMessage = ''; 145 | page.once('dialog', async dialog => { 146 | alertMessage = dialog.message(); 147 | await dialog.accept(); 148 | }); 149 | 150 | await page.locator('button').filter({ hasText: 'Verify Code' }).first().click(); 151 | 152 | // Give brief time/event loop ticks to ensure dialog handler fires 153 | await page.waitForTimeout(500); 154 | expect(alertMessage).toBe('Incorrect code. Enter 123456'); 155 | await expect(page.getByText('✓ Mobile & WhatsApp Verified')).toBeHidden(); 156 | 157 | // Correct the code to enable proceed 158 | await page.locator('input[placeholder="Enter 123456"]').first().clear(); 159 | await page.locator('input[placeholder="Enter 123456"]').first().fill('123456'); 160 | await page.locator('button').filter({ hasText: 'Verify Code' }).first().click(); 161 | await expect(page.getByText('✓ Mobile & WhatsApp Verified')).toBeVisible(); 162 | 163 | // Submit invalid Email OTP 164 | await page.locator('button').filter({ hasText: 'Send Email OTP' }).click(); 165 | await page.locator('input[placeholder="Enter 123456"]').last().fill('999999'); 166 | 167 | page.once('dialog', async dialog => { 168 | alertMessage = dialog.message(); 169 | await dialog.accept(); 170 | }); 171 | 172 | await page.locator('button').filter({ hasText: 'Verify Code' }).last().click(); 173 | await page.waitForTimeout(500); 174 | expect(alertMessage).toBe('Incorrect code. Enter 123456'); 175 | await expect(page.getByText('✓ Email Verified')).toBeHidden(); 176 | await expect(page.locator('button').filter({ hasText: 'Next Step: Identity Verification' })).toBeDisabled(); 177 | }); 178 | }); 179 | ```