Spaces:
Sleeping
Sleeping
| import type { Page } from 'playwright'; | |
| import { logger } from '../../utils/logger'; | |
| import { SELECTORS } from '../selectors'; | |
| import { acceptEulaEverywhere, acceptEulaUntilSettled } from './login'; | |
| /** | |
| * Navigate to the target assignment within a class. | |
| * | |
| * 1. Find and click the class by title | |
| * 2. Find and click the assignment (by title or first available) | |
| * 3. Return the assignment launch URL for later refresh | |
| */ | |
| export async function navigateToAssignment( | |
| page: Page, | |
| classTitle: string, | |
| assignmentTitle?: string | null, | |
| ): Promise<string> { | |
| // ---- Open class ---- | |
| logger.info('Opening class', { classTitle }); | |
| if (!classTitle || classTitle.trim() === '') { | |
| throw new Error('Class title is empty - cannot navigate to assignment.'); | |
| } | |
| const escapedTitle = classTitle.replace(/"/g, '\\"'); | |
| const exact = page.locator(`a[title="${escapedTitle}"]`).first(); | |
| const fallback = page | |
| .locator(SELECTORS.class.classNameLink) | |
| .filter({ hasText: classTitle }) | |
| .first(); | |
| const link = | |
| (await exact.isVisible({ timeout: 5000 }).catch(() => false)) | |
| ? exact | |
| : fallback; | |
| await link.waitFor({ state: 'visible', timeout: 30000 }); | |
| await Promise.all([ | |
| page | |
| .waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 60000 }) | |
| .catch(() => null), | |
| link.click({ force: true }), | |
| ]); | |
| await page.waitForTimeout(1500); | |
| await acceptEulaEverywhere(page); | |
| const classUrl = page.url(); | |
| logger.info('Class page loaded', { classUrl }); | |
| // ---- Open assignment ---- | |
| // Ensure we're on the class page | |
| if (page.url() !== classUrl) { | |
| await page.goto(classUrl, { | |
| waitUntil: 'domcontentloaded', | |
| timeout: 60000, | |
| }); | |
| await page.waitForTimeout(1500); | |
| } | |
| await acceptEulaUntilSettled(page, 5000); | |
| let assignmentButton; | |
| if (assignmentTitle) { | |
| logger.info('Looking for assignment', { assignmentTitle }); | |
| assignmentButton = page | |
| .locator(SELECTORS.assignment.assignmentRow) | |
| .filter({ hasText: assignmentTitle }) | |
| .locator(SELECTORS.assignment.openButton) | |
| .first(); | |
| } else { | |
| logger.info('Looking for first available assignment'); | |
| assignmentButton = page | |
| .locator(SELECTORS.assignment.allOpenButtons) | |
| .first(); | |
| } | |
| await assignmentButton.waitFor({ state: 'visible', timeout: 30000 }); | |
| await Promise.all([ | |
| page | |
| .waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 60000 }) | |
| .catch(() => null), | |
| assignmentButton.click({ force: true }), | |
| ]); | |
| await page.waitForTimeout(5000); | |
| await acceptEulaUntilSettled(page, 7000); | |
| const assignmentLaunchUrl = page.url(); | |
| logger.info('Assignment page loaded', { assignmentLaunchUrl }); | |
| return assignmentLaunchUrl; | |
| } | |