Repository: cal-itp/benefits

Issue:
Figure out why Login.gov button tests don't pass in GitHub
See #402 

E.g. in run [`5841870888`](https://github.com/cal-itp/benefits/runs/5841870888?check_suite_focus=true) the "Contains Login.gov button" test failed.

Eventually in [`29fb047`](https://github.com/cal-itp/benefits/pull/402/commits/29fb047b64327c7d1cee2a2ea39c2d0165ecc3da) we skipped the failing test to unblock the merge.

Yet this test (and other UI tests) pass when running locally, in the devcontainer:

![image](https://user-images.githubusercontent.com/1783439/161853938-7b04790f-a48b-453d-9527-9464f95be12c.png)

![image](https://user-images.githubusercontent.com/1783439/161853989-20de0ba6-3e2c-4888-973b-1fc51cb54f6d.png)

And in the Cypress runner:

![image](https://user-images.githubusercontent.com/1783439/161855976-d2380550-3c0d-42ad-bc8a-939ab649e6eb.png)


Discussion:

Resolving patch:
diff --git a/benefits/core/viewmodels.py b/benefits/core/viewmodels.py
--- a/benefits/core/viewmodels.py
+++ b/benefits/core/viewmodels.py
@@ -88,20 +88,6 @@ def __init__(self, icon, alt):
         self.alt = alt
 
 
-class MediaItem:
-    """
-    Represents a list item:
-    * icon: core.viewmodels.Icon
-    * heading: str
-    * details: str
-    """
-
-    def __init__(self, icon, heading, details):
-        self.icon = icon
-        self.heading = heading
-        self.details = details
-
-
 class Page:
     """
     Represents a page of content:
@@ -109,7 +95,6 @@ class Page:
     * noimage: bool
     * icon: core.viewmodels.Icon
     * content_title: str
-    * media: core.viewmodels.MediaItem[]
     * paragraphs: str[]
     * form: django.forms.Form
     * forms: django.forms.Form[]
@@ -128,7 +113,6 @@ def __init__(self, **kwargs):
         self.noimage = kwargs.get("noimage", False)
         self.icon = kwargs.get("icon")
         self.content_title = kwargs.get("content_title")
-        self.media = kwargs.get("media", [])
         self.paragraphs = kwargs.get("paragraphs", [])
         self.steps = kwargs.get("steps")
 
diff --git a/benefits/eligibility/views.py b/benefits/eligibility/views.py
--- a/benefits/eligibility/views.py
+++ b/benefits/eligibility/views.py
@@ -58,35 +58,71 @@ def index(request):
 def start(request):
     """View handler for the eligibility verification getting started screen."""
 
-    session.update(request, eligibility_types=[])
+    session.update(request, eligibility_types=[], origin=reverse("eligibility:start"))
     verifier = session.verifier(request)
 
     if verifier.requires_authentication:
         auth_provider = verifier.auth_provider
-        button = viewmodels.Button.external(text=_(auth_provider.sign_in_button_label), url="#", id="login")
+        button = viewmodels.Button.external(
+            text=_(auth_provider.sign_in_button_label),
+            url="http://calitp.org",  # Placeholder URL for now, for UI specs to pass
+            id="login",
+        )
+        auth_media = dict(
+            icon=viewmodels.Icon("idscreencheck", pgettext("image alt text", "core.icons.idscreencheck")),
+            heading=_("eligibility.media.heading"),
+            details=_("eligibility.media.details"),
+            links=[
+                viewmodels.Button.link(
+                    classes="btn-text btn-link",
+                    text=_("eligibility.media.link_text"),
+                    url=_("eligibility.media.link_url"),
+                    target="_blank",
+                    rel="noopener noreferrer",
+                )
+            ],
+        )
     else:
         button = viewmodels.Button.primary(text=_("eligibility.buttons.continue"), url=reverse("eligibility:confirm"))
 
     page = viewmodels.Page(
         title=_("eligibility.pages.start.title"),
-        content_title=_(verifier.start_content_title),
-        media=[
-            viewmodels.MediaItem(
-                icon=viewmodels.Icon("idcardcheck", pgettext("image alt text", "core.icons.idcardcheck")),
-                heading=_(verifier.start_item_name),
-                details=_(verifier.start_item_description),
-            ),
-            viewmodels.MediaItem(
-                icon=viewmodels.Icon("bankcardcheck", pgettext("image alt text", "core.icons.bankcardcheck")),
-                heading=_("eligibility.pages.start.items[1].title"),
-                details=_("eligibility.pages.start.items[1].text"),
-            ),
-        ],
+        noimage=True,
         paragraphs=[_(verifier.start_blurb)],
         button=button,
     )
 
-    return TemplateResponse(request, "eligibility/start.html", page.context_dict())
+    ctx = page.context_dict()
+    ctx["title"] = _(verifier.start_content_title)
+    ctx["media"] = [
+        dict(
+            icon=viewmodels.Icon("idcardcheck", pgettext("image alt text", "core.icons.idcardcheck")),
+            heading=_(verifier.start_item_name),
+            details=_(verifier.start_item_description),
+        ),
+        dict(
+            icon=viewmodels.Icon("bankcardcheck", pgettext("image alt text", "core.icons.bankcardcheck")),
+            heading=_("eligibility.pages.start.items[1].title"),
+            details=_("eligibility.pages.start.items[1].text"),
+            links=[
+                viewmodels.Button.link(
+                    classes="btn-text btn-link",
+                    text=_("eligibility.pages.start.items[1].button[0].link"),
+                    url=_("eligibility.pages.start.items[1].button[0].url"),
+                ),
+                viewmodels.Button.link(
+                    classes="btn-text btn-link",
+                    text=_("eligibility.pages.start.items[1].button[1].link"),
+                    url=_("eligibility.pages.start.items[1].button[1].url"),
+                ),
+            ],
+        ),
+    ]
+
+    if verifier.requires_authentication:
+        ctx["media"].insert(0, auth_media)
+
+    return TemplateResponse(request, "eligibility/start.html", ctx)
 
 
 @decorator_from_middleware(middleware.AgencySessionRequired)


Test patch:
diff --git a/tests/cypress/package-lock.json b/tests/cypress/package-lock.json
--- a/tests/cypress/package-lock.json
+++ b/tests/cypress/package-lock.json
@@ -408,6 +408,7 @@
       "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==",
       "dev": true,
       "dependencies": {
+        "colors": "1.4.0",
         "string-width": "^4.2.0"
       },
       "engines": {
@@ -748,6 +749,7 @@
       "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
       "dev": true,
       "dependencies": {
+        "@types/yauzl": "^2.9.1",
         "debug": "^4.1.1",
         "get-stream": "^5.1.0",
         "yauzl": "^2.10.0"
@@ -1111,6 +1113,7 @@
       "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
       "dev": true,
       "dependencies": {
+        "graceful-fs": "^4.1.6",
         "universalify": "^2.0.0"
       },
       "optionalDependencies": {
diff --git a/tests/cypress/specs/ui/eligibility-auth.spec.js b/tests/cypress/specs/ui/eligibility-auth.spec.js
new file mode 100644
--- /dev/null
+++ b/tests/cypress/specs/ui/eligibility-auth.spec.js
@@ -0,0 +1,39 @@
+const agencies = require("../../fixtures/transit-agencies");
+
+const eligibility_start_url = "/eligibility/start";
+
+describe("Multiple verifier, with AuthProvider: Eligibility start page spec", () => {
+  beforeEach(() => {
+    cy.visit("/");
+    // Selecting ABC will go down the multiple verifier flow
+    cy.contains(agencies[0].fields.short_name).click();
+    cy.contains("Get started").click();
+    // Selecting first radio button, Senior Discount Program, will go down Login.gov flow
+    cy.get("input:radio").first().click();
+    cy.contains("Continue").click();
+  });
+
+  it("Has the correct URL", () => {
+    cy.url().should("include", eligibility_start_url);
+  });
+
+  it("Has the correct copy for Senior Discount Program instructions", () => {
+    cy.contains(
+      "Great, you’ll need to do three things to link your transit discount to your bank card."
+    );
+    cy.contains("Provide your California ID number");
+    cy.get(".media-list").children().should("have.length", 3);
+  });
+
+  it("Has the correct copy for Authorization instructions", () => {
+    cy.get(".media-list").contains("Sign in to your Login.gov account");
+    cy.contains(
+      "You will be able to create an account if you’re not already signed up."
+    );
+    cy.contains("Learn more about Login.gov");
+  });
+
+  it("Has a Login.gov button", () => {
+    cy.contains("Continue with Login.gov");
+  });
+});
diff --git a/tests/cypress/specs/ui/eligibility.spec.js b/tests/cypress/specs/ui/eligibility-no-auth.spec.js
similarity index 85%
rename from tests/cypress/specs/ui/eligibility.spec.js
rename to tests/cypress/specs/ui/eligibility-no-auth.spec.js
--- a/tests/cypress/specs/ui/eligibility.spec.js
+++ b/tests/cypress/specs/ui/eligibility-no-auth.spec.js
@@ -60,14 +60,19 @@ describe("Multiple Verifier, no AuthProvider: Verifier selection page spec", ()
 describe("Multiple verifier, no AuthProvider: Eligibility confirmation form spec", () => {
   beforeEach(() => {
     cy.visit("/");
+    // Selecting ABC will go down the multiple verifier flow
     cy.contains(agencies[0].fields.short_name).click();
     cy.contains("Get started").click();
+    // Selecting last radio button, MST Courtesy Cardholder will go down flow without authorization step
     cy.get("input:radio").last().click();
     cy.contains("Continue").click();
-    cy.contains("You’ll need two things before we get started:");
   });
 
   it("Has a Courtesy Card number form label and corresponding field", () => {
+    cy.contains(
+      "You’ll need to do two things to link your transit discount to your bank card."
+    );
+    cy.get(".media-list").children().should("have.length", 2);
     cy.contains("Continue").click();
     cy.get("input:focus").should("have.length", 0);
     cy.contains("MST Courtesy Card number *").click();
@@ -77,6 +82,8 @@ describe("Multiple verifier, no AuthProvider: Eligibility confirmation form spec
   });
 
   it("Has a last name form label and corresponding form field", () => {
+    cy.contains("Your MST Courtesy Card");
+    cy.contains("An active card that has not expired");
     cy.contains("Continue").click();
     cy.get("input:focus").should("have.length", 0);
     cy.contains("Last name (as it appears on Courtesy Card) *").click();
@@ -85,18 +92,3 @@ describe("Multiple verifier, no AuthProvider: Eligibility confirmation form spec
     cy.url().should("include", eligibility_confirm_url);
   });
 });
-
-describe("Multiple verifier, with AuthProvider: Eligibility start page spec", () => {
-  beforeEach(() => {
-    cy.visit("/");
-    cy.contains(agencies[0].fields.short_name).click();
-    cy.contains("Get started").click();
-    cy.get("input:radio").first().click();
-    cy.contains("Continue").click();
-    cy.url().should("include", eligibility_start_url);
-  });
-
-  it.skip("Has a Login.gov button", () => {
-    cy.contains("Continue with Login.gov");
-  });
-});