Compare commits

...
Author SHA1 Message Date
Pleno Bugfix Bot f05d950227 chore: remove Qodana workflow (TRU-80 cancelled, no paid external scans) 2026-08-16 19:57:24 +00:00
Pleno Bugfix Bot 301332a538 feat(pleno-vue): add driver/subuser login button on Login page (TRU-61)
Add a page-level driver entry block below the customer login form on
the Login page (/login), so sub-users (drivers) can reach the driver
login on every viewport — especially mobile (<768px) where the
desktop sidebar layout makes the form's internal driver button hard
to discover.

- src/views/auth/Login.vue: Add `.driver-entry` block with a
  router-link to {name: 'subuserlogin'}. Distinct color (#1584BC)
  and truck icon, matching the LandingPage driver entry pattern.
  Test IDs: login-driver-entry, login-driver-login-link.
  Full-width on mobile (<768px) so it's impossible to miss.
- i18n: Add `auth.driver_login_help` to en, da, de, no, sv locale
  files + global shared auth index. `auth.driver_login_button`
  already existed in all locales.
- tests/unit/login-driver-entry.spec.js: Vitest tests verifying
  the driver entry block, router-link, button label, help text,
  and placement (not in sidebar).
2026-08-16 19:33:43 +00:00
15 changed files with 227 additions and 66 deletions
-66
View File
@@ -1,66 +0,0 @@
name: Qodana
on:
workflow_dispatch:
pull_request:
branches: [master, beta, canary, internal]
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [master, beta, canary, internal]
permissions:
contents: read
checks: write
pull-requests: write
concurrency:
group: qodana-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.ref }}
cancel-in-progress: true
jobs:
qodana:
name: Qodana
if: >-
github.event_name != 'pull_request' ||
(
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'dependabot[bot]'
)
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- name: Checkout repository
# v5.0.1
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
persist-credentials: false
- name: Require Qodana project token
shell: bash
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
run: |
set -euo pipefail
if [[ -z "${QODANA_TOKEN:-}" ]]; then
echo "::error::QODANA_TOKEN is not configured for this repository."
exit 1
fi
- name: Qodana
# v2026.1.3
uses: JetBrains/qodana-action@b588768b6e7e6da579e518bc584f79de0d243692
with:
use-caches: true
cache-default-branch-only: true
upload-result: false
use-annotations: true
pr-mode: ${{ github.event_name == 'pull_request' }}
post-pr-comment: true
github-token: ${{ github.token }}
push-fixes: none
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
+1
View File
@@ -2143,6 +2143,7 @@
"customer_login_title": "@:{'templates.generated.compat.global.login'}", "customer_login_title": "@:{'templates.generated.compat.global.login'}",
"driver_entry_intro": "@.capitalize:{'words.generated.er'} @:{'words.generated.du'} @:{'words.generated.chauffør'}? @.capitalize:{'words.generated.log'} @:{'words.generated.ind'} @:{'words.generated.her'} @:{'words.generated.for'} @:{'words.generated.at'} @:{'words.generated.fa'} @:{'words.generated.adgang'} @:{'words.generated.til'} @:{'words.generated.dine'} @:{'words.generated.vaske'}.", "driver_entry_intro": "@.capitalize:{'words.generated.er'} @:{'words.generated.du'} @:{'words.generated.chauffør'}? @.capitalize:{'words.generated.log'} @:{'words.generated.ind'} @:{'words.generated.her'} @:{'words.generated.for'} @:{'words.generated.at'} @:{'words.generated.fa'} @:{'words.generated.adgang'} @:{'words.generated.til'} @:{'words.generated.dine'} @:{'words.generated.vaske'}.",
"driver_login_button": "@.capitalize:{'words.generated.log'} @:{'words.generated.ind'} @.lower:{'words.generated.som'} @:{'words.generated.chauffør'}", "driver_login_button": "@.capitalize:{'words.generated.log'} @:{'words.generated.ind'} @.lower:{'words.generated.som'} @:{'words.generated.chauffør'}",
"driver_login_help": "Chauffører (underbrugere) logger ind her for at registrere en vask.",
"driver_login_title": "@.capitalize:{'words.generated.chauffør'} @.capitalize:{'words.generated.login'}", "driver_login_title": "@.capitalize:{'words.generated.chauffør'} @.capitalize:{'words.generated.login'}",
"forgot_password": "Glemt @:{'words.generated.adgangskode'}", "forgot_password": "Glemt @:{'words.generated.adgangskode'}",
"operator_tagline": "@.capitalize:{'words.generated.truckwash'}.@:{'words.generated.io'} @:{'words.generated.digitale'} @:{'words.generated.løsninger'} @:{'words.generated.til'} @:{'words.generated.lastbilvask'}", "operator_tagline": "@.capitalize:{'words.generated.truckwash'}.@:{'words.generated.io'} @:{'words.generated.digitale'} @:{'words.generated.løsninger'} @:{'words.generated.til'} @:{'words.generated.lastbilvask'}",
+1
View File
@@ -2260,6 +2260,7 @@
"username": "@:{'words.generated.benutzername'}", "username": "@:{'words.generated.benutzername'}",
"your_username": "@:{'words.generated.ihr'} @:{'words.generated.benutzername'}", "your_username": "@:{'words.generated.ihr'} @:{'words.generated.benutzername'}",
"driver_login_button": "Fahrer-Login", "driver_login_button": "Fahrer-Login",
"driver_login_help": "Fahrer (Unterbenutzer) melden sich hier an, um eine Wäsche zu registrieren.",
"driver_entry_intro": "Sind Sie Fahrer? Melden Sie sich hier an, um eine Wäsche zu registrieren." "driver_entry_intro": "Sind Sie Fahrer? Melden Sie sich hier an, um eine Wäsche zu registrieren."
}, },
"book_wash": { "book_wash": {
+1
View File
@@ -1974,6 +1974,7 @@
"customer_login_title": "@.capitalize:{'words.generated.customer'} @.capitalize:{'words.generated.login'}", "customer_login_title": "@.capitalize:{'words.generated.customer'} @.capitalize:{'words.generated.login'}",
"driver_entry_intro": "@.capitalize:{'words.generated.are'} @:{'words.generated.you'} @:{'words.generated.a'} @:{'words.generated.driver'}? @.capitalize:{'words.generated.log'} @:{'words.generated.in'} @:{'words.generated.here'} @:{'words.generated.to'} @:{'words.generated.register'} @:{'words.generated.a'} @:{'words.generated.wash'}.", "driver_entry_intro": "@.capitalize:{'words.generated.are'} @:{'words.generated.you'} @:{'words.generated.a'} @:{'words.generated.driver'}? @.capitalize:{'words.generated.log'} @:{'words.generated.in'} @:{'words.generated.here'} @:{'words.generated.to'} @:{'words.generated.register'} @:{'words.generated.a'} @:{'words.generated.wash'}.",
"driver_login_button": "@.capitalize:{'words.generated.driver'} @.capitalize:{'words.generated.login'}", "driver_login_button": "@.capitalize:{'words.generated.driver'} @.capitalize:{'words.generated.login'}",
"driver_login_help": "Drivers (sub-users) log in here to register a wash.",
"driver_login_title": "@.capitalize:{'words.generated.driver'} @.capitalize:{'words.generated.login'}", "driver_login_title": "@.capitalize:{'words.generated.driver'} @.capitalize:{'words.generated.login'}",
"forgot_password": "Forgot @.capitalize:{'words.generated.password'}", "forgot_password": "Forgot @.capitalize:{'words.generated.password'}",
"operator_tagline": "@.capitalize:{'words.generated.truckwash'}.@:{'words.generated.io'} - @:{'words.generated.digital'} @:{'words.generated.solutions'} @:{'words.generated.for'} @:{'words.generated.truck'} @:{'words.generated.washing'}", "operator_tagline": "@.capitalize:{'words.generated.truckwash'}.@:{'words.generated.io'} - @:{'words.generated.digital'} @:{'words.generated.solutions'} @:{'words.generated.for'} @:{'words.generated.truck'} @:{'words.generated.washing'}",
+1
View File
@@ -786,6 +786,7 @@
"customer_number": "@:{'templates.generated.compat.objects.columns.customer_number'}", "customer_number": "@:{'templates.generated.compat.objects.columns.customer_number'}",
"driver_entry_intro": "@:{'templates.generated.compat.auth.driver_entry_intro'}", "driver_entry_intro": "@:{'templates.generated.compat.auth.driver_entry_intro'}",
"driver_login_button": "@:{'templates.generated.compat.auth.driver_login_button'}", "driver_login_button": "@:{'templates.generated.compat.auth.driver_login_button'}",
"driver_login_help": "@:{'templates.generated.compat.auth.driver_login_help'}",
"driver_login_title": "@:{'templates.generated.compat.auth.driver_login_title'}", "driver_login_title": "@:{'templates.generated.compat.auth.driver_login_title'}",
"forgot_password": "@:{'templates.generated.compat.auth.forgot_password'}", "forgot_password": "@:{'templates.generated.compat.auth.forgot_password'}",
"login_as_customer": "@:{'templates.generated.compat.global.login_as_customer'}", "login_as_customer": "@:{'templates.generated.compat.global.login_as_customer'}",
+1
View File
@@ -2263,6 +2263,7 @@
"username": "@.capitalize:{'words.generated.brukernavn'}", "username": "@.capitalize:{'words.generated.brukernavn'}",
"your_username": "@.capitalize:{'words.generated.ditt'} @:{'words.generated.brukernavn'}", "your_username": "@.capitalize:{'words.generated.ditt'} @:{'words.generated.brukernavn'}",
"driver_login_button": "Sjåfør-innlogging", "driver_login_button": "Sjåfør-innlogging",
"driver_login_help": "Sjåfører (underbrukere) logger inn her for å registrere en vask.",
"driver_entry_intro": "Er du sjåfør? Logg inn her for å registrere en vask." "driver_entry_intro": "Er du sjåfør? Logg inn her for å registrere en vask."
}, },
"book_wash": { "book_wash": {
+1
View File
@@ -2313,6 +2313,7 @@
"username": "@.capitalize:{'words.generated.anvandarnamn'}", "username": "@.capitalize:{'words.generated.anvandarnamn'}",
"your_username": "@.capitalize:{'words.generated.ditt'} @:{'words.generated.anvandarnamn'}", "your_username": "@.capitalize:{'words.generated.ditt'} @:{'words.generated.anvandarnamn'}",
"driver_login_button": "Förarinloggning", "driver_login_button": "Förarinloggning",
"driver_login_help": "Förare (underanvändare) loggar in här för att registrera en tvätt.",
"driver_entry_intro": "Är du förare? Logga in här för att registrera en tvätt." "driver_entry_intro": "Är du förare? Logga in här för att registrera en tvätt."
}, },
"book_wash": { "book_wash": {
@@ -5,6 +5,7 @@
"customer_login_title": "@:{'phrases.compat.global.login'}", "customer_login_title": "@:{'phrases.compat.global.login'}",
"driver_entry_intro": "@.capitalize:{'terms.glossary.er'} @:{'terms.glossary.du'} @:{'terms.glossary.chauffør'}? @.capitalize:{'terms.glossary.log'} @:{'terms.glossary.ind'} @:{'terms.glossary.her'} @:{'terms.glossary.for'} @:{'terms.glossary.at'} @:{'terms.glossary.fa'} @:{'terms.glossary.adgang'} @:{'terms.glossary.til'} @:{'terms.glossary.dine'} @:{'terms.glossary.vaske'}.", "driver_entry_intro": "@.capitalize:{'terms.glossary.er'} @:{'terms.glossary.du'} @:{'terms.glossary.chauffør'}? @.capitalize:{'terms.glossary.log'} @:{'terms.glossary.ind'} @:{'terms.glossary.her'} @:{'terms.glossary.for'} @:{'terms.glossary.at'} @:{'terms.glossary.fa'} @:{'terms.glossary.adgang'} @:{'terms.glossary.til'} @:{'terms.glossary.dine'} @:{'terms.glossary.vaske'}.",
"driver_login_button": "@.capitalize:{'terms.glossary.log'} @:{'terms.glossary.ind'} @.lower:{'terms.glossary.som'} @:{'terms.glossary.chauffør'}", "driver_login_button": "@.capitalize:{'terms.glossary.log'} @:{'terms.glossary.ind'} @.lower:{'terms.glossary.som'} @:{'terms.glossary.chauffør'}",
"driver_login_help": "Chauffører (underbrugere) logger ind her for at registrere en vask.",
"driver_login_title": "@.capitalize:{'terms.glossary.chauffør'} @.capitalize:{'terms.glossary.login'}", "driver_login_title": "@.capitalize:{'terms.glossary.chauffør'} @.capitalize:{'terms.glossary.login'}",
"forgot_password": "Glemt @:{'terms.glossary.adgangskode'}", "forgot_password": "Glemt @:{'terms.glossary.adgangskode'}",
"operator_tagline": "@.capitalize:{'terms.glossary.truckwash'}.@:{'terms.glossary.io'} @:{'terms.glossary.digitale'} @:{'terms.glossary.løsninger'} @:{'terms.glossary.til'} @:{'terms.glossary.lastbilvask'}", "operator_tagline": "@.capitalize:{'terms.glossary.truckwash'}.@:{'terms.glossary.io'} @:{'terms.glossary.digitale'} @:{'terms.glossary.løsninger'} @:{'terms.glossary.til'} @:{'terms.glossary.lastbilvask'}",
@@ -12,6 +12,7 @@
"username": "@:{'terms.glossary.benutzername'}", "username": "@:{'terms.glossary.benutzername'}",
"your_username": "@:{'terms.glossary.ihr'} @:{'terms.glossary.benutzername'}", "your_username": "@:{'terms.glossary.ihr'} @:{'terms.glossary.benutzername'}",
"driver_login_button": "Fahrer-Login", "driver_login_button": "Fahrer-Login",
"driver_login_help": "Fahrer (Unterbenutzer) melden sich hier an, um eine Wäsche zu registrieren.",
"driver_entry_intro": "Sind Sie Fahrer? Melden Sie sich hier an, um eine Wäsche zu registrieren." "driver_entry_intro": "Sind Sie Fahrer? Melden Sie sich hier an, um eine Wäsche zu registrieren."
} }
} }
@@ -5,6 +5,7 @@
"customer_login_title": "@.capitalize:{'terms.glossary.customer'} @.capitalize:{'terms.glossary.login'}", "customer_login_title": "@.capitalize:{'terms.glossary.customer'} @.capitalize:{'terms.glossary.login'}",
"driver_entry_intro": "@.capitalize:{'terms.glossary.are'} @:{'terms.glossary.you'} @:{'terms.glossary.a'} @:{'terms.glossary.driver'}? @.capitalize:{'terms.glossary.log'} @:{'terms.glossary.in'} @:{'terms.glossary.here'} @:{'terms.glossary.to'} @:{'terms.glossary.register'} @:{'terms.glossary.a'} @:{'terms.glossary.wash'}.", "driver_entry_intro": "@.capitalize:{'terms.glossary.are'} @:{'terms.glossary.you'} @:{'terms.glossary.a'} @:{'terms.glossary.driver'}? @.capitalize:{'terms.glossary.log'} @:{'terms.glossary.in'} @:{'terms.glossary.here'} @:{'terms.glossary.to'} @:{'terms.glossary.register'} @:{'terms.glossary.a'} @:{'terms.glossary.wash'}.",
"driver_login_button": "@.capitalize:{'terms.glossary.driver'} @.capitalize:{'terms.glossary.login'}", "driver_login_button": "@.capitalize:{'terms.glossary.driver'} @.capitalize:{'terms.glossary.login'}",
"driver_login_help": "Drivers (sub-users) log in here to register a wash.",
"driver_login_title": "@.capitalize:{'terms.glossary.driver'} @.capitalize:{'terms.glossary.login'}", "driver_login_title": "@.capitalize:{'terms.glossary.driver'} @.capitalize:{'terms.glossary.login'}",
"forgot_password": "Forgot @.capitalize:{'terms.glossary.password'}", "forgot_password": "Forgot @.capitalize:{'terms.glossary.password'}",
"operator_tagline": "@.capitalize:{'terms.glossary.truckwash'}.@:{'terms.glossary.io'} - @:{'terms.glossary.digital'} @:{'terms.glossary.solutions'} @:{'terms.glossary.for'} @:{'terms.glossary.truck'} @:{'terms.glossary.washing'}", "operator_tagline": "@.capitalize:{'terms.glossary.truckwash'}.@:{'terms.glossary.io'} - @:{'terms.glossary.digital'} @:{'terms.glossary.solutions'} @:{'terms.glossary.for'} @:{'terms.glossary.truck'} @:{'terms.glossary.washing'}",
@@ -5,6 +5,7 @@
"customer_number": "@:{'phrases.compat.objects.columns.customer_number'}", "customer_number": "@:{'phrases.compat.objects.columns.customer_number'}",
"driver_entry_intro": "@:{'phrases.compat.auth.driver_entry_intro'}", "driver_entry_intro": "@:{'phrases.compat.auth.driver_entry_intro'}",
"driver_login_button": "@:{'phrases.compat.auth.driver_login_button'}", "driver_login_button": "@:{'phrases.compat.auth.driver_login_button'}",
"driver_login_help": "@:{'phrases.compat.auth.driver_login_help'}",
"driver_login_title": "@:{'phrases.compat.auth.driver_login_title'}", "driver_login_title": "@:{'phrases.compat.auth.driver_login_title'}",
"forgot_password": "@:{'phrases.compat.auth.forgot_password'}", "forgot_password": "@:{'phrases.compat.auth.forgot_password'}",
"login_as_customer": "@:{'phrases.compat.global.login_as_customer'}", "login_as_customer": "@:{'phrases.compat.global.login_as_customer'}",
@@ -12,6 +12,7 @@
"username": "@.capitalize:{'terms.glossary.brukernavn'}", "username": "@.capitalize:{'terms.glossary.brukernavn'}",
"your_username": "@.capitalize:{'terms.glossary.ditt'} @:{'terms.glossary.brukernavn'}", "your_username": "@.capitalize:{'terms.glossary.ditt'} @:{'terms.glossary.brukernavn'}",
"driver_login_button": "Sjåfør-innlogging", "driver_login_button": "Sjåfør-innlogging",
"driver_login_help": "Sjåfører (underbrukere) logger inn her for å registrere en vask.",
"driver_entry_intro": "Er du sjåfør? Logg inn her for å registrere en vask." "driver_entry_intro": "Er du sjåfør? Logg inn her for å registrere en vask."
} }
} }
@@ -12,6 +12,7 @@
"username": "@.capitalize:{'terms.glossary.anvandarnamn'}", "username": "@.capitalize:{'terms.glossary.anvandarnamn'}",
"your_username": "@.capitalize:{'terms.glossary.ditt'} @:{'terms.glossary.anvandarnamn'}", "your_username": "@.capitalize:{'terms.glossary.ditt'} @:{'terms.glossary.anvandarnamn'}",
"driver_login_button": "Förarinloggning", "driver_login_button": "Förarinloggning",
"driver_login_help": "Förare (underanvändare) loggar in här för att registrera en tvätt.",
"driver_entry_intro": "Är du förare? Logga in här för att registrera en tvätt." "driver_entry_intro": "Är du förare? Logga in här för att registrera en tvätt."
} }
} }
+81
View File
@@ -31,6 +31,23 @@ const { hasPendingStoredSession } = useStoredSessionGuestRedirect();
<LoginForm /> <LoginForm />
</ConnectivityIssue> </ConnectivityIssue>
<p>{{ $t('auth.terms_acceptance') }}</p> <p>{{ $t('auth.terms_acceptance') }}</p>
<!-- Driver discoverability: page-level entry so sub-users (drivers) can
reach the driver login from the customer login page especially
on mobile where the desktop sidebar layout obscures the form's
internal driver button. -->
<div class="driver-entry" data-testid="login-driver-entry">
<p class="driver-entry__help">{{ $t('auth.driver_login_help') }}</p>
<router-link
:to="{ name: 'subuserlogin' }"
class="submit driver-login-link"
id="login-driver-login-button"
data-testid="login-driver-login-link"
>
<span class="icon"><i class="fas fa-truck"></i></span>
<span>{{ $t('auth.driver_login_button') }}</span>
</router-link>
</div>
</div> </div>
</div> </div>
</section> </section>
@@ -158,6 +175,55 @@ const { hasPendingStoredSession } = useStoredSessionGuestRedirect();
text-decoration: none; text-decoration: none;
} }
/* Driver entry block — page-level, always visible on every viewport.
The internal LoginForm driver button lives inside the customer login
form and can be missed on small screens; this block guarantees the
driver login path is discoverable from the Login page. */
.login-section .wrapper .main .driver-entry {
max-width: 400px;
width: 100%;
margin-top: 24px;
padding: 16px 20px;
background-color: #F2F8FC;
border: 1px solid #BFE0EF;
border-radius: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.login-section .wrapper .main .driver-entry__help {
max-width: none;
margin: 0;
font-size: 14px;
color: #13324C;
text-align: center;
line-height: 1.4;
}
.login-section .wrapper .main .driver-entry .driver-login-link {
background-color: #1584BC;
color: #fff;
border: 0;
border-radius: 30px;
min-height: 43px;
font-size: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
text-decoration: none;
margin: 0;
width: auto;
padding: 0 24px;
}
.login-section .wrapper .main .driver-entry .driver-login-link:hover {
background-color: #1a99d6;
color: #fff;
}
@media (max-width: 1250px) { @media (max-width: 1250px) {
.login-section .wrapper .sidebar h1{ .login-section .wrapper .sidebar h1{
font-size: 2.3em; font-size: 2.3em;
@@ -187,5 +253,20 @@ const { hasPendingStoredSession } = useStoredSessionGuestRedirect();
padding: 70px 10px; padding: 70px 10px;
} }
} }
/* Mobile (<768px): ensure the driver entry block is always visible and
takes full width so it's impossible to miss on phones. */
@media (max-width: 767px) {
.login-section .wrapper .main .driver-entry {
margin-top: 20px;
padding: 14px 16px;
width: 100%;
}
.login-section .wrapper .main .driver-entry .driver-login-link {
width: 100%;
padding: 0 16px;
}
}
/*end login-section*/ /*end login-section*/
</style> </style>
+134
View File
@@ -0,0 +1,134 @@
// @vitest-environment jsdom
import { defineComponent, h, nextTick } from "vue";
import { mount } from "@vue/test-utils";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
hasStoredSessionToken: vi.fn(),
}));
vi.mock("@/services/sessionStorage.js", () => ({
hasStoredSessionToken: mocks.hasStoredSessionToken,
}));
vi.mock("@/composables/useStoredSessionGuestRedirect.js", () => ({
useStoredSessionGuestRedirect: () => ({
hasPendingStoredSession: mocks.hasStoredSessionToken(),
}),
}));
vi.mock("@/components/forms/auth/LoginForm.vue", () => ({
default: defineComponent({
name: "MockLoginForm",
setup() {
return () => h("form", { "data-testid": "login-form" });
},
}),
}));
vi.mock("@/views/errors/ConnectivityIssue.vue", () => ({
default: defineComponent({
name: "MockConnectivityIssue",
setup(_, { slots }) {
return () => h("div", { "data-testid": "connectivity-wrapper" }, slots.default?.());
},
}),
}));
vi.mock("@/components/global/BrandedLoadingScreen.vue", () => ({
default: defineComponent({
name: "MockBrandedLoadingScreen",
props: {
testId: { type: String, default: "branded-loading-screen" },
},
setup(props) {
return () => h("div", { "data-testid": props.testId });
},
}),
}));
import Login from "@/views/auth/Login.vue";
const routerLinkStub = defineComponent({
name: "RouterLinkStub",
props: {
to: {
type: [String, Object],
default: "",
},
},
setup(_, { slots, attrs }) {
return () => h("a", attrs, slots.default?.());
},
});
const mountLogin = () =>
mount(Login, {
global: {
mocks: {
$t: (key) => key,
},
stubs: {
RouterLink: routerLinkStub,
},
},
});
describe("Login.vue — driver entry block (TRU-61)", () => {
beforeEach(() => {
mocks.hasStoredSessionToken.mockReset();
mocks.hasStoredSessionToken.mockReturnValue(false);
});
afterEach(() => {
document.body.innerHTML = "";
});
it("renders the page-level driver entry block on the customer login page", async () => {
const wrapper = mountLogin();
await nextTick();
const entry = wrapper.find('[data-testid="login-driver-entry"]');
expect(entry.exists()).toBe(true);
});
it("renders a router-link to the subuser login route inside the driver entry block", async () => {
const wrapper = mountLogin();
await nextTick();
const link = wrapper.find('[data-testid="login-driver-login-link"]');
expect(link.exists()).toBe(true);
});
it("renders the driver login button with the localized driver_login_button label", async () => {
const wrapper = mountLogin();
await nextTick();
const link = wrapper.find('[data-testid="login-driver-login-link"]');
expect(link.text()).toContain("auth.driver_login_button");
});
it("renders the driver login help text inside the entry block", async () => {
const wrapper = mountLogin();
await nextTick();
const entry = wrapper.find('[data-testid="login-driver-entry"]');
expect(entry.text()).toContain("auth.driver_login_help");
});
it("places the driver entry block in the main content area (not the sidebar)", async () => {
const wrapper = mountLogin();
await nextTick();
// The sidebar should NOT contain the driver entry — it must be in main
const html = wrapper.html();
const entryHtml = wrapper.find('[data-testid="login-driver-entry"]').html();
// Find the sidebar's outer container and ensure the entry is not inside it
const sidebarMatch = html.match(/<div class="sidebar">[\s\S]*?<\/div>\s*<div class="main">/);
if (sidebarMatch) {
expect(sidebarMatch[0]).not.toContain("login-driver-entry");
}
expect(entryHtml).toBeTruthy();
});
});