@@ -21,6 +21,8 @@ const test = require("../src/test.js")({
21
21
OTV_NATIONALITY : null ,
22
22
OTV_NATIONALITY_OF_FAMILY : null ,
23
23
OTV_LAST_NAME : null ,
24
+ OTV_REASON_TYPE : "Erwerbstätigkeit" ,
25
+ OTV_REASON : "selbstständigen Tätigkeit - Erteilung" ,
24
26
} ) ;
25
27
26
28
test ( "appointment" , async ( { context, params } , testInfo ) => {
@@ -44,46 +46,45 @@ test("appointment", async ({ context, params }, testInfo) => {
44
46
lastName : params . OTV_LAST_NAME ,
45
47
} ) ;
46
48
return ;
47
- } else {
48
- const dateURLs = await getDateURLs ( servicePage , {
49
- locations : params . APPOINTMENT_LOCATIONS ,
50
- earliestDate : params . APPOINTMENT_EARLIEST_DATE ,
51
- latestDate : params . APPOINTMENT_LATEST_DATE ,
52
- } ) ;
53
- expect ( dateURLs . length , "No available appointment dates" ) . toBeGreaterThan (
54
- 0
55
- ) ;
49
+ }
50
+ const dateURLs = await getDateURLs ( servicePage , {
51
+ locations : params . APPOINTMENT_LOCATIONS ,
52
+ earliestDate : params . APPOINTMENT_EARLIEST_DATE ,
53
+ latestDate : params . APPOINTMENT_LATEST_DATE ,
54
+ } ) ;
55
+ expect ( dateURLs . length , "No available appointment dates" ) . toBeGreaterThan (
56
+ 0
57
+ ) ;
56
58
57
- const appointmentURLs = await getAppointmentURLs ( context , dateURLs , {
58
- earliestTime : params . APPOINTMENT_EARLIEST_TIME ,
59
- latestTime : params . APPOINTMENT_LATEST_TIME ,
60
- } ) ;
61
- expect (
62
- appointmentURLs . length ,
63
- "No available appointments on any appointment date"
64
- ) . toBeGreaterThan ( 0 ) ;
65
-
66
- for ( const appointmentURL of appointmentURLs ) {
67
- try {
68
- await bookAppointment (
69
- context ,
70
- appointmentURL ,
71
- {
72
- mailSlurpAPIKey : params . MAILSLURP_API_KEY ,
73
- mailSlurpInboxId : params . MAILSLURP_INBOX_ID ,
74
- formName : params . FORM_NAME ,
75
- formTakeSurvey : params . FORM_TAKE_SURVEY ,
76
- formNote : params . FORM_NOTE ,
77
- formPhone : params . FORM_PHONE ,
78
- } ,
79
- testInfo
80
- ) ;
81
- return ;
82
- } catch ( e ) {
83
- logger . error (
84
- `Booking appointment failed at ${ appointmentURL } : ${ e . message } `
85
- ) ;
86
- }
59
+ const appointmentURLs = await getAppointmentURLs ( context , dateURLs , {
60
+ earliestTime : params . APPOINTMENT_EARLIEST_TIME ,
61
+ latestTime : params . APPOINTMENT_LATEST_TIME ,
62
+ } ) ;
63
+ expect (
64
+ appointmentURLs . length ,
65
+ "No available appointments on any appointment date"
66
+ ) . toBeGreaterThan ( 0 ) ;
67
+
68
+ for ( const appointmentURL of appointmentURLs ) {
69
+ try {
70
+ await bookAppointment (
71
+ context ,
72
+ appointmentURL ,
73
+ {
74
+ mailSlurpAPIKey : params . MAILSLURP_API_KEY ,
75
+ mailSlurpInboxId : params . MAILSLURP_INBOX_ID ,
76
+ formName : params . FORM_NAME ,
77
+ formTakeSurvey : params . FORM_TAKE_SURVEY ,
78
+ formNote : params . FORM_NOTE ,
79
+ formPhone : params . FORM_PHONE ,
80
+ } ,
81
+ testInfo
82
+ ) ;
83
+ return ;
84
+ } catch ( e ) {
85
+ logger . error (
86
+ `Booking appointment failed at ${ appointmentURL } : ${ e . message } `
87
+ ) ;
87
88
}
88
89
}
89
90
throw new Error ( "Booking failed for all appointments." ) ;
@@ -130,9 +131,9 @@ async function getServicePage(page, url) {
130
131
async function getDateURLs ( page , { locations, earliestDate, latestDate } ) {
131
132
return await test
132
133
. step ( "get date urls" , async ( ) => {
133
- page . on ( "load" , async ( ) => {
134
- await Promise . all ( [ checkRateLimitExceeded ( page ) , checkCaptcha ( page ) ] ) ;
135
- } ) ;
134
+ // page.on("load", async () => {
135
+ // await Promise.all([checkRateLimitExceeded(page), checkCaptcha(page)]);
136
+ // });
136
137
await selectLocations ( page , {
137
138
locations : locations ? locations . split ( "," ) : [ ] ,
138
139
} ) ;
@@ -562,44 +563,65 @@ async function otvAppointment(
562
563
page . getByRole ( "heading" , { name : "Sitzungsende" } ) ,
563
564
"Unexpectedly logged out"
564
565
) . not . toBeVisible ( { timeout : 1 } ) ,
565
- checkCaptcha ( page ) ,
566
- checkRateLimitExceeded ( page ) ,
567
- expect (
568
- page . getByText ( "aktuell keine Termine frei" ) ,
569
- "No appointments currently available"
570
- ) . not . toBeVisible ( { timeout : 1 } ) ,
566
+ // expect(
567
+ // page.getByText("aktuell keine Termine frei"),
568
+ // "No appointments currently available"
569
+ // ).not.toBeVisible({ timeout: 1 }),
571
570
] ) ;
572
571
} ) ;
573
572
await page . getByRole ( "link" , { name : "Termin buchen" } ) . click ( ) ;
574
573
await page . waitForURL ( "**/otv.verwalt-berlin.de/**" ) ;
575
574
await page . getByRole ( "link" , { name : "Termin buchen" } ) . click ( ) ;
576
- await page . getByRole ( "checkbox" ) . check ( ) ;
575
+ await page . waitForURL ( "https://otv.verwalt-berlin.de/ams/TerminBuchen" ) ;
576
+ await page . getByRole ( "checkbox" , { name : "Ich erkläre hiermit" } ) . check ( ) ;
577
577
await page . getByRole ( "button" , { name : "Weiter" } ) . click ( ) ;
578
- await page . getByLabel ( "Staatsangehörigkeit" ) . selectOption ( nationality ) ;
579
- await page . getByLabel ( "Anzahl der Personen" ) . selectOption ( numberOfPeople ) ;
580
578
await page
581
- . getByLabel ( "mit einem Familienangehörigen" )
582
- . selectOption ( withFamily === "true" ? "1" : "2" ) ;
583
- if ( withFamily ) {
584
- await page
585
- . getByLabel ( "Staatsangehörigkeit des Familienangehörigen" )
586
- . selectOption ( familyNationality ) ;
587
- }
588
- await page . getByLabel ( serviceName ) . check ( ) ;
589
- if (
590
- serviceName === "Aufenthaltstitel - beantragen" ||
591
- serviceName === "Aufenthaltstitel - verlängern"
592
- ) {
593
- await page . getByLabel ( residenceReasonType ) . check ( ) ;
579
+ . getByLabel ( "Staatsangehörigkeit (Wenn Sie" )
580
+ . selectOption ( nationality ) ;
581
+ await page . locator ( "#xi-sel-422" ) . selectOption ( numberOfPeople ) ;
582
+ await expect ( async ( ) => {
583
+ const withFamilyLocator = page . getByLabel (
584
+ "Leben Sie in Berlin zusammen mit einem Familienangehörigen (z.B. Ehepartner, Kind)*" ,
585
+ { exact : true }
586
+ ) ;
587
+ // Select the wrong option first to retry selecting the correct option.
588
+ await withFamilyLocator . selectOption ( withFamily === "true" ? "2" : "1" ) ;
589
+ // Select the correct option.
590
+ await withFamilyLocator . selectOption ( withFamily === "true" ? "1" : "2" ) ;
591
+ // TODO: familyNationalityLocator is untested so far.
592
+ const familyNationalityLocator = page . getByLabel (
593
+ "Staatsangehörigkeit des Familienangehörigen"
594
+ ) ;
595
+ if ( await familyNationalityLocator . isVisible ( ) ) {
596
+ await familyNationalityLocator . selectOption ( familyNationality ) ;
597
+ }
598
+ await expect ( page . getByLabel ( serviceName ) ) . toHaveCount ( 1 ) ;
599
+ } ) . toPass ( ) ;
600
+ // TODO: serviceLocator is not visible for some reason.
601
+ const serviceLocator = page . getByLabel ( serviceName ) ;
602
+ await serviceLocator . check ( ) ;
603
+ // TODO: Everything below is untested so far.
604
+ const residenceReasonTypeLocator = page . getByLabel ( residenceReasonType ) ;
605
+ if ( await residenceReasonTypeLocator . isVisible ( ) ) {
606
+ await residenceReasonTypeLocator . check ( ) ;
594
607
}
595
608
await page . getByLabel ( residenceReason ) . check ( ) ;
596
- if (
597
- residenceReason === "Aufenthaltsgestattung - verlängern" ||
598
- residenceReason === "Duldung - verlängern"
599
- ) {
600
- await page . getByLabel ( "Nachnamen" ) . fill ( lastName ) ;
609
+ const lastNameLocator = page . getByLabel ( "Nachnamen" ) ;
610
+ if ( await lastNameLocator . isVisible ( ) ) {
611
+ await lastNameLocator . fill ( lastName ) ;
601
612
}
602
613
await page . getByRole ( "button" , { name : "Weiter" } ) . click ( ) ;
603
- // TODO: If we actually get a calendar, book the appointment lol
614
+ await page . getByRole ( "row" ) . getByRole ( "link" ) . first ( ) . click ( ) ;
615
+ await page
616
+ . getByLabel ( "Bitte wählen Sie einen Tag" )
617
+ . selectOption ( { label : / d { 2 } : \d { 2 } / } ) ;
618
+ // Solve captcha with 2Captcha chrome extension
619
+ // TODO: Solve captcha with 2Captcha API
620
+ await page . locator ( ".captcha-solver" ) . click ( ) ;
621
+ await expect (
622
+ page . locator ( `.captcha-solver[data-state="solved"]` )
623
+ ) . toBeVisible ( { timeout : 150_000 } ) ;
624
+ // Submit booking
625
+ await page . getByRole ( "button" , { name : "Weiter" } ) . click ( ) ;
604
626
} ) ;
605
627
}
0 commit comments