File size: 2,747 Bytes
521a9b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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;
}