# 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 >> enforces security constraints and validation rules (negative test cases) - Location: playwright/e2e/onboarding.spec.ts:118:3 # Error details ``` Error: expect(locator).toBeVisible() failed Locator: getByText('Step 1 of 3: Contact Verification') Expected: visible Timeout: 5000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for getByText('Step 1 of 3: Contact Verification') ``` ```yaml - banner: - text: A Global Artisans Hub - navigation: - button "Platform" - button "Pricing" - button "Success Stories" - button "Support" - button "Login" - button "Get Started" - main: - button "Login" - button "Register" - heading "Create Your Supplier Account" [level=2] - text: Business Email * - textbox "Business Email *": - /placeholder: Enter email address - text: security_test_1786700927306@example.com - text: Mobile Number * - textbox "Mobile Number *": - /placeholder: Enter 10-digit number - text: "9358500184" - text: Create Password * - textbox "Create Password *": - /placeholder: Minimum 8 characters - text: Password123! - button "🙈" - text: Confirm Password * - textbox "Confirm Password *": - /placeholder: Re-enter password - text: Password123! - button "🙈" - checkbox "I accept the Terms of Service and Privacy Policy *" [checked] - text: I accept the - link "Terms of Service": - /url: "#terms" - text: and - link "Privacy Policy": - /url: "#privacy" - text: "*" - button "Register Business" - 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 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')).toBeVisible(); 105 | await page.locator('button').filter({ hasText: 'Accept' }).first().click(); 106 | await expect(page.getByText('Ready to Ship')).toBeVisible(); 107 | 108 | // 10. Barcode Generator 109 | await page.locator('button, a').filter({ hasText: 'Barcode Generator' }).click(); 110 | await expect(page.getByText('Product Barcode Generator')).toBeVisible(); 111 | await page.locator('select#barcode-product').selectOption({ index: 1 }); 112 | await page.locator('button').filter({ hasText: 'Generate Barcode Graphic' }).click(); 113 | await expect(page.getByText('Generated Barcode Preview')).toBeVisible(); 114 | await expect(page.getByText('Print Label')).toBeVisible(); 115 | await expect(page.getByText('Download SVG')).toBeVisible(); 116 | }); 117 | 118 | test('enforces security constraints and validation rules (negative test cases)', async ({ page }) => { 119 | // 1. Visit Home and verify dashboard components are not in DOM (route guarding) 120 | await page.goto('/'); 121 | await expect(page.locator('.dashboard-container')).toBeHidden(); 122 | await expect(page.locator('.sidebar-menu')).toBeHidden(); 123 | 124 | // 2. Go to Registration 125 | await page.locator('button, a').filter({ hasText: 'Get Started Today' }).first().click(); 126 | const randSecurityUser = `security_test_${Date.now()}@example.com`; 127 | const randSecurityPhone = `9${Math.floor(100000000 + Math.random() * 900000000)}`; 128 | await page.locator('input#reg-email').fill(randSecurityUser); 129 | await page.locator('input#reg-phone').fill(randSecurityPhone); 130 | await page.locator('input#reg-pass').fill('Password123!'); 131 | await page.locator('input#reg-confirm-pass').fill('Password123!'); 132 | await page.locator('input#reg-policy').check(); 133 | await page.locator('button').filter({ hasText: 'Register Business' }).click(); 134 | 135 | // 3. Step 1: Negative OTP validations > 136 | await expect(page.getByText('Step 1 of 3: Contact Verification')).toBeVisible(); | ^ Error: expect(locator).toBeVisible() failed 137 | 138 | // Proceed button must be disabled initially 139 | await expect(page.locator('button').filter({ hasText: 'Next Step: Identity Verification' })).toBeDisabled(); 140 | 141 | // Submit invalid WhatsApp OTP 142 | await page.locator('button').filter({ hasText: 'Send WhatsApp OTP' }).click(); 143 | await page.locator('input[placeholder="Enter 123456"]').first().fill('000000'); 144 | 145 | // Capture dialog 146 | let alertMessage = ''; 147 | page.once('dialog', async dialog => { 148 | alertMessage = dialog.message(); 149 | await dialog.accept(); 150 | }); 151 | 152 | await page.locator('button').filter({ hasText: 'Verify Code' }).first().click(); 153 | 154 | // Give brief time/event loop ticks to ensure dialog handler fires 155 | await page.waitForTimeout(500); 156 | expect(alertMessage).toBe('Incorrect code. Enter 123456'); 157 | await expect(page.getByText('✓ Mobile & WhatsApp Verified')).toBeHidden(); 158 | 159 | // Correct the code to enable proceed 160 | await page.locator('input[placeholder="Enter 123456"]').first().clear(); 161 | await page.locator('input[placeholder="Enter 123456"]').first().fill('123456'); 162 | await page.locator('button').filter({ hasText: 'Verify Code' }).first().click(); 163 | await expect(page.getByText('✓ Mobile & WhatsApp Verified')).toBeVisible(); 164 | 165 | // Submit invalid Email OTP 166 | await page.locator('button').filter({ hasText: 'Send Email OTP' }).click(); 167 | await page.locator('input[placeholder="Enter 123456"]').last().fill('999999'); 168 | 169 | page.once('dialog', async dialog => { 170 | alertMessage = dialog.message(); 171 | await dialog.accept(); 172 | }); 173 | 174 | await page.locator('button').filter({ hasText: 'Verify Code' }).last().click(); 175 | await page.waitForTimeout(500); 176 | expect(alertMessage).toBe('Incorrect code. Enter 123456'); 177 | await expect(page.getByText('✓ Email Verified')).toBeHidden(); 178 | await expect(page.locator('button').filter({ hasText: 'Next Step: Identity Verification' })).toBeDisabled(); 179 | }); 180 | }); 181 | ```