@@ -24,6 +24,7 @@ import org.openqa.selenium.By
2424import org .openqa .selenium .support .ui .Select
2525import org .slf4j .event .Level
2626
27+ import scala .jdk .CollectionConverters .*
2728import java .util .Optional
2829
2930class SvFrontendIntegrationTest
@@ -308,6 +309,171 @@ class SvFrontendIntegrationTest
308309 }
309310 }
310311
312+ def createProposal (action : String , effectiveAtThreshold : Boolean = true )(
313+ extraFormOps : WebDriverType => Unit
314+ )(implicit
315+ env : SpliceTestConsoleEnvironment
316+ ) = {
317+ val requestReasonUrl = " https://new-proposal-url.com/"
318+ val requestReasonBody = " This is a summary of the proposal"
319+ val thresholdDeadline = " 2034-07-12 00:12"
320+ val effectiveDate = " 2034-07-13 00:12"
321+
322+ withFrontEnd(" sv1" ) { implicit webDriver =>
323+ val previousInflightProposalsSize = getInflightProposals().size
324+ previousInflightProposalsSize shouldBe 0
325+ // logger.debug(s"tesco at definition previousInflightProposalsSize: $previousInflightProposalsSize")
326+
327+ actAndCheck(
328+ " sv1 operator can login and browse to the governance tab" , {
329+ go to s " http://localhost: $sv1UIPort/governance-beta "
330+ loginOnCurrentPage(sv1UIPort, sv1Backend.config.ledgerApiUser)
331+ },
332+ )(
333+ " sv1 can navigate to the create proposal page" ,
334+ _ => {
335+ val initiateProposalButton = find(id(" initiate-proposal-button" ))
336+ clue(" initiate proposal button is visible" ) {
337+ // eventuallySucceeds() {
338+ initiateProposalButton should not be empty
339+
340+ click on id(" initiate-proposal-button" )
341+ // }
342+ }
343+
344+ clue(" Select an Action page is visible" ) {
345+ find(id(" select-action" )) should not be empty
346+ }
347+
348+ clickOn(id(" select-action" ))
349+
350+ eventually() {
351+ val actionItem = webDriver.findElement(By .cssSelector(s " [data-testid=' $action'] " ))
352+ actionItem.click()
353+ }
354+
355+ webDriver.findElement(By .tagName(" body" )).click()
356+
357+ val nextButton = webDriver.findElement(By .cssSelector(s " [data-testid='next-button'] " ))
358+ nextButton.click()
359+
360+ find(id(" offboard-sv-action" )) should not be empty
361+
362+ },
363+ )
364+
365+ actAndCheck(
366+ " sv1 operator can create a new proposal" , {
367+
368+ setThresholdDeadline(" sv1" , thresholdDeadline, " offboard-sv-expiry-date-field" )
369+
370+ if (effectiveAtThreshold) {
371+ inside(find(id(" effective-at-threshold-radio" ))) { case Some (element) =>
372+ element.underlying.click()
373+ }
374+ } else {
375+ setEffectiveDate2(" sv1" , effectiveDate)
376+ }
377+
378+ inside(find(id(" offboard-sv-summary" ))) { case Some (element) =>
379+ element.underlying.sendKeys(requestReasonBody)
380+ }
381+
382+ inside(find(id(" offboard-sv-url" ))) { case Some (element) =>
383+ element.underlying.sendKeys(requestReasonUrl)
384+ }
385+
386+ extraFormOps(webDriver)
387+
388+ clickVoteRequestSubmitButtonOnceEnabled2()
389+ },
390+ )(
391+ " sv1 can see the new proposal" ,
392+ _ => {
393+ // find(id("inflight-proposals-section-title")) should not be empty
394+
395+ val currentInflightProposals = getInflightProposals()
396+ currentInflightProposals.size shouldBe previousInflightProposalsSize + 1
397+
398+ clue(" click the new proposal" ) {
399+ // println(s"tesco currentinflight: ${currentInflightProposals.asScala.head}")
400+ val link = webDriver
401+ .findElement(By .cssSelector(" [data-testid='inflight-proposals-row-link']" ))
402+ // webDriver.executeScript("arguments[0].scrollIntoView(true);", link)
403+ // Not sure why this is the only way to make it work but hewre we are.
404+ webDriver.executeScript(" arguments[0].click();" , link)
405+
406+ // link.click()
407+ // webDriver.executeScript("arguments[0].click();", link)
408+ // currentInflightProposals.asScala.head.click()
409+ }
410+ },
411+ )
412+
413+ }
414+
415+ withFrontEnd(" sv2" ) { implicit webDriver =>
416+ val (_, reviewButton) = actAndCheck(
417+ " sv2 operator can login and browse to the governance page" , {
418+ go to s " http://localhost: $sv2UIPort/governance-beta "
419+ loginOnCurrentPage(sv2UIPort, sv2Backend.config.ledgerApiUser)
420+ },
421+ )(
422+ " sv2 can see the new vote request" ,
423+ _ => {
424+ eventuallySucceeds() {
425+ val actionsRequired = getActionRequiredElems()
426+ actionsRequired.size shouldBe 1
427+
428+ webDriver.executeScript(" arguments[0].click();" , actionsRequired.asScala.head)
429+ }
430+ // actionsRequired.asScala.head.click()
431+
432+ inside(find(id(" your-vote-reason-input" ))) { case Some (element) =>
433+ element.underlying.sendKeys(" A sample reason" )
434+ }
435+
436+ inside(find(id(" your-vote-url-input" ))) { case Some (element) =>
437+ element.underlying.sendKeys(" https://my-splice-vote-url.com" )
438+ }
439+
440+ webDriver.findElement(By .cssSelector(s " [data-testid='your-vote-accept'] " )).click()
441+
442+ eventuallyClickOn(id(" submit-vote-button" ))
443+
444+ clue(" wait for the vote submission success message" ) {
445+ eventuallySucceeds() {
446+ inside(find(xpath(" //*[@data-testid='vote-submission-success']" ))) {
447+ case Some (element) =>
448+ element.text shouldBe " Vote successfully updated!"
449+ }
450+ }
451+ }
452+ },
453+ )
454+ }
455+
456+ withFrontEnd(" sv1" ) { implicit webDriver =>
457+ clue(" sv1 operator can see the new vote from sv2" ) {
458+ val sv2PartyId = sv2Backend.getDsoInfo().svParty.toProtoPrimitive
459+ val votes =
460+ webDriver.findElements(By .cssSelector(" [data-testid='proposal-details-vote']" ))
461+ votes.size shouldBe 1
462+
463+ val voterInput = votes.asScala.head
464+ .findElement(
465+ By .cssSelector(" [data-testid='proposal-details-voter-party-id-input']" )
466+ )
467+ voterInput.getAttribute(" value" ) shouldBe sv2PartyId
468+ }
469+
470+ // actAndCheck(
471+ // "sv1 operator can see the vote request detail", {
472+ // },
473+ // )("", _ => {})
474+ }
475+ }
476+
311477 def testCreateAndVoteDsoRulesAction (action : String , effectiveAtThreshold : Boolean = true )(
312478 fillUpForm : WebDriverType => Unit
313479 )(validateRequestedActionInModal : WebDriverType => Unit )(implicit
@@ -564,6 +730,24 @@ class SvFrontendIntegrationTest
564730 }
565731 }
566732
733+ " NEW UI: Offboard" in { implicit env =>
734+ val sv3PartyId = sv3Backend.getDsoInfo().svParty.toProtoPrimitive
735+
736+ createProposal(" SRARC_OffboardSv" ) { implicit webDriver =>
737+ // eventually() {
738+ find(id(" offboard-sv-member-dropdown" )) match {
739+ case Some (element) => element.underlying.click()
740+ case None =>
741+ fail(" Could not find offboard-sv-member-dropdown" )
742+ }
743+
744+ val memberSelect = webDriver.findElement(By .cssSelector(s " [data-value=' $sv3PartyId'] " ))
745+ memberSelect.click()
746+ webDriver.findElement(By .tagName(" body" )).click()
747+ // }
748+ }
749+ }
750+
567751 " can create a valid SRARC_OffboardSv vote request and cast vote on it" in { implicit env =>
568752 val sv3PartyId = sv3Backend.getDsoInfo().svParty.toProtoPrimitive
569753 testCreateAndVoteDsoRulesAction(" SRARC_OffboardSv" ) { webDriver =>
@@ -1141,6 +1325,14 @@ class SvFrontendIntegrationTest
11411325 .getOrElse(0 )
11421326 }
11431327
1328+ def getInflightProposals ()(implicit webDriver : WebDriverType ) = {
1329+ webDriver.findElements(By .cssSelector(" [data-testid='inflight-proposals-row-link']" ))
1330+ }
1331+
1332+ def getActionRequiredElems ()(implicit webDriver : WebDriverType ) = {
1333+ webDriver.findElements(By .cssSelector(" [data-testid='action-required-card-link']" ))
1334+ }
1335+
11441336 def getVoteRequestsRejectedSize ()(implicit webDriver : WebDriverType ) = {
11451337 val tbodyRejected = find(id(" sv-vote-results-rejected-table-body" ))
11461338 tbodyRejected
0 commit comments