Created
December 16, 2025 01:04
-
-
Save peteonrails/bc4c46a6ec3a7ee0196edb6981d95245 to your computer and use it in GitHub Desktop.
Playwright test for datepicker calendar positioning fix (PR #10638)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { chromium } = require('playwright'); | |
| const TARGET_URL = 'http://localhost:3000'; | |
| const LOGIN_EMAIL = 'emmie@tern.travel'; | |
| const LOGIN_PASSWORD = 'abc12345!1!1'; | |
| (async () => { | |
| console.log('Testing EXTREME edge case - datepicker at very top of viewport...\n'); | |
| const browser = await chromium.launch({ | |
| headless: false, | |
| slowMo: 50 | |
| }); | |
| const page = await browser.newPage(); | |
| await page.setViewportSize({ width: 1280, height: 600 }); // Smaller height to test more easily | |
| try { | |
| // Login | |
| console.log('Logging in...'); | |
| await page.goto(TARGET_URL, { waitUntil: 'networkidle' }); | |
| if (page.url().includes('session')) { | |
| await page.getByLabel('Email Address').fill(LOGIN_EMAIL); | |
| await page.getByLabel('Password').fill(LOGIN_PASSWORD); | |
| await page.getByRole('button', { name: 'Sign In', exact: true }).click(); | |
| await page.waitForLoadState('networkidle'); | |
| await page.waitForTimeout(1000); | |
| } | |
| console.log('Navigating to Commission page...'); | |
| await page.click('text=Commission'); | |
| await page.waitForLoadState('networkidle'); | |
| await page.waitForTimeout(500); | |
| // Click on Filter to open the filter panel | |
| const filterBtn = page.locator('button:has-text("Filter")'); | |
| if (await filterBtn.isVisible()) { | |
| await filterBtn.click(); | |
| await page.waitForTimeout(500); | |
| } | |
| // Find the first visible datepicker in the filter panel | |
| const datepickers = await page.locator('[data-controller="datepicker"]').all(); | |
| console.log(`Found ${datepickers.length} datepicker elements`); | |
| // Find a datepicker that's visible and can be interacted with | |
| let testDatepicker = null; | |
| for (let i = 0; i < datepickers.length; i++) { | |
| const dp = page.locator('[data-controller="datepicker"]').nth(i); | |
| if (await dp.isVisible().catch(() => false)) { | |
| const toggle = dp.locator('[data-datepicker-target="toggle"]'); | |
| if (await toggle.isVisible().catch(() => false)) { | |
| testDatepicker = dp; | |
| console.log(`Using datepicker at index ${i}`); | |
| break; | |
| } | |
| } | |
| } | |
| if (!testDatepicker) { | |
| console.log('No suitable datepicker found'); | |
| await page.screenshot({ path: '/tmp/datepicker-extreme-noselector.png' }); | |
| await browser.close(); | |
| return; | |
| } | |
| // Scroll so the datepicker is positioned right at the top edge (within 50-70px) | |
| console.log('\n=== TEST: Positioning datepicker at extreme top ==='); | |
| await page.evaluate(() => { | |
| // Scroll the filter panel contents or the page so datepicker is at top | |
| const dp = document.querySelector('[data-controller="datepicker"]:not([style*="display: none"])'); | |
| if (dp) { | |
| const rect = dp.getBoundingClientRect(); | |
| // Position it very close to top (around 50px from top - just below header) | |
| window.scrollBy(0, rect.top - 55); | |
| } | |
| }); | |
| await page.waitForTimeout(300); | |
| // Get the datepicker's new position | |
| const bounds = await testDatepicker.boundingBox(); | |
| console.log(`Datepicker input is now at y=${bounds.y}px (aiming for ~50-60px from top)`); | |
| // Take screenshot before opening | |
| await page.screenshot({ path: '/tmp/datepicker-extreme-1-before.png' }); | |
| // Open the calendar | |
| const toggle = testDatepicker.locator('[data-datepicker-target="toggle"]'); | |
| await toggle.click(); | |
| await page.waitForTimeout(500); | |
| // Take screenshot with calendar open | |
| await page.screenshot({ path: '/tmp/datepicker-extreme-2-calendar.png' }); | |
| // Check calendar position | |
| const calendar = page.locator('[data-datepicker-target="calendar"]'); | |
| if (await calendar.isVisible()) { | |
| const calBounds = await calendar.boundingBox(); | |
| console.log(`\nCalendar positioned at y=${calBounds.y}px`); | |
| console.log(`Calendar height: ${calBounds.height}px`); | |
| console.log(`Calendar bottom: ${calBounds.y + calBounds.height}px`); | |
| // The fix ensures calendar y is at least 60px | |
| if (calBounds.y >= 60) { | |
| console.log('\n✅ PASS: Calendar y position is >= 60px'); | |
| console.log(' The fix is working - calendar stays below the header!'); | |
| } else if (calBounds.y >= 0) { | |
| console.log('\n⚠️ WARNING: Calendar y position is ' + calBounds.y + 'px (< 60px)'); | |
| console.log(' Calendar might partially overlap with header'); | |
| } else { | |
| console.log('\n❌ FAIL: Calendar y position is negative!'); | |
| console.log(' Calendar is cut off at the top'); | |
| } | |
| // Check if month/year navigation is visible (the main issue from the ticket) | |
| const monthNav = calendar.locator('button').first(); | |
| if (await monthNav.isVisible()) { | |
| console.log('\n✅ Calendar navigation controls are visible'); | |
| } | |
| } else { | |
| console.log('Calendar not visible'); | |
| } | |
| // Close and test with even more extreme positioning | |
| await page.keyboard.press('Escape'); | |
| await page.waitForTimeout(200); | |
| console.log('\n=== TEST 2: Even more extreme - datepicker at y=10px ==='); | |
| await page.evaluate(() => { | |
| const dp = document.querySelector('[data-controller="datepicker"]:not([style*="display: none"])'); | |
| if (dp) { | |
| const rect = dp.getBoundingClientRect(); | |
| window.scrollBy(0, rect.top - 10); | |
| } | |
| }); | |
| await page.waitForTimeout(300); | |
| const bounds2 = await testDatepicker.boundingBox(); | |
| console.log(`Datepicker input is now at y=${bounds2.y}px`); | |
| await toggle.click(); | |
| await page.waitForTimeout(500); | |
| await page.screenshot({ path: '/tmp/datepicker-extreme-3-very-top.png' }); | |
| if (await calendar.isVisible()) { | |
| const calBounds2 = await calendar.boundingBox(); | |
| console.log(`Calendar positioned at y=${calBounds2.y}px`); | |
| if (calBounds2.y >= 60) { | |
| console.log('\n✅ PASS: Even with extreme positioning, calendar stays at y >= 60px'); | |
| console.log(' The limiter in the code is working correctly!'); | |
| } else { | |
| console.log('\n❌ FAIL: Calendar at y=' + calBounds2.y + 'px is too high'); | |
| } | |
| } | |
| console.log('\n=== All tests completed ==='); | |
| console.log('Check screenshots in /tmp/datepicker-extreme-*.png'); | |
| } catch (error) { | |
| console.error('Test error:', error.message); | |
| await page.screenshot({ path: '/tmp/datepicker-extreme-error.png' }); | |
| } finally { | |
| await page.waitForTimeout(2000); | |
| await browser.close(); | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment