// Shared helpers. Everything here drives the UI the way a person would: the // point of this suite is the wiring between browser, DDP and Mongo, so reaching // into Meteor.call() from the page would defeat it. // // ⚠️ NADA de selectores por id. `imports/ui/components/Utils/TestUtils.js` // devuelve el id SOLO en desarrollo, así que contra un bundle de producción // —que es justo lo que levanta el job nocturno de CI— esos elementos no lo // llevan. Aquí se va por href, rol y nombre de campo, que existen en los dos. export const NAV = { zonas: 'nav a[href="/zones"]', fuegos: 'nav a[href="/fires"]', perfil: 'nav a[href="/profile"]', entrar: 'nav a[href="/login"]', salir: 'nav a[href="/logout"]', misZonas: 'nav a[href="/subscriptions"]' }; export const botonRegistro = page => page.getByRole('button', { name: 'Registrarse', exact: true }); export const botonEntrar = page => page.getByRole('button', { name: 'Iniciar sesión', exact: true }); // A fresh address per test: the seed removes every e2e+* user, and reusing one // across specs makes failures depend on the order they ran in. export const newEmail = () => `e2e+${Date.now()}${Math.floor(Math.random() * 1000)}@test.com`; export const signUp = async (page, email = newEmail()) => { await page.goto('/signup'); await page.fill('input[name=firstName]', 'E2E'); await page.fill('input[name=lastName]', 'Tester'); await page.fill('input[name=emailAddress]', email); await page.fill('input[name=password]', 'password'); await page.check('input[name=tos]'); await botonRegistro(page).click(); // Signing up lands on the zones page. await page.waitForURL('**/subscriptions', { timeout: 30000 }); return email; }; export const logIn = async (page, email, password = 'password') => { await page.goto('/login'); await page.fill('input[name=emailAddress]', email); await page.fill('input[name=password]', password); await botonEntrar(page).click(); }; // The map only settles once leaflet has laid out its panes and the tiles for the // current viewport are in. export const waitForMap = async (page) => { await page.locator('.leaflet-container').first().waitFor({ state: 'visible', timeout: 60000 }); await page.waitForTimeout(1500); }; // Creates a zone through the real flow: the button on the zones map, the // selection map, and the subscribe button. This is the flow that froze staging. export const addZoneThroughTheMap = async (page) => { await page.goto('/subscriptions'); await waitForMap(page); await page.getByRole('button', { name: 'Añadir zona' }).click(); await page.waitForURL('**/subscriptions/new', { timeout: 30000 }); await waitForMap(page); const map = page.locator('.leaflet-container').first(); const box = await map.boundingBox(); // Click slightly off-centre: the marker moves there, which also proves the // map is interactive and not a dead tile layer. await page.mouse.click(box.x + (box.width / 2) + 20, box.y + (box.height / 2) + 20); await page.waitForTimeout(1000); await page.getByRole('button', { name: /Suscribirme/ }).click(); await page.waitForURL('**/subscriptions', { timeout: 60000 }); };